The PCF8574 is an 8-bit I/O expander integrated circuit that provides an additional 8-bit I/O port that can be controlled via I2C. This allows a micro-controller to access and control more I/O pins than it would have available on its own. It can be used in projects that require lots of pins such as LED displays or button matrices. The operating voltage range is: 2.5V to 6.0V.
The advantages over a classical shift register is that it can also read the
pins and with the use of the INT (interrupt) pin, the micro-controller can be
notified when another device starts sending data.
Since this IC is used in the PCF8574 backpack for the alphanumeric LCD modules, I've decided to make a library for it.
Contents
- Using the PCF8574 backpack with the alphanumeric LCD modules
- The library and the PCF8574 IC
- API
- Init function
- Set pin high or as input
- Setting the PCF8574 port
- Set pin and latch it
- Read PCF8574 port
- Code example
- Links
Using the PCF8574 backpack with the alphanumeric LCD modules
These modules are designed for alphanumeric LCD modules to lower the pin count that a micro-controller needs to use to control them. Normally this type of LCD requires 4 pins for data and 3 for control but since this module is based on a pin expander such as PCF8574, all those interface pins can be replaced by just to pins: SDA and SCL that are part of the I2C protocol.
The jumper is used to disable the on-board led (not the LCD backlight led).
The potentiometer is used to adjust the LCD contrast so in case there is nothing displayed on the LCD, try turning it clockwise.
The A0, A1 and A2 pins can be used to change the device I2C address. By default they are pulled to VCC through pull-up resistors so the jumper pads can be used to pull the pins low either by using a 0 ohm resistors or using a solder bridge.
Connecting the PCF8574 adapter to an LCD
Some LCD modules have already mounted an I2C backpack module but in case you have one without you can buy the I2C module separately and connect to the LCD module yourself. The correct mounting position can be seen in this image.
In case your LCD has pins from a previous use, you need to remove them to be
able to connect the I2C module. This can be a bit difficult if you don't have
the proper tools. The cheapest and easiest way is to use a hand desoldering
pump. Just be sure the soldering iron is hot enough so the solder can stay
fluid for 1 or 2 seconds to be sucked by the desoldering pump.
Schematic of the PCF8574 I2C adapter for LCD modules
The library and the PCF8574 IC
A typical implementation of the PCF8574 can be seen in the LCD adapter schematic shown earlier. There, the INT pin is not used since the LCD controller will only send data on request. Depending on the application, the INT pin can be connected to an interrupt pin on the micro-controller to trigger an interrupt whenever a device starts sending data.
PCF8574 I2C address reference
From the
PCF8574 datasheet |
The I2C address of the PCF8574 can be calculated based on the A2, A1 and A0 pins, the first 4 MSB which are 0b0100, and first LCB R/W bit. Example:
Assuming the A2, A1 and A0 are tied to VCC so they are high (H) and the mode is Write (0), the 8-bit address would be:
0b01001110 = 0x4E
Changing the first bit to 1 for read mode will result with the address:
0b01001111 = 0x4F
API
Init function
void PCF_Init(PCF_t* ic, uint8_t addr)
Used to initialize the I2C library at 100kHz which is the maximum I2C frequency specified in the PCF8574 datasheet.
ic
A pointer to a structure object in case there are more than one devices.
addr
The address of the PCF8574 device shifted right by one to ignore the first
read/write bit which will be set by the library. For example if the calculated
address is 0x4F or 0x4E, shifting it by one 0x4F >> 1 = 0x27. Here is an
useful online tool to do this:
https://bitwisecmd.com.
Usage:
PCF_t pcf; PCF_Init(&pcf, 0x27);
Set pin high or as input
void PCF_setPin(PCF_t* ic, uint8_t pin_number) // set pin high void PCF_clearPin(PCF_t* ic, uint8_t pin_number) // set pin as input
Sets a bit to 1 or 0, using a local 8-bit variable where each bit represents a pin on the 8-bit port of the IC. The actual pin state will not change until the latchPort() is used. Useful when you need to change the state of more pins with one I2C command issued only by the latchPort() function. When the pin is set to 0 it can be used as an input pin.
The 8-bit port can also be set directly by writing to the structure member like so:
pcf.portPins = 0xF0
This sets the pins 7:4 to 1.
pin_number
Pin number from 0 to 7.
Setting the PCF8574 port
void PCF_latchPort(PCF_t* ic)
Sends an 8-bit variable set by the setPin() and clearPin() to
set the state of the device port.
Set pin and latch it
void PCF_latchPinHigh(PCF_t* ic, uint8_t pin_number) void PCF_latchPinLow(PCF_t* ic, uint8_t pin_number)
A combination of setPin/clearPin and latchPort. Used when you need to set just one pin with a single function.
Read PCF8574 port
uint8_t PCF_readPort(PCF_t* ic)
Returns an 8-bit variable representing the state of pins of the PCF8574 port.
Code example in C
#include "PCF8574.h" int main(void){ // PCF device 1 PCF_t pcf; // Initialization PCF_Init(&pcf, PCF8574_ADDRESS); // Virtually set pin 7 high and pin 2 low (input) PCF_setPin(&pcf, 7); PCF_clearPin(&pcf, 2); // Send an I2C command to the device // to actually set the pins PCF_latchPort(&pcf); // Set pin 0 high in one go // Equivalent to: // PCF_setPin(&pcf, 0); // PCF_latchPort(&pcf); PCF_latchPinHigh(&pcf, 0); // Read pins uint8 pcf1_port = 0; pcf1_port = PCF_readPort(&pcf); while(1){ } }
Links
v1.0 |
PCF8574.h |
PCF8574.c |
I2C (TWI) library - project page |
twi.h |
twi.c |
External links |
PCF8574 datasheet |
Changelog |
v1.0 (22-01-2025) - Public release under GNU GPL v3 license. |
No comments:
Post a Comment