Sunday, May 10, 2009

Digital Clock

I have finally managed to build my own digital clock. This is basically 4 seven segment LEDs put together and driven by my micro-controller (an ATMega8).

I had been working on this for few weeks now. The difficult part about making this clock was multiplexing 4 seven segment LEDs. Soldering 4 LEDs to suit the multiplexing circuit was a nightmare. Having a printed circuit on a PCB would be the right way to go; but without it, it is clumsy to build clumsier to debug. I spent a considerable amount of time to get this soldering done -- as it has to be really firm, accurate all within a limited space. Me, not being an experienced guy, it was tough for me. See it for yourself.





Other than this there are only two more hurdles to the problem:

1. Timing a second -- this is the crucial part of the project, although not that difficult. Will explain shortly.

2. Multiplexing 4 seven segments -- previously I had done only two; Also to make that dot (separator between hour and minute digits) to blink every second.

Timing a second:
Usually I clock the uC to run at 1MHz, this time I had clocked it to run at 2MHz (though it wasn't necessary, I thought it might be useful to have precise control and more power to drive 4 seven-segs along with running the clock.).

Anyways, I used a 16-bit counter to measure a second. This counter gets incremented on every cycle. ie., on a 2MHz clock, this counter would get incremented 2 million times a second. This was a bit too much for timing, so I configured the prescaler to bring down the clock for the timer by 1/8th (smallest possible) which is 256KHz (2 ^ 18). Incidentally, it is possible to program the uC to notify you on every overflow of this 16bit counter instead of you checking for an overflow everytime. So the overflow routine would get called for every 2 ^ 16 increments of the counter. With the current clock configuration, the overflow routine should get notified 4 times a second -- this seems good enough to time a second. So for every 4th call on this routine, it increments the seconds counter. The rest is obvious.

Here is the code for the overflow routine:

// g_* are global variables.
ISR(TIMER1_OVF_vect)
{
static int t = 0; // no. of times overflow has happened.

t++;
g_dot_point = (t/2); // dot point stays on for half a second and off for half.

if(4 >= t) {
t = 0;

g_ss++; // increment the seconds
if(g_ss > 59) {
g_ss = 0; g_mm++;
}
if(g_mm > 59) {
g_mm = 0; g_hh++;
}
if(g_hh > 23) g_hh = 0;
}
}
Multiplexing the 4 seven-segs:
If you do not know how multiplexing displays work and if you have not read my earlier post, please consider reading it.

This is pretty similar to my earlier multiplexing code -- just an extension. Now there are 8 data pins (one extra now for dot point) and 4 control lines one per 7segment. The multiplexing is done on the overflow interrupt of a different timer (as 4Hz of timer1 is too slow to multiplex 4 seven-segs). The following code should be self-explanatory.


ISR(TIMER0_OVF_vect)
{
static int n = 0; // decides which digit to update now.(right to left, 0 -> 3)
static int tp[4] = {1, 10, 100, 1000};

int cur_time = g_hh*100 + g_mm;

PORTC = 0;

seg7_write_digit_dot( (cur_time / tp[n]) % 10, // manipulate the appropriate digit
(g_dot_point && n == 2)); // 3rd digit -> print dot if req.

PORTC = 1 << n; // select the right digit by sending the correct control line.

n++; // next digit on next overflow.
if(n >= 4) n = 0;
}

One missing piece in this project is the means to configure the time. The amount of benefit that gives did not excite me for the amount of work required to do that. It was kind of boring stuff. So I have now configured the clock to always start at 13.25 (that is the time I was testing this today), so I can just choose to start the clock at the right time, and then on it just runs fine. Anyways, I can reprogram the clock to whatever time I want to start with. :)

Here is the digital clock in action:

No comments:

Post a Comment