Ekspander 2x8bit I2C MCP23017
Posted: 26 October 2016, 21:19 - Wed
Tym razem zajmiemy się dość popularnym ekspanderem 16 bitowym (2x8bit) MCP23017, który to ze względu na swoje możliwości znacznie przewyższa omawiany już wcześniej PCF8574. Mimo iż MCP23017 posiada w swojej strukturze aż 21 rejestrów, jego sterowanie wcale nie jest skomplikowane a w przypadku prostych adaptacji wręcz sprowadza się do kilku linijek kodu. Niestety nie posiadam gotowego modułu, postanowiłem zatem zmontować coś na szybko:
Jest to typowa najprostsza aplikacja, Ze schematu można wyczytać, że układ będzie znajdował się pod adresem bazowym 0x20 (A0 = A1 = A2 = GND). Należy też pamiętać o podciągnięciu pinu RESET (rezystor 1k) oraz ograniczeniu prądu diod LED (300 ohm). Oczywiście, w naszych dalszych projektach można użyć drugiego portu (np jako wejściowego) oraz sygnałów przerwań (by np. nasz CT zareagował na zmiany na porcie). Na potrzeby naszego tutoriala wystarczy nam informacja, że układ MCP23017 będzie pracował w trybie domyślnym (IOCON.BANK = 0), czyli rejestry od obu portów poukładane są zamiennie jeden po drugim... po szczegóły odsyłam do serwisówki (str. 17). A oto masz krótki program:
Program zwyczajnie zapisuje (po wcześniejszym ustawieniu w trym wyjściowy) kolejne wartości binarne do rejestru OLATA (Output Latch PortA) co skutkuje zapalaniem się i gaszeniem poszczególnych diod LED:
Obsługa wejścia i wyjścia jednocześnie
Rozbudujmy nasz układ o włącznik astabilny (mikroswitch), który pozwoli nam kontrolować przebieg programu. Do ostatniej linii GPIO portu B dołączmy nasz mikroswitch a jego drugą końcówkę dołączmy do masy układu. Warto zadbać o podciągnięcie (pullup) GPB8 do zasilania przez rezystor ograniczający (1k). Można użyć wewnętrznego rejestru GPPULB i użyć do tego celu rezystorów zawartych w układzie. Ja zdecydowałem się na użycie rezystora zewnętrznego.
Mało kto wie, ale jest możliwość jednoczesego używania GPIO jako wejścia i wyjścia.. ale o tym następnym razem...
Jest to typowa najprostsza aplikacja, Ze schematu można wyczytać, że układ będzie znajdował się pod adresem bazowym 0x20 (A0 = A1 = A2 = GND). Należy też pamiętać o podciągnięciu pinu RESET (rezystor 1k) oraz ograniczeniu prądu diod LED (300 ohm). Oczywiście, w naszych dalszych projektach można użyć drugiego portu (np jako wejściowego) oraz sygnałów przerwań (by np. nasz CT zareagował na zmiany na porcie). Na potrzeby naszego tutoriala wystarczy nam informacja, że układ MCP23017 będzie pracował w trybie domyślnym (IOCON.BANK = 0), czyli rejestry od obu portów poukładane są zamiennie jeden po drugim... po szczegóły odsyłam do serwisówki (str. 17). A oto masz krótki program:
Code: Select all
import smbus
import time
'''
CONTROL REGISTER SUMMARY (IOCON.BANK = 0)
Register Address 7bit 6bit 5bit 4bit 3bit 2bit 1bit 0bit POR/RST
---------------------------------------------------------------------------------------------
IODIRA 0x00 IO7 IO6 IO5 IO4 IO3 IO2 IO1 IO0 1111 1111
IODIRB 0x01 IO7 IO6 IO5 IO4 IO3 IO2 IO1 IO0 1111 1111
IPOLA 0x02 IP7 IP6 IP5 IP4 IP3 IP2 IP1 IP0 0000 0000
IPOLB 0x03 IP7 IP6 IP5 IP4 IP3 IP2 IP1 IP0 0000 0000
GPINTENA 0x04 GPINT7 GPINT6 GPINT5 GPINT4 GPINT3 GPINT2 GPINT1 GPINT0 0000 0000
GPINTENB 0x05 GPINT7 GPINT6 GPINT5 GPINT4 GPINT3 GPINT2 GPINT1 GPINT0 0000 0000
DEFVALA 0x06 DEF7 DEF6 DEF5 DEF4 DEF3 DEF2 DEF1 DEF0 0000 0000
DEFVALB 0x07 DEF7 DEF6 DEF5 DEF4 DEF3 DEF2 DEF1 DEF0 0000 0000
INTCONA 0x08 IOC7 IOC6 IOC5 IOC4 IOC3 IOC2 IOC1 IOC0 0000 0000
INTCONB 0x09 IOC7 IOC6 IOC5 IOC4 IOC3 IOC2 IOC1 IOC0 0000 0000
IOCON 0x0A BANK MIRROR SEQOP DISSLW HAEN ODR INTPOL - 0000 0000
IOCON 0x0B BANK MIRROR SEQOP DISSLW HAEN ODR INTPOL - 0000 0000
GPPUA 0x0C PU7 PU6 PU5 PU4 PU3 PU2 PU1 PU0 0000 0000
GPPUB 0x0D PU7 PU6 PU5 PU4 PU3 PU2 PU1 PU0 0000 0000
INTFA 0x0E INT7 INT6 INT5 INT4 INT3 INT2 INT1 INTO 0000 0000
INTFB 0x0F INT7 INT6 INT5 INT4 INT3 INT2 INT1 INTO 0000 0000
INTCAPA 0x10 ICP7 ICP6 ICP5 ICP4 ICP3 ICP2 ICP1 ICP0 0000 0000
INTCAPB 0x11 ICP7 ICP6 ICP5 ICP4 ICP3 ICP2 ICP1 ICP0 0000 0000
GPIOA 0x12 GP7 GP6 GP5 GP4 GP3 GP2 GP1 GP0 0000 0000
GPIOB 0x13 GP7 GP6 GP5 GP4 GP3 GP2 GP1 GP0 0000 0000
OLATA 0x14 OL7 OL6 OL5 OL4 OL3 OL2 OL1 OL0 0000 0000
OLATB 0x15 OL7 OL6 OL5 OL4 OL3 OL2 OL1 OL0 0000 0000
---------------------------------------------------------------------------------------------
CONTROL REGISTER SUMMARY (IOCON.BANK = 1)
Register Address 7bit 6bit 5bit 4bit 3bit 2bit 1bit 0bit POR/RST
---------------------------------------------------------------------------------------------
IODIRA 0x00 IO7 IO6 IO5 IO4 IO3 IO2 IO1 IO0 1111 1111
IPOLA 0x01 IP7 IP6 IP5 IP4 IP3 IP2 IP1 IP0 0000 0000
GPINTENA 0x02 GPINT7 GPINT6 GPINT5 GPINT4 GPINT3 GPINT2 GPINT1 GPINT0 0000 0000
DEFVALA 0x03 DEF7 DEF6 DEF5 DEF4 DEF3 DEF2 DEF1 DEF0 0000 0000
INTCONA 0x04 IOC7 IOC6 IOC5 IOC4 IOC3 IOC2 IOC1 IOC0 0000 0000
IOCON 0x05 BANK MIRROR SEQOP DISSLW HAEN ODR INTPOL - 0000 0000
GPPUA 0x06 PU7 PU6 PU5 PU4 PU3 PU2 PU1 PU0 0000 0000
INTFA 0x07 INT7 INT6 INT5 INT4 INT3 INT2 INT1 INTO 0000 0000
INTCAPA 0x08 ICP7 ICP6 ICP5 ICP4 ICP3 ICP2 ICP1 ICP0 0000 0000
GPIOA 0x09 GP7 GP6 GP5 GP4 GP3 GP2 GP1 GP0 0000 0000
OLATA 0x0A OL7 OL6 OL5 OL4 OL3 OL2 OL1 OL0 0000 0000
IODIRB 0x10 IO7 IO6 IO5 IO4 IO3 IO2 IO1 IO0 1111 1111
IPOLB 0x11 IP7 IP6 IP5 IP4 IP3 IP2 IP1 IP0 0000 0000
GPINTENB 0x12 GPINT7 GPINT6 GPINT5 GPINT4 GPINT3 GPINT2 GPINT1 GPINT0 0000 0000
DEFVALB 0x13 DEF7 DEF6 DEF5 DEF4 DEF3 DEF2 DEF1 DEF0 0000 0000
INTCONB 0x14 IOC7 IOC6 IOC5 IOC4 IOC3 IOC2 IOC1 IOC0 0000 0000
IOCON 0x15 BANK MIRROR SEQOP DISSLW HAEN ODR INTPOL - 0000 0000
GPPUB 0x16 PU7 PU6 PU5 PU4 PU3 PU2 PU1 PU0 0000 0000
INTFB 0x17 INT7 INT6 INT5 INT4 INT3 INT2 INT1 INTO 0000 0000
INTCAPB 0x18 ICP7 ICP6 ICP5 ICP4 ICP3 ICP2 ICP1 ICP0 0000 0000
GPIOB 0x19 GP7 GP6 GP5 GP4 GP3 GP2 GP1 GP0 0000 0000
OLATB 0x1A OL7 OL6 OL5 OL4 OL3 OL2 OL1 OL0 0000 0000
'''
bus = smbus.SMBus(1)
ADDRESS = 0x20
IODIRA = 0x00 # IO Direction PortA
OLATA = 0x14 # Output Latch PortA
GPIOA = 0x12 # Output Latch PortA
# Set all GPA pins as outputs by setting
# all bits of IODIRA register to 0
bus.write_byte_data(ADDRESS,IODIRA,0x00)
# Set output all 7 output bits to 0
bus.write_byte_data(ADDRESS,OLATA,0)
for x in range(1,256):
bus.write_byte_data(ADDRESS,OLATA,x)
print "POTRA:",x
time.sleep(.1)
# After while - switch off PORTA
bus.write_byte_data(ADDRESS,OLATA,0)
print "POTRA: 0"
Obsługa wejścia i wyjścia jednocześnie
Rozbudujmy nasz układ o włącznik astabilny (mikroswitch), który pozwoli nam kontrolować przebieg programu. Do ostatniej linii GPIO portu B dołączmy nasz mikroswitch a jego drugą końcówkę dołączmy do masy układu. Warto zadbać o podciągnięcie (pullup) GPB8 do zasilania przez rezystor ograniczający (1k). Można użyć wewnętrznego rejestru GPPULB i użyć do tego celu rezystorów zawartych w układzie. Ja zdecydowałem się na użycie rezystora zewnętrznego.
Code: Select all
import smbus
import time
'''
CONTROL REGISTER SUMMARY (IOCON.BANK = 0)
Register Address 7bit 6bit 5bit 4bit 3bit 2bit 1bit 0bit POR/RST
---------------------------------------------------------------------------------------------
IODIRA 0x00 IO7 IO6 IO5 IO4 IO3 IO2 IO1 IO0 1111 1111
IODIRB 0x01 IO7 IO6 IO5 IO4 IO3 IO2 IO1 IO0 1111 1111
IPOLA 0x02 IP7 IP6 IP5 IP4 IP3 IP2 IP1 IP0 0000 0000
IPOLB 0x03 IP7 IP6 IP5 IP4 IP3 IP2 IP1 IP0 0000 0000
GPINTENA 0x04 GPINT7 GPINT6 GPINT5 GPINT4 GPINT3 GPINT2 GPINT1 GPINT0 0000 0000
GPINTENB 0x05 GPINT7 GPINT6 GPINT5 GPINT4 GPINT3 GPINT2 GPINT1 GPINT0 0000 0000
DEFVALA 0x06 DEF7 DEF6 DEF5 DEF4 DEF3 DEF2 DEF1 DEF0 0000 0000
DEFVALB 0x07 DEF7 DEF6 DEF5 DEF4 DEF3 DEF2 DEF1 DEF0 0000 0000
INTCONA 0x08 IOC7 IOC6 IOC5 IOC4 IOC3 IOC2 IOC1 IOC0 0000 0000
INTCONB 0x09 IOC7 IOC6 IOC5 IOC4 IOC3 IOC2 IOC1 IOC0 0000 0000
IOCON 0x0A BANK MIRROR SEQOP DISSLW HAEN ODR INTPOL - 0000 0000
IOCON 0x0B BANK MIRROR SEQOP DISSLW HAEN ODR INTPOL - 0000 0000
GPPUA 0x0C PU7 PU6 PU5 PU4 PU3 PU2 PU1 PU0 0000 0000
GPPUB 0x0D PU7 PU6 PU5 PU4 PU3 PU2 PU1 PU0 0000 0000
INTFA 0x0E INT7 INT6 INT5 INT4 INT3 INT2 INT1 INTO 0000 0000
INTFB 0x0F INT7 INT6 INT5 INT4 INT3 INT2 INT1 INTO 0000 0000
INTCAPA 0x10 ICP7 ICP6 ICP5 ICP4 ICP3 ICP2 ICP1 ICP0 0000 0000
INTCAPB 0x11 ICP7 ICP6 ICP5 ICP4 ICP3 ICP2 ICP1 ICP0 0000 0000
GPIOA 0x12 GP7 GP6 GP5 GP4 GP3 GP2 GP1 GP0 0000 0000
GPIOB 0x13 GP7 GP6 GP5 GP4 GP3 GP2 GP1 GP0 0000 0000
OLATA 0x14 OL7 OL6 OL5 OL4 OL3 OL2 OL1 OL0 0000 0000
OLATB 0x15 OL7 OL6 OL5 OL4 OL3 OL2 OL1 OL0 0000 0000
---------------------------------------------------------------------------------------------
CONTROL REGISTER SUMMARY (IOCON.BANK = 1)
Register Address 7bit 6bit 5bit 4bit 3bit 2bit 1bit 0bit POR/RST
---------------------------------------------------------------------------------------------
IODIRA 0x00 IO7 IO6 IO5 IO4 IO3 IO2 IO1 IO0 1111 1111
IPOLA 0x01 IP7 IP6 IP5 IP4 IP3 IP2 IP1 IP0 0000 0000
GPINTENA 0x02 GPINT7 GPINT6 GPINT5 GPINT4 GPINT3 GPINT2 GPINT1 GPINT0 0000 0000
DEFVALA 0x03 DEF7 DEF6 DEF5 DEF4 DEF3 DEF2 DEF1 DEF0 0000 0000
INTCONA 0x04 IOC7 IOC6 IOC5 IOC4 IOC3 IOC2 IOC1 IOC0 0000 0000
IOCON 0x05 BANK MIRROR SEQOP DISSLW HAEN ODR INTPOL - 0000 0000
GPPUA 0x06 PU7 PU6 PU5 PU4 PU3 PU2 PU1 PU0 0000 0000
INTFA 0x07 INT7 INT6 INT5 INT4 INT3 INT2 INT1 INTO 0000 0000
INTCAPA 0x08 ICP7 ICP6 ICP5 ICP4 ICP3 ICP2 ICP1 ICP0 0000 0000
GPIOA 0x09 GP7 GP6 GP5 GP4 GP3 GP2 GP1 GP0 0000 0000
OLATA 0x0A OL7 OL6 OL5 OL4 OL3 OL2 OL1 OL0 0000 0000
IODIRB 0x10 IO7 IO6 IO5 IO4 IO3 IO2 IO1 IO0 1111 1111
IPOLB 0x11 IP7 IP6 IP5 IP4 IP3 IP2 IP1 IP0 0000 0000
GPINTENB 0x12 GPINT7 GPINT6 GPINT5 GPINT4 GPINT3 GPINT2 GPINT1 GPINT0 0000 0000
DEFVALB 0x13 DEF7 DEF6 DEF5 DEF4 DEF3 DEF2 DEF1 DEF0 0000 0000
INTCONB 0x14 IOC7 IOC6 IOC5 IOC4 IOC3 IOC2 IOC1 IOC0 0000 0000
IOCON 0x15 BANK MIRROR SEQOP DISSLW HAEN ODR INTPOL - 0000 0000
GPPUB 0x16 PU7 PU6 PU5 PU4 PU3 PU2 PU1 PU0 0000 0000
INTFB 0x17 INT7 INT6 INT5 INT4 INT3 INT2 INT1 INTO 0000 0000
INTCAPB 0x18 ICP7 ICP6 ICP5 ICP4 ICP3 ICP2 ICP1 ICP0 0000 0000
GPIOB 0x19 GP7 GP6 GP5 GP4 GP3 GP2 GP1 GP0 0000 0000
OLATB 0x1A OL7 OL6 OL5 OL4 OL3 OL2 OL1 OL0 0000 0000
'''
bus = smbus.SMBus(1)
ADDRESS = 0x20
# Settings for IOCON.BANK = 0
IODIRA = 0x00 # IO Direction PortA
OLATA = 0x14 # Output Latch PortA
IODIRB = 0x01 # IO Direction PortB
OLATB = 0x15 # Output Latch PortB
GPIOA = 0x12 # General Purpose Input/Output PortA
GPIOB = 0x13 # General Purpose Input/Output Portb
# Set all GPIOA pins as outputs by setting
# all bits of IODIRA register to 0
bus.write_byte_data(ADDRESS,IODIRA,0x00)
# Set output all 8 output bits to 0
bus.write_byte_data(ADDRESS,OLATA,0x00)
# Set all GPIOB pins as input.
bus.write_byte_data(ADDRESS,IODIRB,0xff)
while True:
for x in range(1,256):
bus.write_byte_data(ADDRESS,OLATA,x)
Switch = bus.read_byte_data(ADDRESS,GPIOB)
if Switch & 0b10000000 == 0b10000000:
print "POTRA:",x, "Switch is OFF"
else:
print "POTRA:",x, "Switch is ON"
time.sleep(.1)