How to use TIMR0 in PIC16F84A using assembly language PLZ I need help

Thread Starter

andrew132

Joined Feb 2, 2017
96
ok can everyone else help me in this
this is my program
Code:
#include<p16f84a.inc>

DELAY 0X0G
COUNTER 0X0C

ORG 0X00
BSF STATUS,RP0
CLRF TRISB
BCF STATUS,RP0
LO:
CLRF PORTB
CALL DELAY
BSF PORTB,1
CALL DELAY
GOTO LO

DELAY:
MOVLW 0X255
MOVWF COUNTER
DECFSZ COUNTER,F
GOTO $-1
RETURN
that is my program now i need to use timer0 if anyone wont help he should not post here
only who want to help just post and thank you
 
Last edited by a moderator:

MaxHeadRoom

Joined Jul 18, 2013
30,762
What is DELAY 0x0G?
Max.
Code:
#include<p16f84a.inc>
   DELAY 0X0G
   COUNTER 0X0C
   org 0X00
     bsf STATUS,RP0
     clrf TRISB
     bcf STATUS,RP0
LO:
     clrf PORTB
     call DELAY
     bsf PORTB,1
     call DELAY
     GOTO LO
DELAY:
     movlw 0X255
     movwf COUNTER
     decfsz COUNTER,F
     goto $-1
    return
 

Thread Starter

andrew132

Joined Feb 2, 2017
96
What is DELAY 0x0G?
Max.
Code:
#include<p16f84a.inc>
   DELAY 0X0G
   COUNTER 0X0C
   org 0X00
     bsf STATUS,RP0
     clrf TRISB
     bcf STATUS,RP0
LO:
     clrf PORTB
     call DELAY
     bsf PORTB,1
     call DELAY
     GOTO LO
DELAY:
     movlw 0X255
     movwf COUNTER
     decfsz COUNTER,F
     goto $-1
    return
My mistake i was want to use 2 counters but i named it wrong and i didnt use it in the program
 

Papabravo

Joined Feb 24, 2006
22,099
What is 0x255? You don't use the hexidecimal prefix "0x" and then write a decimal number, especially one as obvious as 255!
Just write "movlw 255"
 

JohnInTX

Joined Jun 26, 2012
4,787
What is 0x255? You don't use the hexidecimal prefix "0x" and then write a decimal number, especially one as obvious as 255!
Just write "movlw 255"
movlw .255 ; default radix is hex. The '.' makes it decimal.

Have you punched your code into MPLAB and used MPSIM to step it? That will identify lots of problems including those syntax errors.

If you haven't flow charted your routine, do it and tweak it until you can trace the operation with your finger. When that is done, code it and debug. Done.

If you don't work along those lines you will run in circles until you run out of time. We can't help you with that. Ignore the time pressures. Slow down and think.
 

Thread Starter

andrew132

Joined Feb 2, 2017
96
movlw .255 ; default radix is hex. The '.' makes it decimal.

Have you punched your code into MPLAB and used MPSIM to step it? That will identify lots of problems including those syntax errors.

If you haven't flow charted your routine, do it and tweak it until you can trace the operation with your finger. When that is done, code it and debug. Done.

If you don't work along those lines you will run in circles until you run out of time. We can't help you with that. Ignore the time pressures. Slow down and think.
I use online pic compiler
 

JohnInTX

Joined Jun 26, 2012
4,787
MPLAB Express?
Code:
#include<p16f84a.inc>

  ERRORLEVEL -302
  cblock 0ch
COUNTER:  1
  endc
  ORG 0X00
   
  BSF STATUS,RP0
  CLRF TRISB
  BCF STATUS,RP0
LO:
  CLRF PORTB
  CALL DELAY
  BSF PORTB,1
  CALL DELAY
  GOTO LO
   
DELAY:
  MOVLW .255
  MOVWF COUNTER
  DECFSZ COUNTER,F
  GOTO $-1
  RETURN
   
  END
I had to make detail changes to even get it to assemble in MPLAB Express. You should have done that.

The problem with Express is that there is no simulator and the F84A is a prehistoric chip that has no current debugging support so... Try downloading and installing MPLABX. You can make a project and paste your code into it. In Project Properties, select Simulator as the debugger. Once you can step the code in a simulator window, you can think about adding TIMER0. I don't see any other way.

