# Need help with PIC Assembly for PIC16F72 Interrupt service routine

#### seifullaah73

Joined Dec 13, 2019
41
Hi

I have been learning PIC assembly language and is very interesting and am doing about interrupt routines I have studied a lot of articles about registers that might be useful.

My personal task is to use the built in timer0 as the source of interrupt to create a square wave or flashing LED. when the interrupt occurs it should turn the light off or set pin to low and after the interrupt the light should be turned back on or set to high until the next interrupt occurs, which is after every 1ms.

My code doesn't work, it doesn't even trigger the interrupt and need some help, have been working at it for weeks, even included the option register to select the clock source and still nothing and even restoring status and w register.

Code:
#include <p16f72.inc>
__config (_HS_OSC & _WDT_OFF & _PWRTE_OFF & _CP_OFF)

; /////////////////////////////////////////////////////////////////////////

;             Define all registers and variable addresses!
;          Note: Crystal frequency is 4MHz, so 1 tick = prescaler * 4 / 4 MHz
;          to get 1ms @40MHz with prescaler of 32
;          256 - ((delay * Fosc)/(prescalar * 4))
;              256 - ((1ms * 4Mhz)/(32*4)) = 225
;
; /////////////////////////////////////////////////////////////////////////

STATUS        EQU        3
PORTC        EQU        7
PORTB        EQU        6
INTCON        EQU        h'B'
TMR0        EQU        1
TRISC        EQU        h'87'
TRISB        EQU        h'86'
OPTION_REG        EQU        h'81'

W_SAVE        EQU         25
STATUS_SAVE    EQU         26
COUNTA        EQU        27

;******************************************************************

list    P=16F72

ORG 000H
GOTO MAIN

ORG 004H
GOTO INTFUNCT

; /////////////////////////////////////////////////////////////////////////

;             Initialize all variables and port pins here!

; /////////////////////////////////////////////////////////////////////////
MAIN:
BSF    STATUS, RP0
MOVLW     B'00000000'
MOVWF    TRISB

MOVLW    B'00101100'
MOVWF    OPTION_REG
BCF    STATUS, RP0
CLRF    PORTB
MOVLW    .225
MOVWF    TMR0
BCF    INTCON, TMR0IF
BSF    INTCON, TMR0IE
BSF    INTCON, GIE

PROGRAM:
BSF    PORTB,0        ;keep light on until after 1ms interrupt will trigger
GOTO PROGRAM

INTFUNCT:
MOVWF W_SAVE        ; save W
SWAPF STATUS, W     ; save STATUS
MOVWF STATUS_SAVE

BCF    INTCON, TMR0IF
BCF    INTCON, GIE
BCF    STATUS, RP0

BCF    PORTB,0        ;turn off the light

MOVLW    .198    ;1ms delay including time it takes to execute delay loop and commands till return
MOVWF CountA        ;create a delay of 1ms - the duration the light will stay off
Call    DelayFunct

MOVLW    .225
MOVWF    TMR0

SWAPF STATUS_SAVE, W
MOVWF STATUS
SWAPF W_SAVE, F
SWAPF W_SAVE, W

RETFIE

DelayFunct:
NOP
DECFSZ    CountA
GOTO DelayFunct
return

END
Would appreciate some insight. This builds without errors on MPLAB but has some messages and warnings but when I send it to the board, the LED just stays on. doesn't flash.

Thanks

#### seifullaah73

Joined Dec 13, 2019
41
I spotted one mistake I selected the wrong bits on the option register

changed it from:
MOVLW B'00101100'
MOVWF OPTION_REG

To

MOVLW B'10000100'
MOVWF OPTION_REG

I can't edit my original post so had to make a reply. So my new code is now.
Code:
#include <p16f72.inc>
__config (_HS_OSC & _WDT_OFF & _PWRTE_OFF & _CP_OFF)

; /////////////////////////////////////////////////////////////////////////

;             Define all registers and variable addresses!
;          Note: Crystal frequency is 4MHz, so 1 tick = prescaler * 4 / 4 MHz
;          to get 1ms @40MHz with prescaler of 32
;          256 - ((delay * Fosc)/(prescalar * 4))
;              256 - ((1ms * 4Mhz)/(32*4)) = 225
;
;
; /////////////////////////////////////////////////////////////////////////

