Estimado Carlos,
Aprecio su interes y por eso y abusando de su gentileza le adjunto el firmware:
;---------------------------------------------------------------------------------------;
; kueyar 2006 ;
; Enero 2006
kueyar@gmail.com ;
; ;
; ;
; ;
; Contador regresivo de 15 a 0 minutos ;
; con alarma al llegar a 10 y a 0 con registro de conteo. ;
; ;
; RBO-RB3 salidas para las bases los transistors connectados display de cátodo común. ;
; RA0-RA3 salidas para los pines 1,2,4,8 del BCD CD4511 7 segment latch and driver. ;
; RB7 Para el boton de Inicio (start) ;
; RB6 Para el boton de seleccion de inicio de cuenta regresiva. ;
; RA4 Detiene el conteo. ;
; RB4 y RB5 salidas para el piezolectro que sirve de alarma. ;
;---------------------------------------------------------------------------------------;
LIST P=16F84
#INCLUDE "p16f84.inc"
;-------------------------------------------------------------------------;
; Definicion de registros ;
;-------------------------------------------------------------------------;
SEC EQU H"0C" ; this register holds the value of seconds
SEC10 EQU H"0D" ; holds value of 10"s of seconds
MIN EQU H"0E" ; holds value of minutes
MIN10 EQU H"0F" ; holds value of 10"s of minutes
DIGCTR EQU H"10" ; 8 bit counter, only 2 lowest bits actually used
DIGIT EQU H"11" ; hold digit number to access table
INTCNT EQU H"12" ; counts # interrupts to determine when 1 sec up
FUDGE EQU H"13" ; allows slight adjustment every 7 interrupts
RUNFLG EQU H"14" ; bit 0 only, tells if countdown in progress
W_TEMP EQU H"15" ; temporarily holds value of W
STATUS_TEMP EQU H"16" ; temporarily holds value of STATUS
SECNT EQU H"17" ; used in counting 50, 20 msec delays for 1 sec
CNTMSEC EQU H"18" ; used in timing of milliseconds
ALARM EQU H"19" ; bit 0 only, used as flag for when to alarm
OFFSET EQU H"1A" ; hold offset of address in EEPROM
;-------------------------------------------------------------------------;
; Aquí damos nombres para algunos números para hacer su uso más claro ;
;-------------------------------------------------------------------------;
#DEFINE START_PB D"7"
#DEFINE SET_PB D"6"
#DEFINE SELECT_PB D"4"
#DEFINE RB4 D"4"
#DEFINE RB5 D"5"
;-------------------------------------------------------------------------;
;Ajustamos el principio de código para organizar un cero de localización ;
;-------------------------------------------------------------------------;
ORG 0
GOTO MAIN ; jump to the main routine
NOP
NOP
NOP
GOTO INTERRUPT ; interrupt routine
;-------------------------------------------------------------------------;
;Esta tabla se usa para obtener un patrón del bit que encenderá un digito ;
;-------------------------------------------------------------------------;
BITPAT ADDWF PCL,f ; get bit pattern for transistors
RETLW H"0E" ; a low, (0), turns the transistor on
RETLW H"0D"
RETLW H"0B"
RETLW H"07"
;-------------------------------------------------------------------------;
; La rutina Initialization establece puertos y cronometro ;
;-------------------------------------------------------------------------;
INIT MOVLW H"C0" ; PB6 & PB7 inputs all others outputs
TRIS PORTB
MOVLW H"10" ; Port RA4 input, others outputs
TRIS PORTA
MOVLW H"03" ; prescaler on TMR0 and 1:16
OPTION
MOVLW H"A0" ; GIE & T0IE set T0IF cleared
MOVWF INTCON
MOVLW H"F4" ; initialize INTCNT
MOVWF INTCNT
MOVLW H"06" ; initialize FUDGE
MOVWF FUDGE
CLRF OFFSET ; initialize OFFSET
RETURN
;-------------------------------------------------------------------------;
;Esto es lo interrumpe rutina que es a la que se lanzó cuando TMR0 se derrama
;
;-------------------------------------------------------------------------;
INTERRUPT MOVWF W_TEMP ; save W
SWAPF STATUS,W ; save status
MOVWF STATUS_TEMP ; without changing flags
INCF DIGCTR,f ; next digit #
MOVF DIGCTR,W ; get it into W
ANDLW H"03" ; mask off 2 lowest bits
MOVWF DIGIT ; save it for later
ADDLW H"0C" ; point at register to display
MOVWF FSR ; use as pointer
MOVF INDF,W ; get value of reg pointed to into W
MOVWF PORTA ; output to CD4511
MOVF DIGIT,W ; recall digit #
CALL BITPAT ; get bit pattern
MOVWF PORTB ; select transistor
DECFSZ INTCNT,f ; finished 1 sec ?
GOTO RESTORE ; not yet, return and enable inter.
CALL EVERYSEC ; go to every second routine
MOVLW H"F4" ; reset INTCNT to normal value
MOVWF INTCNT
DECFSZ FUDGE,f ; time for fudge?
GOTO RESTORE ; not yet, continue on
MOVLW H"06" ; reset FUDGE to 6
MOVWF FUDGE
INCF INTCNT,f ; INTCNT to 245
RESTORE SWAPF STATUS_TEMP,W ; get original status back
MOVWF STATUS ; into status register
SWAPF STATUS_TEMP,f ; old no flags trick again
SWAPF STATUS_TEMP,W ; to restore W
BCF INTCON,T0IF ; clear the TMR0 interrupt flag
RETFIE ; finished
;-------------------------------------------------------------------------;
;Esta rutina es llamada por ahí lo interrumpe rutina cada segunda ;
;-------------------------------------------------------------------------;
EVERYSEC BTFSS RUNFLG,0 ; return if runflg not set
RETURN
DECF SEC,f ; decrement seconds digit
INCFSZ SEC,W ; test for underflow
GOTO CKZERO
MOVLW H"09" ; reset sec to 9
MOVWF SEC
DECF SEC10,f ; decrement SEC10
INCFSZ SEC10,W ; check underflow
GOTO CKZERO
MOVLW H"05"
MOVWF SEC10
DECF MIN,f
INCFSZ MIN,W
GOTO CKZERO
MOVLW H"09"
MOVWF MIN
DECF MIN10,f
CKZERO MOVF SEC,f ; test SEC for zero
BTFSS STATUS,Z
RETURN
MOVF SEC10,f ; check SEC10 for zero
BTFSS STATUS,Z
RETURN
MOVF MIN,f ; check MIN for zero
BTFSS STATUS,Z
RETURN
MOVF MIN10,f ; check MIN10 for zero
BTFSS STATUS,Z
RETURN
CLRF RUNFLG ; stop the countdown
BSF ALARM, 0 ; set the alarm flag
RETURN
;-------------------------------------------------------------------------;
;Ésta es una rutina para leer un byte del datos EEPROM ;
;-------------------------------------------------------------------------;
READEE MOVWF EEADR ; set up eeprom address from W
BSF STATUS,RP0 ; change to page 1
BSF EECON1,RD ; set the read bit
BCF STATUS,RP0 ; back to page 0
MOVF EEDATA,W ; return value in W
RETURN
;-------------------------------------------------------------------------;
;Esta rutina llena los registros de despliegue de datos EEPROM ;
;-------------------------------------------------------------------------;
GETEE MOVLW H"01" ; EEprom location 1 +
ADDWF OFFSET,W ; offset from start
CALL READEE ; into W
MOVWF SEC ; into SEC register
MOVLW H"02" ; location 2 +
ADDWF OFFSET,W ; offset from start
CALL READEE ; into W
MOVWF SEC10 ; into SEC10 register
MOVLW H"03" ; location 3 +
ADDWF OFFSET,W ; offset from start
CALL READEE ; into W
MOVWF MIN ; into MIN register
MOVLW H"04" ; location 4 +
ADDWF OFFSET,W ; offset from start
CALL READEE ; into W
MOVWF MIN10 ; into MIN10 register
RETURN
;-------------------------------------------------------------------------;
; Esta rutina escribe un byte para datos EEPROM ;
;-------------------------------------------------------------------------;
WRITEEE BSF STATUS,RP0 ; set up EEADR and EEDATA first
CLRF EECON1
BSF EECON1,WREN ; enable write
MOVLW H"55" ; magic sequence
MOVWF EECON2
MOVLW H"AA"
MOVWF EECON2
BSF EECON1,WR
EELOOP BTFSC EECON1,WR ; wait for WR to go low
GOTO EELOOP ; not yet
BSF EECON1,WREN
BCF EECON1,EEIF ; clear the interrupt flag
BCF STATUS,RP0 ; return to page 0
RETURN
;-------------------------------------------------------------------------;
;Esta rutina mete registros de despliegue en datos EEPROM ;
;-------------------------------------------------------------------------;
PUTEE MOVF SEC,W ; put digit registers into EEprom
MOVWF EEDATA
MOVLW H"01" ; EEPROM location 1 +
ADDWF OFFSET,W ; offset from start
MOVWF EEADR
CALL WRITEEE
MOVF SEC10,W
MOVWF EEDATA
MOVLW H"02" ; EEPROM location 2 +
ADDWF OFFSET,W ; offset from start
MOVWF EEADR
CALL WRITEEE
MOVF MIN,W
MOVWF EEDATA
MOVLW H"03" ; EEPROM location 3 +
ADDWF OFFSET,W ; offset from start
MOVWF EEADR
CALL WRITEEE
MOVF MIN10,W
MOVWF EEDATA
MOVLW H"04" ; EEPROM location 4 +
ADDWF OFFSET,W ; offset from start
MOVWF EEADR
CALL WRITEEE
RETURN
;-------------------------------------------------------------------------;
;Ésta es la rutina principal, el programa comienza aquí ;
;-------------------------------------------------------------------------;
MAIN CALL INIT ; set up ports etc.
;-------------------------------------------------------------------------;
; Regresaremos a este punto cuando la alarma sea desconectada ;
;-------------------------------------------------------------------------;
EE2D CALL GETEE ; put eeprom in display regs.
BCF RUNFLG, 0 ; clear run flag so no countdown
BCF ALARM, 0 ; clear alarm flag
CALL WAITSTARTUP ; wait till no switches pressed
CALL WAITSETUP
CALL WAITSELECT
;-------------------------------------------------------------------------;
;Este lazo inspecciona para ya sea pushbutton y actúa consecuentemente ;
;-------------------------------------------------------------------------;
KEYCHKLOOP BTFSS PORTB,START_PB ; check for start pressed
GOTO STARTCNT ; yes, start count
BTFSS PORTB,SET_PB ; check for set pressed
GOTO SETDISP ; yes, set display
BTFSS PORTA,SELECT_PB ; check select pushbutton pressed
GOTO SETSELECT ; yes, select starting count
GOTO KEYCHKLOOP ; loop to catch key press
;-------------------------------------------------------------------------;
;Si el boton de inicio se ha presionado entonces inicia cuenta regresiva ;
;El TMR0 al cero. El TMR0 es gratis correr y podría tener cualquier ;
;valor de 0-255 cuando el botón sea presionado. También INTCNT tiene ;
;que ser initialized porque la cuenta previa pudo haber sido cancelada. ;
;-------------------------------------------------------------------------;
STARTCNT CALL WAITSTARTUP ; wait for release of start key
MOVLW D"244" ; reset INTCNT
MOVWF INTCNT
CLRF TMR0 ; and clear timer 0
BSF RUNFLG, 0 ; start the countdown
;-------------------------------------------------------------------------;
;Una vez que se comienza justamente el lazo mirando pues cancela o ;
; alcanzando 0000 ;
;-------------------------------------------------------------------------;
MAINLOOP BTFSS PORTB,START_PB ; countdown in progress, check start
GOTO EE2D ; start over again if pressed
BTFSC ALARM, 0 ; reached 0000 yet?
GOTO SOUNDALARM ; yes, turn alarm on
GOTO MAINLOOP ; no start switch, continue looping
;--------------------------------------------------------------------------;
;Este código sondea la alarma y espera en el principio para estar en apuros;
;--------------------------------------------------------------------------;
SOUNDALARM
FINALWAIT BCF PORTB,RB4 ; speaker leads set up
BSF PORTB,RB5 ; opposite polarity
MOVLW 2 ; delay 2 milliseconds
CALL NMSEC
BSF PORTB,RB4 ; flip the speaker leads
BCF PORTB,RB5
MOVLW 2 ; another 2 msec delay
CALL NMSEC
BTFSC PORTB,START_PB ; start button pressed
GOTO FINALWAIT ; not yet
CALL DLY20 ; debounce just to make sure
BTFSC PORTB,START_PB ; second look
GOTO FINALWAIT ; nah, keep waiting
BCF PORTB,RB4 ; speaker leads set to same polarity
BCF PORTB,RB5
CALL WAITSTARTUP ; now wait for the switch up
GOTO EE2D ; start all over again
;-------------------------------------------------------------------------;
; Retardo para el botón de Inicio (1) ;
;-------------------------------------------------------------------------;
WAITSTARTUP BTFSS PORTB,START_PB ; wait for release
GOTO WAITSTARTUP ; not released yet
CALL DLY20 ; debounce release
BTFSS PORTB,START_PB ; 2nd check, make sure released
GOTO WAITSTARTUP ; keep checking
RETURN
;-------------------------------------------------------------------------;
; Retardo para el botón de Seleccion de tiempo de inicio (2) ;
;-------------------------------------------------------------------------;
WAITSETUP BTFSS PORTB,SET_PB ; wait for release
GOTO WAITSETUP ; not yet
CALL DLY20 ; debounce release
BTFSS PORTB,SET_PB ; 2nd check, make sure released
GOTO WAITSETUP ; keep checking
RETURN
;-------------------------------------------------------------------------;
; Retardo para el botón de Parada o Fin de conteo (3) ;
;-------------------------------------------------------------------------;
WAITSELECT BTFSS PORTA,SELECT_PB ; wait for release
GOTO WAITSELECT ; not yet
CALL DLY20 ; debounce release
BTFSS PORTA,SELECT_PB ; 2nd check, make sure released
GOTO WAITSELECT ; keep checking
RETURN
;-------------------------------------------------------------------------;
; La rutina a seguir ajusta el dígito de tiempo de cuenta regresiva ;
;-------------------------------------------------------------------------;
SETDISP CALL WAITSETUP ; wait for set key to be released
MOVLW H"0A" ; put A"s in digits, (no display)
MOVWF MIN10 ; 10"s of minutes
MOVWF MIN ; minutes
MOVWF SEC10 ; 10"s of seconds
MOVWF SEC ; seconds
STARTMIN10 CLRF MIN10 ; 0 now in MIN10
MOREMIN10 MOVLW H"32" ; 50 delays of 20 msec
MOVWF SECNT ; into counting register
WAIT1 CALL DLY20
BTFSS PORTB,SET_PB ; set key pressed?
GOTO MINSET ; yes MIN10 now set
DECFSZ SECNT,f ; finished 1 sec delay?
GOTO WAIT1 ; continue wait
INCF MIN10,f ; every second increment 10"s MIN
MOVLW H"0A" ; reached 10?
SUBWF MIN10,W
BTFSC STATUS,Z ; Z set if reached 10
GOTO STARTMIN10 ; start again with 0
GOTO MOREMIN10 ; set up another 1 sec delay
MINSET CALL WAITSETUP ; wait for release of set key
STARTMIN CLRF MIN ; 0 into MIN
MOREMIN MOVLW H"32" ; 50 delays of 20 msec
MOVWF SECNT ; into counting register
WAIT2 CALL DLY20
BTFSS PORTB,SET_PB ; set pressed?
GOTO SETSEC10 ; yes, finished with MIN
DECFSZ SECNT,f ; finished 1 sec delay?
GOTO WAIT2 ; continue wait
INCF MIN,f ; every second increment MIN
MOVLW H"0A" ; reached 10?
SUBWF MIN,W
BTFSC STATUS,Z ; Z set if reached 10
GOTO STARTMIN ; put zero in if Z set
GOTO MOREMIN ; set up another 1 sec delay
SETSEC10 CALL WAITSETUP ; wait release
STARTSEC10 CLRF SEC10 ; 0 into SEC10
MORESEC10 MOVLW H"32" ; 50 delays of 20 msec
MOVWF SECNT ; into counting register
WAIT3 CALL DLY20
BTFSS PORTB,SET_PB ; set pressed?
GOTO SETSEC ; yes quit incrementing
DECFSZ SECNT,f ; finished 1 sec delay?
GOTO WAIT3 ; continue wait
INCF SEC10,f ; every second increment 10"s SEC
MOVLW H"06" ; reached 6?
SUBWF SEC10,W
BTFSC STATUS,Z ; Z set if reached 6
GOTO STARTSEC10 ; put zero in if Z set
GOTO MORESEC10 ; set up another 1 sec delay
SETSEC CALL WAITSETUP ; wait for release
STARTSEC CLRF SEC ; 0 into SEC
MORESEC MOVLW H"32" ; 50 delays of 20 msec
MOVWF SECNT ; into counting register
WAIT4 CALL DLY20
BTFSS PORTB,SET_PB ; set button pressed?
GOTO FINSET ; yes finished setting digits
DECFSZ SECNT,f ; finished 1 sec delay?
GOTO WAIT4 ; continue wait
INCF SEC,f ; every second increment SEC
MOVLW H"0A" ; reached 10?
SUBWF SEC,W
BTFSC STATUS,Z ; Z set if reached 10
GOTO STARTSEC ; put zero in if Z set
GOTO MORESEC ; set up another 1 sec delay
FINSET BCF INTCON, GIE ; disable interrupts
CALL PUTEE ; put new digits into EEPROM
BSF INTCON, GIE ; re-enable interrupts
CALL WAITSETUP ; make sure set switch up
GOTO KEYCHKLOOP ; start checking buttons again
;-------------------------------------------------------------------------;
;Selecciona comenzar cuenta cambiando localización EEPROM 0 ;
;-------------------------------------------------------------------------;
SETSELECT MOVLW D"4" ; offset up 4
ADDWF OFFSET,F ; next offset position
MOVLW D"60" ; reached 16th yet?
SUBWF OFFSET,W ; will give zero if yes
BTFSC STATUS,Z ; skip if not 64
CLRF OFFSET ; reset position to zero
MOVLW 0 ; EEPROM location
MOVWF EEADR ; set up address
MOVF OFFSET,W ; offset # into W
MOVWF EEDATA ; set up data
BCF INTCON,GIE ; clear GIE, disable interrupts
CALL WRITEEE ; save # in location 0
BSF INTCON,GIE ; re-enable interrupts
CALL GETEE ; get new start count into display
CALL WAITSELECT ; make sure select switch is up
GOTO KEYCHKLOOP ; start checking buttons again
;-------------------------------------------------------------------------;
;Lo siguiente es retraso diversos que las rutinas basaron en el largo de ;
;instrucción. ;
;Se asume que del largo instrucción es 1 microsegundo (el cristal 4Mhz). ;
;-------------------------------------------------------------------------;
DLY20 MOVLW 20 ; delay for 20 milliseconds
;*** N millisecond delay routine ***
NMSEC MOVWF CNTMSEC ; delay for N (in W) milliseconds
MSECLOOP MOVLW D"248" ; load takes 1 microsec
CALL MICRO4 ; by itself CALL takes ...
; 2 + 247 X 4 + 3 + 2 = 995
NOP ; 1 more microsec
DECFSZ CNTMSEC,f ; 1 when skip not taken, else 2
GOTO MSECLOOP ; 2 here: total 1000 per msecloop
RETURN ; final time through takes 999 to here
; overhead in and out ignored
;*** 1 millisecond delay routine ***
ONEMSEC MOVLW D"249" ; 1 microsec for load W
; loops below take 248 X 4 + 3 = 995
MICRO4 ADDLW H"FF" ; subtract 1 from "W"
BTFSS STATUS,Z ; skip when you reach zero
GOTO MICRO4 ; loops takes 4 microsec, 3 for last
RETURN ; takes 2 microsec
; call + load W + loops + return =
; 2 + 1 + 995 + 2 = 1000 microsec
;-------------------------------------------------------------------------;
;Aquí establecemos los valores iniciales de los dígitos en datos EEPROM ;
;-------------------------------------------------------------------------;
ORG H"2100"
DE 0, 1, 0, 0, 0 ; 1st starting #
DE 2, 0, 0, 0 ; 2nd starting #
DE 3, 0, 0, 0 ; 3rd starting #
DE 4, 0, 0, 0 ; 4th starting #
DE 5, 0, 0, 0 ; 5th starting #
DE 6, 0, 0, 0 ; 6th starting #
DE 7, 0, 0, 0 ; 7th starting #
DE 8, 0, 0, 0 ; 8th starting #
DE 9, 0, 0, 0 ; 9th starting #
DE 0, 1, 0, 0 ; 10th starting #
DE 1, 1, 0, 0 ; 11th starting #
DE 2, 1, 0, 0 ; 12th starting #
DE 3, 1, 0, 0 ; 13th starting #
DE 4, 1, 0, 0 ; 14th starting #
DE 5, 1, 0, 0 ; 15th starting #
END
Está casi como lo encontre en la Red. quedo a la espera de su importante ayuda.
Gracias!.
Omar