Файл: C Programming for microcontrollers (Joe Pardue, 2005).pdf
ВУЗ: Не указан
Категория: Не указан
Дисциплина: Не указана
Добавлен: 13.06.2025
Просмотров: 2458
Скачиваний: 2
Chapter 4: C Types, Operators, and Expressions
Which will scroll by so fast you won’t see it, so you’ll assume the compile was good. Notice how clear (NOT) this warning was? Most complier warnings are even more cryptic. Not all compilers will flag this error with a warning. It is a very easy mistake to make, and you will feel really dumb after an hour of debugging, looking for something obscure, only to find a lousy missing ‘=’ character. I do this all the time.
Note: Some of these operators may seem strange at this point, but they are explained fully in later sections. Then they’ll seem really strange.
Table 1: Arithmetic Operators
Operator |
Name |
Example |
Defined |
* |
Multiplication |
x*y |
Multiply x times y |
/ |
Division |
x/y |
Divide x by y |
% |
Modulo |
x%y |
Provide the remainder of x divided by y |
+ |
Addition |
x+y |
Add x and y |
- |
Subtraction |
x-y |
Subtract y from x |
++ |
Increment |
x++ |
Increment x after using it |
-- |
Decrement |
--x |
Decrement x before using it |
- |
Negation |
-x |
Multiply x by –1 |
+ |
Unary Plus |
+x |
Show x is positive (not really needed) |
Table 2: Data Access and Size Operators
Operator |
Name |
Example |
Defined |
[] |
Array element |
x[6] |
Seventh element of array x |
. |
Member selection |
PORTD.2 |
Bit 2 of Port D |
-> |
Member selection |
pStruct->x |
Member x of the structure pointed to |
by pStruct |
|||
* |
Indirection |
*p |
Contents of memory located at |
address p |
|||
& |
Address of |
&x |
Address of the variable x |
51
Chapter 4: C Types, Operators, and Expressions
Table 3: Miscellaneous Operators
Operator |
Name |
Example |
Defined |
() |
Function |
wait(10) |
call wait with an argument of 10 |
(type) |
Type cast |
(double)x |
x converted to a double |
?: |
Conditional |
x?y:z |
If x is not 0 evaluate y, otherwise evaluate |
z |
|||
, |
Sequential |
x++,y++ |
Increment x first, then increment y |
evaluation |
Relational and Logical Operators
Table 4: Logical and Relational Operators
Operator |
Name |
Example |
Defined |
> |
Greater than |
x>y |
1 if x is greater than y, otherwise 0 |
>= |
Greater than |
x>=y |
1 if x is greater than or equal to y, |
or equal to |
otherwise 0 |
||
< |
Less than |
x<y |
1 if x is less than y, otherwise 0 |
<= |
Less than or |
x<=y |
1 if x is less than or equal to y, otherwise |
equal to |
0 |
||
== |
Equal to |
x==y |
1 if x equals y, otherwise 0 |
!= |
Not equal to |
x!=y |
1 if x is not equal to y, otherwise 0 |
! |
Logical NOT |
!x |
1 if x is 0, otherwise 0 |
&& |
Logical AND |
x&&y |
0 if either x or y is 0, otherwise 1 |
|| |
Logical OR |
x||y |
0 if both x and y are 0, otherwise 1 |
52
Chapter 4: C Types, Operators, and Expressions
Bitwise Operators
Table 5: Bitwise Operators
Operator |
Name |
Example |
Defined |
~ |
Bitwise complement |
~x |
Changes 1 bits to 0 and 0 bits to 1 |
NOT |
|||
& |
Bitwise AND |
x&y |
Bitwise AND of x and y |
| |
Bitwise OR |
x|y |
Bitwise OR of x and y |
^ |
Bitwise exclusive OR |
x^y |
Bitwise XOR of x and y |
<< |
Left shift |
x<<2 |
Bits in x shifted left 2 bit |
positions |
|||
>> |
Right shift |
x>>3 |
Bits in x shifted right 3 bit |
positions |
Bitwise operators are critically important in microcontroller software. They allow us to do many things in C that can be directly and efficiently translated into microcontroller machine operations. Keep in mind that these operators work on bits but are similar enough to the logical operators that you will get confused. Let’s look at the truth tables for &, |, and ^:
AND |
OR |
XOR |
0 & 0 = 0 |
0 | 0 = 0 |
0 ^ 0 = 0 |
0 & 1 = 0 |
0 | 1 = 1 |
0 ^ 1 = 1 |
1 & 0 = 0 |
1 | 0 = 1 |
1 ^ 0 = 1 |
1 & 1 = 1 |
1 | 1 = 1 |
1 ^ 1 = 0 |
Let’s create a variable, myByte and do some bitwise operations on it:
unsigned char myByte = 0;
We can set bit 3 (numbering from the right starting with 0):
myByte = myByte | 0x08;
To see what’s happening Let’s look at these in binary:
myByte = 00000000 = 0x00
53
Chapter 4: C Types, Operators, and Expressions
0x08 = 00001000 = 0x08
------------------------
OR = 00001000 = 0x08
Suppose myByte = 0xFF:
myByte = 11111111 = 0xFF 0x08 = 00001000 = 0x00
------------------------
OR = 11111111 = 0xFF
Or maybe myByte = 0x55:
myByte = 01010101 = 0x55 0x08 = 00001000 = 0x08
-----------------
OR = 01011101 = 0x5D
This all shows that only the 3rd bit of myByte is affected by the OR operation, since it is the only bit equal to 1 in 0x08.
Now let’s do the same thing with the & operator:
unsigned char myByte = 0;
We can set bit 3 with:
myByte = myByte & 0x08;
To see what’s happening Let’s look at these in binary:
myByte = 00000000 = 0x00 0x08 = 00001000 = 0x08
------------------------
AND = 00000000
Suppose myByte = 0xFF:
myByte = 11111111 = 0xFF 0x08 = 00001000 = 0x08
------------------------
54
Chapter 4: C Types, Operators, and Expressions
AND = 00001000
Or maybe myByte = 0x55:
myByte = 01010101 = 0x55 0x08 = 00001000 = 0x08
------------------------
AND = 00000000 = 0x00
And maybe myByte = 0xAA:
myByte = 10101011 = 0xAA 0x08 = 00001000 = 0x08
------------------------
AND = 00001000 = 0x08
In each of the above cases we are only dealing with a single bit, but we might be interested in any or all of the bits. One of the most important features of using masks with bitwise operators is that it allows us to set or clear a specific bit or set of bits in a byte without knowing or affecting the bits we aren’t interested in. For example, suppose we are only interested in bits 0, 2, and 6. Let’s set bit 6, regardless of its present value, then clear bits 0 and 2, also regardless of their present value and, here’s the trick, leave bits 1, 2, 4, 5, and 7 as they were when we began. Let’s have myByte starting equal to the secret to life the universe and everything, which according to Douglas Adams is 42, but remember that the start value doesn’t matter to us since we are going to force 3 bits to values regardless of the start value.
NOTE:
myByte = myByte | 0x08; is the same as
myByte |= 0x08; which we will use from no on.
At the beginning myByte is equal to 42 = 0x2B = 00101011. We set bit 6 with:
myByte |= 0x40;
which does the following:
55
Chapter 4: C Types, Operators, and Expressions
myByte = 00101011 = 0x2B 0x40 = 01000000 = 0x40
------------------------
AND = 01101011 = 0x6B
Next we want to clear bits 0 and 2:
myByte &= 0xFA;
which does the following:
myByte = 01101011 = 0x6B 0x40 = 11111010 = 0xFA
------------------------
AND = 01101010 = 0x6A
So in summary we set bits with ‘|’ and clear bits with ‘&’.
The Butterfly Software has a clever snippet in LCD_driver.c where the ‘&’ and ‘~’ operators are used to convert a lowercase letter to a capital:
// c is a letter |
// Convert to upper case |
if (c >= 'a') |
|
c &= ~0x20; |
// if necessary |
This statement first checks to see if the character c is greater than or equal to ‘a’ and uses the convenient fact that in ASCII the letters are sequential with the capitals beginning at 0x41 and the lowercase beginning at 0x61. So if the character is >= 0x61 then it is lowercase and we can derive the uppercase version by subtracting 0x20. So why do we use ‘c &= ~0x20’ instead of subtracting as in ‘c -= 0x20’? Well, it is more efficient for the machine to take the inverse of the minuend and then AND it with the subtrahend (this by the way, is the first time since grammar school that I’ve actually used minuend and subtrahend, I’m amazed that these terms actually stuck. Maybe it was the teachers steely glare and the dangerous looking pointer she held.) Let’s look at it shall we?
0x20 = 00100000 ~0x20 = 11011111
56