The code in the last few posts have numbers such as 0x28 and characters such as "&" and "^". Those numbers are written in hexadecimal notation, or in hex, and the "&" and "^" are characters used to minipulate binary bits. In this post, I will indicate a hexadecimal, or hex, number like this: XXh.
Hexadecimal numbers are numbers to the base 16 rather than 10. Consequently, they require 16 different digits. The first 10 are 0 through 9, the remaining 6 consist of "A" through "F", inclusive. What is so special about hexacecimal numbers and why do we need them ,if indeed we do need them? There is nothing special or magical about hexadecimal numbers, and we really could do without them. Any hexadecimal number can be expressed in another way. For example, 20h can be expressed as decimal 32 or binary 100000. So why bother? The answer is convenience.
How long could you remember a binary number such as 01101011? For me, about one second. Perhaps it would be easier to remember the decimal equivalent. So let's convert 01101011 to decimal. Well, let's see, I know I have to add up all the power of 2's that are represented by a 1. So, I add 1, and 2, not 4, but 8, not 16, but 32, and 64. Gee, anybody have a calculator?
How long would it take to convert 01101011 to hexadecimal? In about 2 seconds I can tell you that 01101011 is 6Bh. Sure I have done it a couple of thousand times, but it's easy. First, I mentally split the binary number into groups of four digits: 0110 and 1011. Now, I do the power of 2 thing for each four bit piece (called a nibble). So, 0110 is 4 + 2 or 6, and the 1011 is 8 + 2 + 1 or 11. I know that ten is A, so eleven must be B. After a while you can do it in your head. The biggest power of 2 I have to add is 8. I don't have to add in my head those larger power of 2's like 16, 32, 1004, 32768, etc.
Converting a large binary number to decimal = time consuming.
Converting a large binary number to hexadecimal = quick.
That is why the code in my posts do not show long binary numbers. It's just easy to convert back and forth from binary and hex numbers in your head. There is another reason why we use hexadecimal notation in the code, rather than decimal, and that is we plan to do some bit minipulation. And, why do we do bit mimipulation? To make the code efficient. We are able to save quite a few lines of code.
In my display code, every time I write a character to one line, I have to erase the character in the same position on the other line. I have a variable address_counter that corresponds to the position of the next character to be displayed. The variable address_counter goes from 0x00 to 0x27 for the first line and 0x40 to 0x67 for the second line. I have to constantly shift from one line to the other. I could do this with the following code:
if address_counter < 0x28
address_counter += 0x40
else
address_counter -= 0x40
Adding 0x40 puts address_counter in the line below at the same horizontal position .Subtracting 0x40 puts address_counter in the line above at the same horizontal position.
OR I could replace all of those lines with the following line:
address_counter = address_counter ^ 0x40
The single line of code with the "^" doesn't care if you are on the top or bottom line, it just switches from one to the other.
It's that character "^" that makes it work. It is one of the bitwise operators. It's called an exclusive OR and is joined by the AND, OR, NOT, and shift right and shift left operators. Here is how those operators work:
The NOT (or complement) Bitwise Operator:
Symbol: ~
Every 1 becomes a 0 and every 0 a 1
~10010110 becomes 01101001
The AND Bitwise Operator
Symbol: &
Applied to two binary numbers. Only if both digits are a 1 will there be a 1 in the resulting number.
1001 0110 96h
1100 1100 CCh
1000 0100 84h
The OR Bitwise Operator
Symbol: |
Applied to two binary numbers. If either digit is a 1 there will be a 1 in the resulting number. Only if both are a 0 will there be a 0 in the resulting number.
1001 0110 96h
1100 1100 CCh
1101 1110 DEh
The Exclusive OR Bitwise Operator
Symbol: ^
Applied to two binary numbers. If the two digits are the same (0,0 or 1,1) the resulting digit will be a 0. If the two digits are different (0,1 or 1,0) the resulting digit will be a 1.
 It is a very convenient way to flip a bit. If the original bit is a 0, exclusive ORing it with a 1 will make it a 1, if it was already a 1, exclusive ORing it with a 1 will make it a 0. Exclusive ORing a bit with a 0, leaves it alone.
 Since 40h is equivalent to 0100 000, all address_counter ^ 0x40 does is flip one bit:
0010 1000 28h 0110 1000 68h
0100 0000 40h 0100 0000 40h
0110 1000 68h 0010 1000 28h
The Shift Left and Shift Right Bitwise Operators
Symbol: << and >>
Shifts the bits to the right or left the number of positions in the second argument. The new bits added to the right or left are 0's.
0xAA << 2 becomes 0xA8 1010 1010 -> 0101 0100 -> 1010 1000
0xAA >> 2 becomes 0x2A 1010 1010 -> 0101 0101 -> 0010 1010
To reiterate the value of hexadecimal numbers, try doing the same operations with the decimal equivalent of the hex numbers.
Have fun using hex numbers and bitwise operators in your python code.