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

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

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

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

Добавлен: 15.06.2025

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

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

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

THE ESSENCE OF THE PIC MICROCONTROLLER 125

Program 5.5 Triple-precision shifting to find the number of set bits.

COUNT_BIT clrw ; Zero the count

; WHILE data is not zero, shift right and increment counter

BLOOP

bcf

STATUS,C

; Clear Carry flag

rrf

30h,f

; Shift right all three bytes

rrf

31h,f

rrf

32h,f

btfsc

STATUS,C

; IF no carry then skip

addlw

1

; ELSE add one to count

; Now check for a triple-byte zero

movf

32h,f

; Test rightmost byte

btfss

STATUS,Z

; IF zero THEN try middle byte

goto

BLOOP

; ELSE shift again

movf

31h,f

; Test middle byte

btfss

STATUS,Z

; IF zero THEN try leftmost byte

goto

BLOOP

; ELSE shift again

movf

30h,f

; Test leftmost byte

btfss

STATUS,Z

; IF zero THEN try middle byte

goto

BLOOP

; ELSE shift again

EXIT

.....

......

; Exit with the count in W

by testing each byte in turn for zero and going back to the top of the loop if any byte test gives a non-zero outcome.

Shifting can be used to multiply and divide data by powers of two. For example, to divide by eight shift left three times:

00011000

(24)

rrf 20h,f

00001100

(12)

÷2

File 20h

File 20h

00001100

(12)

rrf 20h,f

00000110

(6)

÷4

File 20h

File 20h

00000110

(6)

rrf 20h,f

00000011

(3)

÷8

File 20h

File 20h

where we are assuming that the Carry flag is cleared before each shift. In general shifting n places right gives a 2n division and similarly to the left gives multiplication by the same factor – see page 11.

As an example consider that the byte in File 22h (called MULTIPLICAND) is to be multiplied by 3 to give a 2-byte product in File 24:5h (PRODUCT_H and PRODUCT_L respectively).

The implementation of Program 5.6 relies on factoring ×3 as ×2+×1. The former is implemented by shifting a 16-bit extension of the byte multipicand (upper byte zeroed) once left. The single byte multiplicand is then added to the 2-byte subproduct to give the desired outcome. Example 5.5 gives the more complex case of multiplying by ten.

Program Counter instructions

The instructions listed in Table 5.4 modify in some way the setting of the Program Counter. The most elementary of these is nop. No OPer-


126 The Quintessential PIC Microcontroller

Program 5.6 Multiplying by three.

STATUS

equ

3

;

The Status register

C

equ

0

;

Bit0 of which is the Carry bit

MULTIPLICAND

equ

22h ;

File 22h

is the multiplicand

PRODUCT_H

equ

24h ;

File 24h

is the High byte of the product

PRODUCT_L

equ

25h ;

File 25h

is the Low

byte of the product

MULT_3 movf

MULTIPLICAND,w

;

Get xplicand from File 22h

movwf

PRODUCT_L

;

and put as

lower product byte

clrf

PRODUCT_H

;

and extend

to a 16-bit datum

; Now shift left 16

bits

bcf

STATUS,C

;

Clear carry

rlf

PRODUCT_L,f

rlf

PRODUCT_H,f

;

giving x2

; Now add multiplicand (still in

W) to give

x2 + x1 = x3

addwf

PRODUCT_L,f

;

Lower byte

btfsc

STATUS,C

;

plus any carry

incf

PRODUCT_H,f

....

....

ation does not alter the state of the system in any way, but the PC will increment as a consequence of the instruction code being fetched from the Instruction store. Thus its sole outcome is [PC] <- [PC] + 1. This takes one bus cycle, so its main use is to implement a short delay, 1 µs for a 4 MHz clock rate. For example, to pulse Port A’s pin low for 2 µs and then high we have:

bcf

PORTA,0

; Pin

RA0

low

nop

;

for

2 us

nop

