I have this circuit: enter image description here

So my problem is that I'm having trouble using the TMR0 interrupt as a delay or substitute to the SLEEP instruction in the PIC16F84A. I can't quite get the concept of using the overflows to generate a timeout.

What I have in mind is that, I have to put the overflow counter loop inside the TMR0 subroutine, and then loop until it reaches the number of overflows required to generate a 1s timeout. Is this correct? If so, how could I implement it in my code?

Side Question: How can I initialize variables in PIC assembly? What is the equivalent of


in PIC assembly?

Here is my code so far:

LIST P=16F84A, F=INHX8M          ; MCU is PIC16F84A, output is Intel Hex
INCLUDE<P16F84A.INC>             ; include this file to use register names instead of addresses
__CONFIG _CP_OFF & _WDT_ON & _XT_OSC ; code protection off, Watchdog Tiemr on, XTAL osc used

 ORG 000H
 ORG 004H               ; interrupt vector
 GOTO INT_RTN           ; jump to label INT_RTN or the interrupt service routine

 ; initialize PIC
 BSF STATUS, RP0            ; set register bank to 1
 CLRF TRISA                 ; clear register TRISA (bank 1)
                            ; sets all bits in PORTA as "output"
 MOVLW 0FFH                 ; load literal value 01H to Wreg
 MOVWF TRISB                ; move data in Wreg to register TRISB (bank 1)
                            ; set ports in PORTB as "input"
 MOVLW 004H                 ; load literal value 04H to Wreg
                            ; prescaler 1:32 assigned to Watchdog Timer (WDT)
 MOVWF OPTION_REG           ; move data in Wreg to register OPTION_REG (bank 0/1)
 BSF OPTION_REG, 6          ; interrupt event during rising edge
 BCF INTCON, INTF           ; clear the RB0/INT interrupt flag
 BSF INTCON, INTE           ; unmask (enable) RB0/INT interrupt source
 BSF INTCON, GIE            ; enable all unmasked interrupt
 BCF INTCON, T0IF           ; clears the TMR0 overflow interrupt flag
 BSF INTCON, T0IE           ; unmasked (enable) TMR0 overflow interrupt
 BCF STATUS, RP0            ; set register bank to 0

 ; program start

 BCF INTCON, GIE             ; disables all unmasked interrupt (no interrupt overriding)
 BTFSC INTCON, INTF          ; check the RB0/INT flag
 GOTO RB0_INT                ; jump to label RB0_INT (routine for RB0_INT)
 BTFSC INTCON, T0IF          ; check the TMR0 interrupt flag
 GOTO TMR0_INT               ; jump to label TMR0_INT (routine for TMR0 interrupt)
 GOTO EXIT                   ; exit INT_RTN 
                             ; hardware interrupt
 BCF INTCON, INTF            ; reset RB0/INT flag
 ;code for RB0

                             ; TMR0 Interrupt
 ;code for TMR
 BSF INTCON, GIE               ; enable all unmasked interrupt
 RETFIE                    ; return from interrupt routine

 MOVLW 09H                 ; load literal value 09H to Wreg
 **COUNTDOWN**  //Countdown timer from 9-0      
 DECFSZ PORTA, 1                 ; decrement register COUNT, skip next line if result is 0
 GOTO COUNTDOWN                  ; jump to label INC
 GOTO START                      ; jump to label START


In your main loop, when you want to have a delay and wait for a while, clear tmr0 and the counter variable and then enable tmr0 interrupts. Immediatly enter a little loop which repetitively compares the value of the counter variable against the limit value (number of required tmr0 interrupts). The counter variable would be incremented in the tmr0 ISR every time the ISR is executed (every time tmr0 overflows). When the counter variable value matches the limit value jump out of the loop, disable tmr0 interrupts and continue on the main loop. The code to achieve an exact 1 second delay would require a little complexity because tmr0 has a count of 256 and this figure combined with the available pre-scaler values can make life a little more complicated.

To compare the counter value against the limit value subtract one from the other and test the zero flag.

Alternatively you could start with the counter value at the required count and decrement it once every tmr0 interrupt. Then test the counter's value for when it reaches zero by repetitively moving it into itself in the repeating loop (MOVF Counter,F) and then testing the zero flag. The MOVF instruction sets the zero flag if the result is zero. This method is a little simpler than the first because no subtraction is necessary.

In the PIC 16F84A there are 68 general purpose registers (SRAM) for holding variables. They start at address 0x0C. So, before your ORG 0x0000 you would initialise your variables like this

Variablename1 equ 0x0C

Variablename2 equ 0x0D

Variablename3 equ 0x0E

and so on...

  • \$\begingroup\$ THANK YOU SO MUCH \$\endgroup\$ – German III Felisarta Dec 17 '20 at 12:52
  • \$\begingroup\$ Umm one last question though, do variables assigned in the general-purpose registers, really behave like variables like in higher level languages? \$\endgroup\$ – German III Felisarta Dec 17 '20 at 12:54
  • \$\begingroup\$ The variables declared in the general purpose registers are variables in the true sense and can have there values incremented, decremented, added, subtracted and processed in just the same way as any high level variable, obviously limited by the capabilities of the particular PIC's instruction set. However they are only 8 bits wide and so would be equivalent to a variable defined as type "char" in C. \$\endgroup\$ – James Dec 17 '20 at 14:21
  • \$\begingroup\$ Again, thanks a lot for the very in-depth explanations! \$\endgroup\$ – German III Felisarta Dec 17 '20 at 14:28

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.