Файл: The quintessential PIC microcontroller (S. Katzen, 2000).pdf
ВУЗ: Не указан
Категория: Не указан
Дисциплина: Не указана
Добавлен: 15.06.2025
Просмотров: 5335
Скачиваний: 0
3. Stored Program Processing 65
the most significant addition becomes the highest bit of the outcome. For example FF FFh + FF FFh = 1 FF FFh (65, 535d + 65, 635d = 131, 070d).
F20h F21h
AUGEND_H AUGEND_L
F24h |
F25h |
F26h |
SUM_H |
SUM_M |
SUM_L |
F22h F23h
ADDEND_H ADDEND_L
Fig. 3.8 The process.
The overall process is diagrammatically shown in Fig. 3.8. However, given that we need to implement the process as a sequence of steps executable by the byte-sized instructions of Table 3.1 then the next step is to produce a task listing.
1.Add the low bytes of the augend and addend, generating the low byte of the sum and carry C1.
F20h F21h
AUGEND_H AUGEND_L
F20h F21h
AUGEND_H AUGEND_L
C1 |
||||||||
F22h |
F23h |
F22h |
F23h |
|||||
ADDEND_H ADDEND_L |
C1 |
C2 |
ADDEND_H ADDEND_L |
|||||
F24h |
F25h |
F26h |
F24h |
F25h |
F26h |
|||
SUM_H |
SUM_M |
SUM_L |
SUM_H |
SUM_M |
SUM_L |
|||
(a) Adding the least-significant bytes |
(b) |
And the most-significant bytes |
||||||
F20h |
F21h |
|||||
AUGEND_H |
AUGEND_L |
|||||
C2 |
F22h |
F23h |
||||
ADDEND_H |
ADDEND_L |
|||||
F24h |
F25h |
F26h |
||||
SUM_H |
SUM_M |
SUM_L |
||||
(c) The most-significant sum byte is the last carry-out
Fig. 3.9 Visualization of the task process.
66The Quintessential PIC Microcontroller
2.Add the high bytes of the augend and addend plus the last carry-out C1 to give the middle byte of the sum and a new carry-out C2.
3.The high byte of the sum is the last carry-out C2, either 0 or 1.
Given that this is our first program of any substance, a detailed visualization of this task list will be useful. For most instances detail at this level is not helpful and subsequently we will use a more abstract visualization known as a flow chart (see Example 3.3).
Once a task list has been established then the next step is to implement this as a sequence of instructions, that is the program. One possible is shown in Program 3.5.
In the listing the three tasks are identified by an appropriate comment.
Task 1
This comprises a Load-Add-Store sequence to add the lower byte of the addend to that of the similarly significant augend. The outcome byte is
Program 3.5 The double-precision add program.
AUGEND_H |
equ 020h |
||
AUGEND_L |
equ 021h |
||
ADDEND_H |
equ 022h |
||
ADDEND_L |
equ 023h |
||
SUM_H |
equ 024h |
||
SUM_M |
equ 025h |
||
SUM_L |
equ 026h |
||
STATUS |
equ |
03 |
; STATUS flag register |
C |
equ |
0 |
; The C flag |
DP_ADD |
clrf |
SUM_M |
; Zero the 2 upper bytes of the sum |
clrf |
SUM_H |
||
; Task 1 |
|||
movf |
AUGEND_L,w |
; Get LSB of the augend |
|
addwf |
ADDEND_L,w |
; Add LSB of addend |
|
movwf |
SUM_L |
; and put it away |
|
; Tasks 2 and 3 |
|||
btfsc |
STATUS,C |
; Was there a carry C1? |
|
incf |
SUM_M |
; IF yes THEN add to middle sum byte |
|
movf |
AUGEND_H,w |
; Get MSB of the augend |
|
addwf |
ADDEND_H,w |
; Now add to MSB of the addend |
|
btfsc |
STATUS,C |
; Was there a carry C2? |
|
incf |
SUM_H |
; IF so THEN add to high byte sum |
|
addwf |
SUM_M,f |
; Add the outcome to mid sum byte |
|
btfsc |
STATUS,C |
; Was there a carry C2 from this? |
|
incf |
SUM_H |
; IF so THEN add to high sum byte |
|
.... |
..... |
; Next program |
|
3. Stored Program Processing 67
stored in memory at File 26h (SUM_L) and the Carry flag bit (bit 0 in File 3) is set as appropriate to C1.
Task 2
If there was a carry-out from Task 1 then the precleared middle byte of the sum is incremented as the carry-in C1. Then the upper bytes of the addend and augend are added. The final outcome of SUM_M (in File 25h) is determined by adding its current state (00h or 01h) to the outcome of this addition.
Task 3
Either of the two additions in Task 2 can result in a carry-out. The C flag in the STATUS register can be tested after each addition and if set, the upper byte of the sum SUM_H (File 26h) is incremented to add C2, as shown in Fig. 3.8(c). There will not be a carry-out generated by both the Task 2 additions.
Example 3.3
Write a program to divide the byte in the Working register by ten. The quotient is to be in File 20h and the remainder in W.
Solution
Division is the process in finding how many times the divisor (ten in our case) can be subtracted from the dividend without underflowing, that is producing a borrow.
The flow chart shown in Fig. 3.10 outlines the task list to implement our algorithm. Initializing the quotient to −1 means that the subtract and increment loop can begin by incrementing, and this process will continue until a borrow is produced after the subtraction by ten process. A
Program 3.6 Dividing by ten.
QUOTIENT |
equ |
020h |
; Where the quotient will be stored |
|
STATUS |
equ |
03 |
; Where STATUS reg. flags are located |
|
DIV_10 |
clrf |
QUOTIENT |
; 1: Zero quotient |
|
decf |
QUOTIENT,f |
; 1: Initial value is -1 |
||
DIV_LOOP |
incf |
QUOTIENT,f |
; 2: Increment quotient |
|
addlw |
-10 |
; 3: Subtract ten from dividend |
||
btfsc |
STATUS,0 |
; 4: Leave loop if borrow (bit 0 = 0) |
||
goto |
DIV_LOOP |
; 4: ELSE repeat increment and subtract |
||
addlw |
10 |
; 5: Add ten to give remainder |
||
.... ..... |
; Next program |
|||
68 The Quintessential PIC Microcontroller
borrow-out indicates that the last subtraction was not successful in that the divisor (i.e. ten) was larger than the residue it was subtracted from. That is the outcome is negative. The loop count on exit represents the number of successful subtractions and thus the quotient.
The coding in Program 3.6 closely follows the flow chart, with comment numbers referring to the statement boxes. The actual subtract constant ten is implemented by adding minus ten! This is because the more obvious sublw 10 instruction actually subtracts W from ten and not ten from W. Notice the mechanism for exiting the loop by testing and skipping if bit 0 in STATUS is clear after this subtraction.
Remembering that bit 0 in File 3 is the Carry flag doubling as the Borrow flag, then a borrow out is indicated if this bit is zero after the subtraction. On exit ten is added back on to compensate for the last unsuccessful subtraction and the outcome then gives the remainder.
Quotient = |
-1 |
LOOP |
|
Increment |
|
quotient |
|
Subtract ten |
|
from dividend |
|
No |
|
Borrow? |
|
Yes |
|
Add ten to give remainder
End
Fig. 3.10 Division by repetitive subtracting.
3. Stored Program Processing 69
Example 3.4
As part of a program to convert degrees Celsius to Fahrenheit it is necessary to multiply the byte in W by nine. Devise a suitable coding.
Solution
There are two ways of multiplying. The fundamental definition of multiplication is repetitive addition, thus we could add the datum nine times to implement our specified function. An alternative approach is the shift and add technique outlined on page 11. Thus the ×9 function is implemented as ×8 +×1. The former is carried out by shifting left three times (i.e. 23). Thus we have:
W × 9 = W × 8 + W × 1 = (W << 3) + W
No matter what technique is used, the outcome by definition will be larger than either the multiplier or multiplicand. In this case we need two bytes. In the coding of Program 3.7 the two memory locations File 20h and File 21h are used to hold the high byte and the low byte respectively of the final 2-byte product. By copying the multiplicand from W to the low byte and clearing the upper byte we make an extended 2-byte version of the multiplicand in Data memory. Shifting left is implemented by using
Program 3.7 Multiplying by nine.
STATUS |
equ |
3 |
; STATUS register flags |
C |
equ |
0 |
; Carry flag is bit0 |
PRODUCT_H equ 020h |
; High byte of the product |
||
PRODUCT_L equ 021h |
; Low byte |
||
MUL_9 |
movwf |
PRODUCT_L |
; Move the multiplicand to memory |
clrf |
PRODUCT_H |
; Extend it to 2 bytes |
|
; Now shift the double byte multplicand three times to give x8
bcf |
STATUS,C |
; |
Clear carry |
|
rlf |
PRODUCT_L,f ; |
Shift left low byte of product |
||
rlf |
PRODUCT_H,f ; |
and |
the high byte |
|
bcf |
STATUS,C |
; |
Clear carry |
|
rlf |
PRODUCT_L,f ; |
Shift left low byte of product |
||
rlf |
PRODUCT_H,f ; |
and |
the high byte |
|
bcf |
STATUS,C |
; |
Clear carry |
|
rlf |
PRODUCT_L,f ; |
Shift left low byte of product |
||
rlf |
PRODUCT_H,f ; |
and |
the high byte |
|
; Now add the original value giving |
x8 + x1 = x9 |
|||
addwf |
PRODUCT_L,f ; |
Add |
to lower byte |
|
btfsc |
STATUS,C |
; |
and |
any carry to the upper byte |
incf |
PRODUCT_H,f |
|||
end |
||||
70 The Quintessential PIC Microcontroller
C
0
PRODUCT_L
1 bcf CCR,C
C
2 rlf PRODUCT_L,f
PRODUCT_H
3 rlf PRODUCT_H,f
Fig. 3.11 Double-precision shifting.
the rlf (Rotate Left File) instruction twice, beginning with the lower byte. As well as shifting the byte PRODUCT_L left once, the most significant bit is moved into the Carry flag. Subsequently rotating the contents of the high byte PRODUCT_H moves this Carry in as the new least significant bit and shifts the high byte left as shown in Fig. 3.11. Of course the Carry flag needs to be cleared prior to this process. This 3-instruction double-precision routine is repeated three times to give the required ×8 function. Adding the original multiplicand, which is still in W gives the final ×9 function.
Example 3.5
The circuit diagram of Fig. 3.12 shows a 7-bit pseudo-random number generator (PRNG) based on a shift register with an Exclusive-OR gate feedback. Devise a routine to continually send these 127 binary random numbers to a port located at File 06. The routine must initialize the PRN to any non-zero value.
1D |
Data in = B5 + B6 |
B6 B5 B4 B3 B2 B1 B0
C1 Sample rate
Fig. 3.12 A 7-bit pseudo-random number generator.
3. Stored Program Processing 71
Solution
A suitable task list is:
1.Initialize the number to 01.
2.DO forever.
(a)Rotate shift a copy of the number once left so that bits 5 & 6 are aligned.
(b)Bitwise XOR the number and its shifted copy.
(c)Rotate the outcome twice left to pop out bit 6 into the C flag, which will be B6 B5.
(d)Rotate the original number once left with C becoming the new bit 0.
Program 3.8 A 7-bit pseudo-random number generator.
PORTB |
equ |
6 |
||
NUMBER |
equ |
0x20 |
||
TEMP |
equ |
0x21 |
||
PRNG |
movlw |
1 |
; Initial value of random number is 01 |
|
P_LOOP |
movwf |
NUMBER |
; Make a copy in memory |
|
rlf |
NUMBER,f |
; Shift number to align bits 5 & 6 |
||
xorwf |
NUMBER,f |
; Bitwize XOR them |
||
rlf |
NUMBER,f |
; Shift twice left to put 5XOR6 in Carry |
||
rlf |
NUMBER,f |
|||
movwf |
TEMP,f |
; Put original number in memory |
||
rlf |
TEMP,w |
; >> with carry coming in, and put in W |
||
movwf |
PORTB |
; and send this new random number out |
||
goto |
P_LOOP |
; and repeat |
||
The listing in Program 3.8 follows the task list fairly closely. The value of the number is temporarily saved in memory so that it can be processed without altering the original number down in W. This is done by specifying the destination to be the file, eg. rlf NUMBER,f. After rotating left once left, bit 5 in the shifted copy in NUMBER is aligned with the original bit 6 in W. After exclusive ORing the two, with the destination again being in File memory (xorwf NUMBER,f), bit 6 in NUMBER is now B5 B6. Shifting twice left puts this bit in the Carry flag. Finally rotating the original pseudo-random number in W moves that pattern once left with the new least-significant bit being the Carry flag, that is B5 B6 as specified in the diagram. The first 32 hexadecimal values output are:
02 04 08 10 20 41 83 06 0C 18 30 61 C2 85 0A 14