Файл: 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.


COUNT0,f D_LOOP COUNT1,f D_LOOP COUNT2,f D_LOOP
; Dec LSB count, H*256*[(256*3)-1]˜ ; to zero
; Then dec NSB count, H*[(256*3)-1]˜ ; to zero and then repeat
; Then dec MSB count, (H*3)-1˜ ; to zero and then repeat
; 2˜
H COUNT2 COUNT1 COUNT0
; Put 5 as the MS count, 1˜ ; 1˜
; Set lower counts to 256, 1˜ ; 1˜

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