Summary: Microcontrollers require more bit manipulation than most typical C programs. The intent of this module is to help programmers new to the MSP430 processor get the results they need from C language bit manipulation instructions. Much of this content applies to C programming for many microcontrollers as well as for computers; the examples are based on the Texas Instruments MSP430.
Hexadecimal numbers will be used in code examples for this tutorial. Each digit of hexadecimal represents four binary bits. If you aren’t familiar with conversions between hexadecimal and binary you should review Binary and Hexadecimal Notation. Our goal is to control individual bits, and they will be represented in code as hexadecimal numbers.
The bitwise operators are AND ‘&’, OR ‘|’, XOR (exclusive or) ‘^’, and NOT ‘~’. These operators should not be confused with logical AND ‘&&’, logical OR ‘||’, and logical NOT ‘!’ which are used to evaluate true verses false.
For example:
int a; int b; int c;
a = 0x0003 | 0x0004; //bitwise OR operation makes integer a equal to 0x0007
while ((a>b) && (b>c)) //logical AND is true if a>b>c
{ }
A truth table shows the operation that a bitwise operator performs on each bit position. Each operator produces results depending on the status of inputs A and B. The operations are performed on each bit position (such as bit 0 through bit 15 for integers) in the data, and the truth table defines the result for each possible combination of data bits.
A | B | AND A&B | OR A|B | XOR A^B |
0 | 0 | 0 | 0 | 0 |
0 | 1 | 0 | 1 | 1 |
1 | 0 | 0 | 1 | 1 |
1 | 1 | 1 | 1 | 0 |
Now lets look at a couple of examples with 16 bit integers
0x0003 & 0x0005 Bitwise AND
0x0003 is 0000000000000011 in binary
0x0005 is 0000000000000101 in binary
Result 0000000000000001 in binary or 0x0001 hex
0x00AA ^ 0x00FE Bitwise exclusive or
0x00AA is 0000000010101010 in binary
0x00FE is 0000000011111110 in binary
Result 0000000001010100 in binary or 0x0054 hex
The NOT operator ‘~’, also called ones complement, is used to reverse the state of each bit.
~0x0F results in 0xF0
Lets put these operators to work for a MSP430. At the beginning of a MSP430 C program there is usually an #include directive that tells the compiler to use a header file for the MSP430 device that will run the program. For example:
#include <msp430x42x0.h>
Inside this header file we can see a number of statements such as:
/* SD16CTL */
#define SD16DIV0 (0x0040) /* SD16 Clock Divider Select 0 */
#define SD16DIV1 (0x0080) /* SD16 Clock Divider Select 1 */
#define SD16DIV_0 (0x0000) /* SD16 Clock Divider Select /1 */
#define SD16DIV_1 (SD16DIV0) /* SD16 Clock Divider Select /2 */
#define SD16DIV_2 (SD16DIV1) /* SD16 Clock Divider Select /4 */
#define SD16DIV_3 (SD16DIV0+SD16DIV1) /* SD16 Clock Divider Select /8 */
These statements assign a name to content that the compiler will substitute into the code where the name is used. When the compiler sees SD16DIV0, it substitutes in the hexadecimal number 0x0040. These particular define statements apply to use of the SD16 analog to digital converter peripheral. The /*SD16CTL */ remark indicates that the following defined names are for use in configuring the SD16CTL register. Notice that names are defined to set individual bits (SD16DIV0, SD16DIV1) or choose the function controlled by those bits (SD16DIV_0 – SD16DIV_3).
These two statements accomplish the same thing:
SD16CTL = SD16DIV0 | SD16DIV1; //0x0040 OR 0x0080 = 0x00C0
SD16CTL = SD16DIV_3; //0x00C0
A switch can be attached to the MSP430 as follows: Connect a 100K ohm resister from the digital power rail to an input pin. Then attach a single pole single throw switch to the same input pin with the other terminal connected to the digital common rail. When the switch is on (closed) the input pin sees a logic 0. When the switch is off (open) the input pin sees a logic 1 because the resistor is carrying minimal current. Assume pins 6.4, 6.5, 6.6, and 6.7 are connected to switches in this way.
void main(void)
{
P6DIR=0xF0; // set 6.4-6.7 to inputs and 6.0 – 6.3 to outputs
while (1) // Begin while forever
{
if ((P6IN & 0xF0) == 0xF0) // &0xF0 isolates the four inputs
{ // execute this code if all switches are off (1111)
}
if ((P6IN & 0xF0) == 0xe0)
{ // execute this code if the switch on 6.4 is on and the others are off (1110)
}
if ((P6IN & 0x80) == 0) // &0x80 isolates only bit 7 for input 6.7
{ // execute this code if the switch on 6.7 is on no matter how the other switches are set
}
} // end while forever
} // end main()
If output pin 6.1 is connected to a LED, we can toggle it to the opposite state with an exclusive or operator. A ^= B is the same thing as writing A = A ^ B.
P6OUT ^= 0x02; // if the LED was off it lights, and if it was lit it turns off
What if we wanted the LED output to be on no matter what its former state was?
P6OUT |= 0x02; // the LED output is on, and the other bits are undisturbed.
What if we wanted the LED output to be off no matter what its former state was?
P6OUT &= 0xFD; // the LED output is off, and the other bits are undisturbed.
What if we wanted to set SD16CTL to ‘clock divide by 4’ and it is currently set to ‘clock divide by 8’?
SD16CTL &= ~( SD16DIV0 | SD16DIV1); // clear clock divider bits
SD16CTL |= SD16DIV_2; // clock divider select /4
0 comments:
Post a Comment