Search code examples
pythonhexgpioi2c

Hexadecimals to pysical variables in Python


I bought a MCP23017 for my Raspberry Pi to increase the GPIO pins.

enter image description here

With the help of you guys I was able to install and read from the device. That means, I've interfaced with the MCP23017 and set the bus to 0x20 as I have A0-A3 connected to ground. Then, I've set the GPA and GPB with pull-up resistors.

The script looks as follows:

import smbus
import time

mcp = 0x20

address_map = {
    0x12: 'GPIOA', 0x13: 'GPIOB',
}
register_map = {value: key for key, value in address_map.iteritems()}
max_len = max(len(key) for key in register_map)

def print_values(bus):
        for addr in address_map:
                value = bus.read_byte_data(mcp, addr)
                print "%-*s: 0x%02X" % (max_len, address_map[addr], value)

bus = smbus.SMBus(1)
bus.write_byte_data(mcp, int(12), 0xFF)
bus.write_byte_data(mcp, int(13), 0xFF)

while True:
    print_values(bus)
    time.sleep(0.1)

This will print out the GPA or GPB in Hex per bank, like so if nothing is connected:

>>> GPIOA = 0xFF
>>> GPIOB = 0xFF

But if I connect GPB0 to GND for example, it becomes:

>>> GPIOA = 0xFF
>>> GPIOB = 0xFE

So the question is, how can I from this Hex (0000 0000 1111 1110) to assigning a dictionary so that I can tell which pin is which?


Solution

  • You could use bitstruct.

    >>> GPIOA = 0xf0
    >>> gpa = list(reversed(bitstruct.unpack('b1'*8, chr(GPIOA))))
    >>> gpa
    [False, False, False, False, True, True, True, True]
    >>> gpa[3]
    False
    >>> gpa[4]
    True
    >>> GPIOA = 0x18
    >>> gpa = list(reversed(bitstruct.unpack('b1'*8, chr(GPIOA))))
    >>> gpa[5]
    False
    >>> gpa[4]
    True
    >>> gpa
    [False, False, False, True, True, False, False, False]
    

    This allows you to access the bits by index. Unfortunately, you have to reverse the resulting tuple for the indexes to be right, but it does work.

    There is also a manual way:

    >>> gpa = [False]*8
    >>> GPIOA = 0xf0
    >>> for i in range(8):
    ...     gpa[i] = bool((1 << i) & GPIOA)
    ... 
    >>> gpa
    [False, False, False, False, True, True, True, True]
    

    With either method, you can get it into a dictionary like this:

    >>> names = ['GPIOA0', 'GPIOA1', 'GPIOA2', 'GPIOA3', 'GPIOA4', 'GPIOA5', 'GPIOA6', 'GPIOA7']
    >>> gpadict = dict(zip(names, gpa))
    >>> gpadict
    {'GPIOA4': True, 'GPIOA5': True, 'GPIOA6': True, 'GPIOA7': True, 'GPIOA0': False, 'GPIOA1': False, 'GPIOA2': False, 'GPIOA3': False}