Файл: The quintessential PIC microcontroller (S. Katzen, 2000).pdf

ВУЗ: Не указан

Категория: Не указан

Дисциплина: Не указана

Добавлен: 15.06.2025

Просмотров: 5358

Скачиваний: 0

ВНИМАНИЕ! Если данный файл нарушает Ваши авторские права, то обязательно сообщите нам.

162 The Quintessential PIC Microcontroller

Example 6.5

Write a subroutine to evaluate the square root of a 16-bit integer located in File 26:7h. The 8-bit outcome is to be returned in the Working register.

Solution

The crudest way of doing this is to try every possible integer k from 1 upwards, generating k2 by multiplication and checking that the outcome is no more than n. A slightly more sophisticated approach is based on the relationship:

k

k2 = (2 × i) + 1

i=0

On this basis a possible structure for this function is:

1.Zero the loop count

2.Set variable I (the magic number) to 1

3.DO forever:

(a)Take I from Number

(b)IF the outcome is under zero THEN BREAK out

(c)ELSE increment the loop count

(d) Add 2 to I

√Number

4. Return loop count as

That is sequentially subtract the series 1, 3, 5, 7, 9, 11…from Number until underflow occurs; with the tally of successful passes being the square

number

SQRT

count = 0

65

count = 0

i = 0

-

1

64

count = 1

LOOP:

-

3

61count = 2

-5

56

count = 3

count = count + 1

number = number - i

-

7

49

count = 4

-

9

40

count = 5

-11

no

29

count = 6

i = i + 2

<0?

-13

16

count = 7

yes

-15

1count = 8

-17

Return

count

-16

Terminate with square root = 8

(a) An example

(b) Flowchart of the process

Fig. 6.9 Finding the square root of an integer.


6. Subroutines and Modules 163

root. An example giving √65 = 8 is given in Fig. 6.9(a) using this series approach. A flowchart visualizing the task list is also given in Fig. 6.9(b).

Program 6.11 Coding the square root subroutine.

; Global declarations

STATUS

equ

3

; Status register is File 3

C

equ

0

; Carry flag is bit0

NB

equ

0

; Alternative name Not Borrow

NUM_H

equ

26h

; Number low byte

NUM_L

equ

27h

; Number high byte

;************************************************************

;* FUNCTION: Calculates the square root of a 16-bit integer *

; *

EXAMPLE

: Number

= FFFFh

(65,535d), Root = FFh (255d)

*

;

*

ENTRY

: Number

in File

26:7h

*

;

*

EXIT

: Root in W. Files 26:7h and 35:6:7h altered

*

;************************************************************

;Local declarations

COUNT

equ

35h

;

The loop count

I_H

equ

36h

;

Magic number high

I_L

equ

37h

;

Magic number low

; Task 1: Zero loop

count

SQR_ROOT

clrf

COUNT

; Task 2: Set magic

number

I to one

clrf

I_L

clrf

I_H

incf

I_L,f

;Task 3: DO

;Task 3(a): Number - I

SQR_LOOP movf

I_L,w

;

Get low byte magic number

subwf

NUM_L,f

;

Subtract from low byte Number

movf

I_H,w

;

Get high byte magic number

btfss

STATUS,NB

;

Skip if No Borrow out

addlw

1

;

Return borrow

subwf

NUM_H,f

; Subtract high bytes

; Task 3(b): IF

underflow

THEN exit

btfss

STATUS,NB

; IF No Borrow THEN continue

goto

SQR_END

; ELSE the process is complete

; Task 3(c): ELSE increment loop count

incf

COUNT,f

; Task 3(d): Add two to the magic number

movf

I_L,w

addlw

2

; IF no carry THEN done

btfsc

STATUS,C

incf

I_H,f

; ELSE add carry to upper byte I

movwf

I_L

goto

SQR_LOOP

; Task 4: Return loop count as the square root

SQR_END movf COUNT,w ; Copy into W return


164 The Quintessential PIC Microcontroller

The coding in Program 6.11 follows the task list closely. The maximum value of the loop count is FFh, as √65535 = 255. Thus a single byte at File 35h is reserved for this local variable. Similarly the maximum possible value of the magic number is 511 (1FFh) and so the two registers File 36:7h are reserved for this local variable. This of course means that Task 3(a) entails a double-byte subtraction. The coding is somewhat simplified as the high byte of I, that is I_H, is never more than 01h and so a borrow from the lower byte can be added to a copy of I_H before the high-byte subtract to return the borrow without overflow. If a borrow is generated from this high-byte subtraction the outcome is under zero and the loop is exited. Otherwise COUNT is incremented and I augmented by two. Actually the latter is always twice COUNT plus one, so COUNT is not needed. Instead, on return the 16-bit value I can be shifted once right. This divides by 2 and by throwing away the one that pops out into the carry, e ectively subtracts by one – I is always odd and so its least significant bit is always 1. Try coding this alternative arrangement.

Example 6.6

Repeat Example 5.5, which multiplies a byte by ten, but using a software stack for data storage and parameter passing. You may assume that the multiplicand byte is in memory at File 46h.

Solution

The global declarations for the subroutine of Program 6.12 and calling procedure is:

PSP

equ

0Ch

; Holds the Pseudo Stack Pointer

