PDA

View Full Version : Bug in my timekeeping code



astouffer
- 27th February 2014, 02:09
Well my numitron clock project is nearly complete. My problem is in the code to set the initial time. It didn't allow for the minutes to be set at 00. I fixed that by moving the "mm = mm + 1" line to the bottom of the setmm loop. That allows for 00 to be selected. Now when the timekeeping loop runs it changes 00 to 01 instantly. The time is set by a button that grounds a pin. It increments the digits until the pin is brought high again. When the hours and minutes are set, grounding the pin a third time starts the timekeeping loop. While setting the time the decimal points are lit up so you know the clock is not running. Here is what the code looks like:


@ __CONFIG _FOSC_INTOSCIO & _WDTE_OFF & _WDT_OFF & _PWRTE_ON & _MCLRE_OFF & _CP_OFF & _CPD_OFF & _IESO_OFF & _FCMEN_OFF


OSCCON = %01110101 'Internal OSC 8MHz
DEFINE OSC 8 '8MHz
PORTA = 0 '
TRISA = %00100100 'Porta.2 input
WPUA = %00100000 'Weak pullup on Porta.5
TRISC = 0 '
PORTC = 0 '
ANSEL = 0 '
CMCON0 = %00000111 'Comparators off and I/O is digital
ADCON0 = 0 'A/D is off
CCP1CON = 0 'PWM and CCP off
OPTION_REG = %01110110 'Timer0 on with 128 prescaler and weak pullups on
INTCON = %11100000 'INTCON.2 overflow bit

Include "modedefs.bas"

hstro VAR portc.3 'Strobe line for hours chip
mstro VAR portc.2 'Strobe line for mins chip
dat VAR portc.5 'Data line for chips
clk VAR portc.4 'Clock line for chips

ss VAR byte 'Seconds
mm VAR byte 'Minutes
hh VAR byte 'Hours


v1 VAR byte 'Display bits for tube V1
v2 VAR byte 'Display bits for tube V2
v3 VAR byte 'Display bits for tube V3
v4 VAR byte 'Display bits for tube V4


ss = 0
mm = 0
hh = 0

shiftout dat, clk, 0, [$80, $80] 'Turn on decimal points to show its working
pulsout hstro, 10
pulsout mstro, 10


waithere: 'Wait until a button is pressed
while porta.5 = 1
@ NOP
wend

sethh: 'Routine for setting the hours
if porta.5 = 1 then goto waitformm
hh = hh + 1
if hh = 13 then hh = 1

v1 = hh DIG 1 'Breaks the double digits into singles
v2 = hh DIG 0 'for the lookup table

if hh < 10 then 'This makes the leading hour digit blank
lookup v1, [$80,$E0,$D7,$F6,$EC,$BE,$BF,$F0,$FF,$FE], v1
else
lookup v1, [$FB,$E0,$D7,$F6,$EC,$BE,$BF,$F0,$FF,$FE], v1
endif
lookup v2, [$FB,$E0,$D7,$F6,$EC,$BE,$BF,$F0,$FF,$FE], v2

shiftout dat, clk, 0, [v2, v1]
pulsout hstro, 10
shiftout dat, clk, 0, [$00, $00]
pulsout mstro, 10
pause 750
goto sethh

waitformm: 'Wait until button is pressed for next loop
while porta.5 = 1
@ NOP
wend

setmm: 'Routine for setting the minutes
if porta.5 = 1 then goto settime
if mm = 60 then mm = 1

v3 = mm DIG 1 'Breaks up double digits into singles
v4 = mm DIG 0 'for the lookup table

lookup v3, [$FB,$E0,$D7,$F6,$EC,$BE,$BF,$F0,$FF,$FE], v3
lookup v4, [$FB,$E0,$D7,$F6,$EC,$BE,$BF,$F0,$FF,$FE], v4
shiftout dat, clk, 0, [v4, v3]
pulsout mstro, 10
pause 750
mm = mm + 1
goto setmm

settime: 'Wait until button is pressed and starts the clock
while porta.5 = 1
@ NOP
wend

startloop: 'Need this for the interrupt routine
enable
on interrupt goto timekeep

main: 'Wait until counter overflows and interrupts
@ NOP
goto main

disable



timekeep: 'Actual timekeeping code. Pretty self explanatory
ss = ss + 1
if ss = 60 then
ss = 0
mm = mm + 1
endif
if mm = 60 then
mm = 0
hh = hh + 1
endif
if hh = 13 then hh = 1 'Change this to 25 for 24 hour time
v1 = hh DIG 1
v2 = hh DIG 0

v3 = mm DIG 1
v4 = mm DIG 0

if hh < 10 then
lookup v1, [$00,$60,$57,$76,$6C,$3E,$3F,$70,$7F,$7E], v1
else
lookup v1, [$7B,$60,$57,$76,$6C,$3E,$3F,$70,$7F,$7E], v1
endif

lookup v2, [$7B,$60,$57,$76,$6C,$3E,$3F,$70,$7F,$7E], v2
lookup v3, [$7B,$60,$57,$76,$6C,$3E,$3F,$70,$7F,$7E], v3
lookup v4, [$7B,$60,$57,$76,$6C,$3E,$3F,$70,$7F,$7E], v4

shiftout dat, clk, 0, [v2, v1]
pulsout hstro, 10
shiftout dat, clk, 0, [v4, v3]
pulsout mstro, 10

INTCON.2 = 0 'Clear interrupt flag
resume startloop 'Go back to the do nothing loop


And here is what it looks like http://i.imgur.com/bNyigGW.jpg