STATUS        EQU        3
PORTC        EQU        7
PORTB        EQU        6
INTCON        EQU        h'B'
TMR0        EQU        1
TRISC        EQU        h'87'
TRISB        EQU        h'86'
OPTION_REG        EQU        h'81'

W_SAVE        EQU         25
STATUS_SAVE    EQU         26
COUNTA        EQU        27

;******************************************************************

list    P=16F72

ORG 000H
GOTO MAIN

ORG 004H
GOTO INTFUNCT

; /////////////////////////////////////////////////////////////////////////

;             Initialize all variables and port pins here!

; /////////////////////////////////////////////////////////////////////////
MAIN:
BSF    STATUS, RP0
MOVLW     B'00000000'
MOVWF    TRISB

MOVLW    B'10000100'
MOVWF    OPTION_REG
BCF    STATUS, RP0
CLRF    PORTB
MOVLW    .225
MOVWF    TMR0
BCF    INTCON, TMR0IF
BSF    INTCON, TMR0IE
BSF    INTCON, GIE

PROGRAM:
BSF    PORTB,0        ;keep light on until after 1ms interrupt will trigger
GOTO PROGRAM

INTFUNCT:
MOVWF W_SAVE        ; save W
SWAPF STATUS, W     ; save STATUS
MOVWF STATUS_SAVE

BCF    INTCON, TMR0IF
BCF    INTCON, GIE
BCF    STATUS, RP0

BCF    PORTB,0        ;turn off the light

MOVLW    .198    ;1ms delay including time it takes to execute delay loop and commands till return
MOVWF CountA        ;create a delay of 1ms - the duration the light will stay off
Call    DelayFunct

MOVLW    .225
MOVWF    TMR0

SWAPF STATUS_SAVE, W
MOVWF STATUS
SWAPF W_SAVE, F
SWAPF W_SAVE, W

RETFIE

DelayFunct:
NOP
DECFSZ    CountA
GOTO DelayFunct
return

END
Thanks for your help

#### Papabravo

Joined Feb 24, 2006
12,684
There are at least two bits you must pay attention to. One is the Timer0 Interrupt Enable Bit which is located in one of the interrupt enable registers. The second bit is the Global Interrupt Enable. You should only turn GIE on, one time only. Do NOT turn it off inside the interrupt routine. Do not waste time in a delay routine inside an interrupt function. Get in, do your business, and get out.

My recomendation(s):
1. Set Timer0 to interrupt periodically
2. Check that it is Timer 0 which is causing the interrupt, and only reset the Timer0 flag and do the rest of your process if it is.
3. Complement a state variable on each interrupt. Something like var ^= 1 ; //Exclusive Or variable with 1 to complement it, or better var = !var ; // var = NOT (var)
4. Turn the light on if the state variable is a 1
5. Turn the light off if the state variable is a 0
6. Exit.
The goal is to spend the absolute minimum time inside the interrupt routine. The time inside an interrupt routine should be measured in microseconds.

#### jpanhalt

Joined Jan 18, 2008
8,303
1) Do you have a crystal or ceramic resonator attached? Show the circuit. Do you know that it is running?
2) Your TMR0 presets will give quite short flashes. That is, the count starts at 225 --> rollover = 30, not 225. TMR0 always counts up.
3) Your count down delay timers will give even shorter periods, as they operate at 1 MHz (Fosc/4) and do not have a prescale.
4) Agree that your ISR is longer than needed and you should not turn GIE off (again) during the interrupt. The interrupt does that. You do need to clear the flag.
5) Your context saving seems a bit clumsy. Is that what microchip recommends? I would first save status with a swapf as that affects no flags. Then you can save WREG with a movwf without worrying. (If W happens to = 0, your first step will affect STATUS,2 .) In some instances, you do not need to save Context, but it doesn't hurt to do so.
6) For longer delays, you can set the prescale for TMR0 higher and count the number of turnovers in the ISR. For example, set a count = 10, then with each interrupt, decrease that count. When zero, toggle the LED. The XOR function is handy for doing that, but your way is OK.
7) Watch capitalization. It's good practice not to ignore it.
8) Watch your columns. Several warnings about directives in the wrong column.

#### seifullaah73

