I am currently working with some low level code optimized for low-space Arduino micro controller, I needed to review some basics of bits manipulation.
Bits bytes and nibbles, binary and hexa
Decimal to Binary conversion:
Binary to decimal conversion
Bits bytes and nibbles, binary and hexa
- 1 Byte is composed of 8 bits, or (2 nibbles of 4 bits): 0102 0120 1201 0201
- A WORD is 2 BYTEs, and a DWORD is 4 BYTES or 32 bits.
- Note: a Dword is an unsigned 32 bits integer
- It takes 4 bits to cover one digit in Hexadecimal (from 0 to 9 and A to F).
- That is why we use a two digit Hexa number to represent a Byte of data.
LSB and MSB
Imagine the following Byte 1001 0010 0100 1000
The first bit starting from the left (1) is the MSB (Most Significant Bit) as it is the bit with the highest weight on the number
The leftmost digit "0", is the LSB (Least significant bit)
Decimal to Binary conversion:
One method:
- find the power of 2 number which is the closest (inferior) of the decimal number.
- do the same with the rest (rest of the subtraction between the decimal number and this power of 2)
Ex: decimal 52
closest power of 2 number : 32, (2^4)
rest: 52 - 32 = 20
closest power of 2 of 20 : 16 (2^3)
rest: 20 - 16 = 4
closest power of 2 : 4 (2^2)
So binary number is: 11100
Binary to decimal conversion
11100
Sum the power of 2 of each bit with value of "1", being careful as the first digit is at position "zero"
ex:
2^4 = 32 (position 4 and not 5 as we start with 0)
+ 2^3 = 16
+ 2^2 = 4
-----------------
52
Bitwise operators
& : AND operator
(logical AND) Compares two values only if they have their bit sets.
| : OR operator
(logical OR)
^ : XOR operator, used to toggle bits
~ : NOT operator (inverts bits values)
Using | to set flags:
For exemple, imagine you have different binary flags defined for different parameters:
enum{
style1 = 1,
style2 = 2,
style3 = 4,
...
};
equivalent to:
Style1 = 0b 00000001
Style2 = 0b 00000010
Style3 = 0b 00000100
To set both style 1 and style 3, we use the bit "or": | which is similar as addition
style1 | style3 == 0b 00000101
Using & to check wether flags are set:
How do we test if the flag of "style3" is set in the DWORD passed in parameter:
DWORD parameter: 00000000 00000000 00000000 00100101
Style3 MASK 00000000 00000000 00000000 00000100
bitwise AND (&) 00000000 00000000 00000000 00000100 bit set
other DWORD parameter: 01100001 01100100 10000001 10100000
Style3 MASK: 00000000 00000000 00000000 00000100
bitwise AND (&) 00000000 00000000 00000000 00000000 bit !set
if the bit and (&) operation returns 0, the bit is not set, if it returns 1 it is!
Using ~ to remove a flag setting:
newStyle = oldStyle & ~style3; (newStyle = oldStyle AND NOT style3)
>> << Right and Left shift operators
>> or << operators (right shift / left shift operators)
Move the bits the number of bit position specified:
>> moves the bits from the higher bit to the lower bit
<< idem from the lower bit to the high bit
These operators are frequently used in enum data structures;
In C enum structures are used to store a list of predefined constants, these constants often use a power of 2, as it is easier to combine them using bit operators.
see here for more details.
Using bit is useful to use the least amount of memory as possible:
ex: date with least amount of memory
Struct date_struct{
BYTE day : 5, //1 to 31
month: 4, //1 to 12
year : 14; // 0 to 9999
} date;
in this exemple the day field takes the lowest 5 bits, month the next 4, and year the next 14, so we can store the date structure in 23 bits, contained in 3 BYTEs.
If we chose an INT for each field, the structure would have taken 12 BYTEs.
| 00000000 0000000 | 0000 | 00000 |
year month day
How does it work: a BYTE is 8 bits, by using it the compiler will allocate 1 BYTE for storage. If we use more than 8 bits in our structure, the compile will allocate another BYTE, as many as it takes to hold our structure.
variable : 8 (8 bits used)
Thanks to this structure notation, we can use the address of the structure.
date.day = 12;
dateauj = &date;
(note &date is the memory location of variable date, see here for more on pointers)
(note &date is the memory location of variable date, see here for more on pointers)
dateauj -> year = 1852;
That's all for tonight!
Commentaires
Enregistrer un commentaire
Tell me what you think