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 https://www.youtube.com/watch?v=EFyFhcmeS2I 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: https://www.abelectronics.co.uk/kb/article/1060/relay-board-for-the-io-pi-plus-2-1 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 https://www.abelectronics.co.uk/p/54/io-pi-plus#code 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 writeThen 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 testthen run with
./testOr, if needed,
./test invertwhich 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 invertwhich 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.