TOS

equ

2Fh

; File 2Fh is the initial Top Of Stack

INDF

equ

0

; INDirect File

FSR

equ

04

; File Select Register

XCAND

equ

46h

; Multiplicand byte

STATUS

equ

3

; Status register is File 3

C

equ

0

; Carry flag is bit0

; The main routine

sets up the Pseudo stack pointer (PSP)

MAIN

movlw TOS

; Set up the PSP

movwf PSP

; to the initial Top Of Stack

;..........................and so on

;Get ready to call up the X10 subroutine

movf PSP,w ; 1st point to current stack position

movwf FSR

the stack

; Now copy multiplicand onto

movf

XCAND,w

; Copy multiplicand into W

movwf

INDF

;

and onto the stack

decf

FSR,w

;

Point

down one

call X10 ; Now call subroutine

;On return PSP is returned to original position

;and product is at PSP+3:PSP+2

NEXT_MAIN ..... ... ; Continuation of main routine


6. Subroutines and Modules 165

Program 6.12 uses the same technique as the original routine. First the multiplicand is shifted left once to multiply by two and then two further shifts multiplies by eight. The two resulting 16-bit data are then added to give the product. In the same manner as Program 6.6, the File Select Register is moved up and down to point the the appropriate datum as the

Program 6.12 Using a software stack to pass parameters and to provide a workspace. (continued next page).

;************************************************************

;* FUNCTION: Xs byte XCAND by 10 giving double-byte product *

; *

EXAMPLE

: 64h x 0Ah = 3E8h (100d x 10d = 1000d)

*

;

*

ENTRY

: Multiplicand

pushed into software stack at PSP *

;

*

EXIT

: Product_H:_L

in PSP-3:PSP-2

*

; ************************************************************

X10

movf

PSP,w

; Point FSR at current stack position

movwf

FSR

clrf

INDF

; Zero XCAND overflow

; Now multiply by two by shifting

16-bit XCAND left once

bcf

STATUS,C

; Clear

Carry-in

incf

FSR,f

; Point

to the XCAND LSB

rlf

INDF,f

; Shift

left LSB

decf

FSR,f

; Point

to MSB

rlf

INDF,f

; Shift left MSB

; Add to 16-bit

subproduct

incf

FSR,f

; Point to XCANDx2_L

movf

INDF,w

; Get it

decf

FSR,f

; Point at PROD_L

decf

FSR,f

movwf

INDF

; Update it with XCANDx2_L

incf

FSR,f

; Point to XCANDx2_H

movf

INDF,w

; Get it

decf

FSR,f

; Point at PROD_H

decf

FSR,f

movwf

INDF

; Update it with XCANDx2_H

; Now shift left twice more to give x8

incf

FSR,f

; Point to XCANDx2_L

incf

FSR,f

incf

FSR,f

bcf

STATUS,C

; Clear Carry-in

rlf

INDF,f

; Shift left LSB

decf

FSR,f

; Point to MSB

rlf

INDF,f

; Shift left MSB

incf

FSR,f

rlf

INDF,f

; Shift left LSB

decf

FSR,f

; Point to MSB

rlf

INDF,f

; Shift left MSB


166 The Quintessential PIC Microcontroller

Program 6.12 (continued.) Using a software stack to pass parameters and to provide a workspace.

; Add to 16-bit

subproduct

incf

FSR,f

; Point to XCANDx8_L

movf

INDF,w

; Get it

decf

FSR,f

; Point at PROD_L

decf

FSR,f

addwf

INDF,f

; Update it with XCANDx8_L

incf

FSR,f

; Point to XCANDx8_H

btfsc

STATUS,C

; IF Carry set THEN inc XCANDx8_H

incf

INDF,f

movf

INDF,w

; ELSE get it

decf

FSR,f

; Point at PROD_H

decf

FSR,f

addwf

INDF,f

; Update it with XCANDx8_H

return

; ************************************************************

program progresses. The double-byte product can be accessed relative to the Pseudo Stack Pointer by the caller. Unlike Program 6.6 this PSP is not altered when pushing out the multiplicand nor in the subroutine. This is because the subroutine is a dead end in that it can never call another subroutine. Thus a new stack frame need not be formed.

Example 6.7

In order to ensure that the 7-segment decoder subroutine of Program 6.4 does not cause the PCL register to overflow when the o set is added, a programmer has used the directive org (ORiGin – see page 200) to tell the assembler to locate the subroutine at the absolute instruction address 700h – as shown in Program 6.13. When the subroutine is tested by calling from another part of the program in the store somewhere lower than 700h the system fails and performs unpredictably. What has gone wrong?

Program 6.13 The software 7-segment decoder revisited.

org

700h

; Start the subroutine at 700h

SVN_SEG addwf

PCL,f

; Add N to PCL giving PC + N

retlw

b’11000000’

; Code for 0

retlw

b’11111001’

; Code for 1

retlw

b’10100100’

; Code for 2

retlw

b’10110000’

; Code for 3

retlw

b’10011001’

; Code for 4

retlw

b’10010010’

; Code for 5

retlw

b’10000010’

; Code for 6

retlw

b’11111000’

; Code for 7

retlw

b’10000000’

; Code for 8

retlw

b’10010000’

; Code for 9