Details- Adding Relay Boards

Ribbon Cable Connections:

Now, for connecting the relay board hardware to the IO Pi Plus board. As for cables and connectors, I bought 20-wire ribbon cable locally. From Amazon. I bought “Antrader 20 Sets 2.54mm Pitch Connector FC-20 Pin Straight IDC Box Headers Connector Box Headers Female Connector”, 20 of ‘em for $7.00+, pictured above. The thinking, here, is that I have to mate up a 20-wire ribbon cable with two 10-pin relay boards, so I can use two 20-socket box headers separated along the ribbon cable, plug one on the relay board pins with the upper row , and plug the other relay board’s pins with the other header’s lower row. …make sense? …more about that later.

Allow plenty of room between connectors along the ribbon cable for being able to bridge the gap between cards. Just make sure you plug the upper row of one connector on one board and the lower row of the other connector on the other board. After testing, you can block the lower row of sockets on one and the upper on the other with a hot glue gun, but don’t do it until you’ve tested everything and make sure that the cables work. They might not work on the first try if you’re fumble-fingered like me.

For the relay boards, I bought four 8-SPDT relay boards from Robot Shop Inc, “8 Channel 5V Relay Shield Module,” code RB-Suf-19 manufactured by SunFounder, $48 total, and two DPDT 4-relay boards, “ELECTRONICS-SALON Four DPDT Signal Relay Module Board, 5V version” from Amazon for $20.00. The 8-relay boards accept 10-pin sockets, as described above. The DPDT boards accept only bare wire for screw-terminal connections, so you have to separate and strip out the ends of that ribbon cable. I suppose I could have done the same with the 8-relay boards and soldered female sockets on the ends, but that’s a lot of work. At the planning stage, I wanted a clean installation. As a fallback position, I could have gone with soldering female individual sockets, or else wire-wrapped and soldered directly to the pins. Testing will tell! As you will see, fortunately mine worked fine.

8-relay SPDT Board. 4-relay DPDT Board

<- 8-SPDT Relay Board ^^-4-DPDT Relay Board

Now for a complicating factor. Have a look at the pin layout on the Pi HAT, at AB Electronics’ website: where, if you scroll down a bit, you can look at the mechanical drawing which lists the pin-outs. Note that, on a 20-wire ribbon cable, the left two wires are +5VDC and GND, and the right two are interrupts IA and IB. On my 8-relay boards, the 10-pin connections are +5VDC on one side, GND on the other side, and eight input pins marked “IN1” through “IN8” between them. Clearly, if you just slap the things in without making changes, neither of the 10-socket two-row female connectors will line up right! You must do a tiny bit of surgery, as follows.

IO Pi Plus 2.1 Ribbon Cable pin layout (facing card electronics)

IO Pi Plus 2.1 pin layout (facing card edge)


20-pin header layout (side facing IO Pi Plus)

20-pin header layout (side facing Relay cards)

The four wires, +5VDC/GND/IA/IB, are clipped between these two headers. On the relay card side, power and ground connections are soldered to the two left wires and the two right wires, and each pair is twisted together as listed below.

Both 20-pin headers layout (facing relay card edge)

20-pin header layout (facing relay card electronics)

Both 8-Relay Boards pin layout (facing card edge)

Both 8-Relay Boards pin layout (facing card electronics)

Note that each row of a female socket carries alternating wires. If you snip the two left wires and the two right wires, that disconnects the one right-hand wire and the one left-hand wire on both of the two sockets. If we then twist the two right-hand wires together and the two left-hand wires together at the end closest to the connections to both relay cards, then apply +5VDC to one set of wire ends and GND to the other set, the power connections for both relay cards are taken care of. Not only that, but Pi-HAT pin 1 goes to one relay card’s pin IN8, Pi-HAT pin 2 goes to the other relay card’s pin IN8, and so on, alternating down the line. Inputs are taken care of, power and ground are taken care of, and all you have to do is figure out which computer code to use to activate whatever desired relay. (There’s software to help with that, later.) Simple, right? “Of course right!”

Take care when assembling the ribbon cables and connectors. My first set had poor connectivity because I used only two of the three components pictured above on each connector. The right-hand-side one is a backing plate to keep things tight. It is essential! See YouTube video for hints on how to assemble them. Be sure to leave plenty of ribbon cable so you can reach all three connection points. I didn’t leave enough ribbon cable to fold back over the connectors on my first try, and had to discard one and rebuild it.

