Introduction: Bit Banging and Boolean Math Without the Math
Overview
When I am bit banging or programming microcontrollers, sometimes I really want to focus on what the bit patterns look like, really visualize what the zeros and ones are doing. But having to do the math in many cases distracts my attention from the task at hand.
Using a calculator is slow and cumbersome, and also distracts me from the binary operations.
We humans work and think in decimal. Bit patterns are in binary. To make the conversion a bit easier we convert to hexadecimal. Having to do this conversion, either mentally, using paper and pen or calculator, at least for me, steals too much attention away from what I am really trying to visualize.
I have thought about writing a small program that will aid me in my visualization, but this too takes up time and takes me away from watching the bit patterns.
So after pondering this dilemma for a while, I came up with a quick and easy solution that give me instance binary visualization without crunching numbers, without manually converting between number bases and is instant and easy.
I normally program in C or C++ so I would like to process binary data using commands that are the same or similar to C Boolean operators.
The answer is Python. For those of you that do not know, Python is an interpreted language that has an interactive shell (command line interface) called Idle.
Using Python Idle I can quickly convert between number bases and perform all of the Boolean operations, using the same operators that I use in C or C++.
If you are new to Boolean operations or want to freshen up your skill set please refer to the following article, do not let the fact that the article is posted in the Arduino Playground put you off. The article is easy to read, clearly written and covers the topic of binary and Boolean operations quite well.
http://playground.arduino.cc/Code/BitMath
If you are new to binary and Boolean operations please feel free to use my “No Math” approach to reading this article. You too can then focus on understanding how to perform Boolean operations without having to do the math.
In my “No Math approach I will be referring to this article from time to time.
When I am bit banging or programming microcontrollers, sometimes I really want to focus on what the bit patterns look like, really visualize what the zeros and ones are doing. But having to do the math in many cases distracts my attention from the task at hand.
Using a calculator is slow and cumbersome, and also distracts me from the binary operations.
We humans work and think in decimal. Bit patterns are in binary. To make the conversion a bit easier we convert to hexadecimal. Having to do this conversion, either mentally, using paper and pen or calculator, at least for me, steals too much attention away from what I am really trying to visualize.
I have thought about writing a small program that will aid me in my visualization, but this too takes up time and takes me away from watching the bit patterns.
So after pondering this dilemma for a while, I came up with a quick and easy solution that give me instance binary visualization without crunching numbers, without manually converting between number bases and is instant and easy.
I normally program in C or C++ so I would like to process binary data using commands that are the same or similar to C Boolean operators.
The answer is Python. For those of you that do not know, Python is an interpreted language that has an interactive shell (command line interface) called Idle.
Using Python Idle I can quickly convert between number bases and perform all of the Boolean operations, using the same operators that I use in C or C++.
If you are new to Boolean operations or want to freshen up your skill set please refer to the following article, do not let the fact that the article is posted in the Arduino Playground put you off. The article is easy to read, clearly written and covers the topic of binary and Boolean operations quite well.
http://playground.arduino.cc/Code/BitMath
If you are new to binary and Boolean operations please feel free to use my “No Math” approach to reading this article. You too can then focus on understanding how to perform Boolean operations without having to do the math.
In my “No Math approach I will be referring to this article from time to time.
Step 1: Setting Up Your Environment
Setting up Your Environment
Python is open source and its free, Python runs on Windows, Linux and Apple OS X.
To set up your environment, head over to the following links:
http://python.org/
If you need assistance installing Python or learning about Python take a look the below link:
http://wiki.python.org/moin/BeginnersGuide
Python is open source and its free, Python runs on Windows, Linux and Apple OS X.
To set up your environment, head over to the following links:
http://python.org/
If you need assistance installing Python or learning about Python take a look the below link:
http://wiki.python.org/moin/BeginnersGuide
Step 2: Let's Get Started
I am going to make the assumption that you know very little about python, bit banging and Boolean operations. If you are more advanced in your level of education, please feel free to skip around.
If your are new to programming, binary operations and bit banging, please feel free to Google any topic you feel you need more information on.
Read this material to gain a better understanding before continuing.
The version of Python I am using is version 3.2, if you are using this version or later versions you should be fine. If you are using a 2.x version of python, please install the current version of 3.x. You can still keep your 2.x version of Python installed.
If you would like a refresher on Binary, Decimal and Hexadecimal number systems please refer to the below link:
http://www.myhome.org/pg/numbers.html
Load the Python Idle application on your desktop. I am running Apple OS X, so my desktop images may look slightly different than yours. But the operations are the same. Once Idle loads you should see the following window:
If your are new to programming, binary operations and bit banging, please feel free to Google any topic you feel you need more information on.
Read this material to gain a better understanding before continuing.
The version of Python I am using is version 3.2, if you are using this version or later versions you should be fine. If you are using a 2.x version of python, please install the current version of 3.x. You can still keep your 2.x version of Python installed.
If you would like a refresher on Binary, Decimal and Hexadecimal number systems please refer to the below link:
http://www.myhome.org/pg/numbers.html
Load the Python Idle application on your desktop. I am running Apple OS X, so my desktop images may look slightly different than yours. But the operations are the same. Once Idle loads you should see the following window:
Step 3: Hello World Example
The >>> prompt is the interactive prompt where you will type your expressions.
The answer to your query will follow on the following line:
Please type the following line after the >>> prompt and press the return key:
>>> print(‘Hello World’)
You should see the following:
Hello World
>>>
The >>> is your next prompt; you are ready for more commands and functions.
Congratulations, your have successfully written your first line of python code.
Step 4: Convert Number Bases
Let’s convert some numbers between number bases:
Type in the following at the >>> prompt and press the return key:
>>> bin(100)
‘0b1100100’
>>>
We are asking Python to convert 100 decimal to binary:
The answer we received is 1100100, notice that a 0b notation is placed at the beginning of the 1100100, this is python notation indicating that the answer is binary. So we have converted 100 decimal to 1100100 in binary.
Type the following:
>>> hex(100)
‘0x64’
>>>
Our answer is 64 hex, the 0x is python notation that our answer is in hexadecimal. We have converted 100 decimal to 64 hex.
Let’s try to go the other way now, type in the following at the >>> prompt:
>>> Int(‘0x64’,16)
100
>>>
Notice there is not a dec() function, we have to use the int() function. Also notice
We had to place the ‘0x64’ in single quotes. The int() function takes a string as a value. We also have to enter a , (comma) and enter a value of 16. The 16 tells the int() function that the 0x64 is a hexadecimal number. The int() function converts string values to decimal values.
Now lets type the following at the >>> prompt:
>>> int(‘1100100’,2)
100
>>>
Using the int() function we also can convert a binary string value to decimal.
The ,2 tells the int() function that we are trying to convert a binary string to a decimal number.
By using these three functions, bin(), hex, and int() we can easily convert between all number bases uses in programming.
Type in the following at the >>> prompt and press the return key:
>>> bin(100)
‘0b1100100’
>>>
We are asking Python to convert 100 decimal to binary:
The answer we received is 1100100, notice that a 0b notation is placed at the beginning of the 1100100, this is python notation indicating that the answer is binary. So we have converted 100 decimal to 1100100 in binary.
Type the following:
>>> hex(100)
‘0x64’
>>>
Our answer is 64 hex, the 0x is python notation that our answer is in hexadecimal. We have converted 100 decimal to 64 hex.
Let’s try to go the other way now, type in the following at the >>> prompt:
>>> Int(‘0x64’,16)
100
>>>
Notice there is not a dec() function, we have to use the int() function. Also notice
We had to place the ‘0x64’ in single quotes. The int() function takes a string as a value. We also have to enter a , (comma) and enter a value of 16. The 16 tells the int() function that the 0x64 is a hexadecimal number. The int() function converts string values to decimal values.
Now lets type the following at the >>> prompt:
>>> int(‘1100100’,2)
100
>>>
Using the int() function we also can convert a binary string value to decimal.
The ,2 tells the int() function that we are trying to convert a binary string to a decimal number.
By using these three functions, bin(), hex, and int() we can easily convert between all number bases uses in programming.
Step 5: Boolean Operations Using Python - Bitwise AND Operator
For this section are we going to refer to the Arduino Playground article, BitMath Tutorial:
http://playground.arduino.cc/Code/BitMath
Bitwise AND Operations
Refer to the section on Bitwise AND operator.
Type in the following expressions:
>>> 0 & 0
0
>>> 0 & 1
0
>>> 1 & 0
0
>>> 1 & 1
1
>>>
Notice we have received the same answers as displayed in the Bitwise AND example.
What we have created is called a Truth table for the Bitwise AND operator.
We have displayed every possible answer that we can receive, performing the Bitwise AND operator.
Let us continue on with the Bitwise AND examples:
Type in the following at the >>> prompt:
>>> a = 92
>>> b = 101
>>> bin(a)
‘0b1011100’
>>> bin(b)
‘0b1100101’
>>> a & b
68
>>> bin(a & b)
‘0b1000100’
>>>
Here we have assigned a value of 92 to variable a and a value of 101 to variable b. We then converted the values of a and b to binary to easily see the results of the bitwise AND operation.
We then performed the bitwise AND operation by typing a & b, this resulted in a value of 68. But we want to visualize the answer in binary, so we typed in the bin(a & b) function.
We now can easily visualize the bitwise AND operation without having to remove our attention from looking at the binary patterns of 92 and 101 to do the math.
Let’s continue the with the bitwise AND examples:
What do you use the bitwise AND operator for in programming or bit banging? One of the uses is to extract one of the bit values from a byte. (eight bits)
Lets say we want to extract the value of the least significant bit of the binary number 101, the right most 1 is the least significant bit.
Type in the following at the >>> prompt:
X = 5
>>> bin(x)
‘0b101’
>>>y = x & 1
>>> bin(y)
‘0b1’
If we wanted to extract the second least significant bit from the value of 101, the second least significant bit of 101 would be the 0.
Type the following at the >>> prompt:
>>> y = x & 2
>>> bin(y)
‘0b0’
>>>
Be careful, different processors define least significant bit positions differently. Some processors use the left most bit as the least significant bit position and some processors use the right most bit position as the least significant bit position.
http://playground.arduino.cc/Code/BitMath
Bitwise AND Operations
Refer to the section on Bitwise AND operator.
Type in the following expressions:
>>> 0 & 0
0
>>> 0 & 1
0
>>> 1 & 0
0
>>> 1 & 1
1
>>>
Notice we have received the same answers as displayed in the Bitwise AND example.
What we have created is called a Truth table for the Bitwise AND operator.
We have displayed every possible answer that we can receive, performing the Bitwise AND operator.
Let us continue on with the Bitwise AND examples:
Type in the following at the >>> prompt:
>>> a = 92
>>> b = 101
>>> bin(a)
‘0b1011100’
>>> bin(b)
‘0b1100101’
>>> a & b
68
>>> bin(a & b)
‘0b1000100’
>>>
Here we have assigned a value of 92 to variable a and a value of 101 to variable b. We then converted the values of a and b to binary to easily see the results of the bitwise AND operation.
We then performed the bitwise AND operation by typing a & b, this resulted in a value of 68. But we want to visualize the answer in binary, so we typed in the bin(a & b) function.
We now can easily visualize the bitwise AND operation without having to remove our attention from looking at the binary patterns of 92 and 101 to do the math.
Let’s continue the with the bitwise AND examples:
What do you use the bitwise AND operator for in programming or bit banging? One of the uses is to extract one of the bit values from a byte. (eight bits)
Lets say we want to extract the value of the least significant bit of the binary number 101, the right most 1 is the least significant bit.
Type in the following at the >>> prompt:
X = 5
>>> bin(x)
‘0b101’
>>>y = x & 1
>>> bin(y)
‘0b1’
If we wanted to extract the second least significant bit from the value of 101, the second least significant bit of 101 would be the 0.
Type the following at the >>> prompt:
>>> y = x & 2
>>> bin(y)
‘0b0’
>>>
Be careful, different processors define least significant bit positions differently. Some processors use the left most bit as the least significant bit position and some processors use the right most bit position as the least significant bit position.
Step 6: Bitwise OR Operations
Refer to the Bitwise OR Operator section in the Arduino Playground article.
I will let you build the bitwise OR truth table using the examples in the article.
We will focus on what you can use the bitwise OR operator for.
We use the bitwise OR operator to set bits in a byte (binary number).
Let say we want to set the least significant bit in the value of 0b100.
Type in the following at the >>> prompt:
>>> x = 4
>>> bin(x)
‘0b100’
>>> y = x | 1
>>> bin(y)
‘0b101’
>>>
Now let’s set the second bit to a value of 1, ie: 111
Type in the following at the >>> prompt:
>>> y = y | 2
>>> bin(y)
‘0b111’
I will let you build the bitwise OR truth table using the examples in the article.
We will focus on what you can use the bitwise OR operator for.
We use the bitwise OR operator to set bits in a byte (binary number).
Let say we want to set the least significant bit in the value of 0b100.
Type in the following at the >>> prompt:
>>> x = 4
>>> bin(x)
‘0b100’
>>> y = x | 1
>>> bin(y)
‘0b101’
>>>
Now let’s set the second bit to a value of 1, ie: 111
Type in the following at the >>> prompt:
>>> y = y | 2
>>> bin(y)
‘0b111’
Step 7: Bitwise XOR Operations
Refer to the Bitwise XOR Operator section in the Arduino Playground article.
I will let you build the bitwise XOR truth table using the example in the article.
We will focus on what you can use the bitwise XOR operator for.
We use the bitwise XOR operator to flip or toggle bits in a number (binary number).
Let say we want to flip the least significant bit in the value of 0b110.
Type in the following at the >>> prompt:
>>> X = 6
>>> bin(x)
‘0b110’
>>> y = x ^ 1
>>> bin(y)
‘0b111’
>>>
Now let’s flip the second bit in the value 0b111
Type in the following at the >>> prompt:
>>> y = y ^ 2
>>> bin(y)
‘0b101’
>>>
This is very cool. We can now control setting and viewing bit values and patterns quickly and easily.
I will let you build the bitwise XOR truth table using the example in the article.
We will focus on what you can use the bitwise XOR operator for.
We use the bitwise XOR operator to flip or toggle bits in a number (binary number).
Let say we want to flip the least significant bit in the value of 0b110.
Type in the following at the >>> prompt:
>>> X = 6
>>> bin(x)
‘0b110’
>>> y = x ^ 1
>>> bin(y)
‘0b111’
>>>
Now let’s flip the second bit in the value 0b111
Type in the following at the >>> prompt:
>>> y = y ^ 2
>>> bin(y)
‘0b101’
>>>
This is very cool. We can now control setting and viewing bit values and patterns quickly and easily.
Step 8: Bitwise NOT and SHIFT Operators
Bitwise NOT Operations
Refer to the Bitwise NOT Operator section in the Arduino Playground article.
Feel free to play around with the NOT operator. But study this operator carefully as zero and negative numbers are represented differently than you might think. Take a look at what a sign bit is and read the article on two’s complement.
The main operation of the bitwise NOT operator is to flip 0 to 1 and 1 to 0. Also this operator works on one number instead of two numbers.
Bit Shift Operators
Refer to the Bitwise Shift Operator section in the Arduino Playground article.
Feel free to play around with both the Left Shift and Right Shift Operators.
Use the bin() function to check the binary values as we have done with the other bitwise operators.
Real use of the Left Shift and Right Operators are to pull off either the least significant or most significant bit from a number one bit at a time.
Rest of the Article
You now have enough information to read the rest of the article on your own and apply the “No Math” Python approach. Let’s now look at a real bit banging example.
Refer to the Bitwise NOT Operator section in the Arduino Playground article.
Feel free to play around with the NOT operator. But study this operator carefully as zero and negative numbers are represented differently than you might think. Take a look at what a sign bit is and read the article on two’s complement.
The main operation of the bitwise NOT operator is to flip 0 to 1 and 1 to 0. Also this operator works on one number instead of two numbers.
Bit Shift Operators
Refer to the Bitwise Shift Operator section in the Arduino Playground article.
Feel free to play around with both the Left Shift and Right Shift Operators.
Use the bin() function to check the binary values as we have done with the other bitwise operators.
Real use of the Left Shift and Right Operators are to pull off either the least significant or most significant bit from a number one bit at a time.
Rest of the Article
You now have enough information to read the rest of the article on your own and apply the “No Math” Python approach. Let’s now look at a real bit banging example.
Step 9: Bit Banging Example
Programming microcontrollers or trying to reverse engineer what a microcontroller program is doing involves processing a lot of binary information. For example, one way in which microcontrollers communicate with other devices is to use a simple two wire interface called I2C, pronounced I squared C.
Using I2C involves sending binary data to an address of a device that is listening for requests from the microcontroller, (master device) Once a request is received by the device, (slave) , the device sends either one or more bytes of data back to the microcontroller.
In learning how to program communications to I2C devices or trying to reverse engineer data coming from I2C devices you have to look at the data in it’s binary form.
I will provide you an easy example of how to do this using the methods you have just learned.
In learning I2C it is often wise to study other programs programmers have written so you can lean how data is passed between microcontrollers and devices.
So for our example we will look at a program snippet of some RobotC code written to bit bang an I2C device.
I have taken a sample bit banged C program written in RobotC by Xander who maintains a Robot Blog called:
http://botbench.com/blog/2011/02/20/bit-banged-i2c-master-on-robotc-for-arduino/#comment-2674
In this blog article he is bit banging an I2C program to communicate with a LED array to flash LED lights in a sequence.
We will reverse engineer the for loop he is using to send a series of bits to the LED array.
If you have never programmed before, please Google variables, for loop, functions and while loops.
Here is the code snippet we will be looking at:
while (true) {
for (int i = 0; i < 8; i++) {
PCF8574write(~(1<<i));
wait1Msec(50);
}
}
Normally I would write a small Python program to print out the values of the for loop. But since I am assuming everyone is new to programming and Boolean logic I will manually type out each iteration of the for loop.
Special Note: Python does not support a byte data type, so in our bit banging example we are going to use the modulo operator to display an integer as an unsigned byte. Please Google inf you need assistance,
For Example: If we perform the the following example: >>> ~(1 <<0), in Python we get -2, If we then use >>> bin(-2), we get '-0b10'. To correct the problem and show a full 8 bits type in the following:
>>> bin(-2 % 256)
'0b11111110'
In order to properly see what is going on with bits we need to see the full 8 bits.
The While is looping forever, ignore this for now.
The for loop loops where the variable i is equal from 0 to 7.
PCF8574write() is a custom function that we will not discuss as part of this article. You can refer to the code to see what this function does on your own.
What we are interested in is the value of i and what binary number we pass to the PCF8574write() function.
Lets translate each iteration of the for loop:
Lets type out each iteration of the loop in Python:
The variable i starts out as 0 and ends up at a value of 7:
>>> ~(1<<0)
-2
Lets pull this expression apart. We are performing a bitwise NOT on the following value. We Left Shift the value of 1, i times.
That is we NOT 1 << 0. We are pushing bits from right to left,.In the first loop we are Left Shifting 1, 0 times, or we NOT the most significant bit.
So if we look at the binary value of -2 we get:
>>> bin(~(1<<0))
‘0b10’
Lets continue, you will soon see the pattern.
>>> ~(1<<0)
-2
>>> bin(-2 % 256)
‘-0b11111110’
>>>~(1<<1)
-3
>>> bin(-3 % 256)
‘-0b11111101’
>>> ~(1<<2)
-5
>>> bin(-5 % 256)
‘-0b11111011’
>>> ~(1<<3)
-9
>>> bin(-9 % 256)
‘-0b11110111’
>>> ~(1<<4)
-17
>>> bin(-17 % 256)
‘-0b11101111’
>>> ~(1<<5)
-33
>>> bin(-33 % 256)
‘-0b11011111’
>>> ~(1<<6)
-65
>>> bin(-65 % 256)
‘0b10111111’
>>> ~(1<<7)
-129
>>> bin(-129 % 256)
‘-0b1111111’
The leading 0 is omitted in this case.
It should read '-0b01111111'
Now if you have not done so already, go to the web page and watch the video:
http://botbench.com/blog/2011/02/20/bit-banged-i2c-master-on-robotc-for-arduino/#comment-2674
Now look at the bit patterns very closely.
Notice that as the for loop increases that the 0 bit keeps on moving to the left.
I will try not to confuse you too much right now, (there is another bitwise AND and a Left Shift operation in the i2c_write() function), the priority is to understand Boolean operations and how to use Python to assist you in understanding these Boolean operations. If you feel up to it, reverse engineer the i2c_write() function to see how the bit patterns are further processed before they are sent to the LED array.
In working with microcontrollers when a bit is high, having a 1 value, normally a device is turned on. If a bit is low, having a 0 value a device is turned off.
Notice that we are working with 8 bits and our LED array has 8 LED’s. Yes , that is correct. Every time we set a bit on, having a value of 1, we turn on the LED. When we set the bit value to 0 or set the bit off, we turn off the LED.
Now watch the video again. Now image that both for loops, one in the main function and the for loop in the i2c_write function are running as fast or faster than the LED’s are blinking.
The logic in the i2c_write() is performing a bit more complex logic, use python to visualize how the High or Low bit states are changing as the 8 bits are being stepped through in the for loop.
Please keep on learning about microcontrollers and Boolean operations, as these are the building blocks to programming microcontrollers.
Using I2C involves sending binary data to an address of a device that is listening for requests from the microcontroller, (master device) Once a request is received by the device, (slave) , the device sends either one or more bytes of data back to the microcontroller.
In learning how to program communications to I2C devices or trying to reverse engineer data coming from I2C devices you have to look at the data in it’s binary form.
I will provide you an easy example of how to do this using the methods you have just learned.
In learning I2C it is often wise to study other programs programmers have written so you can lean how data is passed between microcontrollers and devices.
So for our example we will look at a program snippet of some RobotC code written to bit bang an I2C device.
I have taken a sample bit banged C program written in RobotC by Xander who maintains a Robot Blog called:
http://botbench.com/blog/2011/02/20/bit-banged-i2c-master-on-robotc-for-arduino/#comment-2674
In this blog article he is bit banging an I2C program to communicate with a LED array to flash LED lights in a sequence.
We will reverse engineer the for loop he is using to send a series of bits to the LED array.
If you have never programmed before, please Google variables, for loop, functions and while loops.
Here is the code snippet we will be looking at:
while (true) {
for (int i = 0; i < 8; i++) {
PCF8574write(~(1<<i));
wait1Msec(50);
}
}
Normally I would write a small Python program to print out the values of the for loop. But since I am assuming everyone is new to programming and Boolean logic I will manually type out each iteration of the for loop.
Special Note: Python does not support a byte data type, so in our bit banging example we are going to use the modulo operator to display an integer as an unsigned byte. Please Google inf you need assistance,
For Example: If we perform the the following example: >>> ~(1 <<0), in Python we get -2, If we then use >>> bin(-2), we get '-0b10'. To correct the problem and show a full 8 bits type in the following:
>>> bin(-2 % 256)
'0b11111110'
In order to properly see what is going on with bits we need to see the full 8 bits.
The While is looping forever, ignore this for now.
The for loop loops where the variable i is equal from 0 to 7.
PCF8574write() is a custom function that we will not discuss as part of this article. You can refer to the code to see what this function does on your own.
What we are interested in is the value of i and what binary number we pass to the PCF8574write() function.
Lets translate each iteration of the for loop:
Lets type out each iteration of the loop in Python:
The variable i starts out as 0 and ends up at a value of 7:
>>> ~(1<<0)
-2
Lets pull this expression apart. We are performing a bitwise NOT on the following value. We Left Shift the value of 1, i times.
That is we NOT 1 << 0. We are pushing bits from right to left,.In the first loop we are Left Shifting 1, 0 times, or we NOT the most significant bit.
So if we look at the binary value of -2 we get:
>>> bin(~(1<<0))
‘0b10’
Lets continue, you will soon see the pattern.
>>> ~(1<<0)
-2
>>> bin(-2 % 256)
‘-0b11111110’
>>>~(1<<1)
-3
>>> bin(-3 % 256)
‘-0b11111101’
>>> ~(1<<2)
-5
>>> bin(-5 % 256)
‘-0b11111011’
>>> ~(1<<3)
-9
>>> bin(-9 % 256)
‘-0b11110111’
>>> ~(1<<4)
-17
>>> bin(-17 % 256)
‘-0b11101111’
>>> ~(1<<5)
-33
>>> bin(-33 % 256)
‘-0b11011111’
>>> ~(1<<6)
-65
>>> bin(-65 % 256)
‘0b10111111’
>>> ~(1<<7)
-129
>>> bin(-129 % 256)
‘-0b1111111’
The leading 0 is omitted in this case.
It should read '-0b01111111'
Now if you have not done so already, go to the web page and watch the video:
http://botbench.com/blog/2011/02/20/bit-banged-i2c-master-on-robotc-for-arduino/#comment-2674
Now look at the bit patterns very closely.
Notice that as the for loop increases that the 0 bit keeps on moving to the left.
I will try not to confuse you too much right now, (there is another bitwise AND and a Left Shift operation in the i2c_write() function), the priority is to understand Boolean operations and how to use Python to assist you in understanding these Boolean operations. If you feel up to it, reverse engineer the i2c_write() function to see how the bit patterns are further processed before they are sent to the LED array.
In working with microcontrollers when a bit is high, having a 1 value, normally a device is turned on. If a bit is low, having a 0 value a device is turned off.
Notice that we are working with 8 bits and our LED array has 8 LED’s. Yes , that is correct. Every time we set a bit on, having a value of 1, we turn on the LED. When we set the bit value to 0 or set the bit off, we turn off the LED.
Now watch the video again. Now image that both for loops, one in the main function and the for loop in the i2c_write function are running as fast or faster than the LED’s are blinking.
The logic in the i2c_write() is performing a bit more complex logic, use python to visualize how the High or Low bit states are changing as the 8 bits are being stepped through in the for loop.
Please keep on learning about microcontrollers and Boolean operations, as these are the building blocks to programming microcontrollers.