Look, you may not like the way other members told you (sometimes I don't either) but they are absolutely correct. You can't expect and will not achieve success without a plan and without adequate tools, the simulator in this case, and an investment of your own time to come up to speed. We can help you but we won't do it for you. There isn't anything you can say to change that, we have all heard it before and we all know how to get from here to there. So read up on TIMER 0 and interrupts in the datasheet sec. 6, think about it and implement a solution. We can help with the debugging.

Good luck.
 

Thread Starter

andrew132

Joined Feb 2, 2017
96
Code:
 ORG 0X00
 BSF STATUS,RP0
 BCF OPTION_REG,T0CS
 BSF OPTION_REG,3
 BCF OPTION_REG,0
 BCF OPTION_REG,1
 BCF OPTION_REG,2
 CLRF TRISB
 BCF STATUS,RP0

LO:
 BSF PORTB,1
 CALL L
 BCF PORTB,1
 CALL L
 GOTO LO
L:
 BSF     INTCON, TMR0IE
 BSF     INTCON, GIE
 MOVLW D'240'
 MOVWF TMR0

D:
 BTFSS INTCON,2
 GOTO D
 RETURN
 END
when the timer0 overflow intcon,2 is set
but when it set its not back to bcf portb,1 its back to the first line of the program what i should do ?
 
Last edited by a moderator:

absf

Joined Dec 29, 2010
1,968
Can someone help me to solve it
With the clock running at 4 MHz., The tmr0 can only count 256 uS with the prescaler set to 1:1.

To get 2 seconds delay, I would use prescaler set to 1:256 and PSA set to TMR0. Then each interrupt would give about 65 mS.

Then setup a counter on the main routine to count to 31 before resetting to zero. That would give you roughly 31*65ms = 2.0xx seconds.

It's too late here and I'll try to make a simple program tomorrow morning if I get some free time.

Allen
 

Thread Starter

andrew132

Joined Feb 2, 2017
96
With the clock running at 4 MHz., The tmr0 can only count 256 uS with the prescaler set to 1:1.

To get 2 seconds delay, I would use prescaler set to 1:256 and PSA set to TMR0. Then each interrupt would give about 65 mS.

Then setup a counter on the main routine to count to 31 before resetting to zero. That would give you roughly 31*65ms = 2.0xx seconds.

It's too late here and I'll try to make a simple program tomorrow morning if I get some free time.

Allen
Thank you
 

JohnInTX

Joined Jun 26, 2012
4,787
You are missing some important things about interrupts.
When the timer interrupt occurs, the processor CALLS a routine at 0x004. That is where your timer service code must live. You don't have a service routine but you have enabled the interrupt. The program is vectored to 0x004 but there is no service routine.
As @absf says, timer 0 isn't big enough to accumulate 2 seconds worth of clocks so you have to set it to interrupt at some rate then use an additional register to count the interrupts (TimerPostScaler below) If you set the timer to interrupt every 10ms, you would count 200 interrupts in the post-scaler. To get an exact 10ms, you might also have to reload the timer itself to some value to adjust the time between interrupts.
Interrupts are covered in 6.8 of the datasheet.

The basic code layout looks like this:
Code:
ORG 000h
GOTO InitSystem ; jump over the interrupt vector

ORG 004h
InterruptService:
;save context ; save W, STATUS and any other register that the
;service routine uses, see databook sec 6.9 for an example

;reload timer if necessary

; decrement TimerPostScaler
; if not Zero, goto to IRQdone

; 2 sec have elapsed, toggle the LED and reload the seconds timer
MOVLW TimerPostScalerValue ; reload post scaler
movwf TimerPostScaler
; handle LED output

IRQdone:
BCF INTCON,T0IF ; clear interrupt flag

;restore context ; the values of W, STATUS and other registers used in the
; service routine must be restored to their EXACT values before the interrupt occurred

RETFIE ; return and re-enable interrupts

InitSystem:
BSF STATUS,RP0
BCF OPTION_REG,T0CS
BSF OPTION_REG,3
BCF OPTION_REG,0
BCF OPTION_REG,1
BCF OPTION_REG,2
CLRF TRISB
BCF STATUS,RP0

MOVLW TimerPostScalerValue; counts enough interrupts to make 2 sec
movwf TimerPostScaler

BCF INTCON,T0IF ; clear stray interrupts
BSF     INTCON, TIE ; enable timer interrupt
BSF     INTCON, GIE

WaitForever:
nop ; do something while the interrupt runs the LED
nop
goto WaitForever
END
 

Thread Starter

andrew132

Joined Feb 2, 2017
96
You are missing some important things about interrupts.
When the timer interrupt occurs, the processor CALLS a routine at 0x004. That is where your timer service code must live. You don't have a service routine but you have enabled the interrupt. The program is vectored to 0x004 but there is no service routine.
As @absf says, timer 0 isn't big enough to accumulate 2 seconds worth of clocks so you have to set it to interrupt at some rate then use an additional register to count the interrupts (TimerPostScaler below) If you set the timer to interrupt every 10ms, you would count 200 interrupts in the post-scaler. To get an exact 10ms, you might also have to reload the timer itself to some value to adjust the time between interrupts.
Interrupts are covered in 6.8 of the datasheet.

The basic code layout looks like this:
Code:
ORG 000h
GOTO InitSystem ; jump over the interrupt vector

ORG 004h
InterruptService:
;save context ; save W, STATUS and any other register that the
;service routine uses, see databook sec 6.9 for an example

;reload timer if necessary

; decrement TimerPostScaler
; if not Zero, goto to IRQdone

; 2 sec have elapsed, toggle the LED and reload the seconds timer
MOVLW TimerPostScalerValue ; reload post scaler
movwf TimerPostScaler
; handle LED output

IRQdone:
BCF INTCON,T0IF ; clear interrupt flag

;restore context ; the values of W, STATUS and other registers used in the
; service routine must be restored to their EXACT values before the interrupt occurred

RETFIE ; return and re-enable interrupts

InitSystem:
BSF STATUS,RP0
BCF OPTION_REG,T0CS
BSF OPTION_REG,3
BCF OPTION_REG,0
BCF OPTION_REG,1
BCF OPTION_REG,2
CLRF TRISB
BCF STATUS,RP0

MOVLW TimerPostScalerValue; counts enough interrupts to make 2 sec
movwf TimerPostScaler

BCF INTCON,T0IF ; clear stray interrupts
BSF     INTCON, TIE ; enable timer interrupt
BSF     INTCON, GIE

WaitForever:
nop ; do something while the interrupt runs the LED
nop
goto WaitForever
END
Where i can add bsf porbt,1 then delay then bcf portb,1 then delay then repeat
 

JohnInTX

Joined Jun 26, 2012
4,787
Where i can add bsf porbt,1 then delay then bcf portb,1 then delay then repeat
No place when you use interrupts. The delay is done by counting interrupts, not by using a delay loop. You change the LED output at line 18 above. That line gets executed every 2 sec so there's your flasher. An easy way to do it is:

movlw 0b00000010 ; LED on RB1..
xorwf PORTB,F ; gets toggled by xor'ing its current value with 1

I'm assuming that you were asking about TMR0 interrupts to drive the LED, no?
 

Thread Starter

andrew132

Joined Feb 2, 2017
96
No place when you use interrupts. The delay is done by counting interrupts, not by using a delay loop. You change the LED output at line 18 above. That line gets executed every 2 sec so there's your flasher. An easy way to do it is:

movlw 0b00000010 ; LED on RB1..
xorwf PORTB,F ; gets toggled by xor'ing its current value with 1
Oh that mean i cant use timer0 as subroutine like a 2 nested loop
 

Thread Starter

andrew132

Joined Feb 2, 2017
96
when i compiled the program it gived me error in postscalervalue
  1. ORG 000h
  2. GOTO InitSystem ; jump over the interrupt vector

  3. ORG 004h
  4. InterruptService:
  5. ;save context ; save W, STATUS and any other register that the
  6. ;service routine uses, see databook sec 6.9 for an example

  7. ;reload timer if necessary

  8. ; decrement TimerPostScaler
  9. ; if not Zero, goto to IRQdone

  10. ; 2 sec have elapsed, toggle the LED and reload the seconds timer
  11. MOVLW TimerPostScalerValue ; reload post scaler
  12. movwf TimerPostScaler
  13. ; handle LED output

  14. IRQdone:
  15. BCF INTCON,T0IF ; clear interrupt flag

  16. ;restore context ; the values of W, STATUS and other registers used in the
  17. ; service routine must be restored to their EXACT values before the interrupt occurred

  18. RETFIE ; return and re-enable interrupts

  19. InitSystem:
  20. BSF STATUS,RP0
  21. BCF OPTION_REG,T0CS
  22. BSF OPTION_REG,3
  23. BCF OPTION_REG,0
  24. BCF OPTION_REG,1
  25. BCF OPTION_REG,2
  26. CLRF TRISB
  27. BCF STATUS,RP0

  28. MOVLW TimerPostScalerValue; counts enough interrupts to make 2 sec
  29. movwf TimerPostScaler

  30. BCF INTCON,T0IF ; clear stray interrupts
  31. BSF INTCON, TIE ; enable timer interrupt
  32. BSF INTCON, GIE

  33. WaitForever:
  34. nop ; do something while the interrupt runs the LED
  35. nop
  36. goto WaitForever
  37. END
 

JohnInTX

Joined Jun 26, 2012
4,787
Oh that mean i cant use timer0 as subroutine like a 2 nested loop
That is correct. The timer works by counting system cycles (Tcyc). The 'time' in timer comes from the fact that it takes time to count a bunch of Tcyc. Also, be very clear on the difference between a subroutine and an interrupt. You call the subroutine. The interrupt is called automatically in response to an event, in this case TMR0 rolling over from FF->00. See 5.3 in the datasheet. It is critical to realize that since the interrupt can happen at any time, the interrupt routine must save any registers it uses then restore them just before returning to the system. Failure to to that will cause endless problems.

The reason to use interrupt-driven timing is that you can do other processing in-between interrupts. When you use delay loops, you consume 100% of your CPU time in mindless counting. It doesn't matter if all you are doing is flashing one LED but it gets ugly fast when you want to do other things.

The reason the code won't assemble is that it is incomplete. You have to fill in the blanks and replace those comment lines like ;handle LED output with code that does that. What I wrote was just a framework.
TimerPostScaler is a byte in RAM (a variable) that you have to declare. TimerPostScalerValue is a defined (names) value that is what the post scaler is loaded to. It is named so that it is consistent across the whole program. Observe that it is used twice. If you used literal values, it would be easy to miss one when you changed the value.

BTW: when you post code, use the CODE tags available on the toolbar 'Insert->Code Tags' of the posting window. Don't post code with line numbers as it make it impossible to copy/paste into MPLAB to test.
 
Last edited:
Top