Joined Dec 13, 2019
41
1) Do you have a crystal or ceramic resonator attached? Show the circuit. Do you know that it is running?
2) Your TMR0 presets will give quite short flashes. That is, the count starts at 225 --> rollover = 30, not 225. TMR0 always counts up.
3) Your count down delay timers will give even shorter periods, as they operate at 1 MHz (Fosc/4) and do not have a prescale.
4) Agree that your ISR is longer than needed and you should not turn GIE off (again) during the interrupt. The interrupt does that. You do need to clear the flag.
5) Your context saving seems a bit clumsy. Is that what microchip recommends? I would first save status with a swapf as that affects no flags. Then you can save WREG with a movwf without worrying. (If W happens to = 0, your first step will affect STATUS,2 .) In some instances, you do not need to save Context, but it doesn't hurt to do so.
6) For longer delays, you can set the prescale for TMR0 higher and count the number of turnovers in the ISR. For example, set a count = 10, then with each interrupt, decrease that count. When zero, toggle the LED. The XOR function is handy for doing that, but your way is OK.
7) Watch capitalization. It's good practice not to ignore it.
8) Watch your columns. Several warnings about directives in the wrong column.
1. I have a crystal resonator attached. part of the PIC16F72 board
2. The preset values are set at 225 because I wanted 1ms and in the prescalar I have chosen 1:32 so that will give me an interrupt after 1ms because 225 - 255 = 30 * 32 = 960us.
3. count down delay timer meaning my delay in the interrupt of 198us and each instruction is 1us and the loop consists of a total of 5us instructions meaning it will have to loop 200 times to get 1ms but also taking in to consideration of other instructions I adjusted the delay.
4. which I done.
5. ok thanks changed it around
6. Oh ok i see, great idea for longer delays like up to get 1 second delay, I would need a delay of 100ms for each interrupt. I'm not sure how I would use the xor function and how it would help. am still kinda new to assembly.
7. tell me more
8. i didn't know this, explain using my code how it should because i do get that warning.

#### jpanhalt

Joined Jan 18, 2008
8,303
On the TMR0 prescale, sorry, I read the wrong column.
@7 COUNTA vs. CountA
@8 I just copied and pasted the code in your post, "Return" and END are in the first column as are some other things early on.

#### seifullaah73

Joined Dec 13, 2019
41
There are at least two bits you must pay attention to. One is the Timer0 Interrupt Enable Bit which is located in one of the interrupt enable registers. The second bit is the Global Interrupt Enable. You should only turn GIE on, one time only. Do NOT turn it off inside the interrupt routine. Do not waste time in a delay routine inside an interrupt function. Get in, do your business, and get out.

My recomendation(s):
1. Set Timer0 to interrupt periodically
2. Check that it is Timer 0 which is causing the interrupt, and only reset the Timer0 flag and do the rest of your process if it is.
3. Complement a state variable on each interrupt. Something like var ^= 1 ; //Exclusive Or variable with 1 to complement it, or better var = !var ; // var = NOT (var)
4. Turn the light on if the state variable is a 1
5. Turn the light off if the state variable is a 0
6. Exit.
The goal is to spend the absolute minimum time inside the interrupt routine. The time inside an interrupt routine should be measured in microseconds.
Timer0 doesn't have the ability to interrupt periodically only relies on starting and stopping automatically depending on clearing the flag

to check if it is timer0 i have used BTFSS if that is what you mean. below is example

Code:
BTFSS    TMR0IF
GOTO ENDIR

rest of interrupt below

ENDIR
RESTORE
RETFIE
with regards to Var, you want me to set it to the opposite of the timer interrupt flag so if flag is 1 meaning interrupt occurred then set var to 1 and then later on do a conditional state if var 1 light off and on if var is 0. so something like

don't know how to do Var = !var in pic assembly so maybe something like
Code:
VAR    EQU    28

MOVWF    INTCON, TMR0IF
XORLW    1
MOVWF    VAR
Then use BTFSS VAR function, which you already mentioned, maybe you are repeating.

#### seifullaah73

Joined Dec 13, 2019
41
On the TMR0 prescale, sorry, I read the wrong column.
@7 COUNTA vs. CountA
@8 I just copied and pasted the code in your post, "Return" and END are in the first column as are some other things early on.
Oh you mean indentation. I removed the delay. So what are the only instructions, that should be in the same column as END and that means the rest have to be indented.

What's the typical spacing between command and value
e.g.
STATUS EQU 3

