Timing in PIC

As we studied before, instructions are implemented in one instruction cycle(except branching, they are implemented in two instruction cycle).

We can calculate instruction cycle by dividing oscillator frequency by 4. Let’s say we have 4MHz oscillator connected to our microcontroller. Then, one instruction cycle will take 4/4Mhz = 1us(micro second).

Now, we know how long it will take to implement one instruction. We can easily calculate how long will it take one part of code. Therefore, in many program, we need time delays for variety reasons.

Let’s say we need 10us delay. To do this, we can put 10 NOP instruction one after another. What if we need, let’s say 10 second  delay? We must put 1000 x 1us = 1ms, 1ms * 1000 = 1s, 1s * 10 = 10s… 10,000,000 NOP instruction one after another. Fortunately, there are easier ways to do this.

Time delays

Time delays are implemented by using loops. The example below, based on a PIC that uses 4MHz oscillator.

1 delay_20us:
2 MOVLW d’4′ ;1us
3 MOVWF CNT1 ;1us
4 LOOP:
5 DECFSZ CNT1,F ;1us
6 GOTO LOOP ;2us
7 NOP ;1us
8 NOP ;1us
9 RETURN 2us

First of all, step 1 and step 4 are labels, so, they aren’t implemented. They only point addresses.

Step 2 and 3 are implemented once to set how many time the loop will count. Each one is implemented in one instruction cycle. CNT1 is user defined register. We have to define it before use.

Step 4,5,6 are our loop. DECFSZ instruction decrease one from the register (here CNT1) and check if the register become zero. This instruction is implemented in one instruction cycle if the register is not zero. If the result is zero, it will take two instruction cycle,  because it will skip next instruction (that means branching). GOTO instruction is implemented in 2 instruction cycle.

NOP instruction is implemented in one instruction cycle.

Finally, RETURN instruction is implemented in two instruction cycle.

For step 2,3, it takes 2us.

We loaded ’4′ to CNT1 register. So, LOOP will repeated for 4 times. Everytime, DECFSZ and GOTO instructions will be implemented.
(1+2)*4=12us. When CNT1 becomes zero, DECFSZ skip next instruction (GOTO LOOP) and it will take 2us. That makes 12+2=14us.
We have two NOP instructions and they will be implemented once. That makes 2us.

RETURN takes 2us.

If we sum all, it makes 20us!

If we make a quick calculation, it can be seen one loop is not enough for longer delays. We have 3us in loop, multiply it with 255, 765us+ a few clock cycles. We can expand this delay by using multiple loops. Here is the example:

1 delay_long:
2 MOVLW d’4′ ;1us
3 MOVWF CNT1 ;1us
4 LOOP1:
5 MOVLW d’255′ ;1us
6 MOVWF CNT2 ;1us
7 LOOP2:
8 MOVLW d’255′ ;1us
9 MOVWF CNT3 ;1us
10 LOOP3:
11 DECFSZ CNT3,F ;1us
12 GOTO LOOP3 ;2us
13 DECFSZ CNT2,F ;1us
14 GOTO LOOP2 ;2us
15 DECFSZ CNT1,F ;1us
16 GOTO LOOP1 ;2us
17 RETURN ;2us

Here we go. Let’s start with Step 10. LOOP3 is the smallest loop. It will count down from 255 to 0. Then it will decrease CNT2 and branch upper loop which is LOOP2. LOOP2 will reload the CNT3 with 255. This will repeat untill CNT2 become zero. When CNT2 becomes 0, CNT1 will decrease and program will branch to LOOP1. This will repeat 4 times, because we load CNT1 with 4.

Let’s calculate above delay. 255x255x4x3us=780300us for LOOP3, 255x4x5us=5100 for LOOP2, 4x5us=20us for LOOP1, 4us for general. It is approximately 780300+5100+20=785420us=0.79s.

Now, we will implement a blinking LED application with 1 second delay as an example.

We need one second delay routine. We need 1s=1000000 instruction cycle. Firstly, we will calculate LOOP3 from above example. Let’s make CNT3=255, CNT2=255 and calculate LOOP3 : 255x255x3us=195,075us. We need 1,000,000. So, choose CNT1=5 to make 195,075×5=975,375us. This value for LOOP3. For LOOP2, 255x5x5us=6375us. And for LOOP1, 5x5us=25us. That makes 975,375+6375+25=981,775us. For blinking LED application, this resolution is enough. But, if you implement let’s say a serial communication application, you should be more precise.

Now, we can use our delay routine in a program. Assume that the LED is connected PORTB.0.

#include «p16f628.inc»

CNT1 EQU h’20′ ;General register for delay
CNT2 EQU h’21′ ;General register for delay
CNT3 EQU h’22′ ;General register for delay

ORG 0×00 ;Start vector
GOTO main

main:
BSF STATUS,RP0 ;Switch BANK1
CLRF TRISB ;Set all pins of PORTB as output
BCF STATUS,RP0 ;Switch BANK0

MAIN_LOOP:
BSF PORTB,0 ;Turn on LED
CALL delay_1s ;Wait one second
BCF PORTB,0 ;Turn off LED
CALL delay_1s ;Wait one second
GOTO MAIN_LOOP ;Repeat

;——1s Delay Routine————-
delay_1s:
MOVLW d’5′
MOVWF CNT1
LOOP1:
MOVLW d’255′
MOVWF CNT2
LOOP2:
MOVLW d’255′
MOVWF CNT3
LOOP3:
DECFSZ CNT3,F
GOTO LOOP3
DECFSZ CNT2,F
GOTO LOOP2
DECFSZ CNT1,F
GOTO LOOP1
RETURN

END

In the delay routine, we can put MOVWF CNT1 instruction to the top. And, before calling delay routine in the MAIN_LOOP, we can implement a MOVLW instruction. So, our time delay can be flexible. See, the example below.

MAIN_LOOP:
BSF PORTB,0 ;Turn on LED
MOVLW h’5′ ;Load W with 5 to make 1 second
CALL delay_1s ;Wait one second
BCF PORTB,0 ;Turn off LED
MOVLW h’A’ ;Load W with 10 to make 2 second
CALL delay_1s ;Wait two second
GOTO MAIN_LOOP ;Repeat

delay1s:
MOVWF CNT1
LOOP1 ;From above example we know that part will be 195,075us
.
.
.

Delay loops are very useful in micro controllers world. You cannot do without them.

The other way of timing in PIC is to use Timers. They are very precise and easier to use once you understand their structure. In the next section, we will discuss Timers.

Share and Enjoy

  • Facebook
  • Twitter
  • Delicious
  • LinkedIn
  • StumbleUpon
  • Reddit
  • Add to favorites
  • Email
  • RSS

Leave a Reply