Файл: The quintessential PIC microcontroller (S. Katzen, 2000).pdf

ВУЗ: Не указан

Категория: Не указан

Дисциплина: Не указана

Добавлен: 15.06.2025

Просмотров: 5320

Скачиваний: 0

ВНИМАНИЕ! Если данный файл нарушает Ваши авторские права, то обязательно сообщите нам.

244 The Quintessential PIC Microcontroller

#define INTCON *(unsigned int *)0x0B #define INTF 0x02

......

if((INTCON & INTF) == 0)

{

INTCON = INTCON & ˜INTF;

}

by ANDing INTCON with the binary pattern 11111101b (that is the complement of INTF, i.e. ˜INTF) bit 1 will be cleared.

The assembly-level code emitted by the CCS compiler for this C code fragment is:

movf

0Bh,w

; Get INTCON register contents

andlw

b’00000010’

; Isolate the INTF bit

btfsc

STATUS,Z

; Skip IF zero

goto

NEXT

; ELSE omit the IF statement

movlw

b’11111101’

; On non zero clear the INTF flag bit

andwf

0Bh,f

; by ANDing

NEXT

This example involved testing and setting a single bit and the compiler used the PIC’s andwf instruction. However, the PIC and most other MCUs have specific bit twiddling instruction which are more e ective than general logic instructions, such as AND, at testing and altering a single bit. C compilers usually have non-standardized extensions to specify single bits and force the compilers to use these more e cient instructions. In the case of the CCS compiler the code fragment above can be written:

#bit INTF = 0x0B.1

......

if(INTF)

{

INTF = 1;

}

which defines the bit INTF as being bit 1 of File 0Bh. The assembly-level code emitted in this case is:

btfsc

0Bh,1

;

Skip

if bit 1 in File 0Bh is zero

bcf

0Bh,1

;

ELSE

clear INTF

a somewhat more satisfactory outcome.


9. High-Level Language 245

Examples

Example 9.1

Write a C function to return the square root of a positive 16-bit integer. The algorithm of Fig. 6.9 on page 162 is to be used to implement the conversion.

Solution

Modifying the task list of Example 6.5 to suit the structure of the C while loop gives:

1.Zero the loop count

2.Set variable i (the magic number) to 1

3.WHILE i is less than or equal to the number

(a)Take i from Number

(b)Add 2 to i

(c)Increment the loop√ count

4. Return loop count as Number

The function heading gives it its name sqr_root and defines the parameters to be passed to the function and the outcome. The form unsigned int sqr_root(unsigned long number) declares that it will return an unsigned int value and one unsigned long int object will be passed to it, which will be known as number within the function. On this basis the coding of Program 9.2 directly implements the task list. As the square root of a 16-bit object will fit into an 8-bit byte, the loop count is declared unsigned int. The magic number i will however be twice (plus one) that of count and is therefore defined as a unsigned long object. At the same time as these internal function variables are defined they are given their initial values.

The while loop is repeated until the value of the reducing number drops below the increasing value of i, at which point any further subtraction will drop the outcome below zero. The value of the loop count is the square root and is returned to the caller at the end of the function.

Program 9.2 Coding the square root function.

unsigned int sqr_root(unsigned long number)

{

unsigned int count = 0; unsigned long i = 1; while(number>=i)

{

number = number - i; i = i + 2;

count++;

}

return count;

}

246 The Quintessential PIC Microcontroller

Example 9.2

Using the C compiler that is available to you compile Example 9.1 and compare the size of the resulting machine code with that of the assemblylevel implementation of Program 6.11 on page 163.

Solution

The CCS C compiler version 2.6 generated executable code with 35 instructions. That of the original assembly program occupied 21 Program store locations. The ratio here is 1.6:1 or e ciency ratio of 60%.

Example 9.3

A K-type thermocouple is characterized by the equation:

t = 7.550162 + 0.0738326 × v + 2.8121386 × 10−7v2

where t is the temperature di erence across the thermocouple in degrees Celsius and v is the generated emf spanning the range 0–52,398 µV, represented by a 14-bit unsigned binary number, for a temperature range of 0–1300◦C. Write a C function which will take as its input parameter a 14-bit output from an analog to digital converter and return the integer temperature in Celsius measured by the thermocouple.

Solution

Our function, named thermocouple() in line 1 of Program 9.3, takes one unsigned long integer (16-bit) parameter, named emf and returns a similar 16-bit value. The internal variable temperature is defined in line 3 to be a floating-point object6 to cope with the complex fractional mathematics of line 5.

Program 9.3 Linearizing a K-type thermocouple.

unsigned long thermocouple(unsigned long emf)

{

float temperature;

unsigned long outcome;

emf = emf & 0x3FFF;

/* Clear upper two bits */

temperature = 7.550162+0.073832605*emf+2.8121386e-7*emf*emf; outcome = (unsigned long)temperature;

return outcome;

}

6Having a mantissa and exponent of the form m × 10e.


9. High-Level Language 247

As we are told that only the 14 lower bits of emf have any meaning, line 4 ANDs the 16-bit object with 3FFFh (0x3FFF) to clear the upper two bits. The 0x prefix is C’s way of denoting hexadecimal.

Finally an unsigned long version of the float object temperature is made and returned in line 8.

The resulting executable code running on a mid-range PIC core takes 667 program words; or around 23 of the Program store of a PIC16F84 device. Because of the size penalty of using floating-point objects, fixedpoint arithmetic is used wherever possible in embedded microcontroller implementations.

Example 9.4

On page 213 we implemented a root mean square program to implement

the mathematical relationship NUM_12 + NUM_22. Write a C function to implement this relationship, where the two 8-bit objects num_1, num_2 are passed to the function which returns the 8-bit value rms.