#### jpanhalt

Joined Jan 18, 2008
8,303
Timer0 doesn't have the ability to interrupt periodically only relies on starting and stopping automatically depending on clearing the flag

to check if it is timer0 i have used BTFSS if that is what you mean. below is example

????
It only interrupts on rollover.

Good luck.

#### seifullaah73

Joined Dec 13, 2019
41
????
It only interrupts on rollover.
View attachment 194465

Good luck.
Sorry my mistake. I meant timer0 didn't have a start or stop function.
it just interrupts everytime the timer0 overflows

#### seifullaah73

Joined Dec 13, 2019
41
Also another it is hard to get a 100ms delay so I decided to get a 10ms delay, which would be about 178 preloaded timer value and a prescale of 128. then have a variable from 100 counting down to 0 using DECFSZ then turn on the light after it has reached 0.

#### seifullaah73

Joined Dec 13, 2019
41
So this is what I have got so far.

Code:
;******************************************************************
;Name:            Daniel Bickerstaff
; led sequence
;Date:            10/06/2014
;Version:            1
;File Name:        ISR_2019_Simple.asm
;Processor:            PIC 16F72
;Clock Speed:         4 MHz (Oscillator Xtal)
;Description:        Brief description

; History of any changes!

; 25/06/19   Modified to make easier to read for learners

;******************************************************************

#include <p16f72.inc>
__config (_HS_OSC & _WDT_OFF & _PWRTE_OFF & _CP_OFF)

; /////////////////////////////////////////////////////////////////////////

;             Define all registers and variable addresses!
;          Note: Crystal frequency is 4MHz, so 1 tick = prescaler * 4 / 4 MHz
;          to get 10ms @40MHz with prescaler of 128
;          256 - ((delay * Fosc)/(prescalar * 4))
;             256 - ((10ms * 4Mhz)/(32*4)) = 178
;          Then to get 1 second delay add a variable counting down from 100
;
;Below are the steps for configuring and using the Timer0 for delay generation:
;
;Calculate the Timer Count for the required delay.
;Set the Presaclar bits in OPTION_REG as per the delay calculations.
;Clear the PSAbit for using the prescalar.
;Select the Clock Source Internal/External using TOCS bit.
;Load the timer value into TMRO register.
;Enable the Timer0 Interrupt by setting TMR0IE bit
;Enable the Global and Peripheral interrupts by setting GIE and PIE bits

; /////////////////////////////////////////////////////////////////////////

STATUS        EQU        3
PORTC        EQU        7
PORTB        EQU        6
INTCON        EQU        h'B'
TMR0        EQU        1
TRISC        EQU        h'87'
TRISB        EQU        h'86'
OPTION_REG    EQU        h'81'

W_SAVE        EQU         25
STATUS_SAVE    EQU         26
INTDELAY    EQU        27

;******************************************************************

list    P=16F72

ORG 000H
GOTO MAIN

ORG 004H
GOTO INTFUNCT

; /////////////////////////////////////////////////////////////////////////

;             Initialize all variables and port pins here!

; /////////////////////////////////////////////////////////////////////////
MAIN:
BSF    STATUS, RP0
MOVLW     B'00000000'
MOVWF    TRISB

MOVLW    B'10000110'
MOVWF    OPTION_REG
BCF    STATUS, RP0
CLRF    PORTB
MOVLW    .178
MOVWF    TMR0
BCF    INTCON, TMR0IF
BSF    INTCON, TMR0IE
BSF    INTCON, GIE
MOVLW    .100
MOVWF    INTDELAY

PROGRAM:
BSF    PORTB,0        ;keep light on until after 10ms interrupt will trigger
GOTO PROGRAM

INTFUNCT:
MOVWF W_SAVE        ; save W
SWAPF STATUS, W     ; save STATUS
MOVWF STATUS_SAVE

BCF    STATUS, RP0

BTFSS    TMR0IF
GOTO ENDIR

BCF    INTCON, TMR0IF
DECFSZ    INTDELAY
GOTO ENDIR        ;once it reaches 0, then do the main part of the interrupt and then reset intdelay

BCF    PORTB,0        ;turn off the light after 1 seconds

MOVLW    .178
MOVWF    TMR0
MOVLW    .100
MOVWF    INTDELAY
GOTO ENDIR

