Methods of delays (18F PIC)

Thread Starter

HarG

Joined Nov 20, 2012
18
Does anyone have any links/info on how to use delays (such as __delay_ms()) and on-chip timers (e.g. timer 0). I think the main question I have is when is best to use each one.

For example which would be better for a small delay in an 'if' statement for debouncing a switch.


Thanks for any help
 

tshuck

Joined Oct 18, 2012
3,534
Essentially, both would do the same thing while you are polling the timer. However, a timer can be configured to generate and interrupt after a delay, which can free up your processor in the mean time to do other things...
 

spinnaker

Joined Oct 29, 2009
7,830
Does anyone have any links/info on how to use delays (such as __delay_ms()) and on-chip timers (e.g. timer 0). I think the main question I have is when is best to use each one.

For example which would be better for a small delay in an 'if' statement for debouncing a switch.


Thanks for any help
For using a delay, tt is going to depend on what compiler your are using and what mcu.

The best one is one that suits your needs. If you don't care if the code "stops" then a call to a delay function is the easiest way to go. If you want your mcu to do other stuff while delaying then you might want to use a timer.
 

tshuck

Joined Oct 18, 2012
3,534
For using a delay, tt is going to depend on what compiler your are using and what mcu.

The best one is one that suits your needs. If you don't care if the code "stops" then a call to a delay function is the easiest way to go. If you want your mcu to do other stuff while delaying then you might want to use a timer.
You can still poll a timer... you'd need to configure for interrupts...
 

tshuck

Joined Oct 18, 2012
3,534
If you are polling a timer then there is no need to configure interrupts (better to have the interrupt just set a flag) or visa versa.
I suppose I should have stated that clearer:p

What I meant to say was that you can poll a timer and still block the processor function.
You would have to use interrupts otherwise...
 

spinnaker

Joined Oct 29, 2009
7,830
I suppose I should have stated that clearer:p

What I meant to say was that you can poll a timer and still block the processor function.
You would have to use interrupts otherwise...
Yes I agree but not sure why you would want to poll then. You could poll in a loop say do stuff for 10ms. That would make sense to poll the timer.
 

Thread Starter

HarG

Joined Nov 20, 2012
18
Really I'm just a bit paranoid about getting bad practices etc but I'm sure I will just establish with trial and error which method is suitable for each problem.


Thanks
 

thatoneguy

Joined Feb 19, 2009
6,359
Interrupt routines, LED example, can be changed to debounce

C Routine, polled, very cycle intensive for little gain

I usually use hardware debouncing, either a small R/C Circuit, or, rarely, a Debouncing IC. Having a controller continually polling for a key press means it cannot go to sleep/low power mode (unless you use a wake on interrupt).

The downside of polled debouncing is that a lot of cycles will be looking for an input that doesn't exist. From controller speed views, button presses are relatively rare event, compared to how fast the actual "work" of the processor needs to be completed.

If out of interrupts and timers, I'd suggest simply letting the rest of the code be your delay, in other words, call the button test routine once for every other time the program makes a loop (toggle a flag bit, then test it).

The button will still be checked several hundred thousand times per second (or more), but less overhead is used looking for it. This is a crude implementation of multitasking, and due to the speeds controllers run at, humans are not going to notice the delay unless your main procedure uses the evil delay_xx functions, try to learn/use timer interrupts to minimize delay calls.
 

THE_RB

Joined Feb 11, 2008
5,438
Timers have a number of advantages, code ROM size is usually smaller (especially on larger delays) as you just clear the timer then wait until timer>X, which also uses no RAM.

Timers are more accurate for repeated periods like testing something every X uS as the overhead "fluff" like calls/returns and decision making branching etc won't affect the timer, this is why you use timers to make 1 second delays in a clock, or make a repeated baud delay in a manual serial transmitter etc.

And an important benefit of timers is that your code can be doing stuff DURING the delay, so you can do this;
1. clear timer
2. do stuff (anything that takes less than 1mS)
3. if timer <1mS goto 3
which lets you do a long task(s) during the delay,

or this;
1. clear timer
2. do stuff (anything that is fast, like checking buttons)
3. if timer <1mS goto 2
which lets you keep checking fast things for the entire delay period.

I suggest you learn to use the timers they are very powerful, and as a general rule using the timers will give you better accuracy and less ROM/RAM used.
 

atferrari

Joined Jan 6, 2004
4,770
To explain how I do debouncing please read about how I do delays in PIC micros, working in Assembler. It is based on a suggestion in the Microchip forum many years ago:

Except when starting the LCD module, most of the delays (if not all) used in the different tasks, progress "in parallel" with the main loop code.

A specific delay starts when its own counter is loadey with a >0 value and is materialized in the time it takes a repetitive "decrement until =0" of it. The decrement is done in an ad hoc routine called from inside the main loop.

The counter for each delay, is defined beforehand.

There is the ISR in charge (triggered by the overflow of Timer 2), setting the pace with a time base ticking every 5 msec, and setting every time, a "time base elapsed" flag.

The decrement routine, when finds that flag set, decrements all non =0 counters.

When a counter reaches =0 it stays like that forever unless reloaded with a new value (>0) somewhere inside the code.

This is the main loop of an application running on my bench right now:

Rich (BB code):
MAIN_LOOP
  CALL DECR_COUNTERS
  CALL READ_KEYB
  BRA MAIN_LOOP
Now for the debouncing:

The keyboard matrix is read for the first time. If a key is pressed, "key-active" is flagged and the debounce counter loaded with 8. (8*5 = 40 msec)

Every time it is called, the decrement routine will check the flag from the ISR indicating a tick's time elapsed. If so, every counter (>0) will be decremented.

Meantime, every time it was called, the keyboard reading routine has checked the key-active flag which is set but did nothing because the debounce counter was not =0 yet.

Once the routine finds the key-active flag set AND the debounce counter =0 it goes to the second reading. If both readings match, that is a valid key.

Additional comments:

The first time I realized how I could use this concept of delays based on counters, I implemented 8 LEDs going ON and OFF in the most arbitrary and complicated patterns whether a continuous blink, randomly or at the push of buttons. The beauty of it: just load a register with a value and away it goes.

I built some years ago an inteligent alarm panel. Using the sopwatch I timed how long it took to sense all inputs. Even using a high number of counters (for delays) it worked quite under the maximum time allowed.

Few days ago, prior writing the code running right now, I revisited the whole thing. Besides a tidy up of the formatting, found good to leave it as is.
 
Last edited:

Thread Starter

HarG

Joined Nov 20, 2012
18
Thank you for your replies, especially the level of detail. It makes understanding these concepts far easier when reading about them in a non-formal context.
 
Top