Файл: The quintessential PIC microcontroller (S. Katzen, 2000).pdf
ВУЗ: Не указан
Категория: Не указан
Дисциплина: Не указана
Добавлен: 15.06.2025
Просмотров: 5283
Скачиваний: 0
446 The Quintessential PIC Microcontroller
Although the table has here been placed at an even 256-byte boundary for convenience, in practice it can be located anywhere in memory. In the general case the table o set nn will need to be added to the 14-bit address TABLE. SAQ 15.2 discusses how this address arithmetic could be done.
Examples
Example 15.1
The CCS compiler has the following built-in functions dealing with the EEPROM Data module:
read_eeprom(address)
Reads a byte from the specified EEPROM address.
write_eeprom(address, value)
Write the value to the specified address and returns only when the Write cycle has finished.
Write a C function to duplicate the odometer update implemented at assembler level in Program 15.3.
Solution
Like its assembly-level counterpart of Program 15.3, the function of Program 15.7 is divided into three phases.
1.This phase creates an array of three bytes named odometer[] which will act as a temporary store for the odometer count located in EEPROM. As the EEPROM Data module handles data in discrete byte
Program 15.7 C-based coding for the odometer.
void odometer(void) |
||
{ |
||
unsigned int odometer[3]; |
/* Define the 3-byte count |
*/ |
odometer[0] = read_eeprom(0x10); /* Get the existing count |
*/ |
|
odometer[1] = read_eeprom(0x11); |
||
odometer[2] = read_eeprom(0x12); |
||
/* Increment array |
*/ |
|
if(++odometer[0] != 0) break; |
||
else if(++odometer[1] != 0) break; |
||
else odometer[2]++; |
||
/* Now return incremented count to the EEPROM |
*/ |
|
write_eeprom(0x10, odometer[0]); |
||
write_eeprom(0x11, odometer[1]); write_eeprom(0x12, odometer[2]);
}
15. To Have and to Hold 447
packages, it is best to model the object in C in the same manner. The array is given the current reading by extracting the data one byte at a time from EEPROM locations 10:11:12h using the read_eeprom() function.
2.Once the 3-byte data is in the Data store it is incremented using an if-else tree:
(a)Increment low byte and check for zero. IF not zero THEN the overall addition is complete ELSE pass on carry to next byte.
(b)Increment the middle byte and check for zero. IF not zero THEN the overall addition is complete ELSE pass on carry to next byte.
(c)Increment most significant byte.
3.Finally each byte is written back into the EEPROM Data module using the write_eeprom() function.
Comparing the hand-coded assembly of Program 15.3 against the code generated from Program 15.7 gives 52 instructions against 91.
Example 15.2
A feasibility study is being undertaken in using a PIC-based Sauna controller. This is to monitor temperature and control heating and cooling units. There is also to be an over-temperature emergency alarm and shut- o .
One possibility is to use an 8-pin PIC with integral A/D conversion, such as the PIC12C672, together with an external temperature transducer. Someone has suggested that an e cient approach to this problem would be to use the variation in the internal Watchdog timer’s period with temperature as a cost e ective, albeit crude, sensor.
Experimental data was collected using a sample of eight production devices from the same manufacturing lot, with a soak time of 30 minutes at each tested temperature and 500 uncalibrated periods averaged to produce the graph of Fig. 15.8.
The data presented in Fig. 15.8 is based on Microchip’s application note AN720 Measuring Temperature Using the Watch Dog Timer (WDT). The two loci give the maximum and minimum across the range of tested devices. The Watchdog period was measured in Timer 0 overflows counting an internal 4 MHz clock. The Watchdog timer used a 1:8 prescale ratio.
From this data it can be seen that there is a correlation between period and rising temperature. However, although the overall trend is predictable, di erent devices will have varying o sets and slopes. For example, within the eight devices tested here the scale factor (scalar) varies from 2.28–2.42 counts per degree Celsius. This will necessitate a calibration phase before the system is used. If the count at one temperature T0 and the scalar are known for any device, then for the specific case where a count COUNTn − COUNT0 is recorded:
∆T = (COUNTn − COUNT0) × Scalar
448 The Quintessential PIC Microcontroller
Fig. 15.8 Watchdog timer period versus temperature.
In order to calibrate these devices it has been decided to soak batches in a refrigerator at 0◦C and save the 2-byte count in the EEPROM data module of a PIC16F83. The soak test is to be repeated in an oven at 30◦C with the di erence between this second count and the original value to be stored in a single EEPROM byte. Once this has been done, the device can be reprogrammed with the final running program overwriting the original calibrate program. This running program can then calculate temperature using the actual Watchdog period COUNTn:
T = (COUNT0 − COUNTn) × (Di erence/30)
where COUNT0 is the 2-byte EEPROM datum showing the count at 0◦C and Di erence is the 1-byte EEPROM datum showing the change in count over 30◦C.
Show how you could code the calibrate program to implement this specification.
Solution
Five tasks can be identified which must be undertaken at the end of a Watchdog period.
•Average the current Timer 0 roll-over count with the existing low-temp- erature (i.e. 0◦C) count.
•Average the current Timer 0 roll-over count with the existing hightemperature (i.e. 30◦C) count.
•Store the low-temperature count in EEPROM.
•Calculate the di erence between lowand high-temperature count and store in EEPROM.
•Do nothing.
15. To Have and to Hold 449
Port lines can be used to signal which of the first four active actions are to be actioned. For example; if RA0 is high then add the current Timer 0 rollover count to the existing 2-byte low-temperature count. Unless this is the first reading, divide by two to give an average. The complete batch of devices could have their RA0 pin held high for a few minutes 30 minutes after the refrigerator stabilizes at 0◦C.
Bringing RA0 low and then RA2 high for a short time signals an EEPROM storage action. With all port lines low, no action is taken representing both time before temperature stabilization and after EEPROM programming.
The Timer 0 and Watchdog timers are initialized together with the count values on a once-only basis on Power-up reset. This will typically only occur when the devices are powered up when in the temperature bath. Subsequent resets will normally be due to Watchdog time-outs. The state of the Status register’s TO flag can be used to ascertain the source of reset – see page 363.
Program 15.8 shows the routine used to initialize the timers and variables entered if TO is 1 on reset; that is on Power-up. Once this is done, the system enters an endless loop goto $ (the assembler replaces the label $ by the instruction’s address) which simply keeps going to itself!
Also shown is the ISR servicing a Timer 0 interrupt. This increments the double-byte variable ROLL_OVER:ROLL_OVER+1 and this is the count value read by the system on a Watchdog reset giving a numerical value for period.
Eventually the Watchdog timer will time-out and reset the processor. This time TO will be 0 and the routine labelled READING in Program 15.9 will be entered. This checks the state of each of the four RA3:0 pins in turn, executing one of the four listed tasks. If no pin is high, the program simply clears ROLL_OVER:ROLL_OVER+1 and Timer 0, the Watchdog timer is restarted and an endless loop entered. This READING_EXIT routine is also entered at the end of the four tasks.
The first two tasks are shown in Program 15.9. Here the 2-byte Timer 0 roll-over count is either added to the existing value LO_TEMP:LO_TEMP+1 or HI_TEMP:HI_TEMP+1 as appropriate and the outcome shifted once right to divide by two to give the average. As the count total is modest, 2-byte arithmetic is su cient to avoid overflow. If this is repeated over a duration of several minutes an averaged value will result.
If this is the very first time a reading has been made then the divide by two operation is skipped and the flag variable FIRST_LO or FIRST_HI as appropriate is made non zero.
The core routine with respect to this chapter is given in Program 15.10. If RA2 is 1 the 2-byte low-temperature count LO_TEMP:LO_TEMP+1 is copied into the bottom two bytes of the EEPROM Data module using the EE_PUT subroutine of Program 15.2.
450 The Quintessential PIC Microcontroller
Program 15.8 The Sauna Power-up reset sequence and ISR.
__config _WDT_ON & _CP_OFF & _RC_OSC |
||||
cblock |
20h |
|||
_work:1, _status:1 |
||||
FIRST_HI:1, FIRST_LO:1 |
||||
ROLL_OVER:2, LO_TEMP:2, HI_TEMP:2 |
||||
DELTA_TEMP:1 |
||||
endc |
||||
org |
0 |
|||
START |
goto |
MAIN |
||
org |
4 |
|||
goto |
ISR |
|||
MAIN |
btfss |
STATUS,NOT_TO |
; |
IF Watchdog timeout |
goto |
READING |
; |
THEN must have a reading |
|
clrwdt |
||||
movlw |
b’11011010’ |
; |
Wdt enabled with a 1:8 prescale |
|
bsf |
STATUS,RP0 |
; |
Change to Bank1 |
|
movwf |
OPTION_REG |
; |
and TMR0 internal clock |
|
bcf |
STATUS,RP0 |
; |
and back to Bank0 |
|
clrf |
FIRST_HI |
|||
clrf |
FIRST_LO |
|||
bsf |
INTCON,T0IE |
; |
Enable Timer0 interrupt |
|
clrf |
TMR0 |
; |
Zero the Timer |
|
clrf |
ROLL_OVER+1 |
; |
Zero the 2-byte Timer roll-over |
|
clrf |
ROLL_OVER |
|||
bsf |
INTCON,GIE |
; |
Enable all interrupts |
|
goto |
$ |
; |
Endless loop |
|
; |
************************************************************** |
|
; |
* The ISR to increment the 2-byte COUNT IF TMR0 interrupt |
* |
;**************************************************************
;First save context in usual way
ISR |
movwf |
_work |
; Put |
away W |
swapf |
STATUS,w |
; and |
the Status register |
|
movwf |
_status |
;**************************************************************
;The core code
incf |
ROLL_OVER+1,f; |
Record one more roll-over |
||
btfsc |
STATUS,C |
; |
Skip if no carry |
|
incf |
ROLL_OVER,f |
; |
Increment upper |
byte |
bcf |
INTCON,T0IF |
; |
Clear interrupt |
flag |
; **************************************************************
swapf |
_status,w |
; Untwist |
the original Status reg |
||
movwf |
STATUS |
||||
swapf |
_work,f |
; Get |
the |
original W reg back |
|
swapf |
_work,w |
; |
leaving |
STATUS unchanged |
|
retfie |
; |
and |
return from interrupt |
||
15. To Have and to Hold 451
If RA3 is 1 the di erence between the 2-byte high and low temperatures is then calculated. With the data shown in Fig. 15.8 it can be seen that a 30◦C di erence will not exceed a byte’s worth of storage so only the
Program 15.9 Reading a new period count.
READING |
btfsc |
PORTA,0 |
; |
Check; new low temp desired? |
goto |
NEW_LO |
; |
IF yes THEN go to it! |
|
btfsc |
PORTA,1 |
; |
Check; new high temp desired? |
|
goto |
NEW_HI |
; |
IF yes THEN go to it! |
|
btfsc |
PORTA,2 |
; |
Check; update low temp desired? |
|
goto |
UPDATE_LO |
; |
IF yes THEN go to it! |
|
btfsc |
PORTA,3 |
; |
Check; update high temp desired? |
|
goto |
UPDATE_HI |
; |
IF yes THEN go to it! |
|
goto |
READING_EXIT ; |
ELSE nothing doing |
||
NEW_LO |
movf |
ROLL_OVER+1,w; |
ELSE get low byte TMR0 roll-over |
|
addwf |
LO_TEMP+1,f |
; |
and add it to low byte low temp |
|
btfsc |
STATUS,C |
; |
Check for Carry |
|
incf |
LO_TEMP,f |
; |
IF so THEN record it |
|
movf |
ROLL_OVER,w |
; |
Now get high byte of roll-over |
|
addwf |
LO_TEMP,f |
; |
and add it to high byte low temp |
|
movf |
FIRST_LO,f |
; |
Is this the 1st low reading? |
|
btfsc |
STATUS,Z |
|||
goto |
FIRST_TIME_LO; |
IF so THEN go to it! |
||
rrf |
LO_TEMP,f |
; |
ELSE divide sum by two |
|
rrf |
LO_TEMP+1,f |
|||
goto |
READING_EXIT ; |
and finished |
||
FIRST_TIME_LO |
; |
IF first reading simply transfer |
||
incf |
FIRST_LO,f |
; |
No longer the first reading |
|
goto |
READING_EXIT |
|||
NEW_HI |
movf |
ROLL_OVER+1,w; |
ELSE get low byte TMR0 roll-over |
|
addwf |
HI_TEMP+1,f |
; |
and add it to low byte high temp |
|
btfsc |
STATUS,C |
; |
Check for Carry |
|
incf |
HI_TEMP,f |
; |
IF so THEN record it |
|
movf |
ROLL_OVER,w |
; |
Now get high byte of roll-over |
|
addwf |
HI_TEMP,f |
; |
and add it to high byte high temp |
|
movf |
FIRST_HI,f |
; |
Is this the 1st high reading? |
|
btfsc |
STATUS,Z |
|||
goto |
FIRST_TIME_HI; |
IF so THEN go to it! |
||
rrf |
HI_TEMP,f |
; |
ELSE Divide sum by two |
|
rrf |
HI_TEMP+1,f |
|||
goto |
READING_EXIT ; |
and finished |
||
FIRST_TIME_HI |
; |
IF first reading simply transfer |
||
incf |
FIRST_HI,f |
; |
No longer the first reading |
|
READING_EXIT |
||||
clrf |
TMR0 |
; |
Zero the timer |
|
clrwdt |
; |
Reset the Watchdog timer |
||
clrf |
ROLL_OVER+1 |
; |
Zero the roll-over count |
|
clrf |
ROLL_OVER |
|||
goto |
$ |
; |
Wait for another Watchdog reset |
|
452 The Quintessential PIC Microcontroller
Program 15.10 Updating the Sauna EEPROM.
UPDATE_LO |
|||
movf |
LO_TEMP,w |
; Get high byte of low temperature |
|
bsf |
STATUS,RP0 |
; To Bank1 |
|
movwf |
EEDATA |
; In EEPROM Data register |
|
clrf |
EEADR |
; EEPROM address 00h |
|
call |
EE_PUT |
; Write datum in |
|
movf |
LO_TEMP+1,w |
; Get low byte of low temperature |
|
bsf |
STATUS,RP0 |
; To Bank1 |
|
movwf |
EEDATA |
; Is new datum |
|
incf |
EEADR,f |
; EEPROM address 01h |
|
call |
EE_PUT |
; Write Datum in |
|
goto |
READING_EXIT |
||
UPDATE_HI ; |
Work out HI_TEMP-LO_TEMP & store at 02 in EEPROM |
||
; Only need |
to subtract the lower bytes as diff fits in one byte |
||
movf |
HI_TEMP+1,w |
; Get low byte high temperature |
|
subwf |
LO_TEMP+1,w |
; Subtract low byte low temperature |
|
movwf |
DELTA_TEMP |
; giving the difference |
|
bsf |
STATUS,RP0 |
; To Bank1 |
|
movwf |
EEDATA |
; Delta temperature in 02h |
|
movlw |
2 |
||
movwf |
EEADR |
||
call |
EE_PUT |
||
goto |
READING_EXIT |
||
lower byte of the subtraction is implemented. This single byte di erence is then written into EEPROM in the normal way.
Self-assessment questions
15.1Good program practice dictates that the datum written into Data EEPROM should be verified as the value that was intended to be written. Show how you could modify the EE_PUT subroutine of Program 15.2 to return a value −1 in a file register if the action is not successful, otherwise zero.
15.2In Program 15.6 we placed the look-up table at a 256-byte boundary in the Program store (specifically 300h) to simplify the computation of the 1-byte table index. Thus to look up table entry nn we simply place the address 3nnh in the EEADRH:EEADR register pair.
Placing program segments at user-defined addresses is never a good idea, as subsequential program alterations can cause code to overlap unless care is taken. Letting the assembler sort out loca-