Also if anyone is curious about the accuracy of the DS32KHZ oscillator chip, here it is on a freshly calibrated frequency counter http://i.imgur.com/N3TGFOJ.jpg

Jerson
- 27th February 2014, 04:06
You seem to be making a basic mistake. The value of minutes should run between 00 and 59 and not 01 to 60 as you have implemented. That is why you seem to have the minutes starting at 1 instead of going to 0.

Dave
- 27th February 2014, 12:21
I also see the same mistake in the 24 hour mode where you say if hour = 25 then hour = 1. 24 hour time starts from 00:00 to 23:59.

BTW, Nice PCB. I have some RCA Numitrons with 9 pin sockets. I was thinking about using them for a clock but the lifetime of the tubes isn't very good so I built a couple of nixie clocks with VM1000 tubes. Attacked is a photo.

Dave Purola,

Amoque
- 28th February 2014, 13:42
I am wondering if it would be easier to keep only a TotalElapsedSeconds count and calculate HRS, MNS, and SDS as needed? I admit that I have not tried this, but it seems feasible. A word variable easily holds 13 hours (in seconds) and AM/PM or 24 hour clock flag provides convenient flags to indicate the 12 hour adjustment needed to avoid rollover (subtract 43200 at 46800). so:

Just a little while after midnight (when the counter and flag resets to zero), TotalElapsedSeconds might be, say... 1146. In that case,

HRS= 1146/ 3600 = 0
MNS= 1146 - (HRS * 3600) / 60 = 19
SCS= 1146- (HRS * 3600) - (MN * 60) = 06 - the time 00:19:06, is correct.

Closer to noon, the total might be 43321.
HRS= (43321/ 3600) = 12
MNS= 43321- (HRS * 3600) / 60 = 02
SCS= 43321- (HRS * 3600) - (MN * 60) = 01 - the time 12:02:01, is correct.

At 1:00, the timer would be 46800 and subtracting 12 hours (43200 seconds) leaves TotalElapsedSeconds = 3600, or exactly 1:00:00 (or by adding 12, 13:00 in 24H mode). The caveat here is that the midnight adjustment and the 1:PM adjustment are not symmetric at 12 hours each - something of a kludge or, perhaps the time as 24:00:01 is of no issue to you? If not, then the time may rollover to 1:00:00 in even 12 hour cycles.

To set the time, adding or subtracting 3600 adjusts the time by an hour, similarly adding or subtracting 60 changes the time a minute.

I have considered this approach as a means of simplifying clock adjustments - say a user wants to subtract 10 minutes at only 5 minutes past the hour - in this way (I think) it may be simpler than fiddling with decrementing the hour separately.

astouffer
- 28th February 2014, 15:25
You seem to be making a basic mistake. The value of minutes should run between 00 and 59 and not 01 to 60 as you have implemented. That is why you seem to have the minutes starting at 1 instead of going to 0.

Now it makes more sense. Change


if mm = 60 then mm = 1

to


if mm = 60 then mm = 0

Always the little stuff. Thanks.

astouffer
- 28th February 2014, 15:37
I also see the same mistake in the 24 hour mode where you say if hour = 25 then hour = 1. 24 hour time starts from 00:00 to 23:59.

BTW, Nice PCB. I have some RCA Numitrons with 9 pin sockets. I was thinking about using them for a clock but the lifetime of the tubes isn't very good so I built a couple of nixie clocks with VM1000 tubes. Attacked is a photo.

Dave Purola,

Dave, nice looking clock as well. The boards came from a place called OSH Park. They run batches of boards so the average time is about two weeks but the quality and price is great. Purple boards seem to be their trademark. If you are worried about longevity of the numitrons you can use the TLC5916 or similar chips from TI. They are meant for driving LEDs and have an adjustable constant current feature. For some reason the minute digits were both dimmer than the hours and needed slightly different resistor values.

astouffer
- 2nd March 2014, 20:41
Forgive my ignorance but I can not see why during the timekeep loop that the minutes increment to 01 if they are set to 00 from the previous loop :confused:


timekeep:
ss = ss + 1
if ss = 60 then
ss = 0
mm = mm + 1
endif
if mm = 60 then
mm = 0
hh = hh + 1
endif
if hh = 13 then hh = 1
v1 = hh DIG 1
v2 = hh DIG 0

v3 = mm DIG 1
v4 = mm DIG 0

if hh < 10 then
lookup v1, [$00,$60,$57,$76,$6C,$3E,$3F,$70,$7F,$7E], v1
else
lookup v1, [$7B,$60,$57,$76,$6C,$3E,$3F,$70,$7F,$7E], v1
endif

lookup v2, [$7B,$60,$57,$76,$6C,$3E,$3F,$70,$7F,$7E], v2
lookup v3, [$7B,$60,$57,$76,$6C,$3E,$3F,$70,$7F,$7E], v3
lookup v4, [$7B,$60,$57,$76,$6C,$3E,$3F,$70,$7F,$7E], v4

shiftout dat, clk, 0, [v2, v1]
pulsout hstro, 10
shiftout dat, clk, 0, [v4, v3]
pulsout mstro, 10

INTCON.2 = 0 'Clear interrupt flag
resume startloop 'Go back to the do nothing loop

Looking at this statement



ss = ss + 1
if ss = 60 then
ss = 0
mm = mm + 1
endif

The minutes should be at 00 until 60 seconds have been counted. Why is it jumping to 01 instead?

Amoque
- 6th March 2014, 02:54
The only other place I see you modifying the mm value is in the "setmm:" routine. You do not say if you are setting the clock (where the code in your OP sets mm = 1) or not.