…almost there, but not so fast! You’ll find that the female header using the back row (farthest from the card edge) collides with the relay board electronics packages when you plug in the front (near card edge) row.. It is important that these connectors seat firmly. To get around this problem, carefully bend the pins on the relay card toward the edge enough that you can seat the 10-sockets of the header firmly. The other socket header will seat firmly on the other relay card without problems.

Alternate Hardware: AB Electronics' 10-Relay PCB

The AB Electronics folks offer a printed circuit board layout for a 16-relay board. See their web page: which offers design schematics and PCB files. To quote them, “The 20 pin IDC connector uses the same pin configuration as the IO Pi Plus 2.1 so you can connect the two together using two 20 pin IDC connectors and a ribbon cable. The relay numbers match the pin numbering on the IO Pi Plus bus making it easy to control the relays using our IO Pi software libraries.” You have to get the PCB board made, then buy all the components and assemble them. Given my bad record at soldering and lacking means of getting the board printed, I elected to use commercially available 8-relay boards as described above. I hope you’ll have better success with whatever option you choose.

Software Mods for Testing

One last check, and you’re almost ready to go. Sure, you can “smoke test” by powering it up, but what about turning things off and on? You’ll need software. What’s cool about the relay cards I’ve used is that each relay has a red LED which is activated when the relay turns on. If yours don’t, you’ll need to wire 16 or so LEDs up so you can check easily. Don’t forget the current-limiting 200 W resistors!

The folks at AB Electronics have provided some great code for testing. See their code libraries on Github, or try for easy access. I modified mine so it would turn on the relays, one at a time, wait for a keystroke, then turn ‘em off. My modified code follows, with apologies to the AB-E folks. First, you’ll need to find, then copy, their files ABE_IoPi.c and ABE_IoPi.h into the same directory as your test code, which I’ve named IO_Pi_test.c which follows below. Then, you may need to make a couple of modifications to ABE_IoPi.c as follows:

If you have a Raspberry Pi Model B revision 0002 or 0003, change line 91 or so as reads

const char *filename = “/dev/i2c-1”

to read

const char *filename = “/dev/i2c-0”

as described on that line in ABE_IoPi.c. This is actually a hardware port. For some reason, port /dev/i2c-0 does not exist in my operating system files, so I didn’t make that change. If you use it and get the error message

Failed to open i2c port for write

Then chances are that you don’t have that port enabled either. Have a look in /dev to see.

The next change to in ABE_IoPi.c is necessary due to the fact that its write_pin() function requires octal arguments. Scroll down to that subroutine, which begins in my copy at line 242 or so. Change the subroutine to:

