Bitwise maths and logic operators [tutorial part 4]

Hello, here I’m again, today I will give a small maths lesson, don’t run away, its easy and its very useful for embedded programming, and its also nice to know a bit more about how our little micro-controller works. In fact I will write about bitwise operator and their usage to set, clear, toggle and even multiply and divide(!), its also the fastest way to configure registers, and to handle digital input and output operations, this bitwise maths is done using basic logic operator, like AND, OR, NOT and other.
Lets start, first I will show what is the correspondent operator for each logic function:

 AND        &
 OR        |
 NOT        ~
 XOR        ^
 Shift left    <<
 Shift right    >>

To help us understand what each logic operator does, there are some little things called truth tables, those are tables/arrays that have all the possible input combinations for each logic operator and the result that each combination produces, to simplify the truth tables they are always shown with only 1 bit input parameters, because for the logic operator it doesn’t matter if we are dealing with 1bit or with 128bits.
But wait, what is all that bitwise here, bitwise there?!
Bitwise means that we are performing operations to lets say a 8bits variable like a char or an uint8_t and working bit by bit, after this tables are shown I think that you will understand this a bit better, if not, just leave a comment 😉
Here are the truth tables for all the logic operator that I will talk about today:

 Truth table for AND:
 0 AND 0 = 0
 0 AND 1 = 0
 1 AND 0 = 0
 1 AND 1 = 1

 Truth table for OR:
 0 OR 0 = 0
 0 OR 1 = 1
 1 OR 0 = 1
 1 OR 1 = 1

 Truth table for XOR:
 0 XOR 0 = 0
 0 XOR 1 = 1
 1 XOR 0 = 1
 1 XOR 1 = 0

 Truth table for NOT:
 NOT 0 = 1
 NOT 1 = 0

 Truth table for Shift left using an 8 bits variable:
 0x01<<0 = 0b00000001
 0x01<<1 = 0b00000010
 0x01<<2 = 0b00000100
 0x01<<3 = 0b00001000
 0x01<<4 = 0b00010000
 0x01<<5 = 0b00100000
 0x01<<6 = 0b01000000
 0x01<<7 = 0b10000000

 Truth table for Shift left using an 8 bits variable:
 0x80>>0 = 0b10000000
 0x80>>1 = 0b01000000
 0x80>>2 = 0b00100000
 0x80>>3 = 0b00010000
 0x80>>4 = 0b00001000
 0x80>>5 = 0b00000100
 0x80>>6 = 0b00000010
 0x80>>7 = 0b00000001

 Table with decimal, binary and hexadecimal conversion:
 Binary       Hexadecimal    Decimal
 0000    =    0     =    0
 0001    =    1     =    1
 0010    =    2     =    2
 0011    =    3     =    3
 0100    =    4     =    4
 0101    =    5     =    5
 0110    =    6     =    6
 0111    =    7     =    7
 1000    =    8     =    8
 1001    =    9     =    9
 1010    =    A     =    10
 1011    =    B     =    11
 1100    =    C     =    12
 1101    =    D     =    13
 1110    =    E     =    14
 1111    =    F     =    15
 Bit numbering of an 8bits variable:

Please note that the shift left and shift right truth tables where done using only two different values, but you can use this logic operators with what ever value you want, but I will talk about this two operator a little more ahead with more depth.
There is a lot of doubts when dealing with binary and hexadecimal number and how to convert between those numbering bases and decimal, so I will show you how to convert a simple 8bits variable from binary to hexa and from that to decimal.
Lets say that you have this 0b10101001, first you remove the 0b part because that’s there only to say to the compiler that that number is in a binary representation, then you split the 8bits in two pairs of 4bits each, so now you have 1010 and 1001, now using the table that I provided you can see that 1010 in hexadecimal is A and 1001 is 9, so the result is 0xA9, again the 0x part is a indicator to the compiler(and people) that this is a hexadecimal represented number, now its much easier to convert to decimal, and 0xA9 is 10 (10 is the A in decimal) plus 9, so 0x10101001 is equal to 0xA9 which is equal to 19, with a bit of practice you will memory all this and its great if you want to make some patterns with leds, or led matrices, or led cubes, and a lot other things!

If you look with some care to the above tables, you can see that there are some similarities between the logic operators and the basic maths operators, and in fact you can use this little idea that I used to distinguish/memorize this operators when I learn about then. The AND is like a multiplication, its not the same as the * operator, because it does it work for each individual bit and not for a full variable at once, the OR is like an addition, and the XOR is like a simple difference detector, because its 1 when its inputs are different and 0 when its inputs are equal, the shift left works as a real multiplier but it can only multiply in powers of 2(this means that we can multiply by 2,4,8,16,32,64,128,256, etc), because its a logic operator, and shift right works as a divisor, again it only divides in powers of 2 and only returns the integer part of a division.

Lets dive a bit more into this bitwise world, now with a more practical side.
In a micro-controller its usual that we need to configure peripherals, and those have registers where we either set or clear bits to enable or disable certain functions of the said peripheral, or to turn an led on or off, so first here is what we can do using the OR function, lets say that we want to set bit 0 of PORTB without affect the other bits that might be set or clear:

 PORTB = PORTB | 0x01;

