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


; Add N to PC giving PC + N
; Code for 0 ; Code for 1 ; Code for 2 ; Code for 3 ; Code for 4 ; Code for 5 ; Code for 6 ; Code for 7 ; Code for 8 ; Code for 9

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


464 The Quintessential PIC Microcontroller

Subroutine OUTPUT listed in Program 16.2 follows the task list calling up the following utility subroutines.

Binary to BCD conversion

Subroutine BIN_2_BCD repetitively subtracts ten from the binary datum in the manner described in Program 5.9 on page 131. Assuming that this datum is never greater than decimal 99 (63h) then this count gives the ten’s digit. The residue is the unit’s digit. The two nybbles are packed together and returned in W.

Binary to 7-segment decoder

Subroutine SVN_SEG converts a single datum nybble in W to its 7-segment coded equivalent as described in Program 6.4 on page 149.

SPI output

Subroutine SPI_WRITE is similar to that described in Program 12.1 on page 308 but transmits two serialized data streams simultaneously. The datum in DATA_OUT_L is sent via RA3 whilst that in DATA_OUT_H is sent out via RA0. A common clock is used.

Before considering the coding for the three processes, we will briefly look at the initialization code common to the entire software system. The function of this startup code is:

Default duration setting

To place a default value for the time-out in location 0 of the Data EEPROM. The address of this cell is in the special/test configuration area at 2100h and the de directive is used to specify the load time data as described on page 437.

The value of 10 as shown means that a freshly programmed PIC will default to a 10 minute count down. This value can subsequently be altered using the Set-time process described below.

Vectors

To initialize the Reset vector at 000h to point to MAIN and Interrupt vector at 004h to point to ISR.

Port setting

To make Port A[4:0] and Port B[7:5] outputs and all other lines inputs.

Timer 0 setting

To set up the Prescale ratio to 1:64 and Timer 0 clock source to internal. The Timer 0 interrupt is also enabled.

Process select

To check the state of the DIAG and SETT switches to choose either the Diagnostic or Set-time processes. If neither switch is closed the normal Main process is entered.

The Set switch is named SETT in the code, as set is a Microchipcompatible assembler directive.4

4set is the same as the equ directive except that the assigned value may be subsequently altered by other set directives.

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