Question about timer/nested delay for PIC1F222

Thread Starter

ZimmerL

Joined Mar 27, 2013
1
Hello All,

I have a question about creating a delay for a PIC10F222.

I need a rather large delay in my program (5 seconds at 8MHz clock speed) and I only have one register available for modification during this time frame. I heard it is possible to create a delay using the timer, and also to use the first 4 nibbles and last 4 nibbles separately (not sure if "nibble" idea will be as large as needed). If anyone has any experience or insight into this matter it would be greatly appreciated.
 
Last edited:

Markd77

Joined Sep 7, 2009
2,806
You can use Timer0. The standard method on baseline PICs would be to check if TMR0 = 0 in a loop, but if you are using prescaler of 256 that condition would be true for multiple loops in a row, so you either need another variable (or maybe just a bit) to stop that from happening.
You could also check for TMR0 = 255 and then reset TMR0 to 0, that wouldn't require the extra variable, but loses some accuracy, because the prescaler count gets reset if you write to TMR0.
Have you looked for any variables that can be eliminated? Often there are variables used in one part of the program that can be reused in other parts without any problems. Also look for bytes that could be replaced by a single bit in a flags variable.
If you post the code, maybe we could find something.
 

JohnInTX

Joined Jun 26, 2012
4,787
If you need one delay from the timer try something like this. It doesn't use additional RAM and works by detecting that TMR0 counted up to 128 (+ some possible extra counts that accumulated while you were busy doing something else). You have to poll/call the the check routine often enough that you catch the timer value between 128 and 255. You could pick off another bit if desired and add its complement to roll the timer to 0. Using the MSbit of TMR0 cuts it to 7 effective bits but you can get that back with the prescaler.

By adding to the timer count you don't lose any in TMR0. You WILL clear the prescaler though so expect some jitter.

Rich (BB code):
checkTMR0:
 btfss TMR0,7 ; if still counting up..
 goto not_yet ; wait..

 movlw .128 ; else, timer just went to 128, add enough to roll to 00h 
 addwf TMR0,F ; plus any counts accumulated due to slow polling
 ; *** do whatever you to when the timer is done
It could also be a subroutine. Call it to maintain the timer. It returns with the carry set if it rolled over:
Rich (BB code):
checkTMR0:
 bcf STATUS,C ; clear carry
 btfss TMR0,7 ; done?
 return ; no, return with NC

 movlw .128 ; else, roll it over
 addwf TMR0,F ; this will set the carry
 return ; C= time out
Mark's way works well. It costs a bit/byte of RAM but you can get away with just reading TMR0, leaving the prescaler alone.

For counts larger than what you can get out of the timer itself, you'll have to use a RAM byte to accumulate the TMR ticks. Note that you don't have to use ALL of the byte, just enough bits to accumulate the count. For example, to count 30 TMR ticks, you need 5 bits in a RAM byte. The other 3 bits are available since you never count past 30 (because you inspect the counter, do something at K=30 then clear the 5 LSbits),. you never count into the other 3 and they can be used at will. You'll need to do some bitwise logic on the register to test and clear the bits but that's easy enough.

All of that said, you'll need 24 bits of Tcyc count to accumulate 5 secs at 8MHz (including TMR0 bits and prescaler). 15 can be in the timer and PS (using my way, 16 plus a bit somewhere using Mark's so its a wash) leaving 9 that you have to find. All of this is for a free-running timer setup that approximates running in the background while you do other things. If you don't have the bits, you might have to do dumb delays using temp registers or some combination of the two..

If you drop the clock to 4MHz, you only need 23 bits, timer+PS+one byte of RAM.

As a last resort, if timing is not real critical and you can do it, sleep the processor against the WDT. Assign the PS to the WDT for longer delays. Inputs can short-circuit the full WDT*PS delay by using the wake-on-change feature of GPIO. Inspect TO/, PD/ and GPWUF to see what woke you up.

Good Luck
 
Last edited:

THE_RB

Joined Feb 11, 2008
5,438
...
You could also check for TMR0 = 255 and then reset TMR0 to 0, that wouldn't require the extra variable, but loses some accuracy, because the prescaler count gets reset if you write to TMR0.
...
Writing to the timer is not required. You just leave it free running and sense the flag bit TMR0IF (or TMR1IF) which is set to 1 when the timer rolls over. You just clear that flag, and count timer rolls with the OP's one variable. That does not intorduce error from clearing the prescaler OR from timer write latency.

With an 8MHz PIC TMR1 can run at 2MHz, 500kHz, or 250kHz (depends on prescaler).

At 250kHz it will roll every 250000/65536 = 3.81 Hz.
To time 5 seconds needs 5 * 3.81 = 19.07 timer1 rolls.