Or in a more compact way that does exactly the same, the |= is called a compound operator, its a faster way of writing the same that is done above but its shorter, the generated assembly code is the same, but we don’t need to type so much, use whatever you like more:

 PORTB |= 0x01;

 Now lets say that we want to clear the bit 0 that we have just set, for that we need two logic operator, the AND and the NOT:

 PORTB = PORTB & ~0x01;
 //or the short version
 PORTB &= ~0x01;

This one is a little bit more complex to understand so I will show you why do we need the NOT to clear a bit:

 //0x01 in binary is 0b00000001
 //if we AND this value with the PORTB value it would clear all the bits and only mantain the original value in bit 0
 //So we negate the 0x01 first
 // NOT 0x01 is NOT 0b00000001 that is 0b11111110
 //Now doing the AND of this will give us the desired result of clearing only the first bit and maintaining all the other bits unchanged

Another use for the AND operator is to detect if a bit is 1 or 0 for example in an if() statement, lets imagine that we have a switch wired in PORTB 3 and we want to detect that:

 if(PORTB & (1<<PB3)){
 //do some stuff

Be aware that the result of PORTB & (1<<PB3) is either 0 or different from 0 and not 0 or 1, in fact the result is 0 or 0x08(0b00001000 in binary or 8 in decimal) if you don’t use any == with this statement with will work perfectly but if you do ==1 it will not work because the result will never be 1 it is only either 0 or 0x08.

Now lets talk about XOR, its not a very common operator and its use might seem limited, but its great to toggle output pins in a very fast and clean way, you want to toggle a led each second for example you could use those usual if() chains were the current state is tested and then changed for the contrary state, using XOR you do that in only one line and way faster than using the if() chains or ever worse, case: chains, or even more stranger ways of doing what is so simple.
Lets toggle for example the PB5 led included in the Arduino board:

 PORTB = PORTB ^ (1<<PB5);
 //And the short way
 PORTB ^= (1<<PB5);

It is really easy and the code is much cleaner, it like XOR a lot!

You might have already heard about bit masks, but what are they and what are they purpose?
A bit masks is a variable that is used with the logic operators, I have been using then in this tutorial, for example (1<<PB5) is a bit-mask that is useful in the XOR example to toggle the value of PORTB5, those masks might be like this one, simple about what they do, but you might have programs that are more complex, and imagine that you use PORTB0,1,2,3 as inputs and PORTB4 and 5 as outputs, you could write (1<<PB0)|(1<<PB1)|(1<<PB2)|(1<<PB3) every time you wanted to check if all the inputs where high or low, or you could define a bit-mask in the begin of your program and just use that instead of writing that small train of letter and symbols every-time.

 #define MASK    (1<<PB0)|(1<<PB1)|(1<<PB2)|(1<<PB3)
 //This define is together with all the other
 //includes in the begin of your program

 if(PORTB & MASK){
 //do some stuff when all your inputs are high

They are handy and the name that you give them will probably make more sense that just seeing that train of letters.

Finally lets head over the shift left/right operators, I’m already using them, the << is the shift left and is very handy to set bits when dealing with the digital PORTS and registers, the PB0,1,2,3 are just defined values in the <avr/io.h> that have the 0,1,2,3 decimal values, they are just small wrappers that show us in a visual manner with port and pin we are dealing with, so as you can this operators are useful when setting bit-masks, lets say that you want to set bit7 of some variable or a bit-mask, using a shift left its easy to do, and because the values are know at compile time this values will all be calculated by the compiler and not in our micro-controller at run-time:

 #define myMask    (1<<7)
 //latter in the program
 myVar |= myMask;

And how about multiplying and dividing with the shift operator?
Lets start with the shift left operator that let us do multiplications by powers of 2, for example:

 2<<1 = 4 //But how?
 //2 in binary is 0b00000010
 0b00000010 << 1 is 0b00000100
 0b00000100 in decimal is 4

The value was shifted to the left one position and doing that it was multiplied by 2, the sift left is the same as multiplying by 2^n where n is the amount of shifts applied to the original variable, always keep in mind that when using an 8 bits variable and doing <<8 will return you an empty variable because the shift inserts 0’s when shifting the original value, and well putting eight 0’s in an 8 bits variable leaves it clean.
Another heads-up when using an 8bits variable every bit shifted after the bit7 is lost, this is called an overflow, to prevent that when using the shift operator you can use an int/uint16_t or an even bigger uint32_t.

The divide is done using the shift right and works exactly in the same way as the shift right, but instead of multiplying you are dividing by 2^n, and with an added limitation, this operator only allows us to do integer divisions, the fractional part of the result is lost, for example 7/2 is 3.5, lets see what is the output of using the shift right:

 7 in binary is 0b00000111
 0b00000111 >> 1 = 0b00000011
 0b00000011 in decimal is 3

Our fractional part was lost, because any bit shifted beyond bit0 is lost because our 8 bits variable cant old it, in fact not even a bigger variable will ever give us back the lost fractional part, but integer divisions are also widely used and using right shifts is a major speed-up than using an division routine, of course it only works when you are dividing in powers of 2.

And for today this is it, you might want to read this tutorial two or three times until you can understand it clearly but I can guarantee you that bitwise maths are a powerful tool!

19 responses to “Bitwise maths and logic operators [tutorial part 4]

  1. Hi, I didnt quite understand what does the PORTB & (1<<PB3) part does when detecting a bit, im not a native english speaker but yours is the best tutorial I could find grats btw

    • I will try to explain.
      The PORTB reads all the bits of portB then using (1<<PB3) the 8 bits from PORTB are ANDED with a bit mask that will only return the value of PORTB3, this means that if PB3 is low it will read 0 and if PB3 is high it will read a value different from 0, in this case the value will be 0x08, or in binary 0b00001000.

      • Thank you very much that nail it, this is really helpful since we are doing a test tomorrow about programming arduino one to a step motor using H bridge. Thank you again!

  2. For the line PORTB = PORTB ^ (1<<PB5);
    what value is PORTB in binary? if it is 00000001 then the answer I make it is:

    so that outputs: 00100001. How does it toggle? Im clearly doing something wrong so please let me know! Thanks!

    • @Jay: PortB is the data register where each bit can be set or cleared. So, PortB can have any value between 0×00 and 0xFF. In your example, if PortB is 0×01, then PortB ^= (1<<PB5) will toggle (toggle meaning that if it is clear then set it, or if it's set then clear it) PORTB5. Thus the result you get is correct, it should yield 0×21 or 0b00100001. If you did the same instruction twice (PortB ^= (1<<PB5)), you should see the result goes back to 0×01.

  3. @Jay: PortB is the data register where each bit can be set or cleared. So, PortB can have any value between 0x00 and 0xFF. In your example, if PortB is 0x01, then PortB ^= (1<<PB5) will toggle (toggle meaning that if it is clear then set it, or if it's set then clear it) PORTB5. Thus the result you get is correct, it should yield 0x21 or 0b00100001. If you did the same instruction twice (PortB ^= (1<<PB5)), you should see the result goes back to 0x01.

    • does PB5 mean 5th bit of PORT B.then it could be either 1 or 0.then 1<<PB5 means either 1<<1 or 1<<0(there is no use with this).that 1<<PB5 is confusing me a lot.could you help me

  4. Ayush Srivastav

    can you please explain the logic of calculating the value of (1<<PB5) ??
    becoz as i read that a<<b = a*b^2… and value PB3 can either be HIGH or LOWi.e either 1 or 0
    so if I take PB5=1 then (1<<PB5)= 1*2^1 = 2
    then how can you use PORTB = PORTB ^ (1<<PB5) ???

    sorry but this is confusing me a lot.. hope to see your reply soon 🙂

  5. Great tutorial; I understand the underlying math but needed it tied in to arduino which is new to me.
    Unless I am really missing something; I believe you have couple of errors that you may want to correct. First, your shift right truth table is incorrectly labeled shift left. Second is your binary>hex>decimal conversion – the example number given is 169 – your incorrectly state that it is 19. The A does in fact represent 10 but you must multiply that by the place value which is 16 for the second digit. This gives you 160 + 9 or 169.

  6. Mizanur Rahaman

    Hi, Please look below & help me.

    temp_int = abs(Cn); // Returns the absolute int value of Cn
    temp = temp_int; // int to char of LS-Byte
    DC1B0 = 1;

    This code might be different.
    please give me example… to realize the meaning of “temp^0b00000001”


  7. Surendar Devasundaram

    i have a problem in executing an IF statement which should be executed only when both the input pins are high. Even if the condition goes false it still executes. my code is
    if (PINA&((1<<PINA0)|(1<PINA1)))

  8. does PB3 mean 3rd bit of the PORTB.if so 1<<PORTB 3 means left shift 1 either by 0 times or 1 i wrong?

  9. Is the command PB3 for example just
    PB3 = (PortB &= 0b00000100) ?
    So if we were to use libraries that did not use PB#, we would use this instead.

  10. Hi, I have a question regarding the MASK example. So you defined the mask with “#define MASK (1<<PB0)|(1<<PB1)|(1<<PB2)|(1<<PB3)"
    I think that would make the mask 00001111.

    Then you wrote:
    if(PORTB & MASK){
    //do some stuff when all your inputs are high

    I dont' understand why this would do some stuff only if all the inputs are HIGH. Would not it take only one HIGH input to execute the statements? For example if the PORTB is 00000110, and you do PORTB & MASK, the result would be 00000110, which is different from 0. Where am I wrong? Thanks a lot.

  11. Amira Syuhada

    hi… I’m really interested in the information given to you. Where are the avr libraries that I can get from here?

  12. Thanks for explaining why we use &~. it was difficult for me to understand before. MANY THANKS!!!!!!!!!!

  13. what logical operators can we use to clear an individual bit, but leave all others unchanged? can you write
    this in words below

Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s