bsf

PORTA,0

;

and now

high

with the assumption that bit 0 of Port A has been set up as an output (see page 95) and that bit 0 (pin RA0) was high before entering the routine.

The goto instruction is an absolute jump instruction allowing the program to transfer to the specified instruction anywhere in the Program store. The process has been described in Fig. 5.4.

The remaining four instructions can skip over the following command if some condition is met. The pair decfsz (DECrement File and Skip on Zero) and incfsz (INCrement File and Skip on Zero) augment the specified file contents and then if the outcome is zero the PC is further incremented. Strangely, the Z flag is not a ected by these instructions.

A typical use for these instructions is to count the number of passes through a loop. For example, suppose it is necessary to pulse Port A pin RA0 low 20 times.


THE ESSENCE OF THE PIC MICROCONTROLLER 127

Table 5.4: Program Counter instructions.

Flags

Operation

Mnemonic Z DC C

Description

Absolute jump

Goto a fixed instruction

Goto an instruction

goto

aaa

[PC] <- aaa

No operation

Do nothing

nop

[PC] <- [PC] + 1

Bit test and skip

Check bit in file and skip if true

Bit clear in File

btfsc

f,n

PC++ IF fn == 0

Bit set in File

btfss

f,n

PC++ IF fn == 1

Decrement and skip on zero

Decrement & skip if result is #00

File

decfsz f,d

d <- f--, PC++ IF [f] == #00

Increment and skip on zero

Increment & skip if result is #00

File

incfsz f,d

d <- f++, PC++ IF [f] == #00

++ Increment contents

--

Decrement contents

aaa Absolute 11-bit instruction address

movlw

d’20’

; Put decimal 20 into W

movwf

30h

; & initialize File 30 as a loop counter

LOOP bcf

PORTA,0

; Pin RA0 low

nop

; for 2 us

nop

bsf

PORTA,0

; and now high

nop

; for 2 us

nop

decfsz

30h,f

; Count down

goto

LOOP

; Repeat loop if not zero

..... ......

; ELSE escape the loop

Notice the assembler notation d’20’ for decimal 20 – see page 223. This is equivalent to 14h but more readily understood by the programmer.

The btfsc (Bit Test File and Skip if Clear) and btfss (Bit Test File and Skip if Set) instructions have been used extensively in programs both here and in Chapter 3. Besides their obvious use in changing the program flow based on the state of a specified bit in any register file, they allow decisions to be make on the state of the various flags in the Status register. Thus in Program 5.5 the series of btfss STATUS,Z (or the more unreadable btfss 3,2) instructions enable the program loop to be exited when the Z flag is set, that is on a series of zero outcomes. Similarly btfsc STATUS,C allows the count action to be skipped over when the C flag is clear. Neither instruction a ects the flags.

All four skip instructions take two cycles to execute when the skip occurs but only one when the condition is not met. As described in Example 4.1 on page 99, the former situation needs to flush the instruction pipeline. This is to reflect the fact that the pre-fetched instruction code


128 The Quintessential PIC Microcontroller

sitting in stage one of the pipeline is not going to be the next instruction executed. This accounts for the additional bus cycle execution time as the true destination instruction has now to be fetched.

Examples

Example 5.1

Code a program to decrement a 2-byte number at File 26:27h ordered as high:low byte, remembering that decf does not alter the Carry/Borrow flag.

Solution

The task list to implement this job is:

1.IF the least significant byte in File 27h is zero THEN decrement the most significant byte.

2.Always decrement the least significant byte.

Program 5.7 gives one possible implementation based directly on this algorithm. Extension to an n-byte word is obvious.

Program 5.7 Double-precision decrement.

STATUS

equ 3

; The Status register

Zequ 2 ; Bit2 of which is the Zero bit

MSB

equ

26h

; The Most Significant byte

LSB

equ

27h

; The Least Significant Byte

movf

LSB,f

; Test for LSbyte zero.

