Файл: The quintessential PIC microcontroller (S. Katzen, 2000).pdf
ВУЗ: Не указан
Категория: Не указан
Дисциплина: Не указана
Добавлен: 15.06.2025
Просмотров: 5317
Скачиваний: 0
6. Subroutines and Modules 157
Program 6.6 (continued.) Implementing a byte multiply using a stack model.
; Task 3C: |
Shift multiplicand right once |
|
MUL_CONT movf |
PSP,w |
; Reset FSR to the bottom of frame |
addlw |
5 |
|
movwf |
FSR |
; FSR ---> MULTIPLICAND |
bcf |
STATUS,C |
; Zero Carry-in |
rlf |
0,f |
|
decf |
FSR,f |
|
decf |
FSR,f |
; FSR ---> MULTIPLICAND_H |
rlf |
0,f |
|
; Task 3D: |
WHILE multiplier not zero |
|
incf |
FSR,f |
; FSR ---> MULTIPLIER |
movf |
0,f |
; Test multiplier for zero |
btfss |
STATUS,Z |
|
goto |
MUL_LOOP |
; IF not THEN go again |
; Task 4: End and clean up stack |
||
incf |
FSR,f |
; FSR ---> Top Of Frame |
movf |
FSR,w |
; Now reset Pseudo Stack Pointer |
movwf |
PSP |
; To TOF |
return |
; Finished |
|
its use of scarce data memory in large software systems. However, in programs running on low and mid-range PICs are often not very complex. Furthermore the small Program memory (1024 instructions for the PIC16F84) may further restrict the use of this relatively extravagant technique. Where real-time execution time is critical the additional burden of stack handling is unlikely to be worthwhile.
Examples
Example 6.1
The binary series approximation to the fraction 13 is:
1 1 1 1 1 1 1 1 3 = 2 − 4 + 8 − 16 + 32 − 64 + 128 · · ·
Using this series, write a subroutine that will divide a byte in the Working register by three with the quotient being returned in the same W register. The actual value of the summation up to 1281 is 0.3359375, which is within 0.78% of the exact value. With an 8-bit datum there is no point in including any further elements in the series, but where 16-bit operands are being processed then further elements up to the desired accuracy can be summed in the same manner.
158 The Quintessential PIC Microcontroller
Solution
The fractions 12 , 14 , 18 etc. can be easily generated by shifting right. The coding listed in Program 6.7 simply repetitively shifts the number as copied to a temporary location in register file File 33h right. Notice that it is necessary to clear the Carry flag before each shift as both the previous Rotate and Subtract instructions can alter its state. As the subwf instruction subtracts the contents of W (the sub quotient) from the datum in the specified file register then the outcome being built up in W will oscillate in sign as desired. In situations where the series element signs
Program 6.7 Dividing by three
; ************************************************************
; * |
FUNCTION: |
Divides a 16-bit word by three |
* |
||||
; * |
EXAMPLE |
: |
Dividend = FFh (255d), Quotient = 55h (85d) |
* |
|||
; * |
ENTRY |
: |
Dividend N |
in W |
* |
||
; |
* |
EXIT |
: |
Quotient |
Q |
= N in W |
* |
; |
* |
EXIT |
: |
File 33h |
altered |
* |
|
;************************************************************
;Local declarations
DIV_TEMP equ 33h |
; |
Temporary work byte |
|
DIV_3 movwf |
DIV_TEMP |
; |
Copy N into memory |
movlw |
0 |
; |
Clear quotient |
bcf |
STATUS,C |
; |
Clear Carry flag |
rrf |
DIV_TEMP,f ; |
N/2 |
|
movf |
DIV_TEMP,w |
; |
Q = N(1/2) |
bcf |
STATUS,C |
; |
Clear Carry flag |
rrf |
DIV_TEMP,f ; |
N/4 |
|
subwf |
DIV_TEMP,w |
; |
Q = N/4-Q = N(+1/4-1/2) |
bcf |
STATUS,C |
; |
Clear Carry flag |
rrf |
DIV_TEMP,f ; |
N/8 |
|
subwf |
DIV_TEMP,w |
; |
Q = N/8-Q = N(1/8-1/4+1/2) |
bcf |
STATUS,C |
; |
Clear Carry flag |
rrf |
DIV_TEMP,f ; |
N/16 |
|
subwf |
DIV_TEMP,w |
; |
Q = N/16-Q = N(1/16-1/8+1/4-1/2) |
bcf |
STATUS,C |
; |
Clear Carry flag |
rrf |
DIV_TEMP,f ; |
N/32 |
|
subwf |
DIV_TEMP,w |
; |
Q = N/32-Q = N(1/32-1/16+1/8-1/4+1/2) |
bcf |
STATUS,C |
; |
Clear Carry flag |
rrf |
DIV_TEMP,f ; |
N/64 |
|
subwf |
DIV_TEMP,w |
; |
Q = N(1/64-1/32+1/16-1/8+1/4-1/2) |
bcf |
STATUS,C |
; |
Clear Carry flag |
rrf |
DIV_TEMP,f ; |
N/128 |
|
subwf |
DIV_TEMP,w ; |
Q = N(1/128-1/64+1/32-1/16+1/8-1/4+1/2) |
|
return |
; |
Return with quotient in W |
|
6. Subroutines and Modules 159
are not so regular then a further file register must be used to build up the quotient. The coding in Program 6.7 can be considered as the shift and subtract analog of the shift and add process outlined in Program 6.5 above. Execution takes 27 cycles including call and return. It can easily be extended to generate the fraction 23 by omitting the first shift right, thereby e ectively multiplying the series by two. The rest of the program remains the same.
Example 6.2
Write a subroutine to give a fixed 208 µs delay. Assume a 4 MHz processor clock rate.
Solution
For a short time period like this the code fragment of page 143 provides adequate delay. The solution shown in Program 6.8 is identical to this coding terminated by a return instruction.
Program 6.8 Coding a 208 µs delay.
COUNT |
equ |
34h |
; Temp location to hold count down |
|
N |
equ |
d’67’ |
; The delay parameter is decimal 67 |
|
DELAY_208 movlw |
N |
; The delay parameter, 1˜ |
||
movwf |
COUNT |
; Stored in File 34h , 1˜ |
||
D_LOOP |
decfsz |
COUNT,f |
; [(N-1)*1] + 2 cycles |
|
goto |
D_LOOP |
; [(N-1)*2] cycles |
||
return |
; Finish |
, 2˜ |
||
In order to calculate the parameter the time equation is:
2(call) + 1 + 1 + (N × 3 − 1) + 2 |
= |
208 µs |
N × 3 |
= |
203 |
N |
= |
67 |
This gives a total delay of 206 µs. Adding two nop instructions just before the return instruction will add the two extra µs.
See Program 12.10 on page 338.
Example 6.3
At the other end of the spectrum write a subroutine to give a delay of one second.
160 The Quintessential PIC Microcontroller
Solution
For a delay as long as this we need to extend Program 6.1 to use a larger count. In the coding of Program 6.9 three file registers are used to give a triple loop.
File register COUNT2 is initialized to the value H whilst the other two file registers are cleared giving an e ective count range of 256. The outer loop exits the program when COUNT2 reaches zero. This single pass therefore contributes (H × 3) − 1 cycles to the total delay. Each pass through the COUNT1 loop takes (256 ×3) −1 cycles and there are H passes giving a contribution of H × [(256 × 3) − 1] cycles. In the same manner the inner loop based on decrementing COUNT0 runs H × 256 times each pass contributing (256 × 3) − 1 cycles to the total. Thus we have a total delay of:
(H × 3) − 1 + H × [(256 × 3) − 1] + H × 256 × [(256 × 3) − 1] + 6
Equating this to 106 ( µs per second) gives H ≈ 5. The actual delay with an H of 5 is 0.985615 s which is accurate to 1.4%. If desired the shortfall of 14,385 cycles can be made up by adding nop instructions to the middle count loop. Each such instruction gives an extra 1280 cycles. The
Program 6.9 A 1-second delay program.
COUNT0 |
equ |
34h |
; 3-byte counter at F 34h |
|||
COUNT1 |
equ |
35h |
; and |
F |
35h |
|
COUNT2 |
equ |
36h |
; |
and |
F |
36h |
H |
equ |
5 |
; |
The |
delay constant |
|
; *************************************************************
; * |
FUNCTION: |
Delays |
for approx |
one second |
for a |
4 MHz XTAL |
* |
||
; |
* |
ENTRY |
: |
None |
* |
||||
; |
* |
EXIT |
: |
Status |
altered. W |
destroyed, |
Files |
34:5:6h zero * |
|
; *************************************************************
DELAY_1_S movlw movwf clrf clrf
D_LOOP
decfsz goto decfsz goto decfsz goto return
6. Subroutines and Modules 161
maximum delay possible with this program is 50.46 s for H = 0 (e ectively 256).
Example 6.4
Design a subroutine to convert a binary byte passed in W to a 3-digit BCD equivalent in HUNDREDS (File 30h), TENS (File 31h) and UNITS (File 32h).
Solution
We have already coded a routine to implement this mapping in Example 5.3 on page 129. However this was restricted to a range 0–99, that is two digits. Nevertheless we can extend the technique used there by first subtracting and counting hundreds from the original binary byte. After this has been computed then the residue will be less than 100 and the rest of the coding will be the same, as shown in Program 6.10. Thus a suitable task list would be:
1.Divide by 100; the remainder is the hundreds digit.
2.Divide the quotient by ten; the remainder is the tens digit.
3.The quotient is the units digit.
Program 6.10 Binary to 3-digit BCD conversion.
;************************************************************
;* FUNCTION: Converts a binary byte in W to three BCD digits*
; * |
EXAMPLE |
: Binary = FFh (255d), HUNDREDS = 02h |
* |
||
; * |
EXAMPLE |
: TENS = 02h, UNITS = 05h |
* |
||
; * |
ENTRY |
: Binary in |
W |
* |
|
; |
* |
EXIT |
: HUNDREDS = |
hundreds digits, TENS = tens digit |
* |
; |
* |
EXIT |
: UNITS = units digit. W holds units |
* |
|
;************************************************************
;First divide by a hundred
BIN_2_BCD |
clrf |
HUNDREDS |
; Zero the loop count |
|
LOOP100 |
incf |
HUNDREDS,f |
; Record one hundred subtracted |
|
addlw |
-d’100’ |
; Subtract decimal hundred |
||
btfsc |
STATUS,NB |
; IF a borrow (NB==0) THEN exit loop |
||
goto |
LOOP100 |
; ELSE do another subtract/count |
||
decf |
HUNDREDS,f |
; Compensate for one inc too many |
||
addlw |
d’100’ |
; Add a hundred to residue |
||
; Next divide by |
ten |
|||
clrf |
TENS |
; Zero the loop count |
||
LOOP10 |
incf |
TENS,f |
; Record one ten subtracted |
|
addlw |
-d’10’ |
; Subtract decimal ten |
||
btfsc |
STATUS,NB |
; IF a borrow (NB==0) THEN exit loop |
||
goto |
LOOP10 |
; ELSE do another subtract/count |
||
decf |
TENS,f |
; Compensate for one inc too many |
||
addlw |
d’10’ |
; Add ten to residue |
||
movwf |
UNITS |
; which gives the remainder |
||
return |
; and return to caller |
|||