Go Down

Topic: Prototype SPI Relay Shield (Read 2 times) previous topic - next topic


Jul 22, 2010, 01:02 pm Last Edit: Jul 22, 2010, 09:52 pm by WanaGo Reason: 1

Whether or not anyone is interested in this, I am not sure, but just something I put together as a test more than anything, and to practice my PCB designing skills again. Its been a while.

I wanted to make a shield that featured a few small relays so I could switch larger devices, as I couldnt find anyone else who had really done this (no doubt there is however).
I then thought about making a shield with a MCP23S17 SPI IO Expander, as I brought 5 of this a while ago but hadnt played with them yet. I was using Bascom-AVR at that stage and hadnt purchased my first Arduino.

Anyway, I then though - instead of taking up IO from the Arduino to drive these relays, why dont I do this with some of the outputs from the SPI expander.

So what I have made is a prototype PCB with a MCP23S17 chip, of which 4 of the outputs drive 4 BC337 transistors, which in turn drive the coils of 4 5volt relays, which are capable of switching 5 Amps at 230VAC.

The rest of the IO pins I have just made available on header pins, which could be used for anything.

As I say, this is a prototype, and I didnt have enough 0.1" header pins to fully populate the board, but all the functional pins are connected. The others would just be pass through, however the relays are quite tall and so this board would most likely need to be the top most board if stacking anyway.

Designed in Protel DXP 2004 and printed by a company here in NZ who prints single and double sided boards however doesnt have the technology to do via's etc, so these are all done manually. Cheap service though and much better than etching my own boards. And since its a prototype I didnt bother getting them to cut the board out completely, but as you will see it is designed with the proper contours that other arduino shields have.

If/When I make a proper version, it will all be reshuffled as some components arent in ideal places - but its a prototype. Not much room on a shield footprint when using through hole components and relays!

Here are a few snaps incase anyone is interested, sorry the lighting in this room is dim at best and the flash is a bit bright.

This is the test code I used if anyone is interested.

Code: [Select]

