Bob, Thanks for the correction. Looking back into my log notes I find that indeed the only prescaler value that worked properly was ONE. I had TRIED 4 as a prescaler value and 6+2 as the correction factor, but according to my notes there was a small jitter corresponding to several instruction cycles. No doubt due to the resetting of the prescaler, though I failed to realize that initially. As you mentioned, when the prescaler is set to 1 this problem goes away and you get perfect timing. Next time I post I will consult my notes first and not just try to rely on my imperfect memory. I apologize for any inconvenience my error may have caused anyone. Fr. Thomas McGahee ----- Original Message ----- From: Bob Ammerman To: Sent: Wednesday, November 08, 2000 5:42 PM Subject: [PIC]: Achieving fast timing -or- PIC16F871 et al and interupts > ----- Original Message ----- > From: Thomas McGahee > To: > Sent: Wednesday, November 08, 2000 5:17 PM > Subject: Re: [PIC]: PIC16F871 et al and interupts > > > > One way I have tackled this problem is to set the prescaler to 4. Now, > > normally this would cause an interrupt every 1024 microseconds when using > > a 4 MHz crystal. The sneaky trick is to *add* 26 to TMR0. We actually want > > to increase the current contents of TMR0 by 24, but we add the extra 2 > > because TMR0 is not incremented for 2 instruction cycles when it is > > changed by our add routine. > > Look out here. Since you have the prescaler set to four, each count of TMR0 > corresponds to 4 instructions. Thus adding 26 is really adding 26*4 = 104 > instructons times. > > So you might think that adding two will work, but you won't get the right > result. > > Also, the process of adding to TMR0 will reset the prescaler. > > This is _not_ going to give you exact timing. > > However, if you set the prescale to 1:1 and add 256-250+2 == 4 then you > _will_ get an interrupt every 250 microseconds, exactly. > > Bob Ammerman > RAm Systems > (contract development of high performance, high function, low-level > software) > > > > We add instead of just stuffing 24 (actually stuffing 24+2 to be exact), > > since the actual count in TMR0 can vary slightly depending on whether > > the interrupt occured during a 1 or 2 cycle instruction. > > Also, some time has elapsed since the interrupt routine was entered and > > the time it took to get to the point in the isr where you are modifying > TMR0. > > > > By ADDING a correction value to TMR0 we get around the problem of trying > > to figure out the current value of TMR0. Now the time it takes between > > interrupts is no longer 1024 microseconds, but 1000 microseconds. > > This is a much nicer number to be working with! > > > > The time between interrupts is corrected such that it is now 1 ms. > > A 16 bit counter inside the isr is counted up from 0 until it gets > > to 1000. When it gets to 1000 it is reset to 0000 and then any > > counters that are based on the 1 second interval are updated. It is > > also very useful to have a software bit flag called one_sec that is > > SET each time the isr's 16 bit counter is reset. Programs in main > > can clear this flag and wait until it goes high. When they see it go high > > they can clear a counter that is usually incremented in the isr. > > Thus the bit flag allows you to synchronize to the beginning of a new > > 1 second period. You don't HAVE to synchronize, though. If you skip > > the synchronization and just reset the appropriate counter immediately, > > the counter will reach a count of 1000 with a timing error of plus > > or minus 1 millisecond. Not too shabby. If you use the synchronization > > method your error will only be a few microseconds instead of plus or > > minus a millisecond. > > > > Let's say you wanted a ten second delay: after resetting the appropriate > > isr counter, you would monitor the state of the counter in a loop. > > When it changes to 10 you know that 10 seconds has elapsed. If you have > > another function that needs to go off at 12 seconds, then just let the > > counter continue to run until it reaches 12. Such cumulative uses of > > a counter will give you a timing accuracy that is just as good at 1000 > > seconds as it is at 1 second. > > > > Relative timing accuracy from second to second will actually be a dozen > > or so microseconds, and the error is non-cumulative! > > > > *************** > > > > I use a variation on this scheme where I have my interrupt period set > > for 1/2 the baud rate period time. Transmission requires only that I > > get my data set up and then synchronize to a bit flag called half_baud. > > From there on, start, data, and stop bits are timed by watching the > > half_baud flag which is SET every half baud period. The program in > > main is responsible for resetting the flag once it goes high. > > > > Any baud rate error that exists is non-cumulative even across hundreds of > > bit times. > > > > The reason I use a half-baud time period is that for uart reception > > we read in the center of the bit time. Since reception cannot be > > synchronized in the way transmission can, I use a different sync > > method for reception. In the isr I maintain a counter that is cleared > > to 0000 each time we reach the end of a half baud period. All other > > times this counter is incremented. When we detect a start bit on the > > uart receive line, we immediately clear the half baud counter that is > > usually incremented in the isr. We then wait until the counter is > > non-zero. Then we wait until the counter returns to zero. It will > > return after a period equal to the half-baud period. This puts us > > right in the middle of the start bit. Every second time the counter > > returns to zero represents one full baud bit period. That puts > > us right in the middle of data bit, which we then read and use to build > > the 8 bit byte value. The beauty of this method is that you don't > > have any instruction counting to deal with to get the baud rate > > right on. Error is non-cumulative. > > > > I even have a switch driven i/o line dedicated to informing the > > isr which of two baud rates I want selected. This determines > > how the isr will handle the specifics of updating. With absolutely > > NO changes in the uart receive code in the main program I can > > switch baud rates on the fly. > > > > Fr. Thomas McGahee > > > > > > ----- Original Message ----- > > From: Hardware Engineering > > To: > > Sent: Wednesday, November 08, 2000 7:56 AM > > Subject: [PIC]: PIC16F871 et al and interupts > > > > > > Never used interupts...but its time. Similar to another post of using > TMR0, > > where he wants to use a 4MHz clock (giving a 1MHz or 1uS state time) and > time > > for 1 second, I need to do a similar thing. But I think the math is off, > > because if you use a /256 on the prescaler thats 256uS per tic for TMR0, > and > > you can only have a max of 256 tic for TMR0 before it rolls over thats > > 65,536us (a bit short of 1000000us for 1 second). Now the purpose of my > > application is to generate a 1 second rate for several timers. I could do > a > > simple loop where I just delay and the decrement the count for the other > > timers, but I need to have several timers running in parallel. > > > > Since I can't generate a 1 second interupt (could change the clock but > then we > > get into custom crystals as well) I figure that I set TMR0 to a value of > 159 > > (decimal) and the prescale to 256. This would give me pretty close to a > > quarter second for the interupt. Thus when vectoring to the interupt, it > > would reload the value to TMR0, decrement a QTRCNT value, check for zero. > If > > zero, that means 4 quarter seconds passed and thus one second....THEN....I > can > > decrement all my other timers...sounds simple? Not sure..how the interupts > > need to be set up and all that. My init code has this: > > > > ; set up TIMER0 for interupt vector for every quarter second > > movlw 0x07 > > movwf OPTION_REG > > > > movlw 0xA0 > > movwf INTCON ; set interupt for TMR0 > > > > movlw 0x9E ; intial set for overflow value > > movwf TMR0 ; to be reloaded on each interupt > > movlw 0x04 ; for 4 quarter seconds > > movwf QTRCNT > > > > Then...for the interupt.... > > > > org 0x004 ; interupt vector > > movlw 0x9E ; intial set for overflow value > > movwf TMR0 ; to be reloaded on each interupt > > decfsz QTRCNT,1 > > goto NOTZ > > movlw 0x04 > > movwf QTRCNT ; we reached the count so reload > > < decrement all the counters etc> > > bsf INTCON, GIE ; enable interupts again > > retfie > > NOTZ: > > ; bsf PORTC,0 > > bsf INTCON, GIE ; enable interupts again > > retfie > > > > Comments? > > > > Again, thanks for all the help on this list. > > > > ____________________________________________________________________ > > Get free email and a permanent address at http://www.netaddress.com/?N=1 > > > > -- > > http://www.piclist.com hint: PICList Posts must start with ONE topic: > > "[PIC]:","[SX]:","[AVR]:" = ONLY! "[EE]:","[OT]:" =her "[BUY]:","[AD]:" -s > > > > -- > > http://www.piclist.com hint: PICList Posts must start with ONE topic: > > "[PIC]:","[SX]:","[AVR]:" =uP ONLY! "[EE]:","[OT]:" =Other > "[BUY]:","[AD]:" =Ads > > > > > > > > > > -- > http://www.piclist.com hint: PICList Posts must start with ONE topic: > "[PIC]:","[SX]:","[AVR]:" =uP ONLY! "[EE]:","[OT]:" =Other "[BUY]:","[AD]:" =Ads > > > > -- http://www.piclist.com hint: The list server can filter out subtopics (like ads or off topics) for you. See http://www.piclist.com/#topics