maurice1
Posts: 39
Joined: Tue Mar 05, 2013 8:55 am
Location: Dublin

MCP23017, how to: 8 inputs and 8 outputs

Thu Sep 17, 2015 8:38 am

I wanted to get 8 inputs on Bank A to control 8 Relays on bank B
I am using 5.6 metres of catV cable without problems
Thanks to: DougieLawson, Davidjlittle, ericcnc, techpaul, rpmines, nathanchantrell for their inspiration

For this to work you need to make a folder mcp23017 under your pi folder and put
https://github.com/nathanchantrell/Pyth ... cp23017.py in it .

Code: Select all

import smbus
import sys
import os
import time

DEVICE = 0x20
bankA = 0x12
bankB = 0x13
delay = 1
bus = smbus.SMBus(1)

bus.write_byte_data(DEVICE,bankB,0xff) # set B7-B0 as output pins high 

def int_to_binary_bool(num):
        return [bool(int(i)) for i in "{0:08b}".format(num)]  

		
while True:
	bus.write_byte_data(DEVICE,0x00,0xff) # set A7-A0 as input pins                            
	bus.write_byte_data(DEVICE,0x01,0x00) # set B7-B0 as output pins
	bus.write_byte_data(DEVICE,0x0C,0xff) #Int pullup resistor on bankA		
	input = bus.read_byte_data(DEVICE,bankA)
	MY1 = int_to_binary_bool(input)  
	print
	
	A0 = MY1[0]  
	print "A0", A0 
	A1 = MY1[1]  
	print "A1", A1 
	A2 = MY1[2]  
	print "A2", A2 
	A3 = MY1[3]  
	print "A3", A3 
	A4 = MY1[4]  
	print "A4", A4 
	A5 = MY1[5]  
	print "A5", A5
	A6 = MY1[6]  
	print "A6", A6 
	A7 = MY1[7]  
	print "A7", A7
	 
	

	if A0 is False:
		os.system("/home/pi/mcp23017/mcp23017.py -b b -o 0 -s low") #BankB0 low
	if A0 is True:
		os.system("/home/pi/mcp23017/mcp23017.py -b b -o 0 -s high")#BankB0 high
	if A1 is False:
		os.system("/home/pi/mcp23017/mcp23017.py -b b -o 1 -s low")
	if A1 is True:
		os.system("/home/pi/mcp23017/mcp23017.py -b b -o 1 -s high")	
	if A2 is False:
		os.system("/home/pi/mcp23017/mcp23017.py -b b -o 2 -s low")
	if A2 is True:
		os.system("/home/pi/mcp23017/mcp23017.py -b b -o 2 -s high")	
	if A3 is False:
		os.system("/home/pi/mcp23017/mcp23017.py -b b -o 3 -s low")
	if A3 is True:
		os.system("/home/pi/mcp23017/mcp23017.py -b b -o 3 -s high")		
	if A4 is False:
		os.system("/home/pi/mcp23017/mcp23017.py -b b -o 4 -s low")
	if A4 is True:
		os.system("/home/pi/mcp23017/mcp23017.py -b b -o 4 -s high")	
	if A5 is False:
		os.system("/home/pi/mcp23017/mcp23017.py -b b -o 5 -s low")
	if A5 is True:
		os.system("/home/pi/mcp23017/mcp23017.py -b b -o 5 -s high")		
	

	if False in MY1:                                                                                             #pump
		os.system("/home/pi/mcp23017/mcp23017.py -b b -o 6 -s low")
	if False not in MY1:
		os.system("/home/pi/mcp23017/mcp23017.py -b b -o 6 -s high")	
	if False in MY1:                                                                                              #Boiler
		os.system("/home/pi/mcp23017/mcp23017.py -b b -o 7 -s low")   #BankB7 low
	if False not in MY1:
		os.system("/home/pi/mcp23017/mcp23017.py -b b -o 7 -s high")  #BankB7 high		
	time.sleep(delay)  

If thermostat A0 goes low, it will switch relays B0, B6 and B7 on.

I am sure this code could be written better but I am just learning.

I hope it saves someone some time

Massi
Posts: 1691
Joined: Fri May 02, 2014 1:52 pm
Location: Italy

Re: MCP23017, how to: 8 inputs and 8 outputs

Thu Sep 17, 2015 10:00 am

maurice1 wrote:

Code: Select all

