Fads to Obsessions and Beyond...




Free domain for life, exceptional technical support, website transfer

Port Expansion PCF8574A

Demonstrate interfacing Arduino Nano with I2C to the PCF8574A 8-bit port expansion chip.

The Arduino Nano is advantageous in terms of small physical size and low cost per GPIO/onboard peripheral available (particularly good for 'small' DIY projects controlling a single sensor and or output for example). However, the small physical size means limited input/output pins.

Conveniently, there are I/O port expanders available such as the PCF8574 which can be interfaced using only 2 pins, and provide 8 GPIO's. Further, the PCF8574 can be daisy-chained so that multiple's of additional 8 GPIO's can be achieved. The interface for connecting the PCF8574 to the Arduino Nano is called I2C (I2C is an acronym for “Inter-Integrated Circuit”).

In addition to the benefit of gaining additional GPIO's by using PCF8574 port expanders is learning how to use the I2C interface. There are literally thousands of components that use the I2C interface such a real-time clocks, digital potentiometers, temperature sensors, digital compasses, memory chips etc. So once the PCF8574 interface to the Arduino Nano is successfully achieved, the same process can then be used with additional components as required.

First some background about I2C and then some specifics about the PCF8574.

Details on how to setup the Arduino IDE and environment to programme Arduino Nano microcontrollers are given in the Arduino Nano introduction.

I2C “Inter-Integrated Circuit”

I2C orginated from Philips Semiconductor (now NXP) as a way of standardising the data lines that travel between various integrated circuits, which only requires two wires (SDA – data, and SCL – clock). In terms of the hardware and communications protocol, the software library abstracts the majority of the details i.e., you don't really need to know - but if interested, the sparkfun page gives an easy introduction (4). However, some knowledge about the hardware/signal levels is necessary so the importance of having pull-up resistors on the SDA/SCL lines is appreciated.

Each I2C bus consists of two signals: SCL and SDA. SCL is the clock signal, and SDA is the data signal. The clock signal is always generated by the current bus master. The I2C bus drivers are “open drain”, meaning that they can pull the corresponding signal line low, but cannot drive it high. This eliminates possibility of data bus contention where one device is trying to drive the line high while another tries to pull it low. However, this means it is mandatory that each signal line has a pull-up resistor on it, to restore the signal to high when no device is asserting it low.

The usual value for these pull-up resistors is 4K7 (but sometimes if multiple devices on the bus 10K may be appropriate). Also, the I2C bus is meant for short distances (generally on the same PCB). The maximum length of an I2C bus is approximately 1 meter.

Devices with I2C can be connected in any physical order, there are 'address pins' on each device which can be phyiscally set to determine unique addresses.

PCF8574 Port Expander

The datasheet (see Bill of Materials Section) gives all the necessary details. Note there are alternatives to the PCF8574 (I just have a bunch of these available) such as the MCP23008 (which has 25mA sink/source per I/O pin) and 16-bit varieties (e.g. MCP23018 which gives 16 I/O lines on a single chip).

Important to realise is that the PCF8574 is a current sink device rather than current source. This means that external components need to be connected to Vcc via pull-up resistors.


The Arduino Nano board has a surface mount microcontroller with headers for all pins. Additionally, the board provides a 5V regulator for external DC power input and PCB copper traces that enable insertion into standard USB connector which can then be used for DC power source. There is an onboard LED to indicate power-on and an additional LED/resistor connected to pin1 for user control.

For convenience for this simple test, the USB power supply is used.

ISP programming is used as detailed in the Arduino Nano introduction.

PCF8574 Port Expander

Pin 8 is connected to ground and pin 16 to Vcc (i.e., 5V). Pins 1 through 3 (A0, A1, A2 respectively) determine the device address. The PCF8574 has a device address of 0100 + A2,A1,A0 whereas the PCF8574A has a device address of 0111 + A2, A1, A0. Therefore, with pins 1 through 3 on the PCF8574A connected to ground, the device address will be 0111000 which is 0x38.

Pin 15 is the I2C data line, which is connected pin 23 (marked A4 on the Nano silk screen) on the Arduino Nano. Whereas, pin 14 is the I2C clock line, and is connected to pin 24 (marked A5 on the Nano silk screen) on the Arduino Nano.

As discussed in the Background Section, pull-up 4K7 resistors are mandatory on pin 14 and 15.

