Introduction: Analog Clock for Graphic LCD

About: I'm mainly interested in music, food and electronics but I like to read and learn about a lot more than that.
Writing a code for an analoge clock may seem a bit of a daunting task. Especially the calculations for the positions of the hands, but it isn't really that hard at all.

In this instructable I will talk a little bit about the theory and then we'll move on to the actual code itself. This was just a project build on the breadboard, while building my wifi radio. It started life as the script for a grafical volume button and ended up as a clock that never made it in the final project but it might come in handy for one of you out there.

My code will be written in Bascom but it will be very easy to translate it into your favorite language once you understand the theory.

Step 1: What Do We Need?

For this instructable, you'll need:

A breadboard
An Atmega16
A grapic LCD (240*128)
A DS1307 Realtime Clock
A 32.768kHz quartz crystal
A 3V battery + holder
Two 4K7 resistors
Two 1K5 resistors
Two pushbuttons
A 10K potentiometer
Your favorite programmer

Step 2: A Bit of Theory.

There are 2 important things we need to agree on, before we start to do some calculations:

Instead of viewing a clock as a set of moving hands, we have to imagine it as a set of concentric circles. A hand is then a line drawn between the centre and a point on one of these circles.

A hand will always be at a certain angle to it's starting point (12 o clock).

If we add a Cartegian coordinate system ( you know, the X axis and Y axis - thingy) and we place the centre of the circle at it's origin (0,0), then we can create a right-angled triangle . The famous greek fellow, Mr Pythagoras, told us that we can determine the lenght of the hypotenuse of a right-angled triangle with the following equation:

a2 + b2 = c2

As the hypotenuse happens to be our radius and the center of the circle is also the origin of the coordinate system, we can state the following:

R2 = X2 + Y2

We know R as it is the radius of our circle. So there has to be a way to calculate X and Y. The only thing that we need for that is some trigonometry.

I could hear some of you moan when hearing the word trigonometry. But trust me it  isn't as difficult as it sounds.

Maybe you remember the mnemonic SOHCAHTOA from your math classes at school. If you also remember what it means , then you know all what you need to know for this. If not, then I'll explain it here.

SOHCAHTOA stands for:

Sine = Opposite/Hypotenuse
Cosine = Adjacent/Hypotenuse
Tangens = Opposite/ Adjacent

For now we can forget about the tangens as we don't need that.

We know that the hypotenuse is the same as our radius so we can swap those. The only thing we need now is an angle to work with. Do we know one? Yes, in fact, we can calculate all three of them if we would like to.
We know for sure that one of them is 90degr. As it is a right-angled triangle but we can't use that one. But, as I said in the beginning, a hand will always be at a certain angle to it's staring point and we can easily calculate that angle.

angle = steps taken * 360(full circle) / max amount of steps

So in case of the seconds and minutes hands this will be:

angle = mins (or secs) * 360 / 60 or angle = mins (or secs) * 6

In case of the hours this will be:

angle = hours * 360 / 12 or angle = hours * 30

This angle is the last thing we needed to calculate X and Y. (if you want to calculate the 3th angle just do 180 minus the two know angles and you have the 3th one).

Lets bring everything together now and fill in what we allready know:

sin angle = opposite/radius
cos angle = adjacent/radius

As the vertex of the angle is the same as the origin of the coordinate system:

sin angle = y/radius
cos angle = x/radius

or

x = radius * cos angle
y = radius * sin angle

But what if the vertex of the angle is not situated at the origin? Then we have to take the coordinates of that point into the equation.

x = a + radius * cos angle
y = b + radius * sin angle
So now we know the coordinates ofthe endpoint of our hand!


Well........Euhh........ not quite yet...... there is a slight problem:

If you would write a code with these equations you would get a clock that starts at 3 o clock and runs counterclockwise. That is because our angular calculations are in relation to the X-axis and those we need for the clock should be in relation to the Y-axis. Luckely with a bit of mathematical magic, this problem is solved very quickly:

x = a + radius * sin angle
y = b - radius * cos angle

What happened here is that we swapped the relation to the axis by swapping sin and cos and we changed the direction from counterclockwise to clockwise by changing + to -.

This was the theory, in the next steps we'll put that into practice.


Step 3: Building the Circuit.

To drive the LCD I've used porta of the atmega16 for transferring the data and portc.2 to portc.7 for control. Don't forget to add the 10K potentiometer for the contrast.

You will have to look up the exact way to connect your LCD in its datasheet, as all LCD's are different.

Pinc.0 and pinc.1 are used for the I2C connection with the DS1307. These lines need the 4K7 pullup resistor.

The two pushbuttons ar connected to INT0 and INT1 an need both a 1K5 pullup resistor.

Step 4: Let's Do a Bit of Code

Ok, let's do some code. As I said in the intro, I'll write my code in bascom but it should be easy to translate it to your favorite language.

We'll write the code for the seconds hand.

Temp = Secs * Div                                Div will be 6
Angle_rad = Deg2rad(Temp)             Converts an angle in to radians
Sinangle = Sin(angle_rad) 
Cosangle = Cos(angle_rad)
Temp = Radius * Sinangle                 Don't take the radius to small, a bigger radius wil give a nicer clock
Xsecond = centerx + Temp                 Centerx is the x value of the center of your clock
Temp = radius * Cosangle
Ysecond = centery - Temp                  Centery is the y value of the center of your clock
Xsecond = Round(xsecond)              Rounds the results
Ysecond = Round(ysecond)
X = Int(xsecond)                                    Makes them into an integer
Y = Int(ysecond)

The same code will work for the minutes and for the hours, except that the hours need a Div of 30 instead of 6.

And that's all there is to tell about it. I added a full code for you to download (for bascom in txt) that will display 2 hands (for hours and minutes) and a dot for the seconds.