Most of us started the embedded programming by blinking a led, and reading a simple input from a push button, which was the correct way to do it, step by step. I already explained the importance of pull-up(down) resistors in a previous article, but now lets take a closer look at the actual digital input and output handling.
Lets start at the input reading, more experienced programmers use the terms bit masking, yes that sounds great but what is it, you probably wondered. In other words bit masking means that only the relevant bits are considered the others are disregarded.
At this moment consider the micro controller input as a simple 8bit variable PINB which can hold any value from 0-255, and we have connected the led and push button like this:
We have the input and output on the same PORTB, we must read the PB5 pin and control the PB0 pin, after configuring the direction of those pins we must check the state of the PB5 pin, which is the number 5 bit in our 8bit variable, since we are interested only about PB5, the other bits doesn’t hold relevant information. How to check only the 5th bit? Some basic Boolean algebra knowledge is needed here:
By masking the irrelevant bits we can focus only to the input we are interested about, for this the AND operation is needed, the PB5 is the 5th bit, so if we clear all the other bits and leave the 5th “unharmed” we have the useful information, this is made with: PINB&0b00100000 (& is the bit level and operation in C, ob0010.. is the binary representation ), if the 5th bit was 1 then the result will be 0b00100000, if not then the result is 0b00000000(just zero). When we put (PINB&0b00100000) into a condition, like if(PINB&0b00100000) the only bit that will count is the 5th, which is what we want, the other bits won’t matter.
Now you will say, that if() expression looks “ugly” and you are right, it isn’t easily readable and has a great potential for typo error, the other way to reference that binary number is this: (1<<5) 1 shifted to left by 5 position, so if(PINB&(1<<5)) will give the same result, and the compiler sees no difference. If you look at that condition you see instantly which bit is checked, the typo error possibility is also greatly reduced.
Some of you might say that these are a lot of operations, first to read the value than make the and operation then check the result and this will increase the program size, well most of the micro controllers have special assembler instructions for bit level testing, and the C compilers are clever enough to use them, so that if statement will result in only one line of assembler code, although make sure to activate the size optimization of your compiler!
Now lets see how to control the digital port output bit by bit, the LED is connected to PB0, we must change only that bit and leave the rest unchanged, imagine the case when you have other components connected to the other pins, you certainly don’t want to bother them.
PORTB |= 0b00000001; //this line will only set (one) PB0 pin PORTB &=0b11111110; //this line will only clear (zero) PB0 pin
Those lines of code are really ugly and you should avoid this programming style, the equivalent is like this:
PORTB |= (1<<0); //set bit PORTB &= ~(1<<0); //clear bit, the ~ operator is the bit level negation
Both operations reference the actual value of the port and with the logical operations the other bits remain unchanged. To further improve the code styling I recommend the use of macro’s, for example:
#define IS_BIT(a,p) (a&(1<#define SET_BIT(a,p) a |= (1< #define CLR_BIT(a,p) a &= ~(1<
Now our if statement will look like this if(IS_BIT(PINB,5)) and the PB0 control like this SET_BIT(PORTB,0); CLR_BIT(PORTB,0); Again don’t worry about the program size, because the micro controller has dedicated assembler instruction for setting or clearing just one bit, and the compiler will use that.
Learn to master the bit level operations because in embedded programming it is crucial, especially for digital I/O handling.
In the next article I will explain how to use this technique with 7 segment display and matrix keyboard.