Part 2 of this project involved learning how to use hardware PWM to control servos. And, then to make the clock actually work with retrograde analogue hands.
First the functional definition. A retrograde movement in horological terms is where the indicators or hands spring back to their home or 0 position at the end of their cycle. So for a minute hand, after 59 minutes and 59 seconds, its next movement would be to reverse move to home at 0 minutes. For the hour hand this could happen after 12 hours or 24 hours. 24 hours is the case that I have chosen to implement. The idea is to have the hour hand trace out a day from sunrise in the east, to vertical noon, and to set in the west.
In part 1, I added the servo headers to align with the Arduino Digital Pins 5 & 6. These pins are driven by the Timer 0 PWM hardware. Following quite a few evenings trying to understand how to generate PWM using the hardware (OK, I’m a bit slow), I realised that it is not very easy to get a good servo signal out of Timer 0 or Timer 2.
To generate the right signal for a servo, you need to produce a pulse every 20mS (50Hz). The width of the pulse should be 1.5mS to get the neutral position. Depending on the servo design, pulses with width from around 0.8mS to around 2.2mS (repeated every 20mS) will drive it to either end of its range. Depending on the servo, 0.8mS may drive it clockwise or anticlockwise. I have both in the clock. For example, the “hour” servo goes clockwise with a wider pulse. The “minute” servo is the reverse case.
The main issue with Timer 0 and Timer 2 is that they are 8 bit timers, counting to 255 before resetting to 0 (ideally after 20mS). Since the required pulses are between 0.8mS and 2.2mS, there are only about 12 “positions” available for the servo to take. Not enough to allow a minute hand to indicate 60 different positions.
Therefore it became clear that, for this application, it was only possible to use the 16 bit Timer 1 to control the servos.
Setting up Timer 1 is relatively easy, once that decision had been made, so the code was implemented. But, this meant that I had to reconnect the servo headers to Arduino Digital Pin 9 and Pin 10, which are driven by the Timer 1 PWM hardware.
Also, in the pictures below, I have added a header to allow power, LCD backlight (32Ohm), and contrast (1kOhm), connections to the standardised HD44780 LCD.
Ok, so here’s the issue. I’m using the Pololu Libraries for writing to the LCD, and the standard connection for the data line 4 on the HD44780 LCD goes to Arduino Pin 9. The same pin I need for the Timer 1 PWM. Ouch.
Modifying the library is not too difficult. We can move the Data line attached to Pin 9 onto Pin 11, and all is well. This is done in the following file.
The changes are noted in the #define lines below
#define LCD_DB4 PORTB3 // Was PORTB1. Use PORTB3 to avoid the Timer1 pins.
#define LCD_DB5 PORTB4 // PB4
#define LCD_DB6 PORTB5 // PB5
#define LCD_DB7 PORTD7 // PD7
// PortB: 7 6 5 4 3 2 1 0
// LCD Data: 2 1 0 Use DB3 to avoid Timer1 pins.
// LCD Data: 2 1 0
// PortD: 7 6 5 4 3 2 1 0
// LCD Data: 3
#define LCD_PORTB_MASK ((1 << LCD_DB4) | (1 << LCD_DB5) | (1 << LCD_DB6)) // Modified to avoid using DB1
#define LCD_PORTD_MASK (1 << LCD_DB7)
#define LCD_PORTB_DATA(data) ((data & 0x07) << 3) // Modified the data mask to avoid using DB1
#define LCD_PORTD_DATA(data) ((data & 0x08) << 4)
The below pictures show the LCD pin layout.
<blockquote”>Red = VCC
Black = GND
BLUE = Voltage for contrast or backlight
Orange = Data lines (4-bit: DB4 – DB7) PB3 (not PB1), PB4, PB5, and PD7. Arduino Digital pins 11 (not 9), 12, 13, and 7
Purple = Control lines (RS, R/W, E) PD2, PB0, and PD4. Arduino Digital pins 2, 8, and 4
So now we have PWM for our retrograde analogue hands, and a LCD display.
But wait, there’s more…
There’s too much display going to waste, so let’s add something else… Hmm… Temperature, and time, make a min/max thermometer that can show what time each extreme temperature was reached during the day.
Quickly getting a LM335Z temperature sensor, I’m now testing whether the 10bit ADC is good enough to generate reasonable temperature readings from the device. At full range of 5000mV across 1024 levels, we have about 4.88mV per level. The LM355Z produces 10mV per degree, so we should be able to get 0.5 degree accuracy. If everything is perfect.
Currently the temperature gauge works, but the accuracy is still a work in progress, as are the min / max functions. The LM335Z has only two connections, and is biased by a single resistor (3200 Ohm), so it will fit into the board if that is all that is needed. Getting perfection may require addition of decoupling capacitors on AREF and across the sensor, but I’m still
experimenting with this.
The overall working product is shown below. But wait, there’s more…
I was not happy with using resistors to tie up the SCL and SDA lines high for the I2C bus, as it should be possible to use the internal pull up resistors in some situations (according to the Atmel datasheet).
So using a new Freetronics 2010 from Little Bird Electronics, the clock is now rebuilt without external pull up resistors. The I2C code is modified to only pull up the lines between the start and stop bus instructions. The levels are messy (not showing sharp transitions in my SLO) but, never the less the code and the clock works.
The working device is shown below. Note the rather funky white on blue display I got from Sparkfun.
In the years since this instruction was writen, I’ve migrated to Github. So the code is hosted here. The freeRTOS code is also posted on Github. I used the Pololu Library for writing to the display, so it needs to be installed along with the normal AVR libraries.
Part 3 will look at how to build a really stylish clock face that can be shown off in public