To provide a simple demonstration of using the port expander (to enable concentrating on any software difficulties with the Arduino Nano) LED's are connected to the pins 4 through 7 of the PCF8574A (i.e., I/O pins 0 through 3). Because the PCF8574 is a current-sink device, the LEDs are connected with pull-up resistors (330ohm to limit the current to ~15mA per LED). The datasheet shows each pin has a maximum of ±20mA with the chip overall maximum of ±100mA.


Note: Image loading can be slow depending on server load.

  • PCF8574 SchematicPCF8574 Schematic

    Silver Membership registration gives access to full resolution schematic diagrams.

    Arduino Nano PCF8574 Schematic

    Arduino Nano with PCF8574A Schematic

  • PCF8574 with LEDs SchematicPCF8574 with LEDs Schematic

    Silver Membership registration gives access to full resolution schematic diagrams.

    Arduino Nano with PCF8574A and LEDs Schematic

    Arduino Nano with PCF8574A and LEDs Schematic

  • PCF8574 with 4x4 Keypad SchematicPCF8574 with 4x4 Keypad Schematic

    Silver Membership registration gives access to full resolution schematic diagrams.

    Arduino Nano with PCF8574A and 4x4 Keypad Schematic

    Arduino Nano with PCF8574A and 4x4 Keypad Schematic

This project did not require a PCB.

The construction was done using prototyping board. See the photographs and schematic diagram sections.

Qty Schematic Part-Reference Value Notes
Resistors
2R10,R114K71/4W, 10% 
4R6 to R93301/4W, 10% 
Diodes
4D6 to D9LED 
Integrated Circuits
1U1Arduino/Nanomicrocontroller datasheet
1U3PCF8574A8-bit port expander datasheet
Miscellaeous
3J1wiresDupont pin jumper wires
Description Downloads
Bill of Materials Text File Download

Before connecting the Arduino Nano to the USB port, check for any shorts (direct positive voltage to ground connection) as this could damage both the Nano board and the USB/PC.

Initial testing of a I2C interfaced device (and if the I2C interface library is working on the Arduino Nano) is to use the I2C scanner sketch (Code Snippet 1 below).

Once it is determined that I2C communication is working with the Arduino Nano and the PCF8574A, the next steps are using the various libraries to set the quasi bidirectional I/O pins on the PCF8574 as both input and output. The simple example of turning LED's on/off connected to the PCF8574 pins is used to determine if correct PCF8574 pins are I/O compared to the transmitted sequences (Code Snippet 2 below).

I2C Device Address Scanner

The I2C device (the PCF8574A in this case) needs to be connected via the SDA and SCK pins (with pullup resistors, and obviously connect Gnd and Vcc) to the Arduino Nano. The Serial Monitor on the Arduino IDE is used so output can be directed via USB to a PC Com serial port.

Using a PCF8574A and PCF8574 pins 1 through 3 (ie A0 to A2) tied to ground produces an I2C device address of 0+0111+0+0+0 = 0x38, so the code below should report a single device found with address of 0x38 hexadecimal. Altering which of the PCF8574A pins 1 through 3 are tied to ground or Vcc will change the reported address (the datasheet gives the table showing what the resultant addresses should be).

Code Snippet 1: I2C Device Address Scanner


 #include 

 void setup() {
     delay(200);
     Serial.begin(115200);

 	  bool PCF_Found = false ;

     // SEARCH FOR PCF8574
     for(int i = 0;i < 8;i++) {
         int address = PCF8574::combinationToAddress(i, false);
         if(PCF8574(address).read() != -1) {
             Serial.print("Found PCF8574: addr = 0x");
             Serial.println(address, HEX);
				 PCF_Found = true ;
         }
     }

     // SEARCH FOR PCF8574A
     for(int i = 0;i < 8;i++) {
         int address = PCF8574::combinationToAddress(i, true);
         if(PCF8574(address).read() != -1) {
             Serial.print("Found PCF8574A: addr = 0x");
             Serial.println(address, HEX);
				 PCF_Found = true ;
         }
     }
     if (!PCF_Found ) {
     Serial.println("Search done. No PCF8574 devices found.") };
 }

 void loop() {}
   				

Checking PCF8574 with LED output

Once it is determined that I2C is working between the Arduino Nano and the PCF8574, the relevant library can be used to read and write to the PCF8574 to either set output pins and or read the state of input pins. The Arduino library for the PCF8574 is on the repository (1) or via the Arduino IDE. This library allows reading/writing to individual PCF8574 port pins and or reading/writing to all the PCF8574 port pins as a single byte. The following code snippet demonstrates setting/resetting PCF8574 pins as output, which control the state of attached LEDs (as per the circuit in the Schematics Section).

