Guía completa: Cómo elegir un controlador industrial
I2C es un bus síncrono de dos hilos: SDA lleva los datos y SCL el reloj, y un maestro habla con esclavos que tienen cada uno una dirección de 7 bits. En un PLC de Industrial Shields basado en Arduino, conectas los dispositivos a los bornes SDA y SCL del PLC (pines 20 y 21 de Arduino en el M-Duino 21+), añades resistencias pull-up y usas la librería Wire: beginTransmission(), write() y endTransmission() para escribir, requestFrom() y read() para leer. I2C está pensado para distancias cortas, dentro del armario.
Todos los controladores de Industrial Shields basados en Arduino, M-Duino y Ardbox, tienen un puerto I2C, igual que el ESP32 PLC y el Raspberry PLC. Muchos dispositivos tienen conexión I2C: convertidores analógico a digital, relojes de tiempo real, memorias EEPROM, pantallas, acelerómetros y brújulas. Esta guía usa un M-Duino 21+. El código de Wire es el mismo en los demás modelos basados en Arduino: solo cambian los bornes SDA y SCL.
¿Cómo funciona el protocolo I2C?
Philips creó I2C (Inter-Integrated Circuit) en 1982 para conectar chips dentro de sus productos. Hoy la especificación la publica NXP (UM10204). El maestro genera el reloj e inicia cada transferencia. Los esclavos nunca inician una transferencia y no hablan entre ellos.
- Inicio. El maestro pone SDA a nivel bajo mientras SCL está a nivel alto.
- Dirección y sentido. 7 bits de dirección y 1 bit de lectura o escritura.
- ACK. El esclavo con esa dirección pone SDA a nivel bajo durante un ciclo de reloj para decir "estoy aquí".
- Datos. Uno o más bytes, cada uno seguido de un ACK. Cuando el maestro lee, responde al último byte con NACK.
- Parada. El maestro libera SDA mientras SCL está a nivel alto. Con un inicio repetido en lugar de una parada, el maestro mantiene el bus e inicia otra transferencia.

| Modo | Velocidad | Wire.setClock() en el AVR |
|---|---|---|
| Modo estándar | 100 kbit/s | 100000 |
| Modo rápido | 400 kbit/s | 400000 |
| Modo rápido plus | 1 Mbit/s | No en todos los procesadores |
| Modo de alta velocidad | 3,4 Mbit/s | No en todos los procesadores |
La dirección de 7 bits da 128 combinaciones. La especificación reserva de 0x00 a 0x07 y de 0x78 a 0x7F, así que los dispositivos usan de 0x08 a 0x77. Cada dispositivo del bus necesita su propia dirección. Muchos dispositivos permiten cambiar los últimos bits con pines de dirección.
Ventajas y límites de I2C

| Ventajas | Límites |
|---|---|
| Dos hilos (más la masa) para muchos dispositivos | Distancia corta: la capacidad del bus limita la longitud del cable |
| Cada byte se reconoce (ACK), así el maestro sabe si un dispositivo responde | Sin CRC: el ACK dice que ha llegado un byte, no que su contenido sea correcto |
| Direccionamiento en el bus, sin una línea de selección por dispositivo | Semidúplex y velocidad media |
| Compatible con la mayoría de microcontroladores y sensores | Un dispositivo que mantiene SDA a nivel bajo puede bloquear todo el bus |
Cableado y resistencias pull-up
Conecta SDA con SDA y SCL con SCL en todos los dispositivos, y conecta las masas. SDA y SCL son líneas de drenador abierto: los dispositivos solo las llevan a nivel bajo, y una resistencia pull-up a Vcc las devuelve a nivel alto.

- Pull-ups.
Wire.begin()activa las pull-up internas del microcontrolador, pero son débiles: los flancos suben despacio y el bus solo funciona a baja velocidad y con cables cortos. Para un bus fiable, añade pull-ups externas de 1 kΩ a 4,7 kΩ. Industrial Shields tiene un módulo de resistencias pull-up I2C para carril DIN. - Nivel lógico. Los microcontroladores del M-Duino y del Ardbox trabajan a 5 V. Un dispositivo de 3,3 V necesita un adaptador de nivel.
- Distancia. Mantén el cableado I2C corto y dentro del armario. Para distancias mayores usa un extensor de bus I2C, o un bus de campo como RS-485 con Modbus.
- Direcciones ocupadas. En los modelos con expansores de E/S en el bus I2C, como el Raspberry PLC, algunas direcciones ya están ocupadas. La hoja de datos del Raspberry PLC las indica.
¿Dónde están SDA y SCL en el PLC?
Cada PLC tiene los bornes SDA y SCL en su conector de comunicaciones. Consulta la guía de usuario de tu modelo. En el M-Duino 21+, SCL es el pin 21 de Arduino y SDA es el pin 20. En el Ardbox HF+, SDA es el pin 2 y SCL es el pin 3.