ENDIR:
SWAPF STATUS_SAVE, W
MOVWF STATUS
SWAPF W_SAVE, F
SWAPF W_SAVE, W
RETFIE

END
I didn't know how to implement the XOR to toggle LED depending on whether bitflag is set or not except that I move value in the flag to W register then do XORLW var but after i don't know how I would do If var==1 then light on else light equals off.

also another thing is how do I add a delay to how long the light should be off, shall I just control the on and off in the main program depending on whether the variable is a 1 or a 0 but i wouldn't know how to do a conditional statement.

Feedback appreciated.

#### seifullaah73

Joined Dec 13, 2019
41
Sorry for the messy thread

Time limit to edit is 10 mins, I just re-edited my code and here is another version with my attempt to XOR the var with 1 so I can use that to toggle LED on or off.

So the interrupt will be used to only toggle the state not actually turn led on for a certain amount.

Code:
;******************************************************************
;Name:            Daniel Bickerstaff
; led sequence
;Date:            10/06/2014
;Version:            1
;File Name:        ISR_2019_Simple.asm
;Processor:            PIC 16F72
;Clock Speed:         4 MHz (Oscillator Xtal)
;Description:        Brief description

; History of any changes!

; 25/06/19   Modified to make easier to read for learners

;******************************************************************

#include <p16f72.inc>
__config (_HS_OSC & _WDT_OFF & _PWRTE_OFF & _CP_OFF)

; /////////////////////////////////////////////////////////////////////////

;             Define all registers and variable addresses!
;          Note: Crystal frequency is 4MHz, so 1 tick = prescaler * 4 / 4 MHz
;          to get 10ms @40MHz with prescaler of 128
;          256 - ((delay * Fosc)/(prescalar * 4))
;             256 - ((10ms * 4Mhz)/(32*4)) = 178
;          Then to get 1 second delay add a variable counting down from 100
;
;Below are the steps for configuring and using the Timer0 for delay generation:
;
;Calculate the Timer Count for the required delay.
;Set the Presaclar bits in OPTION_REG as per the delay calculations.
;Clear the PSAbit for using the prescalar.
;Select the Clock Source Internal/External using TOCS bit.
;Load the timer value into TMRO register.
;Enable the Timer0 Interrupt by setting TMR0IE bit
;Enable the Global and Peripheral interrupts by setting GIE and PIE bits

; /////////////////////////////////////////////////////////////////////////

STATUS        EQU        3
PORTC        EQU        7
PORTB        EQU        6
INTCON        EQU        h'B'
TMR0        EQU        1
TRISC        EQU        h'87'
TRISB        EQU        h'86'
OPTION_REG    EQU        h'81'

W_SAVE        EQU         25
STATUS_SAVE    EQU         26
INTDELAY    EQU        27
VAR        EQU        28

;******************************************************************

list    P=16F72

ORG 000H
GOTO MAIN

ORG 004H
GOTO INTFUNCT

; /////////////////////////////////////////////////////////////////////////

;             Initialize all variables and port pins here!

; /////////////////////////////////////////////////////////////////////////
MAIN:
BSF    STATUS, RP0
MOVLW     B'00000000'
MOVWF    TRISB

MOVLW    B'10000110'
MOVWF    OPTION_REG
BCF    STATUS, RP0
CLRF    PORTB
MOVLW    .178
MOVWF    TMR0
BCF    INTCON, TMR0IF
BSF    INTCON, TMR0IE
BSF    INTCON, GIE
MOVLW    .100
MOVWF    INTDELAY
MOVLW    1
MOVWF    VAR

PROGRAM:
BTFSS    VAR
CALL   LOWSTATE                ;better programming efficiency to use call instead of goto as i have heard
CALL    HIGHSTATE

GOTO PROGRAM

HIGHSTATE:
BSF    PORTB,0
RETURN

LOWSTATE:
BCF    PORTB,0
RETURN

INTFUNCT:
MOVWF W_SAVE        ; save W
SWAPF STATUS, W     ; save STATUS
MOVWF STATUS_SAVE

BCF    STATUS, RP0

BTFSS    TMR0IF
GOTO ENDIR

BCF    INTCON, TMR0IF
DECFSZ    INTDELAY
GOTO ENDIR        ;once it reaches 0, then do the main part of the interrupt and then reset intdelay