The LED's are connected with current limiting resistors to 5V rather than to ground. This "pull-up" arrangement means that when the relevant PCF8574 port is set to 'low' the PCF8574 can then "sink current" and the LED will light brightly (i.e., dependant upon the 5V source and 330 ohm current limiting resistor). The alternative arrangement with the PCF8574 port being set 'high' (and then the corresponding LED would need to connected to ground) means that the PCF8574 port supplies the '5V' but since the output of the PCF8574 ports is only in the mA range, the LED will be very dim.

The Photographs Section shows the circuit on breadboard, whereas, the Videos Section shows the circuit in operation.

Code Snippet 2: PCF8574 as output controlling LED's


 #include 

 PCF8574 ex1(0x38);
 byte ledRegister = 0b11111110; //each bit corresponds to a I/O port on the PCF8574
// a '0' means the port is connected to ground
// a '1' means the port is high, i.e., 5V

 void setup() {
 }

 void loop() {
   ex1.write(ledRegister);

   delay(500);

   ledRegister = ledRegister << 1;
   ledRegister = ledRegister + 1;

   if (ledRegister < 0b11111011) { ledRegister = 0b11111110;};

 }
                

Using 4x4 Matrix keypad with PCF8574

The matrix keypad library by 'joeyoung' on github (2) contains several separate arduino format libraries, each one adding to the library Keypad external expansion port communication via an I2C port on the Arduino Nano. The 'Keypad_I2C' is the particular library for use with the PCF8574 expansion chip.

The library by 'joeyoung' builds upon the 'Keypad library for Arduino' (3) which also needs to be installed with the Arduino IDE.

The benefit of using the PCF8574 with the keypad, rather than just using the normal Arduino method of direct connection to the various ports on the Nano (or other Arduino board), is that only 2 pins on the Nano are required.

The following code snippet demonstrates using the PCF8574 to interface the Arduino Nano with a 4x4 matrix keypad (as per the circuit in the Schematics Section). The schematic shows 10 Kohm pull-up resistors for the columns (which is needed for a 'direct connect' version). However, this is not required for the PCF8574A which has lightly pulled up 'input' state for I/O pins - by default it will read as a high logic level, but connecting the GPIO to ground will cause it to read as a low logic level.

Code Snippet 3: 4x4 Matrix keypad connected to PCF8574


#include 
#include 
#include 
#define I2CADDR 0x38

const byte ROWS = 4; //four rows on keypad
const byte COLS = 4; //four columns on keypad

// define the character represented by each key
char keys[ROWS][COLS] = {
 {'1','4','7','0'},
 {'2','5','8','F'},
 {'3','6','9','E'},
 {'A','B','C','D'}
};

byte rowPins[ROWS] = {0, 1, 2, 3}; //PCF8574 pins connect to the row pinouts of the keypad
byte colPins[COLS] = {4, 5, 6, 7}; //PCF8574 pins connect to the column pinouts of the keypad

TwoWire *jwire = &Wire;   //test passing pointer to keypad lib
Keypad_I2C kpd( makeKeymap(keys), rowPins, colPins, ROWS, COLS, I2CADDR, PCF8574, jwire );

void setup(){
 Serial.begin(9600);
 while( !Serial ){ /*wait*/ }
 jwire->begin();
 kpd.begin();
 Serial.print( "start with pinState = " );
 Serial.println( kpd.pinState_set(), HEX );
}
void loop(){

 char key = kpd.getKey();

 if (key){
   Serial.println(key); //echo key to the serial monitor/connected PC
 }
}
               

The circuit is the basic minimum required to enable the Arduino Nano microcontroller to operate after being programmed with a suitable .hex file. So this circuit was only laid out on a breadboard.

Before connecting the Arduino Nano to the USB port, check for any shorts (direct positive voltage to ground connection) as this could damage both the Digispark board and the USB/PC.

As discussed in the Background Section, pull-up 4K7 resistors are mandatory on pin 14 and 15 of the PCF8574. This is probably the most common Gotch'ya.

Another common problem is to remember that the I2C address for the PCF8574 (0100+A2,A1,A0) is different to the PCF8574A (0111+A2,A1,A0).


Note: Video loading can be slow depending on server load.

No video's for this topic.


Comments/Questions

No comments yet.

Add Comment/Question

Only Logged-In Members can add comments

"If we could sell our experiences for what they cost us, we'd all be millionaires".

Please donate any amount to help with hosting this web site.

If you subscribe (only $2/annum) you can view the site without advertisements and get emails abouts updates etc.

X

Sorry!

Only logged-in users with Silver Membership and above can download.


Silver Membership is only $2, so join now!