My first adventure in PCB production
March 14th, 2010
After being a member of PING for a while I got more and more interested in electronics and microcontroller programming. As I didn’t own a standalone digital clock, I decided to make one myself. We had all the necessary components: Seven-segment displays, a microcontroller and appropriate resistors.
Prototyping
Multiplexing the displays
I connected every segment on all the displays to pins on the controller, and the ground pin of each display to their own pins on the controller, as seen here:
To give the illusion that all the displays are on, I quickly connect the ground pin of the first display to GND, and the active segment pins to VCC, disconnect the ground pin of the first display, and then repeat the procedure for each display forever.
Programming the controller
Updating the display
I constantly update the displays:
while(1)
{
putdigit(DISP_0, hours/10, seconds & 32);
putdigit(DISP_1, hours%10, seconds & 16);
putdigit(DISP_2, minutes/10, seconds & 8);
putdigit(DISP_3, minutes%10, seconds & 4);
putdigit(DISP_4, seconds/10, seconds & 2);
putdigit(DISP_5, seconds%10, seconds & 1);
}
putdigit updates each display:
static void putdigit(uint8_t display, uint8_t digit, uint8_t dot)
{
int i;
PORTA = pgm_read_byte(&seg[digit]);
if (dot)
PORTA |= SEG_0;
for (i=DISP_0; i<=DISP_5; ++i)
PORTC |= (1 << i);
PORTC &= ~(1 << display);
_delay_ms(DELAY);
}
The fonts are stored in program memory:
static uint8_t seg[] PROGMEM = {
SEG_1 | SEG_2 | SEG_3 | SEG_5 | SEG_6 | SEG_7,
SEG_1 | SEG_7,
SEG_2 | SEG_3 | SEG_4 | SEG_6 | SEG_7,
SEG_1 | SEG_2 | SEG_4 | SEG_6 | SEG_7,
SEG_1 | SEG_4 | SEG_5 | SEG_7,
SEG_1 | SEG_2 | SEG_4 | SEG_5 | SEG_6,
SEG_1 | SEG_2 | SEG_3 | SEG_4 | SEG_5 | SEG_6,
SEG_1 | SEG_6 | SEG_7,
SEG_1 | SEG_2 | SEG_3 | SEG_4 | SEG_5 | SEG_6 | SEG_7,
SEG_1 | SEG_2 | SEG_4 | SEG_5 | SEG_6 | SEG_7,
SEG_1 | SEG_3 | SEG_4 | SEG_5 | SEG_6 | SEG_7,
SEG_1 | SEG_2 | SEG_3 | SEG_4 | SEG_5,
SEG_2 | SEG_3 | SEG_5 | SEG_6,
SEG_1 | SEG_2 | SEG_3 | SEG_4 | SEG_7,
SEG_2 | SEG_3 | SEG_4 | SEG_5 | SEG_6,
SEG_3 | SEG_4 | SEG_5 | SEG_6,
SEG_3 | SEG_4,
SEG_3 | SEG_4 | SEG_1 | SEG_5,
};
where SEG_? corresponds to these physical segments:
/*
* Segments:
*
* 6
* 5 7
* 4
* 3 1
* 2 0
*/
Timers, buttons and interrupts
Putting the digits on the displays is well enough, but this is a clock, so we want to update the time as well. Enter the timer. I enable the internal timer on the Atmega16, and make it trigger an interrupt every second:
TCCR1B |= (1 << WGM12);
TIMSK |= (1 << OCIE1A);
sei();
OCR1A = 15624;
TCCR1B |= (1 << CS12) | (1 << CS10);
MCUCR |= (1 << ISC11) | (1 << ISC10) | (1 << ISC01) | (1 << ISC00);
GICR |= (1 << INT1) | (1 << INT0);
The interrupts need to be handled, so I make them increment the seconds variable:
ISR(TIMER1_COMPA_vect)
{
++seconds;
if (seconds == 60)
{
seconds = 0;
++minutes;
if (minutes == 60)
{
minutes = 0;
++hours;
if (hours == 24)
hours = 0;
}
}
}
The only thing missing now is a way to set the time. For that, I use one button for incrementing minutes, and one for incrementing hours:
ISR(INT0_vect)
{
hours = (hours + 1) % 24;
}
ISR(INT1_vect)
{
minutes = (minutes + 1) % 60;
}
The final prototype
I hooked a breadboard up to an STK500 developement board, and connected everything together.
The finished product
After a night of etching and soldering, this was the result.


October 16th, 2012 at 6:41 pm
i am building the same clock as you for a semester project i would like a detail explanation of what you did here if that’s possible