Project 016 - Arduino I2C 32ch Digital I/O Extender Board
This is my first Arduino shield. The "IanJ I2C 32ch Digital I/O Extender Board".
Specifications/Info:-
- 32 digital I/O channels, each configurable as input or output.
- Configured as inputs, you can assume internal pull up resistors on each channel.
- I2C addresses configurable via DIP switches.
- +5vdc supply from Arduino main board (see note 1).
- Interrupt line available to tie back to main Arduino
Note 1:-
Each output is capable of 25mA sink, however, with 32 possible outputs this is 800mA (0.8A)
and so an external 5vdc supply must be used.
See the board I/O diagram below (coming soon) for info on selecting this mode.
With a relatively low current consumption expectation, such as when using a lot of inputs, you can use the Arduino +5vdc supply to power the board.
References:
For more information on usage of the interrupt line, how to independently assign each pin as input or output, driving high current loads, or learn about the I2C commands, refer to:
http://www.nxp.com/documents/data_sheet/PCA8574_PCA8574A.pdf
http://www.arduino.cc/en/Reference/Wire
Here's a partial 3D rendered interpretation of the board (missing the pushbutton & the screw terminals).
And here's a photo of the 1st prototype, minus the switches:-
Demo sketch:-
There are many ways to pass data via I2C and to manipulate bits/bytes of data. This sketch offers a minimal demo (showing how easy it is!) on how to control the board.
{codecitation}
/*
Demo program for "IanJ I2C 32ch Digital I/O Extender Board"
V1.0 - By Ian Johnston, Feb 2010.
The Pcb has 4off IC's, designated U1, U2, U3 & U4.
In this demo sketch:-
U1 = All 8 channels set for digital output
U2 = All 8 channels set for digital input
U3 = All 8 channels set for digital output
U4 = All 8 channels set for digital input
*/
#include <Wire.h> // The I2C library
// Setup I2C addresses for the 4off IC's. These are 7-bit addresses.
// 4off bits internal to IC, last 3 bits via switches on pcb, i.e. 0100 [A1] [A2] [A3]
// Note: An 8th bit sets direction, however Wire.h takes care of this automatically.
byte U1_ADDR = 33; // B0100001 = Pcb Switch setting = 001
byte U2_ADDR = 34; // B0100010 = Pcb Switch setting = 010
byte U3_ADDR = 35; // B0100011 = Pcb Switch setting = 011
byte U4_ADDR = 36; // B0100100 = Pcb Switch setting = 100
// Setup variables
byte I2C_dataTx; // Data to outputs IC's
byte I2C_dataRx; // Data from input IC's
int I2C_TxAddr; // IC Address holder for output
int I2C_RxAddr; // IC Address holder for input
int i=0; // Demo variable only
int delaytime=100; // Demo variable only
void setup() {
Wire.begin();
}
void loop() {
// DIGITAL OUTPUT - A few examples on how to drive outputs
// Demo turn all outputs on in one go, on U1
I2C_dataTx = B11111111; // Make up byte to be sent from binary data of port P7,P6,P5,P4,P3,P2,P1,P0
I2C_TxAddr = U1_ADDR; // Set 7-bit I2C address to send to
I2C_Send(); // Run subroutine and send data to I2C bus
delay(delaytime);
// Demo turn all outputs off in one go, on U1
I2C_dataTx = B00000000; // Make up byte to be sent from binary data of port P7,P6,P5,P4,P3,P2,P1,P0
I2C_TxAddr = U1_ADDR; // Set I2C address to send to
I2C_Send(); // Run subroutine and send data to I2C bus
delay(delaytime);
// Demo rotate round all 8off bits on U1 turning them on one by one
I2C_TxAddr = U1_ADDR; // Set I2C address to send to
for(i = 0; i < 7; i++) {
bitSet(I2C_dataTx, i);
I2C_Send(); // Run subroutine and send data to I2C bus
delay(delaytime);
}
// Demo rotate round all 8off bits on U1 turning them off one by one
I2C_TxAddr = U1_ADDR; // Set I2C address to send to
for(i = 0; i < 7; i++) {
bitClear(I2C_dataTx, i);
I2C_Send(); // Run subroutine and send data to I2C bus
delay(delaytime);
}
// DIGITAL INPUT - A few examples on how to read inputs
// Demo receive data from U2
I2C_RxAddr = U2_ADDR; // set I2C address
I2C_Receive(); // Run subroutine and receive data from I2C bus, data appears in var I2C_dataRx
// Now do something with one of the bits, let's speed up the whole main loop a bit. Note: inputs are normally high so test for 0
if (bitRead(I2C_dataRx, 0) == 0) { // Check bit 0
delaytime=50;
}
// And one of the other bits, let's speed up the whole main loop a lot
if (bitRead(I2C_dataRx, 1) == 0) { // Check bit 1
delaytime=25;
}
// And one of the other bits, reset the speed back to default
if (bitRead(I2C_dataRx, 2) == 0) { // Check bit 2
delaytime=100;
}
}
void I2C_Send() {
// I2C send routine
Wire.beginTransmission(I2C_TxAddr); // setup I2C address to send to
Wire.send(I2C_dataTx); // send byte to that address
Wire.endTransmission(); // end send
}
void I2C_Receive() {
// I2C receive routine
Wire.requestFrom(I2C_RxAddr, 1); // request 1 byte from I2C address
if (Wire.available()) I2C_dataRx = Wire.receive();
}
{/codecitation}