On a PIC 10F222 you may not have a TMR1, so you set TMR0 to 256:1 prescaler, and it rolls at 2MHz / 256/256 = 30.52Hz.
To time 5 seconds you count 5 * 30.52 = 152.6 timer0 rolls.
Still fine with only 1 register used.

If you want to get creative you can count timer0 rolls in the W register, so it does not use ANY registers from RAM. :)
 

JohnInTX

Joined Jun 26, 2012
4,787
Good advice for midrange PICs, but baseline ones don't have a TMR0IF flag.
There's also no way to directly use W as a counter without adding 1 from some other register.. The two added instructions for midrange included add/subtract literal to W which would be better for sure.

RB is saying it another way but you still need 24 bits of counting at 8MHz (23 at 4MHz) for a straight count up affair.

If you did dumb delay loops, instead of using multiple registers you could extend the time by loading the loop with Tcycs if you have the codespace:

nop = 1Tcyc each
goto $+1 = 2Tcyc each
call a_dummy_return = 4 Tcyc each, the most bang for the buck but you have to have the stack available. Something like this...

Rich (BB code):
 movlw .255
 movwf  a_register

loop:
 call a_dummy_return ; 4 Tcyc each, as many as you need
 call a_dummy_return
 decfsz a_register,F
 goto  loop
  ; fall through to ret
a_dummy_return:
 return
A final trick for borrowing a register would be to move it to W for storage. Clear the register and use it to count 256 tiks to Z (or fewer if you bit test individual bits in the register itself as it counts). When done with it, movwf the stored value in W back to the register.

EDIT: Don't forget that FSR is an 8 bit register that can be used if you are not currently doing indirect addressing.
 
Last edited:

THE_RB

Joined Feb 11, 2008
5,438
Good advice for midrange PICs, but baseline ones don't have a TMR0IF flag. ...
Thanks for the correction, it's been a few years since I used a 10F part.

JohnInTX said:
There's also no way to directly use W as a counter without adding 1 from some other register.. The two added instructions for midrange included add/subtract literal to W which would be better for sure. ...
Darn! It has been a while since I used these PICs! :eek: No SUBLW hey?

OK, as one solution for timing accuracy and not having to write to the TMR0 (so you don't upset the prescaler) you can loop and wait for bit7 to go hi, then immediately loop and wait for bit7 to go lo. That only takes a few asm instructions.

The total loop time will always average an accurate 256 timer ticks. Then use the one register as a timer roll counter to make 5 seconds like in my previous example.

Rich (BB code):
delay_5secs:
  movlw d.152       ; 152 TMR0 rolls = 5 seconds
  movwf counter     ; counter is the only var used

delay_5secs_loop
  BTFSS TMR0,7
  goto $-1
  BTFSC TMR0,7
  goto $-1          ; total always takes 256 TMR0 ticks!

  decfsz counter    
  goto delay_5secs_loop
 
Last edited:

absf

Joined Dec 29, 2010
1,968
Too bad:mad: I just ordered 10 pieces of 10F206 to do some mTouch projects. Not sure if I can modify the software to work on 12F629..:rolleyes:

Allen
 

Markd77

Joined Sep 7, 2009
2,806
I like them, they are simple like me.
About the same price as a 555 timer, but lower component count and better accuracy. Handy for when a 12F part would be overkill.
There's a little LED chaser in my blog.
 

JohnInTX

Joined Jun 26, 2012
4,787
Too bad:mad: I just ordered 10 pieces of 10F206 to do some mTouch projects.
Not sure if I can modify the software to work on 12F629..:rolleyes: Sure you can.
I like them, they are simple like me.
About the same price as a 555 timer, but lower component count and better accuracy. Handy for when a 12F part would be overkill.
There's a little LED chaser in my blog.
If you have analyzed your requirements and the 10F or 12F fits your needs then have at it. Mark's point about replacing the 555 is perfect. Simple requirement, known solution. But, Allen's lament is also pertinent. He bought 10F and now is thinking 12F, maybe due to the fear of some unknowns as the project develops.

One of the things the characterizes embedded systems development is the existence of real, finite resource limits. Once you solder your chip down, your playground is defined. In the PIC world, once you pick your family (baseline, midrange, 18F etc) you have in essence determined your resource set and eventually, your programming paradigm. If you run out of horsepower you're toast. When that happens you have to resort to being inventive and imaginative to overcome those limits, not unlike this thread. That's expensive. Really expensive if you have to move up into another family. Much more than the raw cost difference between initially picking a baseline PIC vs. one with more steam.

One way I've survived as a contractor is to develop on the biggest part in a particular family but use resources like it was the smallest one. If everything fits into a smaller part, YAY! for production. If it's no yay and the bigger part winds up being really necessary, its a change to the BOM and an incremental bump in cost. Its not a redesign.

Just my $.03 (inflation, you know)
 
Last edited:
Top