La librería Wire
El IDE de Arduino incluye la librería Wire (Wire.h), que controla el hardware I2C del microcontrolador. Con las placas de Industrial Shields instaladas, encontrarás sus ejemplos en File > Examples > Wire.

| Función | Qué hace |
|---|---|
Wire.begin() | Inicia I2C como maestro. Wire.begin(address) lo inicia como esclavo con esa dirección |
Wire.setClock(100000) | Fija el reloj: 100000 (estándar) o 400000 (rápido) |
Wire.beginTransmission(address) | Prepara una escritura al esclavo con esa dirección de 7 bits |
Wire.write(data) | Pone en cola uno o más bytes. Devuelve el número de bytes en cola |
Wire.endTransmission(stop) | Envía los bytes en cola. Con false termina con un inicio repetido y mantiene el bus. Devuelve 0 si ha funcionado, 1 datos demasiado largos, 2 NACK en la dirección, 3 NACK en los datos, 4 otro error, 5 timeout |
Wire.requestFrom(address, quantity, stop) | Lee un número de bytes de un esclavo. Devuelve los bytes recibidos |
Wire.available() y Wire.read() | Número de bytes en espera, y el byte siguiente |
Wire.onReceive(handler) y Wire.onRequest(handler) | En un esclavo: funciones que se llaman cuando el maestro envía datos o los pide |
Wire.setWireTimeout(us, reset) | Tiempo máximo de una transferencia, para que un bus bloqueado no detenga el programa |
Ejemplo completo: explora el bus y lee un registro
Este sketch convierte el PLC en maestro I2C. Al arrancar explora el bus y muestra la dirección de cada dispositivo que responde. Después, cada segundo, lee dos bytes de un registro de un dispositivo: escribe el número de registro, mantiene el bus con un inicio repetido y lee la respuesta. Cambia DEVICE_ADDRESS, FIRST_REGISTER y BYTES_TO_READ con los datos de tu dispositivo.
// I2C master on an Industrial Shields Arduino based PLC (M-Duino, Ardbox)
// 1. Scans the bus and prints the address of every device that answers.
// 2. Reads N bytes from a register of one device (write pointer + repeated start).
#include <Wire.h>
const uint8_t DEVICE_ADDRESS = 0x48; // 7-bit address of your device (see its datasheet)
const uint8_t FIRST_REGISTER = 0x00; // register to read
const uint8_t BYTES_TO_READ = 2;
void scanBus() {
uint8_t found = 0;
for (uint8_t address = 0x08; address <= 0x77; address++) { // 0x00-0x07 and 0x78-0x7F are reserved
Wire.beginTransmission(address);
if (Wire.endTransmission() == 0) { // 0 = the device answered with ACK
Serial.print("Device found at 0x");
Serial.println(address, HEX);
found++;
}
}
if (found == 0) Serial.println("No I2C device found: check SDA, SCL, GND and pull-ups");
}
bool readRegisters(uint8_t address, uint8_t reg, uint8_t *buffer, uint8_t length) {
Wire.beginTransmission(address);
Wire.write(reg); // register pointer
if (Wire.endTransmission(false) != 0) { // false = repeated start, keep the bus
return false; // NACK, bus error or timeout
}
if (Wire.requestFrom(address, length) != length) {
return false;
}
for (uint8_t i = 0; i < length; i++) {
buffer[i] = Wire.read();
}
return true;
}
void setup() {
Serial.begin(115200);
Wire.begin(); // this PLC is the master
Wire.setClock(100000); // standard mode, 100 kHz
Wire.setWireTimeout(25000, true); // 25 ms: do not hang if a device blocks the bus
scanBus();
}
void loop() {
uint8_t data[BYTES_TO_READ];
if (readRegisters(DEVICE_ADDRESS, FIRST_REGISTER, data, BYTES_TO_READ)) {
uint16_t value = ((uint16_t)data[0] << 8) | data[1]; // most devices send the high byte first
Serial.print("Register value: ");
Serial.println(value);
} else {
Serial.println("Read failed");
if (Wire.getWireTimeoutFlag()) {
Wire.clearWireTimeoutFlag();
Serial.println("I2C timeout: the bus was reset");
}
}
delay(1000);
}
- La exploración usa una escritura vacía:
endTransmission()devuelve 0 cuando un dispositivo reconoce su dirección. endTransmission(false)deja el bus con un inicio repetido, como esperan la mayoría de dispositivos con registros entre la escritura del registro y la lectura.setWireTimeout(25000, true)detiene una transferencia después de 25 ms y reinicia el hardware I2C, así un dispositivo bloqueado no congela el programa del PLC.- La mayoría de dispositivos envían primero el byte alto. Comprueba el orden de los bytes y el significado del registro en la hoja de datos de tu dispositivo.
Qué hemos probado. El sketch compila sin errores para el M-Duino 21+ con las placas AVR de Industrial Shields (9.478 bytes de memoria de programa, 3,6 %). No lo hemos ejecutado con un dispositivo I2C para esta actualización.
Problemas habituales con I2C
| Qué ves | Causa habitual | Qué revisar |
|---|---|---|
| La exploración no encuentra ningún dispositivo | Cableado, alimentación o pull-ups | SDA y SCL sin cruzar, masa común, dispositivo alimentado, pull-ups externas, nivel lógico |
endTransmission() devuelve 2 | Ningún dispositivo responde en esa dirección | La dirección de la hoja de datos es de 7 bits. Algunas hojas la dan ya desplazada con el bit R/W (8 bits) |
| Las lecturas fallan de vez en cuando | Cable largo, pull-ups débiles o ruido eléctrico | Cableado más corto, pull-ups más fuertes, 100 kHz en lugar de 400 kHz |
| El programa se detiene | Un dispositivo bloquea el bus | Wire.setWireTimeout() y la alimentación del dispositivo |
| Dos dispositivos con la misma dirección | El mismo modelo en el mismo bus | Los pines de dirección del dispositivo, o un multiplexor I2C |
Un dispositivo I2C en un proyecto con PLC. La PLC Solution Library tiene un ejemplo completo que lee un convertidor analógico a digital ADS1015 por I2C, con entradas diferenciales y ganancia automática.
Preguntas frecuentes sobre I2C en un PLC basado en Arduino
¿Cuántos dispositivos puedo conectar al bus I2C?
Hasta 112 direcciones con direccionamiento de 7 bits (de 0x08 a 0x77). En la práctica, el límite es la capacidad del bus: muchos dispositivos y cables largos hacen más lentos los flancos.
¿Qué longitud puede tener el cable I2C?
I2C está pensado para conexiones en una placa o dentro de un armario. La longitud depende de la velocidad, las pull-ups y la capacidad del cable. Para conexiones entre armarios, usa un extensor de bus o un bus de campo como RS-485.
¿El PLC puede trabajar como esclavo I2C?
Sí. Inícialo con Wire.begin(address) y registra Wire.onReceive() y Wire.onRequest().
¿Qué diferencia hay entre I2C y SPI?
I2C usa dos líneas compartidas y direcciones. SPI usa cuatro líneas, una selección de chip por dispositivo, y es más rápido y dúplex completo. Los dos son para distancias cortas.
¿Qué valor de pull-up debo usar?
4,7 kΩ es un valor habitual a 100 kHz. Valores más bajos, hasta 1 kΩ aproximadamente, dan flancos más rápidos para cableados más largos o 400 kHz, siempre que todos los dispositivos puedan absorber la corriente.
Más sobre comunicaciones en un PLC
- Cómo usar SPI en un PLC basado en ESP32
- Conceptos básicos del RS-485 de un PLC industrial
- Modbus RTU con PLC basados en Arduino y ESP32
- Comunicaciones y protocolos usados en la automatización industrial
- Cómo instalar las placas de Industrial Shields en el IDE de Arduino
Mira el M-Duino 21+, el Ardbox Analog y la guía para elegir un controlador industrial.