; Nixie csoves ora ; Osszevagta Tom025 ; http://bthamps.extra.hu ; Verzio 1.0 ; Csak alap ora funkciokat tamogat title "Binary LED Clock" list P = 16F628A include "p16F628A.inc" __CONFIG _CP_OFF & _XT_OSC & _WDT_OFF & _PWRTE_ON & _MCLRE_OFF & _BODEN_OFF & _LVP_OFF ; Variables for delay loop teller EQU 070h teller2 EQU 071h ; Variables for time-keeping sece EQU 072h ; Second units sect EQU 073h ; Second tens mine EQU 07Bh ; Minute units mint EQU 07Ch ; Minute tens hre EQU 07Dh ; Hour units hrt EQU 07Eh ; Hour tens ; Variables for the one second timer bres_hi EQU 076h ; hi byte of our 24bit variable bres_mid EQU 077h ; mid byte bres_lo EQU 078h ; lo byte ; Variables to save register statusses during interrupt temp_s EQU 079h temp_w EQU 07Ah ; Variables for debouncing and inputs bounce_timer EQU 07Fh ; Counter for the debounce routine csa EQU 060h cva EQU 061h count_A EQU 062h count_B EQU 063h prev_val EQU 064h ORG 0x0 ; Choose starting adress GOTO init ORG 0x4 ; Choose starting adress ; Interrupt routine. This is called every 256 instructions. isr MOVWF temp_w ; save w register MOVF STATUS, W ; W = STATUS MOVWF temp_s ; save STATUS register ; First, see if we need to call the debouncing routine ; We don't call the debouncing routine every interrupt, but every 10 ; interrupts. That's once every 2560 instructions. Because an input needs ; to be the same for 4 consecutive calls to the debouncing routine, it ; needs to be the same for roughly 0.01 seconds. DECFSZ bounce_timer, f ; Decrement bounce_timer, see if it's 0 GOTO bookkeeping ; Not 0, skip the debouncing routine MOVLW 009h ; Bounce_timer == 0 MOVWF bounce_timer ; Reset bounce_timer to 9 CALL read_inputs CALL debounce CALL process_inputs ; Here comes the bookkeeping for the timer routine bookkeeping ; TSTF bres_mid ; first test for mid==0 ; SKPNZ ; nz = no underflow needed ; DECF bres_hi,f ; z, so is underflow, so dec the msb ; ; DECFSZ bres_mid,f ; dec the mid byte (subtract 256) ; GOTO end_isr ; nz, so definitely not one second yet. ; ; TSTF bres_hi ; test hi for zero too ; SKPZ ; z = both hi and mid are zero, is one second! ; GOTO end_isr ; nz, so not one second yet. ; ; MOVLW 0x0F ; get msb value ; MOVWF bres_hi ; load in msb ; MOVLW 0x42 ; get mid value ; MOVWF bres_mid ; load in mid ; MOVLW 0x40 ; lsb value to add ; ADDWF bres_lo,f ; add it to the remainder already in lsb ; SKPNC ; nc = no overflow, so mid is still ok ; ; INCF bres_mid,f ; c, so lsb overflowed, so inc mid incfsz bres_lo,f goto end_isr incfsz bres_mid,f goto end_isr movlw low(0x10000 - .4000) movwf bres_lo movlw high(0x10000 - .4000) movwf bres_mid CALL continue ; A second has passed, increase the second count ; End of the interrupt routine end_isr ; BCF INTCON, T0IF ; clear the TMR0 flag bit bcf PIR1,TMR2IF ; clear the TMR2 flag bit MOVF temp_s, W ; Put STATUS and W back where they belong MOVWF STATUS SWAPF temp_w, F SWAPF temp_w, W RETFIE ; Return from interrupt ; Initialisation routine init BSF STATUS,5 ; Choose bank 1 CLRF TRISA ; All pins of port A are outputs movlw 0xC0 movwF TRISB ; All pins of port B are outputs... ; BSF TRISB, 6 ; BSF TRISB, 7 ; ...except for the last two MOVLW b'10001000' ; Set the options (prescaler for watchdog timer) MOVWF OPTION_REG movlw .250 - 1 movwf PR2 bsf PIE1,TMR2IE BCF STATUS,5 ; Choose bank 0 CALL initial_vals ; Set initial values ; MOVLW 0x0F ; get msb value ; MOVWF bres_hi ; put in hi ; MOVLW 0x42 +1 ; get mid value (note we added 1 to it) ; MOVWF bres_mid ; put in mid ; MOVLW 0x40 ; get lsb value ; MOVWF bres_lo ; put in lo movlw low(0x10000 - .4000) movwf bres_lo movlw high(0x10000 - .4000) movwf bres_mid movlw (1 << TMR2ON) movwf T2CON movlw (1 << GIE) | (1 << PEIE) movwf INTCON ; CLRF INTCON ; BSF INTCON, T0IE ; BSF INTCON, GIE ; Set Timer interrupt ; Routine to show the numbers on the display shownumbers clrf PORTB ; All LEDs off clrf PORTA CALL delay100us MOVF sece,w ; Load sece into W MOVWF PORTA ; Set the LEDs BSF PORTB, 0 ; Show the first row CALL delay ; Call our delay routine clrf PORTB ; All LEDs off clrf PORTA CALL delay100us MOVF sect,w ; Load sect in W MOVWF PORTA ; Set the LEDs BSF PORTB, 1 ; Show the second row CALL delay clrf PORTB ; All LEDs off clrf PORTA CALL delay100us MOVF mine,w ; Load mine into W MOVWF PORTA ; Set the LEDs BSF PORTB, 2 ; Show the third row CALL delay clrf PORTB ; All LEDs off clrf PORTA CALL delay100us MOVF mint,w ; Load mint into W MOVWF PORTA ; Set the LEDs BSF PORTB, 3 ; Show the fourth row CALL delay clrf PORTB ; All LEDs off clrf PORTA CALL delay100us MOVF hre,w ; Load hre into W MOVWF PORTA ; Set the LEDs BSF PORTB, 4 ; Show the fifth row CALL delay clrf PORTB ; All LEDs off clrf PORTA CALL delay100us MOVF hrt,w ; Load hrt into W MOVWF PORTA ; Set the LEDs BSF PORTB, 5 ; Show the sixth row CALL delay GOTO shownumbers ; Just keep on showing those numbers -- the ; rest of the functionality is called from the interrupt ; routine. ; This routine is called whenever a second has passed. continue INCF sece, 1 ; Increase sece MOVF sece, w ADDLW 0F6h ; sece > 9? SKPNC GOTO overflow_sece ; sece == 10, so increment sect RETURN overflow_sece CLRF sece ; Set sece back to 0 INCF sect, 1 ; Increase sect with 1 MOVF sect, w ADDLW 0FAh ; sect > 5? SKPNC GOTO overflow_sect ; sect == 5, so increment mine RETURN overflow_sect CLRF sect ; Set sect back to 0 CLRF sece INCF mine, 1 ; Increase mine MOVF mine, w ADDLW 0F6h ; mine > 9? SKPNC GOTO overflow_mine ; mine == 10, so increment sect RETURN overflow_mine CLRF mine ; Set mine back to 0 INCF mint, 1 ; Increase mint MOVF mint, w ADDLW 0FAh ; mint > 5? SKPNC GOTO overflow_mint ; mint == 5, so increment hre RETURN overflow_mint CLRF mint ; Reset mint to 0 incr_hre INCF hre, 1 ; Increase hre MOVF hre, w ADDLW 0FCh ; hre > 4? SKPNC GOTO check_hre ; hre > 4, so we need to check whether we need ; to overflow hrt RETURN check_hre MOVF hrt, w ADDLW 0FEh ; hrt > 1? SKPNC GOTO overflow_hre ; hrt == 2, hre == 5 -> overflow! MOVF hre, w ; hrt == 1 ADDLW 0F6h ; hre > 9? SKPNC GOTO overflow_hre ; hrt == 1, hre == 10 -> overflow! RETURN overflow_hre CLRF hre ; Reset hre to 0 INCF hrt, 1 ; Increase hrt MOVF hrt, w ADDLW 0FDh ; hrt > 2? SKPNC GOTO overflow_hrt ; hrt == 2; overflow hrt (it's midnight!) RETURN overflow_hrt CLRF sece ; Midnight, reset everything to 0! CLRF sect CLRF mine CLRF mint CLRF hre CLRF hrt RETURN ; Sets the initial values. We start 9 seconds before midnight! initial_vals MOVLW 001h MOVWF sece CLRF sect CLRF mine CLRF mint CLRF hre CLRF hrt MOVLW 005h MOVWF sect MOVLW 009h MOVWF mine MOVLW 005h MOVWF mint MOVLW 003h MOVWF hre MOVLW 002h MOVWF hrt ; Also, set the variables for the counters etc. MOVLW 009h MOVWF bounce_timer CLRF csa CLRF cva CLRF count_A CLRF count_B CLRF prev_val RETURN ; Our delay loop. Waits roughly 1000 instructions, that's 1 msec ; :-)) instead 1000 instructions those routine waits for 3043 instructions delay MOVLW 00Ah ;10 times... MOVWF teller outerloop MOVLW 064h ;100 times... MOVWF teller2 innerloop DECFSZ teller2, 1 GOTO innerloop DECFSZ teller, 1 GOTO outerloop RETURN ; Our delay loop. Waits roughly 1000 instructions, that's 1 msec delay100us outerloop100 MOVLW .100/.3 ;33 times... MOVWF teller2 innerloop100 DECFSZ teller2, 1 GOTO innerloop100 RETURN ; Read the inputs read_inputs ; Check minute pin, sets the appropriate bit in the csa variable BTFSC PORTB, 6 GOTO minute_een minute_nul BCF csa, 0 GOTO einde_minute minute_een BSF csa, 0 einde_minute ; Check hour pin, sets the appropriate bit in the csa variable BTFSC PORTB, 7 GOTO hour_een hour_nul BCF csa, 1 GOTO einde_hour hour_een BSF csa, 1 einde_hour RETURN ; Debounce routine debounce ;Increment the vertical counter MOVF count_B,W XORWF count_A,F COMF count_B,F ;See if any changes occurred MOVF csa,W XORWF cva,W ;Reset the counter if no change has occurred ANDWF count_B,F ANDWF count_A,F ;Determine the counter's state MOVF count_B,W IORWF count_A,W ;Clear all bits that are filtered-or more accurately, save ;the state of those that are being filtered ANDWF cva,F XORLW 0xff ;Re-write the bits that haven't changed. ANDWF csa,W IORWF cva,F RETURN ; Process the debounced inputs ; We have two variables to work with: prev_val, which contains the previous (debounced) states of the inputs; ; and cva, the debounced current state of the inputs. ; Each input is set as a bit in both the variables. process_inputs ; Check the previous value of the minute-input BTFSS prev_val, 0 GOTO minute_was_zero minute_was_one BTFSS cva, 0 BCF prev_val, 0 ; from 1 to 0 -> reset prev_val to 0 GOTO check_hour minute_was_zero BTFSC cva, 0 GOTO minute_press GOTO check_hour minute_press BSF prev_val, 0 CALL overflow_sect ; from 0 to 1 -> tick! check_hour ; Check the previous value of the hour input BTFSS prev_val, 1 GOTO hour_was_zero hour_was_one BTFSS cva, 1 BCF prev_val, 1 ; from 1 to 0 -> reset prev_val to 0 RETURN hour_was_zero BTFSC cva, 1 GOTO hour_press RETURN hour_press BSF prev_val, 1 CALL incr_hre ; from 0 to 1 -> tick! RETURN END