Home‎ > ‎Homebrew‎ > ‎PICs in Radio‎ > ‎

PIC Basics - Timing and Delays

There are many sites and books (I've referred you to two already) but here are my musings - THERE IS NO CODE HERE YET!

PICs need an Oscillator, this can be built in or external (Crystal or RC). The Oscillator frequency is not the same as the PICs internal timing frequency (the instruction cycle), in fact the instruction cycle is a quarter of the oscillator frequency. So for a 4 MHz oscillator, we see the PIC 'working at' 1 MHz - referred to as the instruction cycle or clock.

To time things we count the number of instruction cycles, so 1,000,000 cycles will be one second. That's great. we can be very,very accurate with timing but counting a million in binary would require 20 bits (honest: 11110100001001000000) and most PICs only use 8 bits (255 in decimal).

There are ways to make PICs count to higher numbers but there is an inbuilt prescaler (divider) especially for the clock. Using this we can divide the clock by either 2,4,8,16,32,64,128 or 256. So if we set our Prescaler to 4 our clock would be = 4 MHz/4/4 = 250 kHz

If we set the Prescaler to 256 we would get 4 MHz/4/256 = 3.90625 kHz

Now as Frequency = 1 / Time so Time = 1 / Frequency

3.90625 KHz gives us a clock time of 256 us or 0.256 ms - just over a quarter of a millisecond.

That's still a very small amount of time.

But I can prescale that even further!

This needs to be done with code rather than setting a value for the PIC,  it effectively counts a number of clock pulses before returning to do what you want to do.

Example (STILL NO CODE!!!)

I want to send lots of morse code dits (using a buzzer) one after the other, I want each dit to be 10ms long. Now 10ms is 39 * 0.256ms (39=10ms/0.256ms) so if we count 39 clock pulses before we move on we will have waited 10ms, let's see.... I'm going to use line numbers to show the flow, note this is not code...

1    Set the PIC prescaler to 256
2    Turn on the buzzer
3    Set my count to 39
4    Take one away from the count
5    Is the result equal to 0 (have I counted 39 times?)
6    No - go back to take another one from the count - go to step 4
7    Yes - we have counted 39 clocks and waited 39 * 0.256ms = 10ms so carry on
8    Turn off the buzzer

That works well as a walk through, can you spot the loop? Line 6 loops back to Line 4 if the answer was No. We could put another loop in there to repeat the same code for ever

1    Set the PIC prescaler to 256
2    Turn on the buzzer
3    Set my count to 39
4    Take one away from the count
5    Is the result equal to 0 (have I counted 39 times?)
6    No - go back to take another one from the count - go to step 4
7    Yes - we have counted 39 clocks and waited 39 * 0.256ms = 10ms so carry on
8    Turn off the buzzer
9    Set my count to 39
10    Take one away from the count
11    Is the result equal to 0 (have I counted 39 times?)
12    No - go back to take another one from the count - go to step 10
13    Yes - we have counted 39 clocks and waited 39 * 0.256ms = 10ms so carry on
14     Go to line 2 to repeat it all again

Now we can see where the tasks are repeated - extra typing means extra code and more PIC memory taken up so we could put the repeated steps into its own little block and just call upon is usefulness when we need it

1    Set the PIC prescaler to 256
2    Turn on the buzzer
3    Call upon the waiting code - go to line 7
4    Turn off the buzzer
5    Call upon the waiting code - go to line 7
    Go to line 2 to repeat it all again

The waiting code is here 
7    Set my count to 39
8    Take one away from the count
9    Is the result equal to 0 (have I counted 39 times?)
10  No - go back to take another one from the count - go to step 8
11  Yes - we have counted 39 clocks and waited 39 * 0.256ms = 10ms so carry on where we left off


Can you see how that works? To assist, get a pen and a piece of paper and move along the paper for each step switching the buzzer on and off and seeing the counts go down from 39 (you'll get bored of counting from 39 down but you'll see the picture!)

So now you know how to create a delay of 10ms using a LOOP and a CALL to another task list which is technically a SUBROUTINE.

Can you rewrite it for a dash? There are a couple of ways!