maurice1
Posts: 37
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: 3718
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: 37
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: 36105
Joined: Sun Jun 16, 2013 11:19 pm
Location: 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: Having anything humorous in your signature is completely banned on this forum. Wear a tin-foil hat and you'll get a ban.

Any DMs sent on Twitter will be answered next month.

This is a doctor free zone.

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