/*Code modified from code I found on http://spikenzielabs.com/SpikenzieLabs/Project_64.html
 Purely to test if the hardware works, which it does.
 Code turns on and off each relay each second

#define            MCP23S17      B01001100      // MCP23017 SPI Address

#define            IOCON            0x0A            // MCP23017 Config Reg.

#define            IODIRA            0x00            // MCP23017 address of I/O direction
#define            IODIRB            0x01            // MCP23017 1=input

#define            IPOLA            0x02            // MCP23017 address of I/O Polarity
#define            IPOLB            0x03            // MCP23017 1= Inverted

#define            GPIOA            0x12            // MCP23017 address of GP Value
#define            GPIOB            0x13            // MCP23017 address of GP Value

#define            GPINTENA      0x04            // MCP23017 IOC Enable
#define            GPINTENB      0x05            // MCP23017 IOC Enable

#define            INTCONA            0x08            // MCP23017 Interrupt Cont
#define            INTCONB            0x09            // MCP23017 1= compair to DEFVAL(A or B) 0= change

#define            DEFVALA            0x06            // MCP23017 IOC Default value
#define            DEFVALB            0x07            // MCP23017 if INTCONA set then INT. if diff.

#define            GPPUA            0x0C            // MCP23017 Weak Pull-Ups
#define            GPPUB            0x0D            // MCP23017 1= Pulled HIgh via internal 100k

#define            OLATA            0x14
#define            OLATB            0x15

#define            INTFA            0x0E
#define            INTFB            0x0F

#define            INTCAPA         0x10
#define            INTCAPB            0x11

// SPI
#define         SS              4                // Pin mapping to Arduino = SELECT
#define         MOSI            6                // Pin mapping to Arduino = Master Out Slave In
#define         SCLK            7                // Pin mapping to Arduino = Serial clock
#define         MISO            5                // Pin mapping to Arduino = Master IN slave OUT

int rx_data = 0;
int buttonPress    = 0;
int error_flag = 0;
int COLUMN = 0;

void setup()

 pinMode(SS, OUTPUT);
 pinMode(MOSI, OUTPUT);
 pinMode(SCLK, OUTPUT);
 pinMode(MISO, INPUT);

 digitalWrite(SS, HIGH);
 digitalWrite(SCLK, LOW);
 digitalWrite(MOSI, LOW);

 delay(1000);                               // This delay seems important for the MCP23S17 power-up

void loop()
 //Turns on and off each relay in turn
 SPI_TX(MCP23S17, GPIOA, B00000000);
 SPI_TX(MCP23S17, GPIOB, B00000000);
 SPI_TX(MCP23S17, GPIOA, B00000001);
 SPI_TX(MCP23S17, GPIOA, B00000000);
 SPI_TX(MCP23S17, GPIOA, B00000010);
 SPI_TX(MCP23S17, GPIOA, B00000000);
 SPI_TX(MCP23S17, GPIOB, B10000000);
 SPI_TX(MCP23S17, GPIOB, B00000000);
 SPI_TX(MCP23S17, GPIOB, B01000000);

void SPI_portexpanderinit()
 // --- Set I/O Direction
 SPI_TX(MCP23S17,IODIRB,B00000000);                                 // MCP23S17 port B = OUTPUT
 SPI_TX(MCP23S17,IODIRA,B00000000);                                 // MCP23S17 port A = OUTPUT
 //  --- Clear ALL Bits of GPIOA and GPIOB
 SPI_TX(MCP23S17,GPIOB,B00000000);                                  // MCP23S17 Clear port B
 SPI_TX(MCP23S17,GPIOA,B00000000);                                  // MCP23S17 Clear port A

void SPI_TX(int device, int regadd, int tx_data)
 digitalWrite(SS, LOW);                                       // Select the Chip

 device = device & B11111110;                                 // Clear last bit for a write

 SPI8BITTXLOOP(device);                                       // SPI Device

 SPI8BITTXLOOP(regadd);                                       // SPI REGISTER ADDRESS

 SPI8BITTXLOOP(tx_data);                                      // Data

 digitalWrite(SS, HIGH);                                      // Done UN-Select the Chip

void SPI8BITTXLOOP(int data)
 int i = 0;
 int temp = 0;
 for(i=1; i < 9; i = i +1)
   temp = (data >> 7);                                        // Test bit 7 of DATA
   temp = temp & 1;
   if (temp == 0)                                             // SET or CLEAR MOSI
     digitalWrite(MOSI, LOW);
     digitalWrite(MOSI, HIGH);
   digitalWrite(SCLK, HIGH);                                   // SET SCLK
   digitalWrite(SCLK, LOW);                                    // Clear Clock
   data = data << 1;                                           // Shift data LEFT by 1

Funky Diver

Jul 22, 2010, 07:06 pm Last Edit: Jul 22, 2010, 07:07 pm by Funky_Diver Reason: 1
I like this...  :D

Is the relay driving limit four?  Also, what's the maximum rating current on the relays themselves?  I'm thinking of an automotive application.

*duh... ignore me, five amps, lol*


Haha yeah - 5A.
And no, the limit isnt 4 relays - however the limit for fitting it on a standard size shield like this is I would think. If I didnt have the SPI Expander then I may be able to fit 2 more, but then it would be IO driven rather than SPI driven and so that takes pins away from other shields.
In theory you can have as many relays as you have SPI outputs, and for each SPI expander you can have 16, and you can have multiple SPI expanders.
I cant recall off the top of my head what the coil current draw is of each of these relays, however its not much - but if you started having like 15 Relays then USB powered wouldnt be possible I think.

Cheers  ;D

Funky Diver

Sweet... so more than enough for my needs then, especially as they would have to be externally powered anyways :D

Thanks for the super quick response! :)


I'm wondering how much current is being sunk by the relay circuit on the output pin.

The MCP23S17 has maximum current draw of 125ma  and a maximum current sunk on the output pins of 25ma. So if you where to build something that would use all of the output pins for relays they would need to draw no more than 7.8ma per output pin. 7.8ma times 16 ports = 124.8ma

Go Up