Файл: The quintessential PIC microcontroller (S. Katzen, 2000).pdf
ВУЗ: Не указан
Категория: Не указан
Дисциплина: Не указана
Добавлен: 15.06.2025
Просмотров: 5272
Скачиваний: 0
16. A Case Study 461
Program 16.1 (continued.) The timebase software.
; *************************************************************
; * FUNCTION: |
Increments the Pause |
flag. |
* |
||
; * FUNCTION: |
IF = 1 |
THEN displays |
the decimal points |
* |
|
; * FUNCTION: |
IF = 0 |
THEN displays |
the normal count |
* |
|
; * RESOURCE: |
Subroutine SPI_WRITE. Var Pause |
* |
|||
; * ENTRY |
: |
PAUSE switch closed |
* |
||
; * EXIT |
: |
Pause switch open; appropriate display |
* |
||
; *************************************************************
FREEZE incf |
Pause,f |
; Update Pause flag, bit 0 |
btfss |
Pause,0 |
; Check status of Pause flag |
goto |
UNFREEZE |
; Change 1 -> 0, unfreeze |
; Display freeze |
||
movlw |
b’01111111’ ; Code for display decimal point |
|
movwf |
DATA_OUT_L |
|
movwf |
DATA_OUT_H |
|
call |
SPI_WRITE |
|
goto |
FREEZE_EXIT |
|
UNFREEZE ; Land |
here if Pause 0 -> 1. |
|
movf |
MINUTE,w |
; Display the normal Minute count |
call |
OUTPUT |
|
FREEZE_EXIT
btfss PORTB,PAUSE ; Wait til switch is opened again goto FREEZE_EXIT
return
From Program 16.1 we see that time is kept as a 3-byte count chain using file registers MINUTE, SECOND and JIFFY to hold the total. Assuming that the state of bit 0 of file register Pause is 0, then one is added to the Ji y count. Normally the ISR then exits but when Ji y reaches 50 it is reset to zero and the Seconds count decremented. The file register NEW_SEC is also made non zero to indicate to background software that a second has elapsed. In the situation where the Second count reaches zero then it is reset to 59 and the Minute count decremented. The procedure is similar to the incrementing count of Example 7.4.
The Timebase task also handles the Pause function. The simplest approach would be to skip over the time decrement code if the PAUSE switch is closed. However, the necessity to keep the switch closed could be irksome if the period was more than a few minutes.
Implementing a push-on push-o scenario is ergonomically superior and can be more economically implemented in software rather than using a di erent type of switch compared to the others. In Program 16.1 the Pause handling code is located in the separate subroutine FREEZE. It is permissible to call a subroutine from an ISR in the same manner as calling one subroutine from another; that is nesting. The 8-deep hardware stack
462 The Quintessential PIC Microcontroller
allows nesting up to eight deep. In our situation only two of the stack locations are used, allowing up to six calls deeper into the stack.
Subroutine FREEZE is only entered if the PAUSE switch is closed. On each entry the value of bit 0 of the file register Pause is toggled. This is implemented by simply incrementing file register Pause.
Once Pause[0] is toggled, its state is tested and if 1 the pattern to only illuminate the two decimal points is sent to the SPI_WRITE subroutine. This is an arbitrary indicator display, another possibility would be . If Pause[0] is 0 then the state of the Minute count is sent to the OUTPUT subroutine and indicates to the user that the Pause function has ended.
Finally, the subroutine does not exit until the user releases the PAUSE switch. This is important, as on exit the ISR will be re-entered again at the next Timer 0 overflow, and this would cause Pause to be repeatedly retoggled. Some measure of switch debounce is obtained by zeroing Timer 0 and the Prescaler when the switch is released. This means that the switch will not be retested for a whole 501 second. It is for this reason that T0IF is cleared on exit from the ISR rather than at the more conventional entry point.
The task displaying the contents of the Working register in decimal is handled by the subroutine OUTPUT in Program 16.2. The task list for this function is:
1.Convert the binary datum to 2-digit BCD.
2.Convert both digits to 7-segment.
3.Serially shift out both bytes to the appropriate display.
Program 16.2 The data display function. (continued next page).
; *************************************************************
; * |
FUNCTION: |
Displays |
datum as a 2-digit decimal output |
* |
||||
; * |
RESOURCE: |
Subroutines |
BIN_2_BCD, SPI_WRITE, SVN_SEG |
* |
||||
; * |
RESOURCE: |
Vars |
DATA_OUT_L, DATA_OUT_H, NEW_SEC, NUMBER |
* |
||||
; |
* |
ENTRY |
: |
Datum in |
W, |
<100d |
* |
|
; |
* |
EXIT |
: |
Data |
displayed, NEW_SEC zeroed |
* |
||
; *************************************************************
OUTPUT bcf |
PORTA,SCK |
; Initialize the clock line |
|
call |
BIN_2_BCD |
; Convert to BCD |
|
movwf |
NUMBER |
; Put BCD MINUTE version in NUMBER |
|
movf |
NUMBER,w |
; Get number count for display |
|
andlw |
b’00001111’ |
; Get Units nybble |
|
call |
SVN_SEG |
; Convert to 7-segment code |
|
movwf |
DATA_OUT_L |
; Copy into the serial low register |
|
swapf |
NUMBER,w |
; Put ten’s digit into lower nybble |
|
andlw |
b’00001111’ |
; Isolate ten’s digit |
|
call |
SVN_SEG |
; Convert to 7-segment code |
|
movwf |
DATA_OUT_H |
; Copy into the serial high register |
|
call |
SPI_WRITE |
; Shift both digits out |
|
clrf |
NEW_SEC |
; Reset NEW_SEC flag |
|
16. A Case Study 463
Program 16.2 (continued.) The data display function.
; *******************************************************
; * |
FUNCTION: |
Clocks out a two |
byte |
in parallel/series |
* |
||||
; * |
ENTRY |
: |
Data in DATA_OUT_L and DATA_OUT_H |
* |
|||||
; |
* |
ENTRY |
: |
The former |
to be |
LSD, |
the |
latter MSD |
* |
; |
* |
EXIT |
: |
DATA_OUT_L |
and DATA_OUT_H |
altered |
* |
||
; *******************************************************
SPI_WRITE |
|||
bcf |
PORTA,SCK |
; Make sure clock starts at low |
|
movlw |
8 |
; Initialize loop counter to 8 |
|
movwf |
COUNT |
||
LOOP |
bcf |
PORTA,SDOH |
; Zero data bit for MSD |
rlf |
DATA_OUT_H,f |
; Shift datum left into Carry |
|
btfsc |
STATUS,C |
; Skip if Carry is 0 |
|
bsf |
PORTA,SDOH |
; ELSE make data bit 1 |
|
bcf |
PORTA,SDOL |
; Zero data bit for LSD |
|
rlf |
DATA_OUT_L,f |
; Shift datum left into Carry |
|
btfsc |
STATUS,C |
; Skip if Carry is 0 |
|
bsf |
PORTA,SDOL |
; ELSE make data bit 1 |
|
bsf |
PORTA,SCK |
; Pulse clock |
|
bcf |
PORTA,SCK |
||
decfsz |
COUNT,f |
; Decrement count |
|
goto |
LOOP |
; and repeat until zero |
|
return SVN_SEG addwf PCL,f
retlw b’11000000’ retlw b’11111001’ retlw b’10100100’ retlw b’10110000’ retlw b’10011001’ retlw b’10010010’ retlw b’10000010’ retlw b’11111000’ retlw b’10000000’ retlw b’10010000’
; *************************************************************
; * |
FUNCTION: |
Converts a |
binary byte |
to |
a |
packed |
BCD byte |
* |
|||
; * |
RESOURCE: |
TEMP byte |
* |
||||||||
; |
* |
ENTRY |
: |
Binary |
byte in W range |
00 |
- |
63h (0 |
- 99d) |
* |
|
; |
* |
EXIT |
: |
Packed |
BCD |
byte in W |
* |
||||
;*************************************************************
;Divide by ten
BIN_2_BCD clrf |
TEMP |
; Zero the loop count |
|
LOOP10 |
incf |
TEMP,f |
; Record one ten subtracted |
addlw |
-d’10’ |
; Subtract decimal ten |
|
btfsc |
STATUS,C |
; IF a borrow (C==0) THEN exit loop |
|
goto |
LOOP10 |
; ELSE do another subtract/count |
|
decf |
TEMP,f |
; Compensate for one inc too many |
|
addlw |
d’10’ |
; Add ten to residue to give units |
|
swapf |
TEMP,f |
; Put ten’s digit in upper nybble |
|
addwf |
TEMP,w |
; Add units nybble right justified |
|
return |
; and return to caller |
||
16. A Case Study 465
Program 16.3 The initialization code. |
||||
include |
"p16f84.inc" |
|||
SDOH |
equ 0 |
|||
SCK |
equ 1 |
|||
BUZ |
equ 2 |
|||
SDOL |
equ 3 |
|||
GREEN |
equ 5 |
|||
YELLOW |
equ 6 |
|||
RED |
equ 7 |
|||
PAUSE |
equ 0 |
|||
DIAG |
equ 1 |
|||
STOP |
equ 2 |
|||
SETT |
equ 3 |
|||
GO |
equ 4 |
|||
cblock |
20h |
JIFFY:1, NUMBER:1, NEW_SEC:1 |
||
MINUTE:1, SECOND:1, |
||||
DATA_OUT_L:1, DATA_OUT_H, COUNT:1, TEMP:1, TIME_OUT:1 |
||||
Pause:1, _work:1, _status:1 |
||||
endc |
||||
__config _XT_OSC & _WDT_OFF & _PWRTE_ON & _CP_OFF |
||||
org |
2100h |
; |
The EEPROM Data module |
|
de |
d’10’ |
; |
Default value is 10 minutes |
|
RESET |
org |
0 |
; |
Reset vector |
goto |
MAIN |
|||
org |
4 |
; |
Interrupt vector |
|
goto |
ISR |
|||
MAIN |
bsf |
STATUS,RP0 |
; |
Change to Bank 1 |
movlw |
b’11100000’ ; |
RA4:0 outputs |
||
movwf |
TRISA |
RB7:5 outputs; RB4:0 inputs |
||
movlw |
b’00011111’ ; |
|||
movwf |
TRISB |
Clock TMR0 internally; assigned PS |
||
movlw |
b’00000101’ ; |
|||
movwf |
OPTION_REG |
; |
Set to 1:64. Enable PORTB pull-ups |
|
bcf |
STATUS,RP0 |
; |
Back to Bank 0 |
|
clrf |
Pause |
; |
The PAUSE switch toggle |
|
clrf |
NEW_SEC |
; |
Reset NEW_SEC second flag |
|
clrf |
TMR0 |
|||
bcf |
INTCON,T0IF |
|||
bsf |
INTCON,T0IE ; |
Enable Timer0 interrupts |
||
bsf |
INTCON,GIE |
; |
Enable all interrupts |
|
btfss |
PORTB,SETT |
; |
Check the Set switch |
|
call |
SET_TIME |
; |
IF closed THEN set total time |
|
btfss |
PORTB,DIAG |
; |
Check the Diagnostic switch |
|
call |
DIAGNOSTIC |
; |
IF closed THEN set total time |
|
If the DIAG switch is closed when the PIC comes out of reset then the code transfers to the subroutine DIAGNOSTIC.
The Diagnostic process aims to exercise the various peripheral devices interfaced to the process in order to verify in a reproducible manner the status of the interconnection and the devices themselves.
466 The Quintessential PIC Microcontroller
Switches
Five switches are input via Port B. By checking each switch in turn and if closed lighting one of the LEDs or sounding the buzzer both switches and the listed output devices are tested. The DIAG switch is of course verified by moving the system into this process and the Reset switch is tested by initiating the startup process.
If there were more switches than output devices then either combinations of the latter could be activated or else one or more segments in the numerical display pushed into service.
Program 16.4 The Diagnostic process.
;*************************************************************
;* FUNCTION: Checks each switch and activates a corresponding*
; * FUNCTION: |
LED or buzzer. Continually activates a unary |
* |
|
; * FUNCTION: |
pattern to both 7-segment displays |
* |
|
; * RESOURCE: |
Subroutines SPI_WRITE |
* |
|
; * RESOURCE: |
Vars TEMP, DATA_OUT_H, DATA_OUT_L |
* |
|
; * ENTRY |
: |
DIAG switch closed |
* |
; * EXIT |
: |
DIAG switch open |
* |
; *************************************************************
DIAGNOSTIC |
b’11111110’ |
; |
The initial 7-segment pattern |
|
movlw |
||||
movwf |
TEMP |
; |
in memory |
|
D_LOOP |
movlw |
b’11111111’ |
; |
Turn off all LEDs and buzzer |
movwf |
PORTB |
|||
bsf |
PORTA,BUZ |
|||
; Now scan switches |
||||
btfss |
PORTB,PAUSE |
; |
IF Pause switch closed |
|
bcf |
PORTB,GREEN |
; |
THEN Green LED |
|
btfss |
PORTB,STOP |
; |
IF Stop switch closed |
|
bcf |
PORTB,YELLOW |
; |
THEN Yellow LED |
|
btfss |
PORTB,SETT |
; |
IF Set switch closed |
|
bcf |
PORTB,RED |
; |
THEN Red LED |
|
btfss |
PORTB,GO |
; |
IF Go switch closed |
|
bcf |
PORTA,BUZ |
; |
THEN Buzzer |
|
; Now turn on each segment in turn of both displays |
||||
movf |
TEMP,w |
; |
Get pattern |
|
movwf |
DATA_OUT_L ; |
Put in output file regs |
||
movwf |
DATA_OUT_H |
|||
call |
SPI_WRITE |
; |
Display it |
|
btfsc |
PORTB,DIAG |
; |
IF Diagnostic switch open |
|
return |
; |
THEN exit the diag subroutine |
||
clrf |
NEW_SEC |
; |
Reset the New Second flag |
|
; Now move the display pattern |
on one and wait for a second |
|||
bcf |
STATUS,C |
; |
Clear Carry |
|
btfsc |
TEMP,7 |
; |
Check MSB of pattern |
|
bsf |
STATUS,C |
; |
IF 1 THEN Carry = 1 |
|
rlf |
TEMP,f |
; |
Shift it in << |
|
D_LOOP2 |
movf |
NEW_SEC,f |
; |
ELSE wait for the new second |
btfsc |
STATUS,Z |
; |
IF non zero THEN skip |
|
goto |
D_LOOP2 |
; |
ELSE try again |
|
goto |
D_LOOP |
; |
Repeat routine |
|