A few months ago I was feeling inspired to create a nice countdown timer. With the next Dorkbot open mic only days away, I finally had the motivation to actually put it together...
Click "Read more" for photos, source code, schematic and other info.
Here's what the back side looks like....
The green buttons starts & stops the countdown. The 2 blue buttons add or substract 1 minute. It's a very simple and minimal user interface!
Here's a rough schematic for the whole project. Well, except I left off the 7805 regulator and maybe some other mundane stuff, but this is pretty close.
The main challenge was driving the LEDs with a constant current, because they need about 10.5 volts across the several series LEDs. I wanted to run from 12 volts, so there wasn't much voltage left over for the normal current limiting resistors. Instead, I used this opamp circuit.
(edit: opps, I wrote LM358A on the schematic, but it's actually a LM324A opamp. Really, they're the same, just 2 vs 4 per package... so you could use either if you try to build this on your own board, but if you use the PCB files below, get a 14 pin LM324A opamps)
The project runs from a Teensy 2.0. The code is very simple, using the SPI and Bounce libraries for the hardware interfacing.
#include <SPI.h> #include <Bounce.h> // pins // 0 - Latch // 1 - Clock // 2 - Data // 4 - Enable (low=on) // 9 - Dots (high=on) Bounce button1 = Bounce(10, 12); Bounce button2 = Bounce(23, 12); Bounce button3 = Bounce(22, 12); uint8_t min=5; uint8_t sec=0; uint8_t unused_pins[] = {3,5,6,7,8,11,12,13,14,15,16,17,18,19,20,21,24}; void setup() { for (uint8_t i=0; i < sizeof(unused_pins); i++) { pinMode(i, OUTPUT); digitalWrite(i, LOW); } pinMode(10, INPUT_PULLUP); PORTC |= 0x80; pinMode(22, INPUT_PULLUP); pinMode(23, INPUT_PULLUP); digitalWrite(4, HIGH); pinMode(0, OUTPUT); pinMode(1, OUTPUT); pinMode(2, OUTPUT); pinMode(4, OUTPUT); pinMode(9, OUTPUT); digitalWrite(0, LOW); digitalWrite(1, LOW); digitalWrite(2, LOW); digitalWrite(4, HIGH); digitalWrite(9, LOW); SPI.begin(); update(); } uint8_t sevenseg[10] = { // gfedcba 0b00111111, // aaa 0b00000110, // f b 0b01011011, // f b 0b01001111, // ggg 0b01100110, // e c 0b01101101, // e c 0b01111101, // ddd 0b00000111, 0b01111111, 0b01101111 }; void update(void) { if (min > 99) min == 99; if (sec > 59) sec = 59; SPI.transfer(min >= 10 ? sevenseg[min/10] : 0); SPI.transfer(min > 0 ? sevenseg[min%10] : 0); SPI.transfer(sevenseg[sec/10]); SPI.transfer(sevenseg[sec%10]); delayMicroseconds(2); digitalWrite(0, LOW); delayMicroseconds(2); digitalWrite(0, HIGH); digitalWrite(9, HIGH); digitalWrite(4, LOW); delayMicroseconds(5); digitalWrite(0, LOW); } elapsedMillis count = 0; uint8_t running = 0; void loop() { button1.update(); button2.update(); button3.update(); if (button1.fallingEdge()) { Serial.println("button1 - Start/Stop"); if (running) { running = 0; } else { running = 1; count = 750; } } if (button2.fallingEdge()) { Serial.println("button2 - Add 1 minute"); if (min < 99) { min++; update(); } } if (button3.fallingEdge()) { Serial.println("button3 - Subtract 1 minute"); if (min > 0) { min--; } else { sec = 0; running = 0; } update(); } if (running && count >= 1000) { count -= 1000; if (sec > 0) { sec--; } else { if (min > 0) { min--; sec = 59; } else { running = 0; } } update(); } }
The 7 segment displays were something I'd purchased from an E-bay merchant about a year ago. I can't find then anymore, which is sad because they were really cheap.
I actually created this PCB only days after the last Dorkbot open mic. Here's a photo of the board.
There's actually quite a few parts on the board. Here are the placement diagrams:
I'll attach the PCB gerber files. I also have 2 extra boards left over, which I'll toss in the Dorkbot free parts pool. If anyone grabs them for a real project, hopefully this info will help.