Aquí hay algo de la ayuda prometida.
El PIC16F628A tiene dos vectores que necesita configurar. A menudo se hace algo como esto:
ORG 000H
GOTO MAIN
ORG 004H
GOTO ALLINTS
ORG 010H
MAIN
Cuando el procesador se reinicie, se iniciará en MAIN. Pero si ocurre una interrupción (de cualquier fuente), entonces se derivará a ALLINTS. Los nombres pueden ser lo que quieras, sin embargo. Pero esos serán suficientes aquí.
Puede anular todos y cada uno de los conmutadores en PORTA, a la vez. (Consulte el código que he proporcionado para un procesador diferente aquí: ¿Diferencias entre interrupciones y muestreo para el botón de hardware?
Su código PRINCIPAL deberá inicializar el temporizador según mis preferencias de \ $ 8 \: \ textrm {ms} \ $. Asumiré que \ $ 4 \: \ textrm {MHz} \ $ es la velocidad del reloj operativo. Si configura una división por 8, su contador deberá comenzar en -1000 y restablecerse a eso, cada evento de interrupción. Por supuesto, deberá inicializar las variables y el registro TMR1 y los bits de configuración asociados en T1CON.
Algunas de las variables que estoy considerando podrían estar ubicadas en un CBLOCK, como este:
CBLOCK
SWDEBPREV
SWDEBCURR
T1_SAVEW
T1_SAVES
T1_STPREV
T1_STCURR
T1_SWPREV
T1_SWCURR
ENDC
Necesitarás una constante, como esta:
COUNTDOWN EQU -1000
El código PRINCIPAL (reemplace el ejemplo anterior con el siguiente) podría comenzar algo como esto:
ORG 010H
MAIN
; TODO: Configure PORTA as required. Assume all switches are on PORTA.
CLRF INTCON
CLRF SWDEBPREV
CLRF SWDEBCURR
CLRF T1_SWPREV
CLRF T1_SWCURR
CLRF T1_STPREV
CLRF T1_STCURR
CLRF PIR1
BSF STATUS, RP0
CLRF PIE1
BSF PIE1, TMR1IE
BCF STATUS, RP0
MOVLW 34H
MOVWF T1CON
MOVLW LOW COUNTDOWN
MOVWF TMR1L
MOVLW LOW (COUNTDOWN >> 8)
MOVWF TMR1H
BSF INTCON, PEIE
BSF INTCON, GIE
BSF T1CON, TMR1ON
LOOP
; TODO: Use SWDEBCURR and SWDEBPREV here.
GOTO LOOP
Eso es antes de entrar en el LOOP principal que sondea las cosas.
Salte del bucle principal por un minuto y vayamos a la rutina de interrupción. He proporcionado un enlace anterior que proporciona la lógica básica de la máquina de estado que se puede aplicar para rebotar un interruptor. Pero ... resulta que esta máquina de estado se puede realizar simultáneamente en un puerto completo a la vez, tan fácilmente como se realiza en un pin de puerto. El procesador funciona en bytes de 8 bits, ¿por qué no aprovechar eso?
El código de interrupción puede parecerse al siguiente código. Pero tenga en cuenta que asumo (por ahora) que solo hay una una interrupción habilitada. Estoy haciendo esta suposición porque (1) no tengo información sobre otras interrupciones; y, (2) complicaría mucho las cosas.
ALLINTS MOVWF T1_SAVEW
SWAPF STATUS, W
MOVWF T1_SAVES
BCF T1CON, TMR1ON
MOVLW LOW COUNTDOWN
MOVWF TMR1L
MOVLW LOW (COUNTDOWN >> 8)
MOVWF TMR1H
BSF T1CON, TMR1ON
MOVF SWDEBCURR, W ; Make the last debounced value
MOVWF SWDEBPREV ; the prior debounced value.
MOVF T1_STCURR, W ; Make the last switch state value
MOVWF T1_STPREV ; the prior switch state value.
MOVF T1_SWCURR, W ; Make the last raw port value
MOVWF T1_SWPREV ; the prior raw port value.
MOVF PORTA, W ; Read the port and save it as
MOVWF T1_SWCURR ; the current raw port value.
MOVWF SWDEBCURR ; Start as debounced value, too.
XORWF T1_SWPREV, W
MOVWF T1_STCURR
IORWF T1_STPREV, F
COMF W, W
ANDWF SWDEBCURR, F
MOVF T1_STPREV, W
ANDWF SWDEBPREV, W
IORWF SWDEBCURR, F ; Generate final debounced value.
MOVF T1_SAVES, W
SWAPF STATUS, W
MOVF T1_SAVEW, W
BCF PIR1, TMR1IF
RETFIE
He intentado evitar cualquier necesidad de cambiar de banco en el código anterior y eso simplifica el ahorro de estado, solo un poco. Ha pasado un tiempo (bueno, 10 años) desde que escribí el código PIC16. Así que por favor revísalo cuidadosamente para ver si hay errores. Creo que tengo la lógica interna básica correcta. Pero el ahorro y restauración del estado merece una mirada de cerca. (También tenga en cuenta que al reiniciar TMR1 sentí que tenía que deshabilitar el contador el tiempo suficiente para cargar el siguiente valor de la cuenta regresiva. Esto hará que el tiempo se "deslice" un poco; el tiempo entre las interrupciones no será exactamente \ $ 8 \: \ textrm {ms} \ $. Pero esto está bien solo para deshacer los interruptores. Por lo tanto, no tuve más problemas al respecto.)
El código PRINCIPAL ahora solo necesita observar los estados de devolución. Si desea buscar un valor de botón específico, puede leer SWDEBCURR y enmascararlo con la máscara apropiada que sea necesaria para extraer el pin específico y luego probar el valor del bit de rebote.
Si, en cambio, desea buscar un cambio en el botón de rebote, lea SWDEBCURR y XOR con SWDEBPREV. Aquellos bits que luego se configuran en 1 son casos en los que ha habido un botón de DEBICACIÓN o LIBERACIÓN de rebote.
La opción que quieras es tuya.