This project was inspired by the Open Display project. The LEDs would now be used to display an analog clock, with second, minute and hour hands. This is obtained by using 8 dual color LEDs and then one additional LED, for the hour marker, and rotating them. We can do this by rotating the board the LEDs are on, and turning the LEDs on and off in the correct positions to get the clock. We also wanted to add the ability to change time, so we added 2 buttons to the back of the board.
Video |
![]() AVI ~4.1Mb |
---|
The design is essentially the same as the Open Display project; using a small motor to rotate a PCB board. We salvaged the motor from a rotating pumpkin toy available from Walgreens. The motor is powered by ~2V, and we stabilize this by a voltage regulator, LM317, in a standard way. It runs at approx. 4200 RPM from 3V with no load. The most viable components on the board are the LEDs (Dual Color & Blue Color), but magic takes place behind them. The board is based off the PIC16F648A from Microchip.
Schematic | PCB design | |
We wanted to include in design the ability to change the time when needed. This was done by adding two switches to the board. We originally were worried if they would be too large for the board, but the switches are quite small. The component that allows us to keep time accurately is the 32,768kHz Crystal. This allows us to increment time in 1 second intervals (more on this later in the software section). A Hall Effect sensor is used to start the display of the clock over at 12:00, similar to the sensor used in the open display, only we needed ours to be in the exact spot. If not, our clock would appear to be off. The sensor picks up input from a magnet mounted on the bracket. The inputs are used as an external interrupt input for the PIC.
While working on the design, we noticed that the LEDs would be getting 1/60th of their normal power, due to the rapid switching from on to off. The max output from the PIC is 25mA and with the LEDs having a current rating of 20mA, we would have very dimm LEDs. We went with having 4 MOSFET transistors, in packs of 2 each. These allow us to supply a peak current of 130mA to the LEDs, which is close to the max of 140mA. The ability to turn the power on and off is also supplied. If we did not use those, the output supplied by the PIC would not be enough to sufficiently light the LEDs brightly, for the short burst. This allowed us to have bright LEDs, and a simpler design for the LEDs.
Front view | Back view | Top view | ||
While working on the design, we noticed that the LEDs would be getting 1/60th of their normal power, due to the rapid switching from on to off. The max output from the PIC is 25mA and with the LEDs having a current rating of 20mA, we would have very dimm LEDs. We went with having 4 MOSFET transistors, in packs of 2 each. These allow us to supply a peak current of 130mA to the LEDs, which is close to the max of 140mA. The ability to turn the power on and off is also supplied. If we did not use those, the output supplied by the PIC would not be enough to sufficiently light the LEDs brightly, for the short burst. This allowed us to have bright LEDs, and a simpler design for the LEDs.
The configuration of the LEDs was done for a few reasons. There are 3 arms we need to display: hour, minute and second. If we output 0 to RC2 & 4, we get the minute hand; RC0 & 1 for second, and RC0 & 4 for hour. In addition, all the components are surface mounted, except the LEDs. We cut a hole down the middle of the board where the LEDs go. This allowed us to surface mount the LEDs on the backside, and the upper part of the LED show through the board. Knowing we would have to program the chip multiple times, we also implemented the chips programming pins, so we could program it after installation to the board.
The problem which made us think the most was getting power to the board. We used metal brush device from the rotating pumpkin toy. The brush is used to conduct plus, and ground is reached through the shaft of the motor and the motor housing. The brush is attached on the side of an aluminum bracket, allowed us to perform the same function as the brushes in the Open Air Display project. This bracket was then mounted on a wooden block for a finished look.
Brushes | Magnet & sensor | Assembled PCB | ||
On startup, the initialization of the variables, and external interrupt input are done, as well as an external clock setup. We also start off by clearing all position variables for hours, minutes, seconds, the tick, hour marker position (tickNotch) and increment the hour marker variable by 1. At this point, we move into the main loop.
The main loop first clears the display by outputting '010111' to PORTC. We output logical 1 to turn the display off because of the MOSFET chips we implemented in the design. Then we first check to see if a tickNotch needs to be displayed. If subtracting leads to the Z bit being set, we turn on the tickNotch, or blue LED for this position, and then proceed to setup tickNotch with 5 again. If not, we proceed to check for displaying the second, minute and hour hands.
loop ; main loop starts here movlw b'010111' ; shut down display movwf PORTC decfsz tickNotch, f ; set the Z flag accordingly goto $+4 bsf PORTC, 3 ; turn on tick mark movlw 5 movwf tickNotch ; tickNotch = 5 movf seconds, w subwf tick, w btfss STATUS, Z goto check_min bcf PORTC, 0 ; display seconds arm bcf PORTC, 1 check_min movf minutes, w subwf tick, w btfss STATUS, Z goto check_hours bcf PORTC, 2 ; display minutes arm bcf PORTC, 4 check_hours movf hrpos, w subwf tick, w btfss STATUS, Z goto $+3 bcf PORTC, 1 ; display hours arm bcf PORTC, 2 call delayOn ; ON delay movlw b'010111' ; shut down display movwf PORTC call delayOff ; gap delay incf tick, f ; update the tick counter movlw 60 subwf tick, w btfss STATUS, Z goto loop setTime ; wait for interrupt call wait4Release ; wait 32msec for button release call wait4Press ; wait 32msec for button press goto setTime |
After computing whether the LEDs are on or off, we move to the delay between events. We shut down the display, perform the gap delay, and update the tick position. The delayOn and delayOff methods determine the width of the gap. The delay between them is about 400 microseconds, resulting in 400·60 = 24 milliseconds clock refresh rate, or 42Hz refreshing frequency. We chose this as a compromise between display flickering and motor noise, which increases at higher rotations. Then if the tick position is 60, we go to the button status checking loop, and wait for an interrupt either from the TMR1 timer, or Hall sensor.
The ISR performs 2 functions, either recalls start, or processes a pulse from the crystal. If the interrupt is from the crystal, we setup the next interrupt and increment the variable seconds. We proceed to increment minutes = seconds (mod 60) and clear seconds. Calculating the hour hand position is next, by multiplying hours by 5, and then adding floor(minutes/12). We came up with 5 because 60 divided by 12 is 5. For every hour, the hour hand needs to move 5 positions. Example: If it is 3:36, thats 3·5 = 15. So we need start the position of the hour hand at 15, or 3:00. The floor(minutes/12), gives us how much farther we need to move the hour hand past 3:00. So, 36/12 = 3. So we have 15 + 3 is 18. The hour hand needs to be displayed when we reach the 18th position. Finally, if minutes equal 60, we update hours, etc.
... btfss PIR1, TMR1IF ; TMR1 interrupt? goto start ; NO - process the synchro pulse movlw 128 ; set next timer interrupt event movwf TMR1H ; 1 sec apart incf seconds, f ; put the ISR main code here movlw 60 subwf seconds, w btfss STATUS, Z goto ISR_end clrf seconds ; seconds = seconds (mod 60) incf minutes, f movf hours, w movwf hrpos ; hrpos = hours addwf hrpos, f addwf hrpos, f addwf hrpos, f addwf hrpos, f ; hrpos = hours * 5 movf minutes, w movwf temp movlw 12 ; hrpos += floor(minutes/12) incf hrpos, f subwf temp, f btfsc STATUS, C goto $-3 decf hrpos, f movlw 60 subwf minutes, w btfss STATUS, Z goto ISR_end clrf minutes ; minutes = minutes (mod 60) incf hours, f movlw 12 subwf hours, w btfss STATUS, Z goto ISR_end clrf hours ; hours = hours (mod 12) ... |
The final parts of code are for button processing of 2 tactile push buttons. We catch the button presses while waiting for an interrupt, as in the code above. We first check for a button release, if a release is found, we pause 4096·8, or 32msec. Checking it again confirms the button press, and not just a bouncing of the button. From there, we process either a minute or hour button. We increment minutes and hours similarly to how we do it above. To give the user a visual confirmation the time has been updated, we blink the blue LED.
After working with two devices that use similar construction, the rotating boards design needs an improvement if this device is to have long term use. The board itself is out in the open and could get damaged. For version II, we would mount the board on a hard drive motor. This would allow for the whole design to be more flat.
With the current device, enclosing it in plastic is the best option for longevity. Also, use as bright LEDs as possible, and use them at maximum pulse current to get the brightest illumination.
Last modified:Mon, Jan 23, 2023.