MOVLW    VAR
XORLW    1
MOVWF    VAR

MOVLW    .178
MOVWF    TMR0
MOVLW    .100
MOVWF    INTDELAY
GOTO ENDIR

ENDIR:
SWAPF STATUS_SAVE, W
MOVWF STATUS
SWAPF W_SAVE, F
SWAPF W_SAVE, W
RETFIE

END

Last edited:

#### jpanhalt

Joined Jan 18, 2008
8,303
Comments and suggestions embedded in code are in RED:
#include <p16f72.inc>
__config (_HS_OSC & _WDT_OFF & _PWRTE_OFF & _CP_OFF)

;STATUS EQU 3 ;#include <> has these definitions
;PORTC EQU 7
;PORTB EQU 6
;INTCON EQU h'B'
;TMR0 EQU 1
;TRISC EQU h'87'
;TRISB EQU h'86'
;OPTION_REG EQU h'81'

W_SAVE EQU 25
STATUS_SAVE EQU 26
INTDELAY EQU 27
VAR EQU 28

;******************************************************************

list P=16F72

ORG 000H
GOTO MAIN

ORG 004H
GOTO INTFUNCT

; /////////////////////////////////////////////////////////////////////////

; Initialize all variables and port pins here!

; /////////////////////////////////////////////////////////////////////////
MAIN:
BSF STATUS, RP0
MOVLW B'00000000'
MOVWF TRISB

MOVLW B'10000110'
MOVWF OPTION_REG
BCF STATUS, RP0
CLRF PORTB
MOVLW .178
MOVWF TMR0
BCF INTCON, TMR0IF
BSF INTCON, TMR0IE
BSF INTCON, GIE
MOVLW .100
MOVWF INTDELAY
MOVLW 1
MOVWF VAR ;at this point VAR contains a .1

PROGRAM:
BTFSS VAR
CALL LOWSTATE ;better programming efficiency to use call instead of goto as i have heard
CALL HIGHSTATE

GOTO PROGRAM

HIGHSTATE:
BSF PORTB,0
RETURN

LOWSTATE:
BCF PORTB,0
RETURN

INTFUNCT:
MOVWF W_SAVE ; save W
SWAPF STATUS, W ; save STATUS
MOVWF STATUS_SAVE

BCF STATUS, RP0

BTFSS TMR0IF
GOTO ENDIR

BCF INTCON, TMR0IF
DECFSZ INTDELAY,F
GOTO ENDIR ;once it reaches 0, then do the main part of the interrupt and then reset intdelay

MOVLW VAR ;W now contains 0x28 -- is that what you want?
XORLW 1
MOVWF VAR ;VAR now contains 0x29 -- is that what you intended?

MOVLW .178
MOVWF TMR0
MOVLW .100
MOVWF INTDELAY
GOTO ENDIR

ENDIR:
SWAPF STATUS_SAVE, W
MOVWF STATUS
SWAPF W_SAVE, F
SWAPF W_SAVE, W
RETFIE

<indent>END

What I meant by using XOR'ing to toggle a bit is something like this:

Code:
     bsf       PORTB,0
<lots of code>
movlw     .1
xorwf     PORTB, F
That toggles PORTB,0. Just don't do another bsf PORTB,0 or it starts over.

As for the movlw VAR, note that you define/equate VAR to 0x28, so that is its literal. If you want to operate on its contents, use movf VAR,w. However, that is not necessary.

Is the LED flashing at all yet?

#### seifullaah73

Joined Dec 13, 2019
41
Regarding the inc file. didn't know it was already specified. that's cool

VAR EQU 28
28 is the address of one of the general purpose registers on the PIC, so var is supposed to equal 1 and the address of var is h'28'

regarding
MOVLW VAR ;W now contains 0x28 -- is that what you want?
XORLW 1
MOVWF VAR

I wanted it to mov the value of W, which is 1 to W and then xor that with 1 and mov that result to var.
how would you implement the method the first response mentioned var = !var in assembly

so in regards to xoring I don't need to use BSF i just use XORWF to set output port high or low.

LED is not flashing

#### seifullaah73

Joined Dec 13, 2019
41
After your suggestion my amended program is below. so the interrupt toggles the output LED. I was hoping the interrupt to stop what is currently executing, which is output is high and change it low for a certain amount of time and then change it back high again after the interrupt, which indirectly creates a square wave. But here the interrupts toggles the led from on to off or off to on. Can you check below.

