;-------- ; mclockT3.asm - modified for 180 degree brush motor ; OK to add 8th LED - blanked in table and 2 other places ; watchdog timer used to ensure startup under all powerups ; "The Propeller" mechanically scanned LED clock ; copyright Bob Blick all rights reserved ; February 12, 1997 ;-------- list p=16C84 radix hex include "p16c84.inc" ;-------- ; remember to set blast-time options: OSC=regular xtal, WDT=ON ; timings all based on 4 MHz crystal ;-------- ; are these equates already in the include file? someday I'll look. ;-------- w equ 0 f equ 1 ;-------- ; Start of available RAM. ;-------- cblock 0x0C safe_w ;not really temp, used by interrupt svc safe_s ;not really temp, used by interrupt svc period_count ;incremented each interrupt period_dup ;copy of period_count safe from interrupt period_calc ;stable period after hysteresis calc. flags ;b2=int b1=minute b4=edge dot_index ;which column is being displayed digit_index ;which digit is being displayed hours ;in display format, not hex(01-12) minutes ;00 to 59 bigtick_dbl ;incremented each interrupt bigtick_hi bigtick_lo keys ;key value scratch ;scratch value tick ;used by delay endc ;-------- ; Start of ROM ;-------- org 0x00 ;Start of code space goto Start ;-------- ; INTERRUPT SERVICE ROUTINE ;-------- org 0x04 ;interrupt vector Intsvc movwf safe_w ;save w swapf STATUS,w ;swap status, w movwf safe_s ;save status(nibble swap, remember) ;-------- ; done saving, now start working ; increment period count ;-------- incf period_count,f btfsc STATUS,Z ;zero set means overflow decf period_count,f ; clear watchdog timer to ensure startup clrwdt ; 234375 interrupts every minute. Increment the bigtick each time. incf bigtick_lo,f btfsc STATUS,Z incf bigtick_hi,f btfsc STATUS,Z incfsz bigtick_dbl,f goto Bigtick_out ;-------- ; here? bigtick has rolled over to zero and one minute has passed. ; reload bigtick and set a flag for the main counter ;-------- movlw 0xFC ;234375 = 0x039387 movwf bigtick_dbl ;0 - 0x039387 = 0xFC6C79 movlw 0x6C movwf bigtick_hi movlw 0x79 movwf bigtick_lo bsf flags,1 ;notify Keep_time Bigtick_out ;-------- ; done working, start restoring ;-------- swapf safe_s,w ;fetch status, reswap nibbles movwf STATUS ;restore status swapf safe_w,f ;swap nibbles in preparation swapf safe_w,w ;for the swap restoration of w bcf INTCON,2 ;clear interrupt flag before return retfie ;return from interrupt ;-------- ; CHARACTER LOOKUP TABLE ; ignore high bit. set=LED off, clear=LED on, bit0=bottom LED, bit6=top LED ;-------- Char_tbl addwf PCL,f dt 0xC1,0xBE,0xBE,0xBE,0xC1 ;"O" dt 0xFF,0xDE,0x80,0xFE,0xFF ;"1" dt 0xDE,0xBC,0xBA,0xB6,0xCE ;"2" dt 0xBD,0xBE,0xAE,0x96,0xB9 ;"3" dt 0xF3,0xEB,0xDB,0x80,0xFB ;"4" dt 0x8D,0xAE,0xAE,0xAE,0xB1 ;"5" dt 0xE1,0xD6,0xB6,0xB6,0xF9 ;"6" dt 0xBF,0xB8,0xB7,0xAF,0x9F ;"7" dt 0xC9,0xB6,0xB6,0xB6,0xC9 ;"8" dt 0xCF,0xB6,0xB6,0xB5,0xC3 ;"9" dt 0xFF,0xC9,0xC9,0xFF,0xFF ;":" Char_tbl_end ;-------- ; SUBROUTINES STARTING HERE ;-------- ; clear important bits of ram ;-------- Ram_init movlw 0x07 movwf keys movlw 0x12 ;why do clocks always start movwf hours ;at 12:00 ? clrf minutes clrf dot_index clrf digit_index movlw 0xFC movwf bigtick_dbl retlw 0 ;-------- ; unused pins I am setting to be outputs ;-------- Port_init movlw 0x00 ;all output, b7=unused tris PORTB ;on port b attached to LEDs movlw b'00010111' ;port a has 5 pins. I need 4 inputs ;b0=minutes, b1=10mins, b2=hours ;b3=unused, b4=rotation index tris PORTA ;on port a retlw 0 ;-------- ; get timer-based interrupts going ;-------- Timer_init bcf INTCON,2 ;clear TMR0 int flag bsf INTCON,7 ;enable global interrupts bsf INTCON,5 ;enable TMR0 int clrf TMR0 ;clear timer clrwdt ;why is this needed? just do it.. movlw b'11011000' ;set up timer. prescaler(bit3)bypassed option ;send w to option. generate warning. clrf TMR0 ;start timer retlw 0 ;-------- ; test for index in rotation and store period in period_dup ;-------- Check_index movf PORTA,w ;get the state of port a xorwf flags,w ;compare with saved state andlw b'00010000' ;only interested in bit 4 btfsc STATUS,Z ;test for edge retlw 0 ;not an edge, same as last xorwf flags,f ;save for next time btfsc flags,4 ;test for falling edge retlw 0 ;must have been a rising edge movf period_count,w ;make a working copy movwf period_dup ;called period dup clrf period_count ;a fresh start for next rotation clrf digit_index ;set to first digit clrf dot_index ;first column ; calculate a period that does not dither or jitter ; period will not be changed unless new period is really different movf period_calc,w subwf period_dup,w ;find difference btfss STATUS,C ;carry flag set means no borrow goto Calc_period_neg ;must be other way sublw 2 ;allowable deviation = 3 btfss STATUS,C ;borrow won't skip incf period_calc ;new value much larger than calc retlw 0 Calc_period_neg addlw 2 ;allowable deviation = 3 btfss STATUS,C ;carry will skip decf period_calc ;no carry means it must be changed retlw 0 ;-------- ; change LED pattern based on state of digit_index and dot_index ;-------- Display_now movlw 0x05 xorwf dot_index,w ;test for end of digit movlw 0xFF ;pattern for blank column btfsc STATUS,Z goto D_lookup_3 ;it needs a blank bcf STATUS,C ;clear carry before a rotate rlf digit_index,w ;double the index because each addwf PCL,f ;takes two instructions D_10hr swapf hours,w goto D_lookup ;what a great rush of power D_1hr movf hours,w ;I feel when modifying goto D_lookup ;the program counter D_colon movlw 0x0A goto D_lookup D_10min swapf minutes,w goto D_lookup D_1min movf minutes,w goto D_lookup D_nothing retlw 0 D_lookup andlw b'00001111' ;strip off hi bits movwf scratch ;multiply this by 5 for lookup addwf scratch,f ;table base position addwf scratch,f ;is this cheating? addwf scratch,f ;I think not. addwf scratch,f ;I think it is conserving energy! btfss STATUS,Z ;test for zero goto D_lookup_2 ;not a zero movf digit_index,f ;this is just to test/set flag movlw 0xFF ;this makes a blank LED pattern btfsc STATUS,Z ;test if it is 10 hrs digit goto D_lookup_3 ;it's a leading zero D_lookup_2 movf dot_index,w ;get column addwf scratch,w ;add it to digit base call Char_tbl ;get the dot pattern for this column D_lookup_3 movwf PORTB ;send it to the LEDs bcf STATUS,C ;clear carry flag before rotate rrf period_calc,w ;period/2 used for dot clock addlw 0xF4 ;subtract 12 to compensate for overhead call Delay ;width of digits with this delay incf dot_index,f ;increment to the next column movlw 0x06 ;6 columns is a digit plus space xorwf dot_index,w ;next digit test btfss STATUS,Z retlw 0 ;not a new digit clrf dot_index ;new digit time incf digit_index,f retlw 0 ;Display_now done. ;-------- ; a short delay routine ;-------- Delay movwf tick Delay_loop decfsz tick,f goto Delay_loop ;w is not damaged, so Delay can return ;be recalled without reloading ;-------- ; test for keypress and call time adjust if needed ;-------- Check_keys movf PORTA,w ;get port "a" xorwf keys,w ;compare with previous andlw b'00000111' ;only care about button pins btfsc STATUS,Z ;zero set=no buttons retlw 0 ;return xorwf keys,f ;store key value movlw 0x64 ;a fairly long delay will movwf scratch ;prevent key bounces Key_delay movlw 0xFF call Delay decfsz scratch goto Key_delay btfss keys,2 ;test "minutes" button goto Inc_mins btfss keys,1 ;test "tens" button goto Inc_tens btfss keys,0 ;test "hours" button goto Inc_hours retlw 0 ;must be a glitch. yeah, right! ;-------- ; increment ten minutes ;-------- Inc_tens movlw 0x0A movwf scratch ;scratch has ten Inc_tens_loop call Inc_mins decfsz scratch goto Inc_tens_loop ;another minute added retlw 0 ;-------- ; increment one hour ;-------- Inc_hours movlw 0x12 xorwf hours,w btfsc STATUS,Z goto Inc_hours_12 movlw 0x07 ;this part gets a little sloppy addwf hours,w movlw 0x07 btfss STATUS,DC movlw 1 addwf hours,f retlw 0 Inc_hours_12 movlw 0x01 movwf hours retlw 0 ;-------- ; increment the time based on flags,1 as sent by interrupt routine ; Inc_mins loop also used by time-setting routine ;-------- Keep_time btfss flags,1 ;the minutes flag retlw 0 ;not this time bcf flags,1 ;clear the minutes flag Inc_mins movlw 0x07 ;start incrementing time addwf minutes,w ;add 7 minutes into w btfsc STATUS,DC ;did adding 7 cause digit carry? goto Sixty_mins ;then test for an hour change incf minutes ;otherwise add 1 for real retlw 0 ;and go back Sixty_mins movwf minutes ;save the minutes movlw 0x60 ;test for 60 xorwf minutes,w ;are minutes at 60? btfss STATUS,Z retlw 0 ;no? go back clrf minutes ;otherwise zero minutes goto Inc_hours ;and increment hours ;-------- ; End of subroutines ; Program starts here ;-------- Start call Ram_init ;set variables to nice values call Port_init ;set port directions call Timer_init ;start timer based interrupt ;-------- ; Done initializing, start the endless loop. ;-------- ; Circle ;begin the big loop ; ;-------- ; detect falling edge on PORTA,4 to determine rotary index ; calculate rotation period and store in period_dup ; compare with working period(period_calc) and adjust if way different ;-------- call Check_index ;-------- ; check display state and change if needed ;-------- call Display_now ;-------- ; check keyboard and adjust time ;-------- call Check_keys ;-------- ; check minute flag and increment time if a minute has passed ;-------- call Keep_time ;-------- ; gentlemen, that's a clock, keep it rolling ;-------- goto Circle ;you heard the man, get going! end ;-------- ; end of file ;--------