Welcome to the final episode of the Gyro’clock firmware. In Gyro’clock Firmware 1 we talked about the trigger detection module, and how it figures out when to trigger the time display. In Gyro’clock Firmware 2, we talked about the real time clock module, and how it accurately keeps track of time using the asynchronous timer of the ATmega328p microcontroller. In this episode we are going to learn how to display the time like this with just a row of 7 LEDs:
When someone asks you what time it is, this is how you show it off
Okay let’s break this down; We have a row of 7 LEDs moving in a circle. The LEDs are pointing radially so the movement is always perpendicular to the row. Let’s divide that display into radial segments. Each segment is seven pixels in size. Each pixel is represented by a single LED. So at each time step we decide to either turn on or off each LED. Then we display the LEDs for a bit, and then again change the status of the LEDs. If we do this fast enough and move the row of LEDs while we are doing it, then we can see the whole image at once. I am not going to get into why we see things that way, since that is not the focus of this post. Some call it “persistence of vision”. But I will tell you a neat way to implement this.
The on/off state of the LEDs can be expressed as either a 1 (on) or a 0 (off). So at a particular time step the LED sequence might look like: 1001110, where LEDs 2,3,4 and 7 are on, while LEDs 1,5 and 6 are off. If we add one more bit to the end of those 7 bits and set it to be always 0, then we have 8 bits (a byte!) representing our LED sequence. And we can have a group of those bytes in an array and display them one after the other, which forms our image.
The LED sequence for each digit is stored as an array of bytes
Now for the Gyro’clock this image is changing every second, since we are displaying time. So we would have to keep constantly adjusting our array sequence. But since our display is fairly simple we can store the sequences for each digit, and then choose which digits to display. Each digit is 5 bytes in size and they are placed in an array like this: [[digit0], [digit1], [digit2]… [digit9] ]. Then let’s say we want to choose digit 6, the start index of the sequence for digit 6 is at 5×6 = 30, and the end is at (5×(6+1))-1 = 34.
So how do you figure out how long to display each sequence? Well, I did this by trying a few values and see which one works best considering the range of speeds the Gyro’clock is typically moving at. If the display time is too long, the pixels will get stretched horizontally as you increase the speed. Display time too short, then the pixels will merge together and the display will get squished as you move slower. I found that for the Gyro’clock it wasn’t necessary to do speed correction. In fact trying to correct for the speed introduced too many rounding errors, which caused the display to change in size unpredictably. At the end I settled for a display time of 0.5 ms for each sequence.
When setting the status of each LED for a particular sequence, you can take either the long and hard way or the short and easy way. The long and hard way would be to change the LED states one by one using the Arduino digitalWrite(pin, state) function. By doing it this way the LEDs don’t change state all at once. Although it still happens pretty quickly with a 8 MHz clock speed, it is too much unnecessary work for the processor.
The quick and easy way is to manipulate the ports directly. It would help if you can connect all the LEDs to pins of the same port (port B let’s say). However, because of the external crystal we used for the real time clock module I wasn’t able to put all the LEDs on pins of the same port. So I put LEDs 1-6 on port pins B0-B5 and the seventh LED on port pin C0. With this setup it is easy to update the ports directly as follows:
//num is a byte representing the state of the LEDs 1-7
PORTC |= (num>>6);
PORTB = num;
First by calling PORTC |= (num>>6) we shift our byte 6 units to the right so that the only bit that is left is the 7th bit (and we don’t care about the 8th bit since its always zero and doesn’t represent a LED). Then we change the PORTB values all at the same time. From two quick and direct steps we have changed the state of all 7 LEDs.
That covers the clock display module, which is actually the simplest part of Gyro’clock to implement. And that wraps up the three part series explanation of how the Gyro’clock firmware works. This however, is not the end of the Gyro’clock project. I liked working on this project so much that I actually want to take this to the next step and build a completely practical store-made-quality product. I will tell you more details about this as I work through it. In my next post I will release the firmware for this version of Gyro’clock. Thanks for reading!