os.system("/home/pi/mcp23017/mcp23017.py -b b -o 0 -s low")
damn, this is so ugly :(
a python script running another python script through a system call :(
why didn't you use one of the dozilion of classes to manage mcp23017?

scotty101
Posts: 3958
Joined: Fri Jun 08, 2012 6:03 pm

Re: MCP23017, how to: 8 inputs and 8 outputs

Thu Sep 17, 2015 10:37 am

Agreed! This should not be used as a good example of how to connect python to a MCP23017.
Electronic and Computer Engineer
Pi Interests: Home Automation, IOT, Python and Tkinter

Massi
Posts: 1691
Joined: Fri May 02, 2014 1:52 pm
Location: Italy

Re: MCP23017, how to: 8 inputs and 8 outputs

Thu Sep 17, 2015 11:39 am

even the logic is not that good:
- you are setting up the chip at every loop (a big waste of i2c calls)
- you can miss some input with that sleep (what if the input is shorter than 1 second?).

i haven't even understood the last part of the program..

Definitely I'd have used 1) a class to manage all 2) the interrupt pin of the MCP to avoid a lot of useless i2c calls

maurice1
Posts: 39
Joined: Tue Mar 05, 2013 8:55 am
Location: Dublin

Re: MCP23017, how to: 8 inputs and 8 outputs

Thu Sep 17, 2015 12:57 pm

Thankyou scotty101 and Massi for your replies.


As I mentioned "I am sure this code could be written better but I am just learning.", so I wasn't going for pretty code just one that works.

@ Massi"what if the input is shorter than 1 second?",
"If thermostat A0 goes low" is unlightly to change with in the 1 second as room temperature doesn't change that quick.


Perhaps as both of you find this code so "UGLY" , each of you would be kind enough to write pretty code that:

A1 going Low, energises B1 solonoid,+B6 pump,+B7 Boiler
A2 going Low, energises B2 solonoid,+B6 pump,+B7 Boiler
etc....

and that the code is easily readable....

User avatar
DougieLawson
Posts: 39182
Joined: Sun Jun 16, 2013 11:19 pm
Location: A small cave in deepest darkest Basingstoke, UK
Contact: Website Twitter

Re: MCP23017, how to: 8 inputs and 8 outputs

Thu Sep 17, 2015 9:48 pm

I'd do that with an array of desired states that you pass to a function to set those states (by OR'ing the value with the current GPIOB register) or resets the states (by AND'ing with 0xFF - the bit that needs to be reset).

Here's a piece of code to get you started with that logic

Code: Select all

#!/usr/bin/python

# (C) 2015 Copyright Dougie Lawson, All rights reserved
# Version 0.5

import smbus

ADDR = 0x20
IODIRA = 0x00
IODIRB = 0x01
GPIOA = 0x12
GPIOB = 0x13
OLATA = 0x14
OLATB = 0x15

bus=smbus.SMBus(1)

bus.write_byte_data(ADDR,IODIRA,0x00)
bus.write_byte_data(ADDR,IODIRB,0x00)
global valueA
global valueB
valueA=0
valueB=0

def pinOff(bank, pin):
#  print (bank,  pin, "== ON")
  global valueA
  global valueB
  bit = pin - 1
  if bank == 'top':
    valueB = valueB | (1 << bit)
    bus.write_byte_data(ADDR, OLATB, valueB)
  else:
    valueA = valueA | (1 << bit)
    bus.write_byte_data(ADDR, OLATA, valueA)

def pinOn(bank, pin):
#  print (bank, pin, "== OFF")
  global valueA
  global valueB
  bit = pin - 1
  if (bank == 'top'):
    valueB = valueB & (0xff - (1 << bit))
    bus.write_byte_data(ADDR, OLATB, valueB)
  else:
    valueA = valueA & (0xff - (1 << bit))
    bus.write_byte_data(ADDR, OLATA, valueA)

def pinStatus(bank, pin):
  global valueA
  global valueB
  bit = pin - 1
  if (bank == 'top'):
    state = ((valueB&(1<<bit))!=0)
  else:
    state = ((valueA&(1<<bit))!=0)
  return state

def pinAllOff():
#  print "All off called"
  global valueA
  global valueB
  valueA = 0xFF
  bus.write_byte_data(ADDR, OLATA, valueA)
  valueB = 0xFF
  bus.write_byte_data(ADDR, OLATB, valueB)
Note: it's currently set-up for "active low" because the relay board I was using had inverters on all eight channels.
Note: Any requirement to use a crystal ball or mind reading will result in me ignoring your question.

Criticising any questions is banned on this forum.

Any DMs sent on Twitter will be answered next month.
All non-medical doctors are on my foes list.

Return to “Interfacing (DSI, CSI, I2C, etc.)”