My young daughter told me the design she wanted for my pumpkin this year. At the last minute, I decided to add LED eyes.
The LED eyes flashed in three "states". The first state was flashing slowly, the second state was flashing quickly like a strobe, and the third state was blinking one eye then the other eye. Then it just repeated, and both sets of eyes were synchronized.
So, the interesting part of this project occurred after Halloween when made the eyes flash out of synch. First, I used the "SimpleTimer.h" library to schedule when the LED's would turn on and off. I didn't care for the code duplication, and the use of timers made it more difficult to understand. So next, I decided to try creating a Class Object which worked out very well. Both sets of code are attached.
Hardware SetupThe setup of the hardware is simple. I used an Arduino Uno as the controller and simply wanted two sets of eyes for the pumpkin, each set a different color.
I have a breadboard shield on my Uno, just to make it easier. And I later added connection wires to the LED's to reach to the pumpkin eyes.
There is a 220 ohm resister from each pin (red eyes: pins 4 & 6, blue eyes: pins 8 & 10), to the anode (long leg) of each LED, and the cathode (short leg) is wired to ground.
Halloween FlashingMy initial code for flashing the eyes used "delay()" statements and each set of eyes were synchronized. So I don't have to code, but it looked something like this to flash the eyes:
digitalWrite(redEye1, HIGH);
delay(1000);
digitalWrite(redEye1, LOW);
delay(250);
Although it worked for Halloween night, I wanted to be able to flash the eyes out of synch, and with different timings.
Timed FlashingAfter Halloween I decided to remove the "delay()'s" and used the "SimpleTimer.h" library. It worked, but was initially challenging to wrap my head around. Basically, SimpleTimer lets you set times (in milliseconds) when a function will run next.
In the Setup function, I'd set two initial timers:
// set timers for each set of eyes
// parameter 1: time in milliseconds until the function runs
// parameter 2: the function to run
myTimer.setTimeout(100, CheckStateRed);
myTimer.setTimeout(125, CheckStateBlue);
Then each set of eyes has it's own state: 1. blinking slowly, 2. blinking fast, 3. winking. Unfortunately, this requires you to set different functions for each set of eyes (which is why my Class example with way better). The flow of code worked like this:
CheckStateRed() functionWhat state are we in?
- Slow Flash or Fast Flash (just using different lengths of timers)Turn the LED's on or off depending on the last value, then set a new timer to return to this function. When the specified number of slow or fast flashes is done, go to the next state.
- WinkTurn one LED on or off, alternating each time. When the specified number of winks is done, go to the next state (start again at slow flashes).
The full code is attached, but the Class example is much more elegant.
Flashing with ClassIt had been years since I did any Object Oriented Programming (OOP) using classes, but I thought this would be the perfect situation. For those who only use structured programming, I think you'll see the benefit for situations when you want multiple of the same or similar objects (set of eyes).
Basically, for someone to now uses my PumpkinEyes Class, you only have to write minimal code:
// create your redEyes and blueEyes objects from the Class
// and tell them what pins to use for each eye (LED)
PumpkinEyes redEyes(4, 6);
PumpkinEyes blueEyes(8, 10);
void setup() {
// tell each set of eyes the different states, in order, you want them to have
// Parameters (on time, off time, number of flashes)
redEyes.setupBlink(1800, 600, 3); // slow flashing 3 times
redEyes.setupBlink(125, 60, 20); // fast flashing 20 times
redEyes.setupWink(1000, 400, 4); // wink 4 times
blueEyes.setupBlink(1500, 400, 2);
blueEyes.setupWink(800, 500, 3);
}
void loop() {
// run each eye object
redEyes.run();
blueEyes.run();
}
So it would be easy to add green eyes, purple eyes, and several other sets of eyes. It's that easy... well not quite.
But writing the Class code actually isn't very complex. The full code is attached, but a few key points:
- Classes have attributes. So you need two pins (one for each eye), the current state of the eyes (slow blink, winking, etc), and I used an array to hold each "State" structure.
- Then to make the object do something, you need methods or functions. For example, the PumpkinEye constructor (when you first create the redEyes object), sets the Arduino pins to use, sets them for output, and turns off the LED's.
// Constructor to setup the Pumpkin Eyes Object
PumpkinEyes(int pinRightEye, int pinLeftEye) {
this->pinRight = pinRightEye;
this->pinLeft = pinLeftEye;
pinMode(pinRight, OUTPUT);
pinMode(pinLeft, OUTPUT);
digitalWrite(pinRight, LOW);
digitalWrite(pinLeft, LOW);
}
- Each PumpkinEyes object needs to know what state or states to run, and the timing for flashing the LED's. This can only be done once, and in my code I've limited it to five States, but it was a completely arbitrary number. So the code for SetupBlink is as follows:
// Function takes the following parameters
// 1. timeOn = how long the LED's stays ON
// 2. timeOff = how long the LED's are OFF
// 3. numBlinks = number of times in this state (ex. blink 4 times)
setupBlink(unsigned long timeOn, unsigned long timeOff, int numBlinks) {
if (numStates < MAX_STATES) {
// set the State structure
arrayStates[numStates].stateType = STATE_BLINK;
arrayStates[numStates].ledOn = timeOn;
arrayStates[numStates].ledOff = timeOff;
arrayStates[numStates].maxTimes = numBlinks;
numStates++;
}
}
- Then the "redEyes.run()" polls the object in a continuous loop to make it work.
The PumpkinEyes.run() method is where the object checks if it's time to flash the LED's or change states. And this is how each set of eyes can run with different number of states, and different timing for each state. Each object (redEyes, blueEyes) has it's own attributes (pins for LED's, timing for blinking) and basically runs independent of the other objects.
Final ThoughtsThis was more of a coding project then anything. But, hopefully demonstrates the benefits of not using "delay()" in your code and the flexibility of Object Oriented Programming.
Comments
Please log in or sign up to comment.