This blinkie is still available for purchase. Contact john@DragonflyDIY.com for pricing - special pricing for educational groups and organizations
Bill of materials:
- Circuit board
- tactile switch
- 10K resistor
- 9 LEDs (red)
- CR2032 battery holder and battery
- ATTiny85 microcontroller
- Standard vinyl tag clip
- C source code (if you want to customize)
- HEX file (if you just want to program the chip)
- Gerber files (if you want to have the board made as-is)
- KiCAD files (if you want to modify the board or schematic)
- Schematic in PDF form
- 3D printed holder (optional) - SCAD source and STL to print
Here's the blinkie in the optional 3D printed case that allows it to hang horizontally and protects the back of the board from shorting out. The battery holder must be mounted on the front of the board to use this holder.
Theory of operation:
As you can see from the schematic, 9 LEDs are driven from just 5 I/O lines, and we somehow work the pushbutton switch in there as well. This is done using a method called Charlieplexing (click here for more detailed info). In short, this method takes advantage of two things: LEDs only light up when power is applied in one direction, and the I/O lines can be put into THREE states - positive, ground, and floating (not connected).
If you look at the top two LEDs in the schematic, you'll notice that they're connected to the same wires but in opposite directions. So if you put power on one of those lines and ground on the other, one of the LEDs will light up. Switch those and the other LED will light up. So far, big deal, we're running two LEDs with two wires. However, by adding a third line, you can then connect two more LEDs between the first line and the third one, and two more between the second and third. We're now controlling six LEDs with three wires.
The downside is that while we can light up any single LED we want, we can't light up every LED in whatever order we want (we can't light up BOTH of those top two LEDs at the same time). In order to light up the LEDs we want, we have to flash through them very quickly, fast enough that your eye will think that all the desired LEDs are on at once. Typically faster than 50 times a second is pretty good, the faster the better. This sort of multiplexing is done on almost all display electronics; if you wave an LED clock radio around in front of your face, you'll see that it is flashing. In fact modern LED car taillights when they're in the dimmer modes are flashing and you can sometimes see them as dotted lines if they sweep across your vision quickly.
I should point one thing out, this question comes up frequently. Normally when driving LEDs, you need to limit the current going to them, typically by using a resistor. If you attach an LED to a power source that can deliver a lot of current (such as a large battery or power supply) and do not limit the current, the LED will quickly overheat and burn out. However, in the case of this circuit, the battery that we are using is not capable of delivering much current - at most about 120 milliamps. In addition, the LEDs are being flashed quickly and are turned on at most about 15% of the time, so they have plenty of time to dissipate any heat that builds up.You'll notice that we only have two choices for an LED - On and Off. But the LEDs can appear to be brighter or dimmer as desired. In order to achieve this, we use a technique called Pulse Width Modulation or PWM. If we want an LED to appear dimmer, we flash it for a shorter amount of time.
PWM is used in a vast number of applications from controlling motors to some types of audio amplifiers (class D amplifiers). Variable speed DC motors almost all use PWM to control speed, and these days with modern digital control, even multiphase AC motors use PWM in their control circuitry.
The software to drive this does get a little complicated. The method used here is to create what's called an interrupt service routine and to set up a timer circuit in the chip so that the routine gets called frequently - ideally about 1000 times a second. Each time the routine gets called, it updates the LED drivers to the next state.
Writing the code with an interrupt service routine really helps simplify things. You can keep all the weird mucking around with the pins to get the right LED to turn on down there, and once it's working you can just concentrate on doing the stuff to make the LED blink in the way you want.
The switch is also read by the display routine since it's attached to one of the display wires. To do this, that pin (PB0) is set into input mode, the internal pull-up resistor (about 10K ohms) is turned on, which without anything going on outside the chip would mean that the input would read "1". However, if someone is pressing the switch, the lead is pulled towards ground with a 5K ohm resistor. This makes the PB0 input read "0" and the software knows someone is pressing the button.
(As an aside, during this phase all the other wires are set into input mode - if they were not, the pull-up resistor on pin PB0 might cause some of the LEDs to glow faintly, causing "ghosting.").
The reason there is a resistor in series with the switch is that since someone may press the button at any time, it might happen that the PB0 line was trying to drive the LED bank at the time and might be driving itself high. If the switch is pressed and shorts it to ground, you're stressing the chip and may damage it.