Arduino – Library Control PCF8574/A for Bus I2C

¿Qué es esto y para qué sirve?

Cuantas veces te has quedado corto con los pines digitales de tu Arduino.
Con esto podremos controlar hasta 128 pines digitales, a través del bus I2C con cualquier versión de Arduino.
Aumentamos el número de pines y nos libramos a la vez de un montón de cableado.
Que podemos pedir más. 🙂


¿Qué necesitamos?

  • Un Arduino que tenga soporte I2C.
  • Una placa PCF8574 por cada 8 canales que deseemos controlar con un máximo de 8 a 16 placas según modelos.

NOTA: Podremos usar un máximo de 8 placas PCF8574 o un maximo de 16 placas, si combinamos 8 del modelo PDC8574 y otras 8 del modelo PF8574A.
Esto es debido ya que parte de la dirección I2C se defino por Hardware.

Los primeros cuatro bits vienen configurados de fábrica y los tres últimos son configurables por hardware, por lo que podemos tener 8 módulos conectados al mismo bus I2C (y si combinamos ambas versiones hasta 16).
Control IO PCF8574 by I2C
PCF8574

¿Dónde encuentro las librerías?

Librería PCF8574 con la que podremos controlar dichas placas a través del bus I2C.

Librería PCF8574_MULTI que nos dará soporte para controlar más de 1 placa PFC8574/A como si de una única placa se tratase.


Diagram

Diagrama de la placa PCF8574.

¿Cómo lo conectamos y como se comunica?

Como cualquier dispositivo I2C la comunicación es a través de dos líneas:

  • SDA: línea serie para los datos.
  • SCL: para la señal de reloj.

Ambas líneas deben de estar conectadas a una alimentación positiva a través de una resistencia pul-up.

El microcontrolador es el que está configurado como maestro y él o los módulos PCF8574 que estén conectados al bus se configuran como esclavos, el maestro es el que realiza las peticiones de lectura o escritura sobre los módulos y controla la señal de reloj (SCL).

La transferencia de datos puede ser inicializada solo cuando el bus no está ocupado.

Una trama de datos en una transmisión consta de:

  • Un bit de inicio de la comunicación.
  • Un byte formado por siete bits que identifican la dirección del esclavo + un bit para indicar si se va hacer una lectura (R/W=1) o escritura (R/W=0) en el módulo.
  • Los datos en sí (de transmisión o recepción); el número de bytes de datos a transmitir o recibir entre el comienzo de la comunicación y la condición de fin de transmisión (bit de parada) no está limitada.
  • Un ACK de reconocimiento. A cada byte transmitido le sigue un bit de reconocimiento, cuando el esclavo recibe un byte este envía el ACK para indicarle al maestro que lo ha recibido correctamente, cuando la petición del maestro al esclavo es de lectura este debe de enviar un ACK al esclavo para indicarle que ha recibido el byte correctamente.
  • Un bit de parada. La condición de parada (P) ocurre cuando la línea SDA cambia de nivel alto a bajo mientras la línea de reloj se encuentra a nivel alto y es controlada por el dispositivo maestro (en nuestro caso el microcontrolador).

Codigo de Ejemplo

#include <PCF8574_MULTI.h>
/*
   Creamos el objeto. 
   Por defecto se configura para controlar 1 placa del modelo PCF8574 y el bus I2C en modo master.
   Podemos configura el objeto para que use un máximo de 8 placas del mismo tipo y la dirección I2C 
   para nuestro Arduino en modo esclavo que nos necesitemos.
 
   Ejemplos:
      Objeto por defecto I2C modo Master, 1 placa del modelo PCF8574.
      PCF8574_MULTI ObjetoA;
 
      En este ejemplo le especificamos el modelo PCF8574A y que use 2 placas con el bus I2C en modo 
      Master.
      PCF8574_MULTI ObjetoB(PCF8574_MULTI_TDEV_PCF8574A, 2);
 
      NOTA I2C: Si se ha ejecutado "Wire.Begin" antes no hará caso al valor que le hemos configurado.
*/
PCF8574_MULTI PCF8574_MULTI_A;
 