void write_pin(char address, char pin, char value){ // requires octal input args /* * CHANGE: * write to an individual pin 1 - 16// * TO: write to an individual pin 0 - 17 octal * @param address - I2C address for the target device * CHANGE: * @param pin - 1 to 16 * TO: @param pins 0 to 7, 10 to 17 * @param value - 0 = logic level low, 1 = logic level high */// THE FOLLOWING LINE should be commented out so code will execute correctly// pin = pin - 1; char cval = 0; if (pin < 8) { cval = read_byte_data(address, GPIOA); cval = updatebyte(cval, pin, value); write_byte_data(address, GPIOA, cval); } else { cval = read_byte_data(address, GPIOB); cval = updatebyte(cval, pin - 8, value); write_byte_data(address, GPIOB, cval); }}

Assume your code is named IO_Pi_test.c in which case you’ll need to build your code with the following line:

gcc ABE_IoPi.c IO_Pi_test.c -o test

then run with


Or, if needed,

./test invert

which we’ll talk about in a moment.

Software for Hardware Testing

Here’s the C code, IO_Pi_test.c:

/* Based on AB Electronics "test.c" */#include "ABE_IoPi.h"#include "ABE_I2CSwitch.h"// Andrew at AB Electronics suggests copying the above two files, both// the .c file and the .h header file, into the same directory, then// using the following build command:// gcc ABE_IoPi.c IO_Pi_test.c -o test// then running with// ./test // This program operates relays 0 thru 7, 10 thru 17 octal (two cards// of 8 relays each). Note that IO Pi Plus pin numbers are not the same// as relay card pin numbers. These are wiring-determined. Use this// program to sort out which software pin number is which relay. // Specify which i2c address to use. Test only one at a time.// For two IO PI Plus 2.1 cards, the following four addresses are// hard-wired.#define ADDRESS 0x20 // right (aux) two relay cards 17 - 0//#define ADDRESS 0x21 // left (main block) two relay cards 17 - 0//#define ADDRESS 0x22 // fwd/rev relays 7 thru 0 (invert required)//#define ADDRESS 0x23 // detectors char on;char off; // global pin on/off zero or onechar invert; // global invert switch void turn_on() // Turn each relay on, wait, then off and go to next.{ printf("Turning ON pin-by-pin. Does next pin after keypress.\n"); // Print which pin number, output the print line to // stdout (display) buffer, flush it to display on-screen, // write to pin, then wait for key before turning that pin // off and going to the next pin #. Do pin 017 down to pin 000. // LOW level triggers relay on. char dummy[1]; dummy[0]=(char)0; // Note that all pin numbers are octal (preceding 0 character). if(dummy[0]>00){dummy[0]=00;} // to avoid "not used" warning for(char i=017;((i>=000)&&(i<=017));i--) // for each pin { printf("\rpin %o",i);fflush(stdout);write_pin(ADDRESS,i,on); dummy[0]=getchar();write_pin(ADDRESS,i,off); } // for() printf("ON test complete\n");} void turn_em_off() // Force all relays off. All addresses octal.{ if(invert) {printf("Initializing (turning all off) with PIN_LOW.\n");} else {printf("Initializing (turning all off) with PIN_HIGH.\n");} for(char i=017;((i>=000)&&(i<=017));i--)write_pin(ADDRESS,i,off);} // Callback handler. Shut down test if CTRL-C signal is detectedvoid my_handler(int s){ printf("Detected CTRL-C signal. Exiting. \n"); turn_em_off(); // reset to OFF first, though. exit(0);} int main(int argc, char **argv){ // Register callback function for CTRL-C signal(SIGINT, my_handler); printf("Initializing i2c address.\n");// ADDRESS must be defined above IOPi_init(ADDRESS); // initialise one of the io pi channels on i2c printf("Enabling bus 0 output. "); set_port_direction(ADDRESS, 0, 000); // set bus 0 to be outputs printf("Enabling bus 1 output.\n"); set_port_direction(ADDRESS, 1, 000); // set bus 1 to be outputs printf("Press Ctrl-C to exit.\n"); if(argc>1) {invert=1;printf("Inverting pin outputs. OFF means PIN_LOW.\n");} else{(invert=0);printf("Standard pin outputs. OFF means PIN_HIGH.\n");} if(invert){ on=1;off=0;} else {on=0;off=1;} turn_em_off(); // initialize turn_on(); // run single pass, then exit return (0);}

Pin Signal Inverting

Now for a hardware item. Some relay cards turn their components on in response to a HIGH pin, while others are the opposite. When you power on your equipment, take a multimeter and check that the normally-closed contacts are actually closed and the normally open contacts are open. Now, fire off the test program, running each relay card through its paces one or two times, just to make sure the indicator led lights light or go out when expected.

Now, run it again, checking with the multimeter to see if powering a pin off or on gets the expected relay contact closure. In my case, the DPDT relays were wired up such that turning a pin OFF turned the relay off and caused the led to go out. You’ll need to take this into account when you wire up the relays as well as when you program your computer code. Do you wire the controlled circuit logic inverted, or the controller software? I’d opt for minimizing relay current draw if I were you, which at first glance, means defaulting the pin signals to PIN_LOW.

As luck would have it, the SPDT relay cards defaulted the other way ‘round. PIN_ON means the relay goes to normally closed, i.e. OFF, position. In these cards, logic is inverted and pins should default to PIN_HIGH. In such a case, you should wire and program accordingly. Test this condition with

./test invert

which in my case will end up with all the LEDs turned off, meaning in my case, everything defaults to “normally-whatever,” be it closed or open. I will need to take the “normal” position into consideration when wiring.

NEXT TOPIC: Wiring Design, Relay Logic

Computer geek since 1964. Upgraded to FORTRAN66 back in the day. Downhill ever since.

05/03/2020 Posted by: andrew Location: United Kingdom

Thank you for your very detailed post. I am glad you found our IO Pi board and software libraries useful.

AB Electronics UK Tech Support

Next topic: Layout Design, Electrical Design, Connections, and Testing details.