Fig. 1

# Programming PIC16F84A Software Delay Routines by Example

by Lewis Loflin

Software delay routines are useful and saves tying up hardware timers to be used for other purposes. The examples I've seen in Microchip PIC assembly are just confusing to modify and use. And often not accurate. Here I'll illustrate a more sane way to program software time days.

As shown in the video without delays the LED would appear to be on all the time.

First, one must know the frequency of the oscillator crystal, which is divided by 4. With a 4mHz oscillator produces a period of 1 uSec for most instructions except branching and jump instructions. Note the following example:

```
DECFSZ DELAY_count1, f ; 1uS
GOTO \$-1 ; 2uS
```

Each cycle will consume 3uS total until DELAY_count1 is zero at which time GOTO will be skipped. That assumes a 4mHz clock. A 16mHz clock (divided by 4) has a period of 1 / 4mHz = 250nS (nano seconds) times 3 in the above equals 750nS. I'll assume as 4mHz clock in this series of tutorials.

```
DELAY_500uS
; the address counter "points" to instruction to be executed
; formula 500uS => DELAY_holdCount1 = (500 - 3)/3 = 166
; time delay = 0 - 771 uS at 4mHz
MOVLW d'164'
MOVWF DELAY_count1
DECFSZ DELAY_count1, f
GOTO \$-1
RETURN

DELAY_100mS
MOVLW d'200'
MOVWF DELAY_count2
CALL DELAY_500uS
DECFSZ DELAY_count2
GOTO \$-2
RETURN

DELAY_500mS
MOVLW d'5' ; value X 100mS
MOVWF DELAY_count3
CALL DELAY_100mS
DECFSZ DELAY_count3
GOTO \$-2
RETURN
```

In the example above I created a 500uS delay subroutine. To test it I created a 1000Hz 50% duty cycle square wave from PB0 and measured it on a frequency county. It was off a few Hertz so I adjusted the calculated value from 166 to 164. From then on simply construct extra delay loops based on calling shorter delay loops as subroutines.

Fig. 2 PIC16F84A Memory Map.

Note the PIC memory configuration in Fig. 2. We have a 8-level deep hardware "stack" that operates like a stack of dinner plates. During every CALL (jump to subroutine) command or hardware interrupt the current program count (PC) can be seen as a note on a plate and "pushed" onto the stack. As we CALL another jump routine that program count is saved another note taped to a plate that's dropped on the stack.

Every RETURN or RETFIE command will retrieve (pop) the last value from the top dinner plate. Too many interrupts or calls to subroutines will cause the loss of the address on the first or bottom dinner plate. Be ware of this problem when using one subroutine to build other subroutines. This is often referred to as FILO - first in last out.

This completes the short introduction to software delay loops.