void setup() {
  Serial.begin(9600);
 
  /*
     Configuramos el tipo de placa que vamos a usar para obtener las direcciones I2C correctas.
  */
  PCF8574_MULTI_A.TypeDev(PCF8574_MULTI_TDEV_PCF8574A);
 
  /*
     Configuramos el objeto para que use 3 placas, ya que al crearlo no le hemos especificado nada, y por 
     defecto se configura para 1 sola placa.
     NOTA: Una vez iniciado el objeto con la función Begin, no se podrá modificar.
  */
  PCF8574_MULTI_A.NumBoards(3);
 
  /*
     Por defecto el objeto Wire se configura en modo maestro, pero puede ser que necesitemos que este en 
     modo esclavo. 
     Para configura el bus i2c en modo esclavo aremos lo siguiente.
     Nota: Esta configuración hay que hacerla antes de iniciar el objeto PCF8574_MULTI con el comando 
           Begin.
     Nota: Si el objeto Wire se ha iniciado antes en algún otra parte del código, no tendrá efecto este 
           ajuste.
  */
  PCF8574_MULTI_A.AddressWire(0x05);
 
  /*
     Iniciamos el objeto.
     NOTA: Si vamos a usar el bus I2C en modo esclavo tendremos que configura la dirección Wire antes de 
           ejecutar Begin().
     NOTA: Si se ha ejecutado antes en algún sitio Wire.Begin(), se usarán los datos que se hayan 
           ejecutando antes, y la dirección Wire que tengamos configurado en el objeto no tendrá efecto.
     NOTA: Una vez ejecutado Begin ya no se podrá modificar el número de Placas.
  */
  PCF8574_MULTI_A.Begin();
 
  /*
     Configuramos el tipo de pin si es IN o OUT.
     NOTE: Todos los pines por defecto están configurados en modo IN.
     NOTA: El pin número 0 se usa para configura todos los pines a la vez.
  */
  PCF8574_MULTI_A.pinMode(0, OUTPUT); 
  PCF8574_MULTI_A.pinMode(4, INPUT);
  PCF8574_MULTI_A.pinMode(5, INPUT);
}
 
void loop() {
  /*
     Reseteamos todos los pines que están configuradas en modo OUPUT y los ponemos en false.
  */
  PCF8574_MULTI_A.ResetPinStatus();
  delay(500);
 
  /*
     Ponemos todos los pines en modo true. Esto afectara a todos menos al 4 y 5 que están en modo INPUT.
  */
  PCF8574_MULTI_A.digitalWrite(0, PIN_STATUS_ON);
  Serial.println("Todo ON!");
  delay(500);
 
  /*
     Ponemos los pines 1 y 2 en modo False.
  */
  PCF8574_MULTI_A.digitalWrite(1, PIN_STATUS_OFF);
  PCF8574_MULTI_A.digitalWrite(2, PIN_STATUS_OFF);
  Serial.println("OFF 1, 2!");
  delay(500);
 
  /*
     Leemos el estado de los pines 5 y 7.
     También leeremos el pin 2. Esta opción sí que está disponible siempre. Podremos
     leer el estado de cualquier pin, pero no podremos modificar su estado.
  */
  byte ValPIN2 = PCF8574_MULTI_A.digitalRead(2);
  byte ValPIN5 = PCF8574_MULTI_A.digitalRead(5);
  byte ValPIN7 = PCF8574_MULTI_A.digitalRead(7);
  Serial.println("READ STATUS:");
  Serial.print("PIN2:"); Serial.println(ValPIN2);
  Serial.print("PIN5:"); Serial.println(ValPIN5);
  Serial.print("PIN7:"); Serial.println(ValPIN7);
  delay(1000);
}