I/O expander driver construction

For PCA8574, we are going to create a separate file, named PCA8574.py, that includes all the driver capabilities and functions for the I/O expander. We are going to use the PCA8574 class specification from the design of our RGB pushbutton application to guide our driver construction.

The first step is to create our class definition and constructor. The class will be named PCA8574_IO so that we have a little description as to what that chip actually is. The class initialization requires two pieces of information: an object that represents the initialized I2C bus and the slave address of PCA8574. This class can be instantiated multiple times for different addresses if we have more than one device connected to our application. The class definition and initialization is as follows:

class Pca8574_Io:

def __init__(self, i2c_object, slave_address):
assert slave_address < 256, "Slave Address >= 256!"

self.Address = slave_address
self.I2C = i2c_object

Notice that I am also using assert to check that the SlaveAddress parameter is within the design address ranges of 0-255. Assertions are good to include during your software development phase. An assertion is basically a sanity check that, at a specific point in a program, checks that the conditions are as you expect them to be. If they are not, then there is a bug in the application. Assertions are normally turned off prior to the final validation testing for production.

Once the class is defined, we need to implement our two methods: read and write. These methods allow our application to interact directly with the PCA8574 I/O expander chip. In the implementation, we will wrap our attempts to write and read from the I2C bus in a try/except block. The try/except block is the equivalent of the C++ try/catch statement. Basically, we are telling the code that we are going to try something and we want to watch for any errors that occur and, if they do occur, that we want to respond accordingly. In our code, we are going to use generic except cases that catch any error and just print a message that an error occurred. In general, Python coding standards don't like us to have all-encompassing except cases, but we are going to do it for now because handling errors will be left to you to investigate on your own.

The implementation of the read method is as follows:

def read(self):
try:
return ord(self.I2C.recv(1, self.Address))
except:
print("Unable to retrieve I/O status")
return 0xFF

There are several interesting points that you may notice about this code. First, we are using the MicroPython I2C library recv method to receive data from the I2C bus. The 1 numeral is telling the driver that we want to receive one byte of data from the bus at the self.Address address. The ord function is used to convert the byte that is received into an ordinal number.

The implementation of the write function is as follows:

def write(self, state):
assert state < 256, "State >= 256"
try:
self.I2C.send(state, self.Address)
except:
print("Unable to set I/O state")

Again, we are using an assertion here to test that the parameters passed from the higher-level application are meeting our requirements for this function: that the state is to be less than 256.

Now that we have implemented our I/O expander driver, let's construct the driver for driving the LEDs.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.19.31.73