I have been exploring options for developing a control board for my home automation project. I started off with the old 74HC595 shift register and I am now currently testing out the MCP23S17 GPIO expander.
So what are the difference between these two candidates?
The 74HC595 is a shift register and allows you to gain extra output ports for your netduino or other MCU. There are a few ways of doing this but I have been focusing on using SPI. SPI is fast and it means that you can even drive things like LCD displays. Each 595 has 8 outputs and you essentially load up 8 bits of information telling it which pins are high or low. They can also be chained to give you more outputs than most situations could ever need.
The problem I have experience many times is with noise. Testing on breadboard has shown no problems, but then when I make that leap to protoboard, the issues begin to manifest. I would say I image that if this was sketched up in to a PCB these issue would most likely be overcome.
Another issue is with errors, if any error occurs your pins state can be wrong and there is no way of finding out. Mario came up with an ingenious idea of creating a buffer stage using a capacitor and resistor per output channel, known as a Schmitt Trigger. In essence the idea is that the charge/discharge time of the capacitor is longer than the frequency at which the state is refreshed.
So if your pin is set HIGH, the capacitor will start charging. If an error then occurs in the state of the pin on the 595 and it goes LOW. Then the capacitor will have enough charge to maintain the HIGH output state, whilst the logic on the 595 is updated.
Before I went through some rationalisation with my electrician, I had decided to control every single light, socket and appliance. In hindsight this was an unrealistic aim and would have resulted in over 100 circuits. I have since revised this down to 51 circuits which is still a lot by any standards, domestic or commercial. This was achieved by grouping sockets in to functional blocks, but more on that in my next post.
With this in mind I planned to have 80, yes 80! channels on my main control board and then 64 on my second control board. I started with the 80 channel board and began by soldering up the first 40 channels to allow me to do some testing. Below are some images through the different stages.
First of all I test with two 74HC595s, two 74HC7541, and two ULN2803 to get the 24v control voltage for switching the relays.
Here is a schematic of the circuit with many thanks to Mario over at the netduino formus.
I then moved to the protoboard and layed out for 10 of each of the chips and the first 40 capacitors and resistors for the Schmitt Trigger. In order to make sure everything stays in place I used some superglue. I al so laid the resistors over the top of the capacitors as one side of the capacitors and resistor goes to an output pin of the 595, then the other side of the capacitor goes to the common ground (pin 10) on the 74HC7541. The other side of the resistor goes to an input pin of the 74HC7541.
Here is a matrix board layout of the board. I just wanted something straight forward to help me make sure I get my layout right.
Another good tip I have here is to create a layout for your solder trace. I have had issues in the past when I flip the board and everything is backwards, I tend to get mixed up in places and as you can imagine this causes problems. I found a free piece of software for laying out matrix boards called diylc.
Here is the first half of the board soldered up.
And this is the other side.
As I said when I tested everything I found there was a lot of noise issue as I found with my first attempt at an aquarium controller. So I started to look for other options as I need a solution up and running in the next few weeks for the completion of my rewire.
So roll on the MCP23S17.
This new chip has some great features, for one thing it has double the ports so that means have the connections for chaining the chips. Also another fantastic benefit is that fact that it creates real GPIO ports, so they can be input or output and with the help of Hanzibals fantastic driver they can easily be interrupt ports or grouped in to busses.
The MCP23S17 also runs on SPI and again is blistering quick. Since I reviewed my circuit needs I now need 31 channels for my main control board and 22 channels for my second control board. Luckily I found some great little 32 channel boards for £7 from Majenko. They have a great form factor and a fantastic design.
The MCP23S17 is an addressable chip and the address is defined by bridging pin 1,2 and 3 in various order allowing for up to 8 chips to be chained together. The board I have break this out in to 2 handy pairs of pads that can be bridged with solder to change the address value. There are also to IRQ pins which are used for the interrupts on the chips, these again are broken out on the board should I wish to use them.
Here is the little board I am using.
The plan is to create a little board that this will connect to in order to provide the 24v stage using ULN2803 chips.
Here is a little video, its not particularly exciting but it shows Hanzibal's driver working with a multi SPI manager to allow for control of both chips.
The netduino connections are as follows:
VCC = 3.3v
Gnd = Gnd
CS = D10
SCK = D13
MISO = D12
MOSI = D11
And here is the code I used for the very simple led blink which loops through all 32 ports switching one of them on for 200ms and then off.
using System.Threading;
using SecretLabs.NETMF.Hardware.Netduino;
using MCP23S17Lib;
using Microsoft.SPOT;
namespace Testspi1
{
public class Program
{
// Number of registers
private static uint icCnt = 2;
// Pins per register
private static uint icPins = 16;
//Total pins
private static uint pinCnt = icCnt * icPins;
// Sleep
private static int sleep = 200;
public static MCP23S17.OutputPort[] Outs = new MCP23S17.OutputPort[pinCnt];
public static MCP23S17[] chip = new MCP23S17[icCnt];
public static void Main()
{
// create a new instance of the driver class using pin 17 for !CS and pin 18 for IRQ
for (int ic = 0; ic < icCnt; ic++) { chip[ic] = new MCP23S17(SPI_Devices.SPI1, Pins.GPIO_PIN_D10, Pins.GPIO_NONE, (byte)ic, 7000); // Define all outputs for (int pin = 0; pin < icPins; pin++) Outs[16 * ic + pin] = chip[ic].CreateOutputPort((MCP23S17.Pins)(1 << pin), false); } while (true) { for (int i = 1; i <= Outs.Length; ++i) { Outs[i - 1].Value = true; Thread.Sleep(sleep); Outs[i - 1].Value = false; } } } } }
And here is a link to Hanzibals driver.
I will be posting soon with details on how my automation is coming along. Stay tuned!