PDA

View Full Version : Difficulty toggling LED with TMR1 overflow interrupt



jgjgjg
- 29th July 2012, 21:09
Hello all. I cannot persuade TMR1 interrupt to toggle an LED. I tried the "ON INTERRUPT...." method and that works fine, toggling the LED 3 or 4 times a second. But I cannot work out how to do this manually by polling the TMR1IF (PIR1.0) flag. I wonder if anyone has any ideas? I have spend hours reading through threads (including the Olympic Timer example thread) but to no avail. Presumably the solution is simple, but I can't work out what it is.

Many thanks in advance.

Jonathan.



define OSC 20

TRISB = %11101111 ' PORTB.4 output
led var PORTB.4
led = 0

INTCON = 0
PIR1 = $00 ' clear interupt flags
TMR1H = 0
TMR1L = 0
T1CON = %00110001 ' TMR1 on, prescaler=1:8, clock=(Fosc/4)
INTCON = $C0 ' Enable global and peripheral interupts
PIE1 = $01 ' Enable TMR1 overflow interrupt

main:
if PIR1.0 then
led = not led
TMR1H = 0 ' reset timer1
TMR1L = 0
PIR1 = $00 ' clear interrupt flags
endif
goto main
end

jgjgjg
- 29th July 2012, 22:41
After a few more hours of sifting through forums, I found the answer in this very forum, in Bruce's post (#2): http://www.picbasic.co.uk/forum/showthread.php?t=6943&p=42824#post42824



If you enable interrupts, then you need an interrupt handler. If you prefer just to monitor the
timer1 overflow flag, then disable global interrupts.

I'm not sure why this would be the case, but I'll work it out!

jgjgjg
- 29th July 2012, 23:39
For reference, here is the solution. The LED is toggled once every second by monitoring the TMR1 interrupt flag. 16F88.

Jonathan.


define OSC 20

' SET UP PORTS
TRISB = 101111 ' PORTB.4 output

' SET UP TMR1
T1CON = 0 ' prescaler=1:1, clock=(Fosc/4)
PIE1.0 = 1 ' Enable TMR1 overflow interrupt
INTCON.6 = 0 ' Disable peripheral interrupts
INTCON.7 = 0 ' Disable global interrupts (disable GIE and PEIE because there
' is no ISR, polling PIR1.0 (TMR1IF) manually instead)

' DECLARE VARIABLES
led var PORTB.4
overflow_counter var word
tmr1_preload var word

' INIT PROGRAMME
init:
led = 0
overflow_counter = 0
tmr1_preload = 15536 ' 15536 for overflow every 10 ms

TMR1H = tmr1_preload.highbyte
TMR1L = tmr1_preload.lowbyte
T1CON.0 = 1 ' Start TMR1

main:
if PIR1.0 = 1 then ' if TMR1IF is set
overflow_counter = overflow_counter + 1
if overflow_counter = 100 then ' 100 overflows = 1 second
led = not led ' toggle led
overflow_counter = 0 ' reset overflow counter
endif
TMR1H = tmr1_preload.highbyte ' reset TMR1 with preload value
TMR1L = tmr1_preload.lowbyte
PIR1.0 = 0 ' clear TMR1IF
endif
goto main
end

HenrikOlsson
- 30th July 2012, 08:32
If you enable interrupts the code will jump to the interrupt vector whenenver an interrupt occurs. If you don't have a interrupt service routine at that location (or a jump TO an interrupt service routine) it won't work properly. The interrupt flags (like the TMR1IF) will get set whenever the cause of the particular interrupt happens/occurs but an actual jump to the interrupt vector will only occur if interrupts are enabled.

So, if you're actually going to use interrupts you need them enabled AND have an interrupt service routine. If you're just going to poll the interrupt flag then you can't have that particullar interrupt enabled.

jgjgjg
- 30th July 2012, 11:17
Thank you for the explanation. Now I understand. From the 16F88 datasheet: "If the global interrupt is enabled, the program will branch to the interrupt vector (0004h)."