btfsc

STATUS,Z

; IF not THEN ship MSbyte decrement

decf

MSB,f

; ELSE must decrement MSByte

decf

LSB,f

; Always decrement LSbyte

Example 5.2

Some early computers used a bi-quinary code to represent BCD digits. This is a 7-bit code with only two bits set to one for any combination:

THE ESSENCE OF THE PIC MICROCONTROLLER 129

01

00001

0

01

00010

1

01

00100

2

01

01000

3

01

10000

4

10

00001

5

10

00010

6

10

00100

7

10

01000

8

10

10000

9

Although this is highly ine cient (with only ten out of a possible 128 code combinations being used as compared to the 16 combinations of the 4-bit natural code) it does have the advantage that it is very easy to determine when an error has occurred. Determine an error-detection routine to check the byte in File 20h. Assume that the most-significant bit is zero. If an error occurs then the Working register is to be set to FFh, otherwise zero.

Solution

All we need to do here is to determine when there are more or less than two bits set to one. Based on this approach we have the task list:

1.Count the number of ones in the bi-quinary byte.

2.Zero W.

3.IF count is not two THEN make FFh to signal an error.

Program 5.8 shows a possible coding implementing this algorithm. Here the loop continually shifts the bi-quinary byte left until the residue is zero. When the carry bit is set, the bit count is incremented. On exit from the loop, two is subtracted from the bit tally after moving into W. If it is zero then the routine is completed and the 00h setting of W shows a correct outcome. Otherwise FFh is placed in W to show an error situation. This is equivalent to decimal −1 and is traditionally used to note an error situation. As there are only ten legal combinations out of 128 possibilities used in this code the likelihood of an undetected error is rather small.

Example 5.3

Write a routine to convert a binary number of magnitude no greater than 63h (decimal 99) in File 20h to two BCD digits in File 21:2h ordered as Tens:Units – see page 6.

Solution

A possible algorithm to implement this binary to BCD conversion is to divide by ten; this generates a quotient between 0 and 9 (remember the


130 The Quintessential PIC Microcontroller

Program 5.8 Bi-quinary error detection.

STATUS

equ

3

; Status register is File 3

C

equ

0

; Carry flag is bit0

Z

equ

2

; Zero flag is bit2

BI_QUIN

equ

20h

; Bi-quinary byte is in File 20h

COUNT

equ

21h

; The bit count is put here

BI_QUINARY

clrf

COUNT

; Bit count is cleared

LOOP

bcf

STATUS,C

; Clear carry flag

rlf

BI_QUIN,f

; Rotate code left

btfsc

STATUS,C

; IF no Carry popped out THEN skip

incf

COUNT,f

; the count increment

movf

BI_QUIN,f

; Test if residue is zero

btfss

STATUS,Z

; IF zero THEN skip out of loop

goto

LOOP

; ELSE repeat shift and count

movf

COUNT,w

; Get count

sublw

2

; Compare with two

btfss

STATUS,Z

; IF ZERO finished with W == 00

movlw 0FFh

; ELSE put FFh (-1) in W

..... ......

; and exit

maximum value is 99) and a remainder. The quotient is the number of tens and the remainder will be the number of units.

We have already seen how to divide by an arbitrary variable datum byte in Program 5.3. Here in Program 5.9 we wish to divide by a constant ten. This simplifies the coding somewhat with the addlw -d’10’ (or addlw -0Ah) instruction used to take away the literal ten. Keeping a count in the TENS file register gives the number of subtractions until a borrow is generated. The required number of tens is one less than this tally; that is the number of successful subtractions. Adding that one extra ten back again to the residue gives the remainder, which is the units tally.

Example 5.4

Using Program 5.2 as a template write a program to evaluate the average temperature over the 24 hours.

Solution

Finding the average involves walking through the array adding each element to a 2-byte grand total. On completion divide by 24 to give the function:

23

Temp[i]

i=0

24