Solution

The solution shown in Program 9.4 uses the internal unsigned long 16-bit variable sum to hold the addition of the two squared 8-bit variables. The squaring operation is simply implemented using the C multiplication operator * rather than coding a squaring function of the manner of Program 8.3 on page 215. The function developed in Program 9.2 is used to

Program 9.4 Generating the root-mean square value of two variables.

unsigned int variance(unsigned int num_1, unsigned int num_2)

{

unsigned long sum; unsigned int rms;

sum = (unsigned long)num_1*num_1 + (unsigned long)num_2*num_2; rms = sqr(sum);

return rms;

}

unsigned int sqr(unsigned long number)

{

unsigned int count = 0; unsigned long i = 1; while(number>=i)

{

number = number - i; i = i + 2;

count++;

}

return count;

}

248 The Quintessential PIC Microcontroller

generate the square root of the 16-bit sum object and is called from the function variance() line 6 with the return value being assigned to the variable sum as part of the call. In compiling the source code using the CCS C compiler, 100 machine-level instructions are needed to implement this problem. This compares to 62 instruction for the assembly-code version of Chapter 8. This gives an e ciency ratio of 62%.

Self-assessment questions

9.1The coding of Program 9.2 can be simplified if it is observed that the variable i is always twice count plus one, so count is not needed. Instead, on return the 16-bit value i can be logic shifted once right (see page 11) and the 8-bit cast version of the remainder is the equivalent of the absent count. In shifting right the datum is divided by two and by throwing away the one that pops out, e ectively subtracts by one (i is always odd and so its least significant bit is always 1). Try coding this alternative arrangement. The C operator to shift right by n places is >> n. If the datum is unsigned then the shift is a logic shift right. See Example 9.3 to see how to cast a datum to another type.

9.2A PIC-based digital thermometer is to display temperatures between 0◦C and 100◦C. To be able to market the device to USA the thermometer is to have the option to display the temperature in Fahrenheit. Write a function for a PIC-based thermometer that is to convert Celsius integers to the equivalent Fahrenheit integer. The input is to be an unsigned int byte representing Celsius and the return Fahrenheit is also to be an unsigned int datum. The relationship is:

fahrenheit = (celsius × 9)/5 + 32

and the arithmetic should be done in 16-bit precision to avoid overrange.

9.3 A cold-weather indicator in an automobile dashboard display comprises three LEDs, which are connected to the lower three bits of Port A. Bit 2 of this location is connected to the red LED, which is to light if the Fahrenheit temperature is less than 30. Bit 1 is the yellow LED for temperatures below 40◦F, and bit 0 is the green LED. Write a function, whose input is ◦F, that activates the appropriate LED.

Access to the LEDs through Port A at File 05h in C can be accomplished by placing the following line of code at the head of the program: You may assume that a logic 0 at the appropriate Port A pin


9. High-Level Language 249

lights the LED. You may also presume that the three appropriate Port A bits have been set to output mode.

#define LED *(unsigned int *)0x05

whereupon the variable LED can be altered like any other variable. You will also need to use the if-else conditional construction:

if(something is true) {do this;}

else if(whatever is true) {do that;}

else

{do the other;}

9.4 Arrays of objects can be defined in C using the notation fred[n] where fred is the name of the array and n is the nth element. For example an array of ten values making up the decimal 7-segment patterns described in Fig. 6.6 on page 148 can be defined and initialized as:

unsigned int 7_seg[10] = {0xc0, 0xf9, 0xa4, 0xb0, 0x99, 0x92, 0x82, 0xf8, 0x80, 0x90};

These ten values for 7_seg[0] through 7_seg[9] will be placed in ten sequential file registers. As most PICs have a severally limited number of GPRs and this example is a array of constants it makes more sense to place these ten constant bytes in Program ROM. Using the key word const in front of the array definition tells the compiler to initialize Program store locations instead.

unsigned int const 7_seg[10] = {0xc0, 0xf9, 0xa4, 0xb0, 0x99, 0x92, 0x82, 0xf8, 0x80, 0x90};

As data in the Program store is not directly accessible in the lowand mid-range PIC Harvard architecture the compiler will actually place a series of retlw <byte> instructions in ROM as described in Table 6.4 on page 149.

Based on the above array definition, code a C functionto return the 7-segment code equivalent of an unsigned int n passed to the function.

9.5 As part of a digital game a PIC is to drive an active-low 7-LED display to implement an electronic die. Our problem, outlined in Fig. 9.4, is to convert a ’throw’ number n between 1 and 6 to the 7-bit display.

250 The Quintessential PIC Microcontroller

Code a C function converting n, which is passed to the function, and returning the appropriate code pattern.

Throw pattern[n] a

b

n

gfedcba

f

g c

e

d

1

0111111

3Fh

Throw

Function

Die pattern

2

1110110

76h

3

0110110

36h

n

die()

pattern[n]

4

1100100

64h

5

0100100

24h

6

1000000

40h

Fig. 9.4 The active-low die patterns.

9.6Driving the die requires seven parallel port lines and the electronic game requires to drive two die displays. By inspection of the patterns of Fig. 9.4 how could you reduce the requirement to four bits only?

9.7As part of the same electronic game a function is to be written to return the next pseudo random number in the 127 sequence defined by the generator configuration of Fig. 3.12 on page 70. The current number is to be passed to the function and the next number in the sequence returned. It may be assumed that this passed datum is never zero.

How could you modify the function to send the sequence of all 127 pseudo random numbers out of Port B beginning with the passed number?

9.8To integrate the outcome to the pseudo random function with the die display we need to map the set of 127 numbers to the range one to six. Devise a modified function to implement the mapping. Hint: What simple mathematical operation would map any number to the range zero to five?