ADVANCE BIT MATH
QUICK REVIEW OF THE PREVIOUS LESSON:
SHIFT LEFT | SHIFT RIGHT | NOT | AND | OR | XOR |
---|---|---|---|---|---|
<< | >> | ~ | & | | | ^ |
1 << 2 = 0000 0100 or 4 |
8 >> 2 = 0000 0010 or 2 |
~0 = 1 ~1 = 0 |
0 & 0 = 0 0 & 1 = 0 1 & 0 = 0 1 & 1 = 1 |
0 | 0 = 0 0 | 1 = 1 1 | 0 = 1 1 | 1 = 1 |
0 ^ 0 = 0 0 ^ 1 = 1 1 ^ 0 = 1 1 ^ 1 = 0 |
In the previous chapter we discussed the basics of bit math. The good news is that we don’t have to learn any more operations; We are simply going to discuss some abbreviations and common multi-operation formulas. Once again a warning, if you do not understand the information in the Bit Math Chapter please re-read it, this chapter builds heavily on the theory introduced in the previous chapter.
ABBREVIATIONS:
Most of the time, we are going to take a register, read its value, perform an operation and load the new value back into the same register. Previously, I had always used “i = i <operation> #” in order to show this. However, there is an easier way that seems to be the preferred way among microcontroller programmers.
If you use “<operand>=” (eg. “|=” for OR) the compiler will assume that your using the destination register data, performing an operation on it and then writing it back into itself.
Confused? Hopefully this code example will clarify things a bit.
i <<= 1; // is the same as i = i << 1 i >>= 2; // is the same as i = i >> 2 i ~=; // is the same as i = ~i i &= 3; // is the same as i = i & 3 i |= 4; // is the same as i = i | 4 i ^=5; // is the same as i = i ^ 5
From now on we will see this a lot. But don’t worry, I will include the long hand version when I’m solving the equations.
MASKING:
Definitely not as fun as Halloween, but a lot more useful.
When we are working with registers we are generally interested in the status of specific bits, the best way to get the information about specific bits is to build what is called a mask. A mask is simply a number (in binary) that contains 1s in the bits that we are interested in.
Say we want to do work on the 3 bit and the 5 bit, we would create a mask that looks like this 0010 1000 (remember the first bit is a 0bit not a 1s bit therefore the highest bit is the 7th bit not the 8th bit … terminology, it will get you all the time). The 0s represent the bits that we are not interested in and the 1s represent the bits that we are interested in.
So now remember back last chapter, the AND operation caused a TRUE(1) if both numbers have the same bits TRUE(1). So if we take our mask and AND it with the original register, we will end up with a value of 0 if the 3th and/or the 5th bit isn’t true and a value greater then 1 one or both of the registers are true.
x = 64; y = x & 0b00101000; // y = 0 if 5th or 7th bits are not true, and y>0 if one or both are true
Mathematically here is what we did above:
Now while the above code works, most programmers will not build a mask in such a way; 00101000 looks confusing, and it is only an 8 bit register, can you imagine how confusing a 16bit or 32 bit register will be? Instead, most will use a combination of a BIT SHIFT LEFT and an OR in order to create a mask as follows:
x = 64; y = x & ( (1<<5) | (1<<3) );
Mathematically here is what we did:
(1 << 3)
creates 0000 0001
shift it left by 3 to get 0000 1000
(1 << 5)
create 0000 0001
shift it left by 5 to get 0010 0000
0000 1000 (1 << 3)
| 0010 0000 (1 << 5)
---------------
0010 1000 notice that we just created 0b00101000
y = x & 0010 1000
0100 0000 x (set to 64 on the first line)
& 0010 1000 mask (created with ( ((1<<5) | (1<<3)) )
---------------
0000 0000 result, loaded into y
You might wonder, why create so much math, the answer is simple, anytime you see (1 << X) you can automatically think that you are putting a 1 into the nth spot of the register. Or make a mask (in binary) a 1 with X Zeros behind it.
PUTTING IT ALL TOGETHER:
Yes you can put both of the above lessons together so lets take y and set the 3 bit and store the value back into y.
y = 64; y |= (1<<3);
y = y | (1 << 3)
(1 << 3)
creates 0000 0001
shift it left by 3 to get a 0000 1000
y = y | 0000 1000
0100 0000 y (set to 64 on the first line)
| 0000 1000 mask (created with (1<<3) )
---------------
0100 1000 result, loaded into y
COMMONLY USED EQUATIONS:
There are 4 major equations that you will see all over the place when dealing with a microcontroller, so let's examine them to debunk any myths or questions.
Set Bit, Clear bit and flip bit are most commonly used for outputs. and Get Bit bit is often used for inputs.
Set Bit:
This equation is used to set a single bit in a register, lets set the 2 bit in the PORTB register.
PORTB = 8; PORTB |= (1 << 2);
PORTB = PORTB | (1 << 2)
(1 << 2)
creates 0000 0001
shift it left by 2 to get a 0000 0100
PORTB = PORTB | 0000 0100
0000 1000 PORTB (set to 8 on the first line)
| 0000 0100 mask (created with (1<<2) )
---------------
0000 1100 result, loaded into PORTB
Clear Bit:
This equation is used to clear a specific bit in a register, lets clear the 5 bit in the PORTC register.
PORTC = 34; PORTC &= ~(1 << 5);
PORTC = PORTC & ~(1 << 5)
(1 << 5)
creates 0000 0001
shift it left by 5 to get 0010 0000
PORTC = PORTC & ~(0010 0000)
~(...) to get 1101 1111
PORTC = PORTC & 1101 1111
0010 0010 PORTC (set to 34 on the first line)
& 1101 1111 mask (created with (1<<5) )
---------------
0000 0010 result, loaded into PORTC
Flip Bit:
If you want to flip the value of a bit in the register, so lets flip bit 5 in the PORTD register.
PORTD = 8; PORTD ^= (1 << 5);
PORTD = PORTD ^ 0010 0000
(1 << 5)
creates 0000 0001
shift it left by 5 to get a 0010 0000
PORTD = PORTD ^ 0010 0000
0000 1000 PORTD (set to 8 on the first line)
^ 0010 0000 mask (created with (1<<5) )
---------------
0010 1000 result, loaded into PORTD
Get Bit:
If you want to find out what the state of a bit within a register is this is the formula. The formula will output 0 if the bit is not set(0) and greater than 1 if it is set(1). Let's see if 3 bit is set.
PORTB = 8; if ( (PORTB & (1 << 3)) > 0) { // do this if the 3 bit is set(1) } else { // do this if the 3 bit is not set(0) }
(1 << 3)
creates 0000 0001
shift it left by 3 to get a 0000 1000
PORTB & 0000 1000
0000 1000 PORTB (set to 8 on the first line)
& 0000 1000 mask (created with (1<<3) )
---------------
0000 1000 result > 0 therefore the 3rd bit is set(1)
Hope that helps.
Cheers
Q