Hi everyone, I’m new to the forum and new to the world of Arduino so go easy on me.
I’m using an EtherTen with two 8 channel relay shields stacked on to it. The shields use I2C to communicate with the EtherTen. So far it works fine with a light web interface that has been programmed into the sketch (see below).
/**
OutputControllerRelay8x2.pde
*/
#include <SPI.h>
#include "Ethernet.h"
#include "WebServer.h"
#include "Wire.h"
#define SHIELD_1_I2C_ADDRESS 0x20 // 0x20 is the address with all jumpers removed
#define SHIELD_2_I2C_ADDRESS 0x21 // 0x21 is the address with a jumper on position A0
#define MAC_I2C_ADDRESS 0x50 // Microchip 24AA125E48 I2C ROM address
static uint8_t mac[] = { 0xFE, 0xDE, 0x8A, 0xAA, 0xFF, 0xB4 };
static uint8_t ip[] = { 192, 168, 2, 111 };
#define PREFIX "/control" // This will be appended to the IP address as the URL
WebServer webserver(PREFIX, 80);
byte shield1BankA = 0; // Current status of all outputs on first shield, one bit per output
byte shield2BankA = 0; // Current status of all outputs on second shield, one bit per output
void serverCmd(WebServer &server, WebServer::ConnectionType type, char *url_tail, bool tail_complete)
{
/* If we've received a POST request we need to process the submitted form values */
if (type == WebServer::POST)
{
bool repeat;
char name[20], value[16];
do
{
/* readPOSTparam returns false when there are no more parameters
to read from the input. We pass in buffers for it to store
the name and value strings along with the length of those
buffers. */
repeat = server.readPOSTparam( name, 20, value, 16);
/* This is a standard string comparison function. It returns 0
when there's an exact match. */
if (strcmp( name, "On" ) == 0)
{
setLatchChannelOn( atoi(value) );
}
if (strcmp( name, "Off" ) == 0)
{
setLatchChannelOff( atoi(value) );
}
if (strcmp( name, "AllOff" ) == 0)
{
sendRawValueToLatch1(0);
sendRawValueToLatch2(0);
}
} while (repeat);
// After procesing the POST data, tell the web browser to reload
// the page using a GET method.
server.httpSeeOther(PREFIX);
return;
}
/* for a GET or HEAD, send the standard "it's all OK" headers */
server.httpSuccess();
/* Don't output the body for a HEAD request, only for GET */
if (type == WebServer::GET)
{
/* store the HTML in program memory using the P macro */
P(message) =
"<html><head><title>16 Channel Test</title>"
"<body style='background-color:powderblue;'>"
"<form action='/control' method='POST'>"
"<h1 style='color:red;font-family:comic sans ms;font-size:200%;text-align:center;'>16 Channel Test</h1><hr>"
"<div style='float:left;width:60%;'>"
"<p style='font-size:140%;'><button style='height:40px;width:75px' type='submit' name='On' value='1'>On</button><button style='height:40px;width:75px' type='submit' name='Off' value='1'>Off</button>1<button style='height:40px;width:75px' type='submit' name='On' value='2'>On</button><button style='height:40px;width:75px' type='submit' name='Off' value='2'>Off</button>2</p>"
"<p style='font-size:140%;'><button style='height:40px;width:75px' type='submit' name='On' value='3'>On</button><button style='height:40px;width:75px' type='submit' name='Off' value='3'>Off</button>3<button style='height:40px;width:75px' type='submit' name='On' value='4'>On</button><button style='height:40px;width:75px' type='submit' name='Off' value='4'>Off</button>4</p>"
"<p style='font-size:140%;'><button style='height:40px;width:75px' type='submit' name='On' value='5'>On</button><button style='height:40px;width:75px' type='submit' name='Off' value='5'>Off</button>5<button style='height:40px;width:75px' type='submit' name='On' value='6'>On</button><button style='height:40px;width:75px' type='submit' name='Off' value='6'>Off</button>6</p>"
"<p style='font-size:140%;'><button style='height:40px;width:75px' type='submit' name='On' value='7'>On</button><button style='height:40px;width:75px' type='submit' name='Off' value='7'>Off</button>7<button style='height:40px;width:75px' type='submit' name='On' value='8'>On</button><button style='height:40px;width:75px' type='submit' name='Off' value='8'>Off</button>8</p>"
//rest of html removed due to post length
"<p style='font-size:140%;text-align:center;'><button style='height:40px;width:75px' type='submit' name='AllOff' value='0'>Off</button>  Turn Everything Off</p></div>"
"</form>"
"</body></html>";
server.printP(message);
}
}
/**
*/
void setup()
{
Wire.begin(); // Wake up I2C bus
Serial.begin( 38400 );
Serial.println("Test Control Output Controller starting up. v1.0, 16 channel relay shield");
// setup the Ethernet library to talk to the Wiznet board
Ethernet.begin(mac, ip); // Use static address defined above
//Ethernet.begin(mac); // Use DHCP
/* Register the default command (activated with the request of
http://x.x.x.x/control */
webserver.setDefaultCommand(&serverCmd);
/* start the server to wait for connections */
webserver.begin();
/* Set up the Relay8 shields */
initialiseShield(SHIELD_1_I2C_ADDRESS);
sendRawValueToLatch1(0); // If we don't do this, channel 6 turns on! I don't know why
initialiseShield(SHIELD_2_I2C_ADDRESS);
sendRawValueToLatch2(0); // If we don't do this, channel 6 turns on! I don't know why
Serial.println("Ready.");
}
/**
*/
void loop()
{
// Process incoming connections one at a time forever
webserver.processConnection();
}
/**
*/
void initialiseShield(int shieldAddress)
{
// Set addressing style
Wire.beginTransmission(shieldAddress);
Wire.write(0x12);
Wire.write(0x20); // use table 1.4 addressing
Wire.endTransmission();
// Set I/O bank A to outputs
Wire.beginTransmission(shieldAddress);
Wire.write(0x00); // IODIRA register
Wire.write(0x00); // Set all of bank A to outputs
Wire.endTransmission();
}
/**
*/
void toggleLatchChannel(byte channelId)
{
if ( channelId >= 1 && channelId <= 8 )
{
byte shieldOutput = channelId;
byte channelMask = 1 << (shieldOutput - 1);
shield1BankA = shield1BankA ^ channelMask;
sendRawValueToLatch1(shield1BankA);
}
else if ( channelId >= 9 && channelId <= 16 )
{
byte shieldOutput = channelId - 8;
byte channelMask = 1 << (shieldOutput - 1);
shield2BankA = shield2BankA ^ channelMask;
sendRawValueToLatch2(shield2BankA);
}
}
/**
*/
void setLatchChannelOn (byte channelId)
{
if ( channelId >= 1 && channelId <= 8 )
{
byte shieldOutput = channelId;
byte channelMask = 1 << (shieldOutput - 1);
shield1BankA = shield1BankA | channelMask;
sendRawValueToLatch1(shield1BankA);
}
else if ( channelId >= 9 && channelId <= 16 )
{
byte shieldOutput = channelId - 8;
byte channelMask = 1 << (shieldOutput - 1);
shield2BankA = shield2BankA | channelMask;
sendRawValueToLatch2(shield2BankA);
}
}
/**
*/
void setLatchChannelOff (byte channelId)
{
if ( channelId >= 1 && channelId <= 8 )
{
byte shieldOutput = channelId;
byte channelMask = 255 - ( 1 << (shieldOutput - 1));
shield1BankA = shield1BankA & channelMask;
sendRawValueToLatch1(shield1BankA);
}
else if ( channelId >= 9 && channelId <= 16 )
{
byte shieldOutput = channelId - 8;
byte channelMask = 255 - ( 1 << (shieldOutput - 1));
shield2BankA = shield2BankA & channelMask;
sendRawValueToLatch2(shield2BankA);
}
}
/**
*/
void sendRawValueToLatch1(byte rawValue)
{
Wire.beginTransmission(SHIELD_1_I2C_ADDRESS);
Wire.write(0x12); // Select GPIOA
Wire.write(rawValue); // Send value to bank A
shield1BankA = rawValue;
Wire.endTransmission();
}
/**
*/
void sendRawValueToLatch2(byte rawValue)
{
Wire.beginTransmission(SHIELD_2_I2C_ADDRESS);
Wire.write(0x12); // Select GPIOA
Wire.write(rawValue); // Send value to bank A
shield2BankA = rawValue;
Wire.endTransmission();
}
/**
Required to read the MAC address ROM
*/
byte readRegister(byte r)
{
unsigned char v;
Wire.beginTransmission(MAC_I2C_ADDRESS);
Wire.write(r); // Register to read
Wire.endTransmission();
Wire.requestFrom(MAC_I2C_ADDRESS, 1); // Read a byte
while (!Wire.available())
{
// Wait
}
v = Wire.read();
return v;
}