Файл: The quintessential PIC microcontroller (S. Katzen, 2000).pdf
ВУЗ: Не указан
Категория: Не указан
Дисциплина: Не указана
Добавлен: 15.06.2025
Просмотров: 5286
Скачиваний: 0
11. One Byte at a Time 291
slope of the load line ∆∆VI is the resistance in kΩ (as current is in mA) and measures 280Ω.
Extending the load line onwards gives the maximum current as the X co-ordinate of the intersection with the Maximum locus, which is approximately 11.5 mA; not much di erent. If the current requirement had been larger, then the minimum/maximum currents diverge showing a significant temperature sensitivity. For example, a 20 mA minimum base current requires a base resistor of ≈ 120Ω (assuming a base voltage of 0.8 V) and the maximum base current would be 28 mA.
Example 11.2
An 18-pin mid-range PIC is to be used as a digital comparator where a parallel-input 8-bit word P is to be compared to a byte datum located in a file register named TRIP. Outputs are to indicate Lower-Than, Equivalent and Higher-Than. The comparator is to have an hysteresis of ±1 bit. That is, if previous comparisons showed N < TRIP then the trigger level is increased to TRIP +1 for equality. Similarly, on a downward trajectory the equality level is to be decreased to TRIP − 1.
Datum P is to be input via Port B set up as input and the lower three Port A pins give the active-high comparator outputs <, ==, > at RA2, RA1, RA0 respectively.
Solution
The task list for such a specification is:
1.Subtract P from LEVEL.
2.IF Equal (EQ when Z=1) THEN == output active.
3.ELSE IF P Higher than LEVEL (HI when C=0, Borrow) THEN > output active AND LEVEL = TRIP − 1.
4.ELSE IF P Lower than LEVEL (LO when C=1, No Borrow) THEN < output active AND LEVEL = TRIP + 1.
The subroutine given in Program 11.4 assumes that the main program has set up the port directions accordingly and the fixed value is in TRIP. Initially LEVEL would have been set to the same value as TRIP but would subsequently vary by ±1 as per the specification – the hysteresis band.
Software solutions to traditional hardware functions, such as comparison, have the advantage of greater flexibility, albeit at the price of a lower data throughput. Using low-cost ‘computing engines’, such as the PIC, means that relatively simple functions traditionally implemented by dedicated hardware can be replaced by embedded processors.
In this instance, flexibility could be replacing the fixed trip level by a variable datum input via, say, Port C – requiring a larger footprint device; eg. PIC16C74 (see SAQ 11.7). Example 12.1 on page 349 shows how an external datum can be serially acquired externally. Alternatively, an analog signal could represent one or both of the levels in devices with integral A/D converters – see Example 14.7 on page 428. In all these situations
11. One Byte at a Time 293
Program 11.5 Driving a stepper motor.
#define |
FREQ |
d’40’ ; |
Programmer gives value in 100k steps |
org |
050h |
; |
Code begins at 050h |
; *************************************************************
; * |
FUNCTION: |
Advances stepper motor 1 -- 256 steps |
* |
||
; * |
ENTRY |
: |
Step number in STEP |
* |
|
; * |
ENTRY |
: |
Current field position in POSITION |
* |
|
; |
* |
EXIT |
: |
POSITION updated, STEP = -1, W destroyed |
* |
; |
* |
RESOURCE: |
Subroutine PATTERN, DELAY_10MS |
* |
|
; *************************************************************
MOTOR incf |
POSITION,w |
; Advance field direction |
andlw |
b’0111’ |
; Module-8 |
movwf |
POSITION |
; updated |
call |
PATTERN |
; Get the energization pattern |
movwf |
PORTA |
; Send to stepper motor |
call |
DELAY_10MS |
; Hold off 10ms |
decfsz |
STEP,f |
; Decrement step count |
goto |
MOTOR |
; until zero |
return |
; *************************************************************
; * |
FUNCTION: |
Maps an integer 0 -- 7 to field pattern |
* |
||
; |
* |
ENTRY |
: |
Modulo-8 integer in W |
* |
; |
* |
EXIT |
: |
Stepper energization pattern in W |
* |
; *************************************************************
PATTERN addwf |
PCL,f |
; Increment Program Counter |
retlw |
b’1000’ |
; North |
retlw |
b’1100’ |
; North east |
retlw |
b’0100’ |
; East |
retlw |
b’0110’ |
; South east |
retlw |
b’0010’ |
; South |
retlw |
b’0011’ |
; South west |
retlw |
b’0001’ |
; West |
retlw |
b’1001’ |
; North west |
; *************************************************************
; * FUNCTION: |
Delays 10 ms |
delay independent of clock freq |
* |
||||||
; |
* |
ENTRY |
: |
FREQ |
is xtal |
frequency in |
multiples |
of 100kHz |
* |
; |
* |
EXIT |
: |
10ms |
delay; DELAY zero, W |
destroyed |
* |
||
; *************************************************************
DELAY_10MS |
|||
movlw |
FREQ |
; The programmer’s statement |
|
movwf |
TEMP |
; Gives the PIC frequency |
|
; Delay loop 10ms at f = 100kHz xtal (1 cycle = 40us) |
|||
DLOOP1 movlw |
d’62’ |
; Loop count |
|
movwf |
DELAY |
||
DLOOP2 decf |
DELAY,f |
; 62 |
* 40us |
btfss |
STATUS,Z |
; 62 |
* 40us |
goto |
DLOOP2 |
; 62 |
* 80us |
decfsz |
TEMP,f |
; Decrement frequency parameter |
|
goto |
DLOOP1 |
; and repeat until zero |
|
return |
|||
11. One Byte at a Time 295
header as a number FREQ in steps of multiples of 100 kHz. Thus for a 8 MHz crystal, giving a 2 MHz machine cycle, FREQ should be defined as 80 using the #define directive, before the program is assembled.
The core of the subroutine is a loop needing a nominal 10 ms execution time at a crystal frequency of 100 kHz – 40 µs machine cycle. This loop is transversed FREQ times. Thus our 8 MHz example will have a loop execution of 1080 ms but will be executed 80 times to give our required 10 ms delay.
Example 11.4
Redo the keypad driver of Program 11.1 but coded in C.
Solution
Software structures of this nature, that is interacting with peripheral devices, are classified as device drivers. Device drivers or handlers have to be able to get at individual register bits in an e cient and sometimes real-time manner. Thus, even in a software system coded in a high-level language, the device drivers are traditionally written at assembly level. However, it is possible to code most device drivers in C, especially where response time is not critical.
The essence of the use of C in interacting with the various peripheral interface devices lies in its ability to operate at the colloquially called bit twiddling (or bit banging) level. To do this the programmer must be able to access fixed addresses in the Data store and to monitor or change individual bits within a datum. We have already seen on page 242 how to directly access a known memory location. For example, the definition:
Contents of
Pointer to byte datum
In File 06
#define PORT_B *(unsigned int *)0x06
defines the name PORT_B as synonymous with the contents of File 6, that is Port B.
Any bit or bits in, say, Port B can be monitored by using the & AND operation ; for example,
if((PORT_B & 0x80) == 0) {do this;} /* Check bit7 for 0 */ if((PORT_B & 0x02) != 0) {do that;} /* Check bit1 for 1 */
executes the statement {do this;} if bit 7 is zero and {do that;} if bit 1 of Port B is a one.
Most microcontrollers have native instructions to bit twiddle single bits directly in memory in a single execution cycle. Where only one bit
296 The Quintessential PIC Microcontroller
is involved this is more e cient than the use of AND and OR operations, and because of this C compilers designed to be used for such hardware targets usually have (non standard) operators designed to make use of this feature.
On page 244 the CCS compiler #bit declaration was used to define individual bits that could subsequently be tested by code. Using this technique our example becomes:
#bit |
B7 |
= |
06.7 |
/* |
PortB, bit |
7 |
*/ |
||||
#bit |
B1 |
= |
06.1 |
/* |
PortB, bit |
1 |
*/ |
||||
...................... |
|||||||||||
if(!B7) |
{do this;} /* |
Do |
this |
if |
Bit7 is false |
(i.e. |
0) |
*/ |
|||
if(B1) |
{do that;} /* |
Do |
that |
is |
Bit1 is true |
(i.e. |
1) |
*/ |
|||
The CCS compiler comes with a header file for each processor which includes a bit description of all that device’s Special-Purpose Register set and I/O pins. Our examples assume that we have included the file
16f84.h. Thus:
if(!input(PIN_B7)) {do this;} /* Do this if bit RB7 == 0 */ if(input(PIN_B1)) {do that;} /* Do that if bit RB1 == 1 */
There is also a complementary output function; for instance:
output_pin(PIN_B1,0); |
/* Make |
RB1 low |
*/ |
||
output_pin(PIN_B2,1); |
/* |
Make |
RB2 |
high |
*/ |
output_pin(PIN_B3,1); |
/* |
Make |
RB3 |
high |
*/ |
The CCS compiler adopts the policy that the inner workings of the various peripheral devices should be as invisible to the programmer as possible. To this end the compiler comes with a rich set of internal functions to set up and use the interface features appropriate to the target device specified by the header file.
As an example of this philosophy, set_tris_b(0xF0); is an alternative to the approach adopted on page 274. Similarly the internal function port_b_pullups(TRUE); is an alternative to setting the RBPU bit in the Option register.
The CCS compiler handles parallel I/O in several di erent ways. The #use fast_io(b) statement below leaves it up to the programmer to explicitly set up the appropriate TRIS registers. Other alternatives allow the programmer to ignore such minutia, but then the compiler will set up the port configuration each time it is used, even if that configuration remains unchanged from the last usage.
Program 11.6 assumes the following code as part of the main routine: