Multiple buttons lighting multiple leds
The IO Pi Plus is a 32 channel MCP23017 GPIO expander for the Raspberry Pi
06/06/2017
Posted by:
TonyE
06/06/2017
Posted by:
andrew
The simplest way to do this with an IO Pi Plus would be to connect the buttons to the bus on one chip and the LEDs to the bus on the second chip with the led pins matching the button pins, so Button 1 connects to bus 1 pin 1 while LED 1 connects to bus 2 pin 1. You can then use a loop to read the values from the two ports on bus 1 and write them to the ports on bus 2.
For each button, you will need to connect the input to the button to 5V and the output to bus 1 on the IO Pi. You may also need a pull-down resistor connected between the button output and ground to make sure the voltage drops to 0V when the button is released. A 10K resistor should do the job. Without a pull-down resistor the input on the IO Pi Plus would be floating which means if there is any stray capacitance in the wire it could cause the input to be read as high or low.
The code below should do what you need.
from ABE_helpers import ABEHelpers
from ABE_IoPi import IoPi
i2c_helper = ABEHelpers()
i2c_bus = i2c_helper.get_smbus()
# create the two buses
bus1 = IoPi(i2c_bus, 0x20)
bus2 = IoPi(i2c_bus, 0x21)
# set bus 1 to be inputs
bus1.set_port_direction(0, 0xFF)
bus1.set_port_direction(1, 0xFF)
# set bus 2 to be outputs and turn all of the pins off
bus2.set_port_direction(0, 0x00)
bus2.set_port_direction(1, 0x00)
bus2.write_port(0, 0x00)
bus2.write_port(1, 0x00)
port0val = 0x00
port1val = 0x00
while True:
port0val = bus1.read_port(0)
port1val = bus1.read_port(1)
bus2.write_port(0, port0val)
bus2.write_port(1, port1val)
07/06/2017
Posted by:
TonyE
07/06/2017
Posted by:
andrew
You can stack up to 4 IO Pi Plus boards on a Raspberry Pi so you could have up to 64 buttons and LEDs connected. You just need to change the solder bridges on the address select pads to give each board a different pair of addresses.
One thing to note is the maximum current the IO controller chip can source is 125mA so if you have 16 LEDs connected and being lit at the same time you would only be able to safely drive 7.8mA to each LED. If you use lower current LEDs and 680R resistors this would keep the total current below the 125mA maximum. Alternatively, you could use external transistors or Darlington arrays to drive higher-current LEDs.
31/08/2017
Posted by:
TonyE
After some delayI have set up my initial system (16 buttons & 16 LEDs) but didn't get the response I expected.
The IO Plus is powered from a separate power supply (solder link removed) and the set up is
5V from board -> input of button; output of button -> 10k resistor -> pin on bus 1
Output of bus 2 -> LED -> resistor -> GND on board
When I run the program all the LEDs light and the buttons do nothing.
I'm sure I must have made a mistake with the wiring somewhere. Can you help?
Regards
Tony
31/08/2017
Posted by:
andrew
With the inputs do you have the internal pull-up resistors enabled? If you have the input of the button connected to 5V you will need to disable the internal pull-ups and use a 10K resistor to connect each button output to ground to act as a pull-down. Without a pull-down resistor the inputs will be floating which means after a button press they may stay high or alternate between high and low due to the internal capacitance on the input lines.
31/08/2017
Posted by:
TonyE
can you remind me how I disable the internal pull up resistors please?
Regards
Tony
31/08/2017
Posted by:
andrew
bus1.set_port_pullups(0,0)
bus1.set_port_pullups(1,0)
bus2.set_port_pullups(0,0)
bus2.set_port_pullups(1,0)
31/08/2017
Posted by:
TonyE
thanks for your response. I added the set.port_pullups statements just before the while True: in the program you suggested I use at the beginning of this string.
Then, by mistake, I lost power to the Raspberry Pi. All the LEDs remained on with no power on rhe R Pi! I'm sure I have done something wrong as the IO Pi Plus still responds to the tutorials I used when I first set it up.
Help!
Regards
Tony
31/08/2017
Posted by:
andrew
The picture below shows the two ways you can connect inputs to the IO Pi Plus.
The 5V input option should be how you have the inputs wired at the moment. In this mode, you will need to make sure the internal pull-up resistors are disabled.
If the button is connected to ground like in the second schematic then you need to enable the internal pull-up resistors and the inputs will show high when the button is open and go low when the button is pressed. You can get around this by using the invert_pin() or invert_port() methods in the python library to invert the inputs so 1 becomes 0 and 0 becomes 1. That way when you press the button and short the pin to ground it will register the input as going high.
The 1K and 500R resistor values are not critical as they are only there to limit the current being fed to and drawn from the IO Pi inputs in the event that the pins are accidentally set as outputs. As long as the resistors limit the current to less than 20mA it should be fine.
01/09/2017
Posted by:
TonyE
spent the evening modifying my breadboard prototype with 16 buttons and LEDs to match the set up you suggested and 'bingo!' it worked.
Once again thank you for the excellent technical support you provide. An example to all technical companies, many much larger than AB Electronics.
Regards
Tony
03/09/2017
Posted by:
TonyE
Now I have my led/button combination working, I want to modify the project to drive 16 solenoids from the IO Pi using this relay board
XSOURCE 12v 16 channel module shield board with opto coupler
i think Sainsmart do something very similar.
I cannot find any instructions anywhere and wondered if you could help or at least be able to point me to somewhere where I might find instructions.
Many thanks in advance,
Regards
Tony
03/09/2017
Posted by:
andrew
Looking at the photo of the relay board it looks like the cathode side of the LED is connected to the input pins. You would activate the relay by connecting the input to ground so you will need to use an NPN transistor to switch the inputs.
We have a tutorial in our knowledge base on driving relays from the IO Pi using a transistor, you should be able to use the same circuit but instead of connecting the collector on the transistor to the relay, you would connect it to the input on the relay board. This should then allow you to safely activate the optocoupler on the relay board without putting too much load on the IO Pi outputs.
03/09/2017
Posted by:
TonyE
once again, many thanks for your prompt help. I'll give it a try.
Regards
Tony
19/10/2017
Posted by:
TonyE
After a long pause I've set things up as you suggested in the tutorial and things are not working as I expected!
Ive a 12v relay board so presumably I can substitute 12v for 5v in the diagram. When I do this I cannot get the relay to trigger but each individual relay triggers if I connect the input pin to ground.
have I wired up something wrong do you think!
regards
tony
19/10/2017
Posted by:
andrew
Try connecting the cathode from the transistors to the inputs on the relay board and the anode to ground. When you power the transistor base from the IO Pi via a resistor it should short the relay input to ground, triggering the relay.
19/10/2017
Posted by:
TonyE
Ive tried your suggestion and all I get is the relay indicator led on the relay board flickering but the relay doesn't operate. I'm using the switch set up (switching to 5v) you mentioned 31/08/17 and assumed that cathode = emitter and anode = collector.
Regards
Tony
19/10/2017
Posted by:
andrew
19/10/2017
Posted by:
TonyE
Ive noticed that the LED light on the relay board is flickering irrespective of me pushing the button or not!
Regards
Tony
19/10/2017
Posted by:
andrew
What happens if you connect the transistors gate resistor directly to a 5V or GND input?
19/10/2017
Posted by:
TonyE
Ive connected the base to +5v via 470 ohm resistor, the emitter to the input pin on the relay and the collector to ground. Using either a separate power supply or the 5v output from the relay board, the relays operate as expected.
The 12v PS is very steady at 12v.
Could the problems be associated different earths? Should all the grounds (12v power supply, 5v power supply, ground on the relay board and ground on the io pi be all connected together?
Regards
Tony
19/10/2017
Posted by:
andrew
06/02/2018
Posted by:
TonyE
for a number of reasons I have not been able to work on this project. I have abandoned the relay board and am now using Darlington arrays. I’ve now wired these all up but the software you suggested I used to link the buttons and leds stops working.
l get the following
Traceback (most recent call last)
bus1 = IoPi(i2c_bus,0x20)
Self.portbval = self._bus.read_byte_data(self.address! self.GPIOB)
OSError:(Errno 121) Remote I/O error
Any suggestions?
Regards
Tony
06/02/2018
Posted by:
andrew
Does the error happen all the time or after the software has been running for a while? The Remote I/O error normally happens when something is blocking access to the I2C bus or the IO Pi library can not find the IO Pi. Do you have any other software running that would be making calls to the I2C bus?
When you run the command "sudo i2cdetect -y 1" does the IO Pi appear on address 0x20?
08/02/2018
Posted by:
TonyE
when I run the command I get a matrix (0 to f, 00 to 70) with 20 at the intersection of 20 and 0 & 21 at the intersection of 20 and 1.i presume this confirms the presence of the IO Pi.
i have the IOPi library in the same folder as the program and I don’t have any other software running that would call to i2c bus that I know of.
The IO Pi is running off an external 5V supply (solder bridge removed) but I only detect less than 2V at the Gnd and 5V pins on both Bus 1 and Bus 2. Would this suggest the IO Pi is faulty?
Regards
Tony
08/02/2018
Posted by:
andrew
If there is only 2V at the power input pins then that suggests there could be a problem with either the power supply not supplying enough voltage or the IO Pi is drawing too much current causing the voltage to drop.
Can you try measuring the amount of current the IO Pi is drawing by connecting your multimeter in current mode between the 5V wire from the power supply and the 5V pin on the IO Pi power connector? The IO Pi should only draw a few milliamps when none of the IO pins is set as outputs so if it is drawing a lot of current that would suggest that one or both of the IO chips are faulty. You could also try touching the chips to see if they are warm as that would also suggest a fault.
Also try checking the continuity between the ground output on your power supply and the ground pins on the Raspberry Pi GPIO connector, or the outside of the Ethernet or USB sockets, to make sure there is a good connection between the grounds on the two power supplies.
The fact that the IO chips are showing up on 0x20 and 0x21 I2C addresses suggest that they are working at least to some degree as faulty chips normally wouldn't show up on the I2C bus so it could be a power supply fault that is causing the problems. The MCP2317 IO chips will work from 1.8V to 5.5V so if your power supply is only providing 2V the chips would appear on the I2C bus but they would also only provide 2V on the output pins which may not be enough to drive your Darlington arrays.
If you are only using the IO Pi to drive Darlington arrays then it should be safe to use the Raspberry Pi to power the IO Pi instead of an external power supply. Darlington arrays like the ULN2003A should draw less than 2mA from each IO Pi output so it will put a minimal load on the Raspberry Pi's power supply.
08/02/2018
Posted by:
TonyE
the 5V is fed in from the 2 pin header and the measurements taken at the 16 pin header. The power supply is 5V, 3.8V stand alone unit.
I’ll check the power draw and the earth continuity tomorrow morning.
Regards
Tony
09/02/2018
Posted by:
TonyE
I traced the problem to a poor connection from my power supply to the IO Pi. One of the cables was faulty hence providing less than 2V. Once this was replaced, all is going to plan!
Until my next problem.......
Thank you so much for you help.
Regards
Tony
21/02/2018
Posted by:
TonyE
The project is growing! I'm now looking at 48 pins in and 48 pins out, so planning to buy further IO-Plus boards soon.
The project works in two ways. FIrstly taking inputs from buttons and using that input to light LEDs. This, I think I know waht I have to do to modify the code you sen me on 06/06/17.
The second part of the project is to take data from an external file with values thta will be fed into the following
bus2.write_pin(note_no, note_change)
note_no takes the value 1-16 and note_change the value 0 or 1
Howwever I want to utilise note_no values 1-48 across 3 busses (bus2, bus4 and bus6). note_no values 1-16 going to the pins on bus2, note_no values 17-32 going to bus4 and note_ no values 33-48 going to bus 6.
I'm not sure how to do this. Can you help?
Regards
Tony
22/02/2018
Posted by:
andrew
The easiest way to map the values to three buses would be to use a function which takes an input pin and state and uses a series of if statements to map it to the correct pin.
The code below should do what you need.
def update_output_pin(pin, state, bus2, bus4, bus6):
'''
Update the output pin for busses 2, 4 and 6 based on an input value of 1 to 48
'''
if state is 0 or state is 1:
if pin >= 1 and pin <= 16:
bus2.write_pin(pin, state)
elif pin >= 17 and pin <= 32:
pinval = pin - 16
bus4.write_pin(pinval, state)
elif pin >= 33 and pin <= 48:
pinval = pin - 32
bus6.write_pin(pinval, state)
else:
print("pin out of range")
else:
print("state out of range")
def main():
'''
Main program function
'''
# Create 6 instances of the IOPi class with an I2C address of 0x20 to 0x25
iobus1 = IOPi(0x20)
iobus2 = IOPi(0x21)
iobus3 = IOPi(0x22)
iobus4 = IOPi(0x23)
iobus5 = IOPi(0x24)
iobus6 = IOPi(0x25)
# Busses 1, 3 and 5 will be inputs
iobus1.set_port_direction(0, 0xFF)
iobus1.set_port_direction(1, 0xFF)
iobus3.set_port_direction(0, 0xFF)
iobus3.set_port_direction(1, 0xFF)
iobus5.set_port_direction(0, 0xFF)
iobus5.set_port_direction(1, 0xFF)
# Busses 2, 4 and 6 will be outputs with the pins initially set to 0
iobus2.set_port_direction(0, 0x00)
iobus2.set_port_direction(1, 0x00)
iobus2.write_port(0, 0x00)
iobus2.write_port(1, 0x00)
iobus4.set_port_direction(0, 0x00)
iobus4.set_port_direction(1, 0x00)
iobus4.write_port(0, 0x00)
iobus4.write_port(1, 0x00)
iobus6.set_port_direction(0, 0x00)
iobus6.set_port_direction(1, 0x00)
iobus6.write_port(0, 0x00)
iobus6.write_port(1, 0x00)
while True:
# count to 48 and and set the pin state high for each pin in turn
for val in range(1, 48):
time.sleep(0.05)
update_output_pin(val, 1, iobus2, iobus4, iobus6)
# count to 48 and and set the pin state low for each pin in turn
for val in range(1, 48):
time.sleep(0.05)
update_output_pin(val, 0, iobus2, iobus4, iobus6)
if __name__ == "__main__":
main()
The update_output_pin(pin, state, bus2, bus4, bus6) function takes the pin number between 1 and 48, the state and the three busses which will be used for outputs.
In the main function, I created 6 instances of the IO Pi class with the i2c addresses 0x20 to 0x25 and set busses 1, 3 and 5 as inputs and 2, 4 and 6 as outputs. The while loop at the bottom contains some for loops that will switch each pin on in turn and then switch them off again in turn. In your program, you would replace the for loops with your code to read from the text file.
22/02/2018
Posted by:
TonyE
Brilliant! Thank you.
Regards
Tony
21/01/2019
Posted by:
TonyE
This has been an intermittent project!
I now have 3 IO Pi Plus cards stacked on top of one another and propose to remove the link from each one so that they are all externally powered. I presume I therefore need to connect the 5V & GND (separate in its own white box between Bus 1 & Bus 2) on each board to a power supply. If so i presume there is a 2 pin equivalent of the 40 pin header I can buy. I’ve tried searching but not sure what to call it!!
Can you help?
Regards
Tony
21/01/2019
Posted by:
andrew
If you are using external power then you will need to connect all of the IO Pi Plus boards together using the 5V and GND pins.
I don't think there is a 2-pin version of the 40-pin header available but the 40-pin header is the same height as the single-row headers that are used on Arduino boards. We sell a 6-pin and 8-pin version which could be cut down to be 2 pins wide.
On the IO Pi Plus, the power connector has holes for 2.54mm and 5.08mm connectors so if you could find a 3-pin version of the Arduino stackable headers you could remove the middle pin and solder it in the 5.08mm holes.
The other alternative is to use a 5mm pitch screw terminal and join the boards together using wires.
21/01/2019
Posted by:
TonyE
Further to my earlier enquiry........
Can I use your 6 pin stackable header and clip off 4 of the legs?
Alternatively can I supply power via the 5V & GND on one or both of the 20 pin headers?
Regards
Tony
21/01/2019
Posted by:
andrew
You can clip off four of the legs on the 6-way connector and use that to power the board. The 5V and GND on the 20-pin headers are connected to the 5V and GND power header so you can supply power through either or both of the 20-pin connectors.
13/05/2021
Posted by:
TonyE
I hope you are well.
Since we last spoke my project is going well but I have come upon a problem of my own making!
This is project to create a computer conrolled 42 strong recorder ensemble (remember them from school!).
I have 3 IO Pi Plus boards on a Raspberry Pi 4. The outputs from the IO Pi PLus run to Darlington arrays which will drive relays opening valves to allow air into the individual recorders. I strip MIDI files to give me the data to create tunes and then this is fed through to the valves via the IO Pi Plus. This tests well driving LEDs at the moment before building the final recorder organ (Recorgan!)
After an SD card corruption I rebuilt the Pi operating system and reinstalled my software. During this process I removed the 3 IO Pi PLus cards on block from the Pi4 and unfortunately replaced them out of line and then powered up. There were pins exposed down the right hand side of the Pi 4. The IO PI Plus cards were moved 2-3mm to the left (looking at the Pi from the USB/ethernet end)
Thi Pi 4 seems to be working OK but sudo i2cdetect -y 1 shows the i2c matrix but unpopulated. Is there a way back form this?
Regards
Tony
13/05/2021
Posted by:
andrew
I am afraid that when you connected the IO Pi Plus boards out of line you may have damaged the I2C bus on your Raspberry Pi or the IO Pi boards.
Moving them one pin to the left would have connected the 5V on the Raspberry Pi GPIO header to the ground pin on the IO Pi which may have fed the 5V back through the IO chips into the I2C SDA pin on the Raspberry Pi. It would have also connected the 5V to pins 7 (GPIO4), 12 (GPIO18), 18 (GPIO 24), 23 (SCLK), 28 (ID_SCK), 32 (GPIO 12) and 37 (GPIO26) so you may have also damaged several other GPIO pins on your Raspberry Pi.
Do you have a spare Raspberry Pi you could use to test the IO Pi Plus boards? It is possible that the IO Pi boards survived as they are designed to operate at 5V but I have never tried connecting them backwards so I can't say for certain if they have been damaged.
You could try connecting the IO Pi Plus boards one at a time to see if they appear on i2cdetect just in case it is one of the boards that died but there is a good chance that it is the Raspberry Pi that has failed.
13/05/2021
Posted by:
TonyE
Thank you for your fast response.
I have a Pi 3 which I have been using to test out other i2c devices. This is connected to a BMP 280. I swapped the two Pi s over and the BMP 280 worked fine on the Pi 4, suggesting that this is fine. I tookm the IO PLus cards one at a time on the Pi 4 and it found 2 of the cards but not the third on i2cdetect. So two out of three survived my error! It looks as if I will be in the market for another IO Pi Plus board!
Regards
Tony
Note: documents in Portable Document Format (PDF) require Adobe Acrobat Reader 5.0 or higher to view.
Download Adobe Acrobat Reader or other PDF reading software for your computer or mobile device.