PDA

View Full Version : PIR1.0 stays ever 1 ?!



mischl
- 4th March 2006, 16:28
hello all

i work with a timer1 on a 16f876 at 20 mhz. i used such a snippet some other times succesful. on this other cases i've ever immedeatly start timer1. probaply so i never found this problem...

the problem is that i fall immeadetly to the interupt handler.
i have a longer while-wend in the pre loop to wait for some user inputs. timer1 should not start until end of pre loop.

i've tested also with the ICD, where i saw that PIR1.0 is set to 1 on boot up and also after reset in interrupt handler it goes back very (too) fast. i've also try with PIR1.0 = 0 at the begin of the code. no success

probaply i search on the wrong end, but i think from there is coming up the problem.

thanks for any hint. cheers, mischl



... init

'-- PRE LOOP ----------------------------------------------------

while not ((buto = 3) and (dezi = 1))

.... stays longer here

wend



T1CON = %00000000 ' set timer1 prescaler as 1:1. stop timer1
PIR1.0 = 0 ' clear timer1 overflow flag
PIE1 = %00000001 ' enable interrupt on timer1 overflow
INTCON.6 = 1 ' enable peripheral (unmasked) interrupts
INTCON.7 = 1 ' enable global interrupts


gosub SetTimer ' start timer1

on interrupt goto handler ' handling interrupt
'-- MAIN LOOP ---------------------------------------------------

main:
... do something

GOTO main

'-- INTERRUPT SERVICE ROUTINE ----------------------------------

disable interrupt ' disable interrupts in handler
handler:
gosub SetTimer

fram = fram + 1
if fram > 24 then
fram = 0
seco = seco + 1
if seco > 59 then
seco = 0
minu = minu + 1
if minu > 39 then
minu = 0
seco = 0
fram = 0
endif
endif
endif

fcnt = fcnt + 1 ' inc frame counter
frsh = 1 ' set refresh lcd flag

resume main


SetTimer:
T1CON.0 = 0 ' stop timer1
TMR1H = $63 ' load with 25536 = 65536 - 40000
TMR1L = $c0

PIR1.0 = 0 ' clear timer1 overflow flag
T1CON.0 = 1 ' start timer1

return


enable interrupt ' enable interrupts after handler


'-- SUB --------------------------------------------------------

Darrel Taylor
- 4th March 2006, 23:54
mischl,

@ 20 mhz, loading TMR1 with $63C0 will result in an interrupt frequency of 125 hz.   The program appears to be looking for 25 hz, which is what it would be at 4 mhz.

But the bigger problem is ... With "resume main", you are restarting the loop after every interrupt. If there's anything substantial going on in the main loop, then it may not even make it through before restarting again.

Just use RESUME without the main.
<br>

mischl
- 5th March 2006, 08:00
dear darrel

thanks for your reply

you are right about preloading timer1, i've changed two steps before from 4mhz to 20 mhz ;-)

RESUME MAIN would be fine theoretical when the interrupt routine is started only when pointer is in main loop. now it is a problem because even when the ISR is executed, the pointer jumps into main loop after.

i've changed the "resume main" to resume" only, and it work better....

but my basic problem is still here, timer1 overflows to early in the programm code (in the while-when of the pre loop). but my idea is to start timer1 not until end of pre loop. why does this appear? in my opinion only T1CON.0 = 1 starts the timer1, isn't it?

i've now solved the problem with a flag :

- clear it at begin of init
- execute ISR only when it is 1, else resume
- set flag = 1 on end of init section

so, fine would be if i could reach that with timer1

thanks for any hints again. cheers

mischl
- 7th March 2006, 18:07
hello all

to the entry above
no one an idea why timer1 runs without a start command? did i done something obviously incorrect? thanks for a feedback

the application is like a stop watch. i will control a loop of about ten minutes and this should be very exact. means about 20ms in relation of 10 minutes. to verify that in real time i need a good idea to control them in real world. for that i send a short serial command after start and one more after stoping the timing sequence. i look at the serial terminal on the pc for the timestamp (resolution 1/100s) when the messages arrived. unfortunalety the difference is not on each run the same.. i think it is a problem of the buffer at the pc end. pic is stable i think.

anyone a good idea how i could verify and measure them also?

thanks a lot

Darrel Taylor
- 7th March 2006, 21:13
mischl,

I've found that you can rely 100% on the power-on states shown in the datasheets. So, there's no way that it's just starting by itself without something in the program doing it.

Check all those "Magic Numbers" that were probably Cut&Paste at the top of the program. Make sure you aren't setting the wrong bit's somewhere.

Of course, if we had the top of the program, we could look too.

And, oh yeah. Third time for this link today...
instruction execution time
http://www.picbasic.co.uk/forum/showthread.php?t=365
<br>

mischl
- 8th March 2006, 18:17
dear darrel

thanks a lot for your message. alone the commitment "it must work" helps me a lot. i tested now a bit and it works fine! unfortunalety i don't know why... it seems that i had somewhere a "magic number" which i've deleted once ....

also thanks for the instruction execution time link, i know them ;-)

probaply i was not really clear : my problem is not "how many cycles i need" because i'm knowing that, my problem is "how long is acycle in realtime"?
menas the instruction time on a 20mhz is 200ns. if i repeat them 5 million times, i need a second. but when the instruction time is only 199ns (only a shift of 0.5%) i get not 1.000s.

so when i make a long time measurement for my ten minute timer, i should see if there is a small shift. that's what i need to check. so the idea was to send out a serial command at start sequence and send anotehr at end sequence. in theorie, this are xyz cycles equal to 10 minutes at the microcontroller. but my tests are around 50ms too short. ok, not the world. but when i want to build a timer for videoframes (25 frames a second) it's one frame away...

so in fact that not ever get the same result, i first of all search for a exact method to measure before i want to calibrate. does anyone know how this is done at the olympic timer example?

thanks a lot

Darrel Taylor
- 8th March 2006, 22:32
The problem may not be in the measurement technique.

More than likely, it's due to two things. The first being ON INTERRUPT. Since it waits until the current Line of code has finished before it branches to the interrupt handler, you never know when the interrupt will actually be handled. If a Long Running statement like SEROUT is in progress when an interrupt occurs, it may be several milliseconds before it gets to the handler.

The second problem comes from just Loading the required "Count" into the timer on each interrupt. This causes it to lose however many cycles it took to get to the handler.

If you ADD the "Count" to the current timer value, it can compensate for the lost time. The way it works is ... Once the timer overflows from 65535 and creates an interrupt, the timers value is now 0, and the timer is still running. Once it finally gets to the interrupt handler, the timer value shows exactly how long it took to get there. So now, if you add "Count" to the timers value (plus the time it actually took to add it), you'll have accounted for everything, and Time will count normaly.

Using the ADD technique with ON INTERRUPT will definately help. But, I would suggest moving to ASM interrupts if you need to keep Long Term time accuracy, or Short term precision.

HTH,
&nbsp; Darrel

P.S. Since you mentioned it. Melanie's Olympic Timer shows one way to do the ADD thing. See the SetTimer routine.

mischl
- 14th March 2006, 12:35
hello darrel

thanks for your hint. sorry my late reply - had some days off :-)

with the add command it works much more better, good tip. thanks!

i searched a while for the asm interrupt and found one older thread from you. what i don't found is an information why asm interrupt routines are much more accurate then pbp statements.... a short info would be very nice.

thanks for all again