Assignment operators available in C are: =, +=, -=, *=, /=, %=,<<=, >>=, &=, ^=, |= which are used to assign a value of the Right hand operand to a storage location or a variable at the Left hand side.
We will illustrate the five basic operators used in AVR programming.
&= a &= b is the same as a = a & b
|= a |= b is the same as a = a | b
^= a ^= b is the same as a = a ^ b
<<= a <<= b is the same as a = a << b
>>= a >>= b is the same as a = a >> b
Other assignment operators (+=, -=, *=, /=, %=) can also be written in a similar method as described above.
By combining the above operators, we can easily control (turn on or turn off) a single bit without affecting other bits. As assigned above, consider the variable “a” where a = 01101111. Suppose we need to make the 5th bit in this byte as 0 (clear 5th bit), how do we do it?
We know that 1 & 0 = 0. All we need to do is AND the particular bit with 0 to clear the bit. But again, we need to perform a series of careful operations so that other bits are not affected. Suppose the existing value of PORTC = a, where a = 01101111, then PORTC &= ~(0x20) will fulfill our requirement of clearing the 5th bit. How?
PORTC &= ~(0x20) is the same as:
PORTC = PORTC & ~(0x20) // Remember Assignment Operators?
PORTC = PORTC & ~(00100000) // 0x20 in binary format
PORTC = PORTC & 11011111 // NOT (00100000)
PORTC = 01101111 & 11011111 // AND Operator
PORTC = 01001111 // Now 5th bit is cleared
It may seem unnecessary to use the NOT operator. We can as well write PORTC = PORTC & DF or even PORTC = 11011111. But it is easier to identify the bit in question in 00100000, rather than 11011111. Hence programmers generally prefer to use a NOT operator.
You can also change more than one bit at a time by changing (0x20) into a desirable value. If you write PORTC = PORTC & ~(0xff), then all the bits in PORTC will be cleared.
Now we have the 5th bit of PORTC cleared. What if we need to set it again? Don’t we require to do this for our blinking LED? PORTC |= (0x20) will help us to set this bit. We have PORTC = 01001111.
PORTC |= (0x20) is the same as:
PORTC = PORTC | (0x20)
PORTC = 01001111 | 0x20
PORTC = 01001111 | 00100000 // OR Operator
PORTC = 01101111 // 5th bit is set
Well, we have achieved what we wanted to. The 5th bit is set again.
What if we wanted to toggle a bit, irrespective of its current state? Do you remember we have parked another operator which we learnt and never used it? It is XOR (^) operator to our rescue now. Let us see how we can exploit it.
Suppose we write PORTC ^= (0x20)
PORTC = PORTC ^ 0x20 // PORTC (XOR) 0x20
PORTC = PORTC ^ 00100000 // 0x20 in binary format
PORTC = 01101111 ^ 00100000 // XOR Operator
PORTC = 01001111 // 5th bit is cleared
Now applying (XOR) on PORTC again,
PORTC = 01001111 ^ 0x20 // PORTC value from previous Operation
PORTC = 01001111 ^ 00100000 // XOR Operator
PORTC = 01101111 // Voila! 5th bit is set again to 1
The above results can also be achieved using binary format.
PORTC |= 0b00100000 // Set a bit
PORTC & = ~0b00100000 // Clear a bit
PORTC ^ = 0b00100000 // Toggle a bit
Finally if you want to check whether a bit is set or clear, then you can use AND.
Let PORTC = 01101111
Bit = PORTC & 0x20
Bit = 01101111 & 00100000
Since the 5th bit is set, this operation results in 1 because 1 & 1 = 1. If it is not set, then 0 & 1 = 0 and “Bit” will be assigned a value of 0. <avr/sfr_defs.h> library has functions which can be utilized to check if a bit is set (bit_is_set) or clear (bit_is_clear) without taking the pain of writing our own code. These functions return a 0 if bit is set and non-zero if it is clear.