'This is a nixie clock driver 'Assumed is an ATMega8 - should work with an S2334 or similar but untested 'Author: Neil Barnes 'Date: 12/01/2003 'This software is released under GPL conditions - see www.gnu.org for details 'clock speed is 4096KHz 'each of four output tubes is directly driven via a 74141 binary-decimal driver 'chip but note that the mapping is incorrect both in the binary and decimal 'domain to simplify the PCB layout 'we will use a software map to translate real codes to required codes 'the output tubes are wired with four bits each 'minutes PC0-PC3 'min tens PB0-PB3 'hours PD4-PD7 'hours tens PD0-PD3 'there are two switches on PB4 and PB5 which will be used to set the time 'and other functions 'a TCN75 temperature sensing chip is wired onto PC4 (SCL) and PC5 (SDA) as a 'Philips I2C bus (slave only) 'CODE STARTS HERE 'declare subroutines declare sub showtime(byval hrs as byte , byval mins as byte) declare sub settime 'global variables dim ticks as byte '62.5 ticks per second dim seconds as byte 'time dim minutes as byte 'time dim hours as byte 'time dim temperature as integer 'temperature is nine bits signed from chip dim oddeven as byte 'temporary use by interrupt routine dim oldtime as byte 'time to re-display time? dim count as integer 'on-going tick count, used to time debounce dim switch1 as bit 'switch temporary store dim switch2 as bit dim oldswitch1 as bit dim oldswitch2 as bit dim twelve as bit 'true for 12 hour display 'variables for set time routine dim hrs as byte dim mins as byte dim lasttick as byte dim flash as byte dim ltwelve as byte 'we also have the lookup table that provides the correct values to compensate 'for the odd wiring of the output drivers dim translate(10) as byte 'we fill it with the number we need to send to generate the index 'basic being an imbecilic language it starts arrays with index 1 rather than 0 'so translate(1) has the value required for 0 etc translate(1) = 3 translate(2) = 8 translate(3) = 4 translate(4) = 0 translate(5) = 12 translate(6) = 9 translate(7) = 1 translate(8) = 2 translate(9) = 10 translate(10) = 11 'set direction port B 'output on 0-3, input on 4,5 DDRB = $0f 'set direction port C 'output on 0-3 DDRC = $0f 'set direction port D 'output on all pins DDRD = $ff 'preset the time to midnight ticks = 0 seconds = 0 minutes = 0 hours = 0 oldswitch1 = 1 twelve = 1 'now we set up the clock to tick nicely 'the system clock is 4096kHz 'if we have the prescaler set to 256, and generate an interrupt every time the 'timer 0 overflows, then we get 62.5 interrupts per second 'the half tick is a minor pain but we can deal with this by making the seconds 'slightly different lengths - if the current second is even, it gets 62 ticks; 'if odd, it gets 63 ticks 'it all evens out in the end, and we're not displaying seconds anyway config timer0 = timer , prescale = 256 'set up the interrupt vector enable interrupts enable ovf0 on ovf0 ticktock 'loop forever - this is where the button scanning will probably go do 'check to see if seconds have changed if oldtime <> seconds then 'yup, display time oldtime = seconds call showtime(hours , minutes) endif 'now we think about the switches 'we only care here about switch one. if it's pressed for more than one 'second then we change mode to set the time 'when we start, the switches are pulled high and we have a 1 in 'switch and oldswitch to reflect this 'if we have a 0 on the pin, the switch is pushed 'remember count is updated by the interrupt routine if pinb.5 = 0 then waitms 30 if pinb.5 = 0 then call settime endif endif loop '''''''''''''''''''''''''''''''''''''''''' 'the interrupt service vector lives here ' 'it's entered 62.5 times per second ' 'updates ticks, seconds, minutes, hours 'we do not display in the interrupt process ' '''''''''''''''''''''''''''''''''''''''''' ticktock: 'we need to know if we have an odd or even second oddeven = seconds and 1 'add one to tick count and also the count incr ticks incr count ' on odd seconds, we have 63 ticks if ticks = 63 then 'it must be odd if it got to 63, no need to check ticks = 0 end if 'on even seconds, we have 62 ticks 'we have to work round not being able to evaluate expressions in 'if-then-else constructs if oddeven = 0 then 'must be an even second if ticks = 62 then 'so it has 62 ticks ticks = 0 endif endif if ticks = 0 then 'update seconds incr seconds if seconds = 60 then seconds = 0 incr minutes if minutes = 60 then minutes = 0 incr hours if twelve = 1 then if hours = 13 then hours = 1 endif else if hours = 24 then hours = 0 endif endif endif endif endif return 'end of interrupt routine '''''''''''''''''''''''''''''''''''''''''''''''''''''' ' 'Display the time (hours and minutes) when requested ' 'takes no parameters, returns nothing ' '''''''''''''''''''''''''''''''''''''''''''''''''''''' dim scratch as byte dim scratch2 as byte sub showtime(hrs as byte , mins as byte): 'outputs hrs and mins (which can be anything calling routine sends) 'to blank a pair of digits, send 255 as the parameter 'start with minutes display if mins <> 255 then scratch = mins / 10 scratch = scratch * 10 scratch = mins - scratch 'that should give the minutes units 'after we translate it, it goes out on PC0-PC3 PORTC = translate(scratch + 1) 'now the minutes tens scratch = mins / 10 'this goes out on PB0-PB3 PORTB = translate(scratch + 1) else PORTB = 255 PORTC = 255 endif 'the hours are more complex 'we're using all of port D but the units go out on PD4-7 and the tens 'on PD0-3 so we use scratch2 as a temporary holding place if hrs <> 255 then scratch = hrs / 10 scratch = scratch * 10 scratch = hrs - scratch 'gives the hours 'incr scratch scratch2 = translate(scratch + 1) 'save it scratch2 = scratch2 * 16 'and shift to top four bits scratch = hrs / 10 'incr scratch scratch = translate(scratch + 1) scratch2 = scratch2 or scratch PORTD = scratch2 'output things else PORTD = 255 endif return end sub sub settime 'settime is used to set the time 'it is entered when switch1 has been pressed for more than half a second. ' 'the hours digits flash ' 'after its release, pressing switch2 will advance the hours 0-23, 1-12, 0-23... ' 'pressing and releasing switch one then sets the hours and causes the minutes 'display to flash ' 'the minutes digits are advanced by pressing switch 2 ' 'a third use of switch1 transfers the time to the actual time locations 'and resets the seconds counter and 12/24 flag, then returns ltwelve = 12 'assume 12 hour mode hrs = hours mins = minutes 'we work with local copies in case time is incremented 'by interrupt tick during our manipulation call showtime (hrs, 255) while pinb.5 = 0 waitms 30 'and debounce delay wend 'wait for button to be released while pinb.5 = 1 'now we wait until switch1 is pressed again 'in which we increment call showtime(hrs,255) if pinb.4 = 0 then 'switch 2 pressed? waitms 30 'debounce if pinb.4 = 0 then incr hrs if ltwelve = 12 then if hrs = 13 then 'cycle to 24 hr mode ltwelve = 24 hrs = 0 endif else if hrs = 24 then 'cycle to 12 hr mode ltwelve = 12 hrs = 1 endif endif while pinb.4 = 0 wend 'wait till switch 2 is released waitms 30 endif endif wend while pinb.5 = 0 'switch 2 is released, wait till pressed waitms 30 wend 'now a similar trick to set the minutes while pinb.5 = 1 call showtime(255 , mins) if pinb.4 = 0 then waitms 30 if pinb.4 = 0 then incr mins if mins = 60 then mins = 0 endif while pinb.4 = 0 wend waitms 30 endif endif wend waitms 30 while pinb.5 = 0 'switch 2 is released, wait till pressed waitms 30 wend 'now update the real time stores seconds = 0 minutes = mins hours = hrs if ltwelve = 12 then twelve = 1 'set twelve hour mode if hours > 12 then hours = hours - 12 endif else twelve = 0 endif call showtime(hours , minutes) return end sub