Also in regards to equ variable
WF - operates on the contents of the register
LW - operates on the direct value mentioned by equ COUNTA EQU 100

This part confuses me a bit, i was taught to assign a register address to the variable and that movlw places the value in that variable via movlw .50 movwf countA but xorlw doesn't use 50 but rather 100.

shouldn't the code be xorwf portb,0 instead of xorwf portb, f

Code:
#include <p16f72.inc>
__config (_HS_OSC & _WDT_OFF & _PWRTE_OFF & _CP_OFF)

W_SAVE        EQU         25
STATUS_SAVE    EQU         26
INTDELAY    EQU            27

;******************************************************************

list    P=16F72

ORG 000H
GOTO MAIN

ORG 004H
GOTO INTFUNCT

; /////////////////////////////////////////////////////////////////////////

;             Initialize all variables and port pins here!

; /////////////////////////////////////////////////////////////////////////
MAIN:
BSF    STATUS, RP0
MOVLW     B'00000000'
MOVWF    TRISB

MOVLW    B'10000110'
MOVWF    OPTION_REG
BCF    STATUS, RP0
CLRF    PORTB
MOVLW    .178
MOVWF    TMR0
BCF    INTCON, TMR0IF
BSF    INTCON, TMR0IE
BSF    INTCON, GIE
BSF    PORTB, 0
MOVLW    .100
MOVWF    INTDELAY

PROGRAM:
NOP
GOTO PROGRAM

INTFUNCT:
MOVWF W_SAVE        ; save W
SWAPF STATUS, W     ; save STATUS
MOVWF STATUS_SAVE

BCF    STATUS, RP0

BTFSS    TMR0IF
GOTO ENDIR

BCF    INTCON, TMR0IF
DECFSZ    INTDELAY
GOTO ENDIR        ;once it reaches 0, then do the main part of the interrupt and then reset intdelay

MOVLW    .1
XORWF    PORTB,F

MOVLW    .178
MOVWF    TMR0
MOVLW    .100
MOVWF    INTDELAY
GOTO ENDIR

ENDIR:
SWAPF STATUS_SAVE, W
MOVWF STATUS
SWAPF W_SAVE, F
SWAPF W_SAVE, W
RETFIE

END

Last edited:

#### Papabravo

Joined Feb 24, 2006
12,684
Timer0 doesn't have the ability to interrupt periodically only relies on starting and stopping automatically depending on clearing the flag
...
Nonsense. Timer0 triggers an interrupt when it rolls over fro 0xFF to 0x00. Each time there is an interrupt you reload the constant value. To go for a longer period you just reload Timer0 29 times out of 30 or whatever number you like and do the processing every 30th interrupt. ANY Timer interrupt on ANY processor can be made periodic with enough ingenuity.

Here is another little trick. If you can start and stop a timer you can set it to roll over in 1 tick and make a general purpose Software Interrupt. The interrupt will shortly after you set the Timer RUN bit. Works great on the 8051 family.

#### seifullaah73

Joined Dec 13, 2019
41
damn 10mins editing.

DECFSZ INTDELAY or XORWF PORTB
do you need to add ,f to them i always though they were optional.

#### seifullaah73

Joined Dec 13, 2019
41
Nonsense. Timer0 triggers an interrupt when it rolls over fro 0xFF to 0x00. Each time there is an interrupt you reload the constant value. To go for a longer period you just reload Timer0 29 times out of 30 or whatever number you like and do the processing every 30th interrupt. ANY Timer interrupt on ANY processor can be made periodic with enough ingenuity.

Here is another little trick. If you can start and stop a timer you can set it to roll over in 1 tick and make a general purpose Software Interrupt. The interrupt will shortly after you set the Timer RUN bit. Works great on the 8051 family.
Then in that case didn't my code already have a periodic interrupt, where I preloaded the timer where the roll over was 30 ticks, and this would cause the interrupt and in the interrupt i reloaded the timer.

#### JohnInTX

Joined Jun 26, 2012
3,896
damn 10mins editing.

DECFSZ INTDELAY or XORWF PORTB
do you need to add ,f to them i always though they were optional.
I always add them for clarity - both ,F and ,W. Plus then the assembler will warn you if you forget. Helpful.