# Debouncing of a push button in assembly using Timer1 interrupt - PIC16F628A [closed]

I am new at assembly programming and I need to develop a debouncing code to use on a push button, for that I am required to use timer1 interrupt.

The push button will be used to increment a counter that will output to a 7seg display. I already have it displaying the numbers, using a counter and a table, but now I am stuck on the interrupt, i never did anything like that.

There should be a second button that will reset the counter. Push buttons will change state with "0" and should only count one number while pressed no matter the duration of the click. If anyone could post an example I would be very thankful. Regards

## closed as off-topic by Michael Karas, Enric Blanco, Dmitry Grigoryev, PeterJ, winnyJul 12 '17 at 9:27

• This question does not appear to be about electronics design within the scope defined in the help center.
If this question can be reworded to fit the rules in the help center, please edit the question.

• VTC - This site is not a software supply house. On top of that the subject of switch debouncing in software can be found in a plethora of web sites. – Michael Karas Jul 7 '17 at 1:12
• @ERS a better way would be to write some debouching code, test it and then ask if it doesn't work. Engineers get really finicky when people don't try things out on their own – Voltage Spike Jul 9 '17 at 5:37

Here's some of that promised help.

The PIC16F628A has two vectors you need to set up. It's often done something like this:

        ORG 000H
GOTO MAIN

ORG 004H
GOTO ALLINTS

ORG 010H
MAIN


When the processor comes out of reset, it will start at MAIN. But if an interrupt happens (from any source), it will then branch to ALLINTS. The names can be anything you want, though. But those will suffice here.

You can debounce any and all switches on PORTA, at once. (See the code I've provided for a different processor here: Differences between Interrupts and sampling for hardware button?

Your MAIN code will need to initialize the timer to my preference of $8\:\textrm{ms}$. I'll assume $4\:\textrm{MHz}$ is the operating clock rate. If you set up for a divide by 8, your counter will need to start out at -1000 and be reset to that, each interrupting event. Of course, you'll need to initialize variables and the TMR1 register and associated configuration bits in T1CON.

Some of the variables I'm considering might be placed in a CBLOCK, like this:

        CBLOCK
SWDEBPREV
SWDEBCURR
T1_SAVEW
T1_SAVES
T1_STPREV
T1_STCURR
T1_SWPREV
T1_SWCURR
ENDC


You'll need a constant, like this:

COUNTDOWN   EQU     -1000


The MAIN code (replace the above example with the following) might start out something like this:

        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


That's before getting into the main LOOP which polls things.

Skip past the main loop for a minute and let's get to the interrupt routine. I've provided a link above which provides the basic logic of the state machine that can be applied to debounce a switch. But... it turns out that this state machine can be performed simultaneously on an entire port at one time, as easily as it is performed on one port pin. The processor works in 8-bit bytes, so why not take advantage of that?

The interrupt code might look like the following code. But be aware that I'm assuming (for now) that there is only one interrupt that has been enabled. I'm making this assumption because (1) I have no information about other interrupts; and, (2) it would greatly complicate things.

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


I have tried to avoid any need to switch banks in the above code and that simplifies the state saving, just slightly. It's been a while (okay -- 10 years) since I've written PIC16 code. So please check it over carefully for mistakes. I think I got the basic inner logic correct. But the state saving and restoring is worth a close look. (Also note that in resetting TMR1 I felt I had to disable the counter long enough to load the next countdown value. This will cause the timing to "slide" a bit -- the time between interrupts won't be exactly $8\:\textrm{ms}$. But this is okay for just debouncing switches. So I didn't go to any further trouble about it.)

The MAIN code now only needs to observer the debounced states. If you want to look for a specific button value, you can read up SWDEBCURR and mask it with whatever appropriate mask is required to extract the specific pin and then just test the debounced bit value.

If, instead, you want to look for a debounced button change, then read up SWDEBCURR and XOR it with SWDEBPREV. Those bits that are then set to a 1 are cases where there has been a debounced button PRESS or RELEASE change.

Whichever choice you want is yours.