En este artículo aprenderás a comunicar dos Arduinos entre sí utilizando el puerto Serie. Con esta aplicación, podrás implementar muchos sistemas de monitoreo y control, transmisión de datos, entre muchas otras aplicaciones.
Tabla de Contenidos
Comunicación por el puerto Serie
Como vimos en un artículo anterior, la placa Arduino contiene un puerto de comunicación Serie, que consta de dos pines: uno de transmisión Tx
y uno de recepción Rx
. Este puerto está internamente conectado al puerto USB, por lo que podemos visualizarlo en un monitor de puerto Serie en nuestra computadora, como lo hicimos en el artículo anterior, si quieres verlo te dejo el video:
¿Cómo comunicar dos Arduinos entre sí?
Si bien el caso anterior es de utilidad, ¿cómo le puedo hacer para comunicar dos placas Arduino entre ellas, sin necesidad de la computadora? Es precisamente lo que veremos el día de hoy.
Muchas veces puede ser interesante que un Arduino le envíe órdenes de control a otro, por ejemplo, cuando estamos monitoreando temperatura y queremos enviarle ese dato a otra placa Arduino para que la almacene, o realice una operación de control como encender un ventilador. Los casos de aplicación son infinitos, te invito a que me comentes qué proyecto se te ocurre con esta idea.
Para explicarte como realizar esta comunicación, realizaremos varios ejemplos.
Encender y apagar LEDs de un Arduino a otro
El primer ejemplo será encender y apagar un LED enviando la orden desde un Arduino distinto como lo muestra el siguiente diagrama. Es importante conectar la terminal de GND del Arduino 1 con el GND del Arduino 2.
Es muy importante que antes de programar cada Arduino, desconectes los cables que unen los dos puertos Serie, ya que este puerto Serie está internamente conectado al puerto USB por lo que es utilizado al reprogramar.
Vamos a agregar dos botones al Arduino 1, uno para encender y uno para apagar el LED, cuando se pulsen, enviará a través del puerto Serie la instrucción de encender el LED en el Arduino 2.
Utilizaremos el siguiente código en el Arduino 1
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
#include "GFButton.h" int pinBotonON = 8; int pinBotonOFF = 9; GFButton boton1(pinBotonON); GFButton boton2(pinBotonOFF); void setup() { pinMode(pinBotonON, INPUT); pinMode(pinBotonOFF, INPUT); boton1.setPressHandler(botonON_pulsado); boton2.setPressHandler(botonOFF_pulsado); Serial.begin(9600); } void loop() { boton1.process(); boton2.process(); } void botonON_pulsado(GFButton & btn){ Serial.print("LED1ON_"); } void botonOFF_pulsado(GFButton & btn){ Serial.print("LED1OFF_"); } |
Recuerda que para evitar los rebotes en el push button, hay que utilizar una librería cómo lo vimos acá.
Sin embargo, esta librería se puede utilizar de una manera más completa, para asegurarnos de eliminar siempre los rebotes. Para eso creamos un evento que en este ejemplo lo estamos llamando «boton1_pulsado
» que solamente se llamará cuando efectivamente sea pulsado y ejecutará la función void boton1_pulsado(GFButton & btn)
solamente una vez.
Si quieres aprender esta manera mejorada de eliminar rebotes déjame tu petición en los comentarios y subiré un video explicando con mayor detalle esta función.
La idea es que al enviar una «palabra clave» el Arduino 2 la reciba y solamente si recibe esta instrucción, realice el encendido del LED. La palabra clave será «LED1ON_» para encender el LED y «LED1OFF_» para apagarlo.
En la función loop
se agregan dos líneas boton1.process(); boton2.process();
estas líneas mandan revisar si los botones fueron pulsados, cuando se detecte el pulso, se ejecutará la función correspondiente al boton1 o boton2 según corresponda. Por ejemplo, si se pulsa el botón 1, se ejecutará la función botonON_pulsado
y se enviará la palabra clave «LED1ON_» por el puerto Serie.
Observa que he agregado un guion bajo (_) al final de la palabra clave, esto nos va a servir para determinar el final de la palabra clave.
En el Arduino 2 agregaremos el siguiente código:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
String inputString = ""; // a String to hold incoming data bool stringComplete = false; // whether the string is complete void setup() { pinMode(8, OUTPUT); Serial.begin(9600); inputString.reserve(200); } void loop() { if (stringComplete) { if (inputString == "LED1ON_") { digitalWrite(8, HIGH); } else if (inputString == "LED1OFF_") { digitalWrite(8, LOW); } inputString = ""; stringComplete = false; } } void serialEvent() { while (Serial.available()) { char inChar = (char)Serial.read(); inputString += inChar; if (inChar == '_') { stringComplete = true; } } } |
Con este código decodificaremos el mensaje que entre por el puerto Serie. Lo primero a observar es la función que viene hasta el final llamada serialEvent
, esta función detecta cuando ha llegado un mensaje por el puerto Serie. Posteriormente guarda todo lo que ha llegado como mensaje en una variable llamada inputString
caracter a caracter hasta que detecta el caracter de final, que para nuestro caso es el guion bajo «_».
En el loop principal, revisamos si el mensaje que llegó ha sido completamente recibido, si fue así, revisa si llegó «LED1ON» o LED1OFF», para realizar el encendido o apagado del LED según corresponda.
Si todo ha funcionado correctamente, deberías de ver algo así:
Este tipo de comunicación se conoce como unidireccional, ya que el Arduino 1 solamente funciona como emisor y el Arduino 2 solamente funciona como receptor, la información solamente tiene un camino.
Algunas recomendaciones:
- No abrir el puerto Serie de tu computadora, ya que interfiere con la sincronización de la información.
- Siempre desconectar los cables que unen los puertos Serie antes de reprogramar.
- No utilizar una velocidad alta de transmisión, aunque no debería de haber problemas, con 9600 baudios es suficiente.
- Evitar enviar mensajes demasiado largos (aunque si se puede).
- No utilizar cables mayores a 10 metros con una velocidad de 9600 baudios.
¿Te está gustando este artículo?
Te invito a descargar totalmente gratis la Guía de Inicio en Arduino
Encontrarás mucha información extra, conceptos y sobre todo podrás llevarla contigo en todo momento
Comunicar 2 Arduinos con puerto Serie y LCD
Ahora realizaremos una comunicación full-dúplex; es decir, el Arduino 1 envía una orden, el Arduino 2 la recibe, la ejecuta y responde con un mensaje, por último, el Arduino 1 la recibe y ejecuta una acción, en nuestro caso será mostrar en un display un mensaje.
Conectaremos el siguiente diagrama utilizando un LCD:
Para esto, utilizaremos el código mostrado a continuación:
ARDUINO 1
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 |
#include "GFButton.h" #include <LiquidCrystal.h> LiquidCrystal lcd(7,6,5,4,3,2); // Crear el objeto lcd con R/W a GND int pinBotonON = 8; int pinBotonOFF = 9; String inputString = ""; // a String to hold incoming data bool stringComplete = false; // whether the string is complete GFButton boton1(pinBotonON); GFButton boton2(pinBotonOFF); void setup() { inputString.reserve(200); pinMode(pinBotonON, INPUT); pinMode(pinBotonOFF, INPUT); boton1.setPressHandler(botonON_pulsado); boton2.setPressHandler(botonOFF_pulsado); Serial.begin(9600); lcd.begin(16,2); // Inicializar el lcd 16x2 lcd.setCursor(0,0); // Mover el cursor a la posición 0,0 lcd.print("Automatizacion"); lcd.setCursor(0,1); // Mover el cursor a la posición 0,1 lcd.print("para Todos"); delay(2000); // Realizar una pausa de 5 segundos } void loop() { boton1.process(); boton2.process(); if (stringComplete) { if (inputString == "L1ON_") { lcd.clear(); lcd.setCursor(0, 0); lcd.print("LED 1 -> ON"); } else if (inputString == "L1OFF_") { lcd.clear(); lcd.setCursor(0, 0); lcd.print("LED 1 -> OFF"); } inputString = ""; stringComplete = false; } } void botonON_pulsado(GFButton & btn){ Serial.print("LED1ON_"); } void botonOFF_pulsado(GFButton & btn){ Serial.print("LED1OFF_"); } void serialEvent() { while (Serial.available()) { char inChar = (char)Serial.read(); inputString += inChar; if (inChar == '_') { stringComplete = true; } } } |
Se agregó al código anterior lo necesario para inicializar el LCD como lo vimos en este artículo.
Posteriormente, utilizamos la misma lógica que en el ejemplo anterior, agregamos una función para detectar cuando ha llegado algo por el puerto serie mediante la función serialEvent()
, esta función se ejecuta de manera automática justo cuando llegó algo al puerto serie, la llamaremos interrupción por el puerto serie, más adelante te enseñaré a utilizar a detalle las interrupciones en Arduino.
Cada vez que al Arduino 1 le llegue el mensaje L1ON_
mandará a escribir en el LCD el mensaje "LED 1 -> ON"
y cuando al Arduino 1 le llegue el mensaje L1OFF_
mandará a escribir en el LCD el mensaje "LED 1 -> OFF"
.
En el ARDUINO 2:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
String inputString = ""; // a String to hold incoming data bool stringComplete = false; // whether the string is complete void setup() { pinMode(8, OUTPUT); Serial.begin(9600); inputString.reserve(200); } void loop() { if (stringComplete) { if (inputString == "LED1ON_") { digitalWrite(8, HIGH); Serial.print("L1ON_"); } else if (inputString == "LED1OFF_") { digitalWrite(8, LOW); Serial.print("L1OFF_"); } inputString = ""; stringComplete = false; } } void serialEvent() { while (Serial.available()) { char inChar = (char)Serial.read(); inputString += inChar; if (inChar == '_') { stringComplete = true; } } } |
Realmente este código es el mismo que utilizamos anteriormente, solamente agregamos una respuesta por el puerto Serie cada vez que llegue el mensaje de encender o apagar.
Los mensajes que envían o reciben los Arduinos, pueden ser personalizados, pueden llevar solamente un caracter o string –como en este caso. Te mostré este ejemplo con strings, ya que es más interesante que solamente enviando un caracter y el funcionamiento es prácticamente el mismo.
Aplicaciones
Realmente este ejemplo demostrativo es muy sencillo, pero puedes aplicarlo a cualquier proyecto de interés, por ejemplo:
Puedes agregar un módulo de comunicación inalámbrico en la salida de cada puerto Serie, de esta manera evitarías el uso de cables para comunicar ambos sistemas, algo así:
En este caso he agregado dos módulos de comunicación ZigBee, son módulos de comunicación inalámbrica de bajo consumo energético, muy utilizados para la comunicación entre dispositivos electrónicos. Con ellos, la distancia de comunicación puede ir desde unos cuantos metros hasta algunos kilómetros (utilizando los accesorios adecuados), yo personalmente los he utilizado para rangos de unos cuantos metros hasta 200 metros sin ningún problema ni antenas adicionales.
También puedes reemplazar el módulo por un emisor/receptor infrarrojo, WiFi, etcétera. Realmente las opciones son demasiadas, lo importante es que aprendas el principio de funcionamiento y tú lo apliques en tu proyecto de acuerdo a tus necesidades.
Si quieres ver un ejemplo como el mostrado anteriormente, déjame tus comentarios solicitando este ejemplo.
¿Qué te ha parecido el artículo de esta ocasión?, déjame tus comentarios, dudas, sugerencias y sobre todo comparte tus resultados!
Recuerda visitar nuestras redes sociales
Hola. Estuve trabajando la comunicación serial. Usé su código para la recepción pero tengo un inconveniente. La primera palabra la recibe y ejecuta la instrucción de encender el bombillo, pero no vuelve a realizar instrucción de apagarlo con la palabra correspondiente ED1OFF_. Me doy cuenta que la función void serialEvent() funciona siempre, por que coloco una instrucción Serial.println(inputString); al final de la función y devuelve lo que escribo en el puerto serial desde el PC. Pero al parecer no está realizando mas de 1 vez la primera comparación después void loop (), es decir no se está realizando la instrucción if (stringComplete) nuevamante después de hacerlo por primera vez. Agradezco su ayuda para resolver este inconveniente.
Hola Edgar, podrías compartirme el código que estás implementando? Solo así podría apoyarte para verificar que todo esté correcto. Probablemente no estás borrando el buffer. Saludos!
Buenisimo articulo, me ha servido de mucha ayuda. Me gustaria ver los codigos para introducir un elemento de comunicacion inalambrico como los esp32lora.
Hola Juan Manuel, lo tendré en cuenta para agregarlo en un futuro. Muchas gracias por tus comentarios.
Enviar variables analógicas por el puerto serie y recibirlas?
Hola Edgar, podrías explicar un poco más tu duda? Para enviar algo por el puerto serie tiene que ser en digital, por lo que la variable analógica primero deberá convertirse a digital. Sigo atento. Saludos!
Saludos. Gracias por compartir el conocimiento. Por favor, me podrias dar una orientacion, Necesito
controlar varias variables en dos arduinos conectados por el puerto serial(tx, rx), una de ellas se llamada «velocidad» ; de tal manera que si aumento o disminuyo la velocidad.en el master, igualmente se refleje en el arduino esclavo; pero cada uno de los botones de control, lo atiende una interrupccion( attachinterrupto(pin)……). La cuestion es que no se, con que instrucion enviar el dato serialmente( NO COMO CHAR, SINO COMO EL VALOR DEL DATO); igualmente en el arduino esclavo necesito recuperar el valor del dato para visualizarlo, ademas, no se, si la variable en cuestion, la tengo que inrementar o disminuir en el arduino esclavo, o el valor enviado desde el master ya lo envio
procesado, es decir, su respectivo valor, sea aumentado o disminuido.
Gracias por su valiosa colaboracion.
Hola Gerardo, siempre que envías por le serial lo enviará y recibirá como una cadena de chars, o propiamente un String. Lo que puedes hacer es al recibir, si son puros números, puedes convertirlo a tipo entero (int) con la función myString.toInt(); Sigo atento a tus duudas. Saludos!
muchas gracias por la gran ayuda.
Hola; buenas, escribo desde Costa Rica, muy completo este elaborado articulo, gracias por sacar el tiempo para elaborarlo de forma tan detalla, llegué a él, por que necesito realzar un proyecto en donde requiero enviar datos serial de forma inalámbrica y económica como lo es por medio de un emisor y receptor infrarrojo (se menciona como una de las posibilidades en este trabajo) dejare mi correo de contacto, por si tiene a la mano algún información que me pueda guiar de una forma mas directa para la realización de este proyecto que apenas tengo en mente y nada concreto. gracias saludos,
luis.hernandez.garcia@una.cr
Hola Luis, con mucho gusto y muchas gracias por tus comentarios. Te recomiendo que realices pruebas, los sensores infrarojos no son complicados de utilizar; sin embargo, entra en juego variables como la luz ambiente, la distancia, etc. Te recomiendo que si la distancia de comunicación es mayor, puedes buscar transmisores/receptores de radiofrecuencia, puede que sea más fácil de evitar la interferencia. Saludos!
Hola estimado,excelente tu articulo, gracias por compartirlo, por favor podrias ayudarme a leer desde una esp32 que tiene grbl para cnc cual es el valor de XYZ para mostrarlo en mi LCD que tengo en mi arduino uno, ambas estan conectadas, pero no se como traerme los valores, gracias de antemano por todo, un abrazo.
Hola gracias por tu comentario. Puedes dejar tu duda para poderte apoyar. Saludos!
Buenas tardes este es el código implementado.
String inputString = «»; // a String to hold incoming data
bool stringComplete = false; // whether the string is complete
void setup() {
pinMode(8, OUTPUT);
Serial.begin(9600);
inputString.reserve(200);
}
void loop() {
if (stringComplete) {
if (inputString == «LED1ON_») {
inputString = «»;
digitalWrite(8, HIGH);
Serial.print(«L1ON_»);
}
else if (inputString == «LED1OFF_») {
inputString = «»;
digitalWrite(8, LOW);
Serial.print(«L1OFF_»);
}
stringComplete = false;
}
}
void serialEvent() {
while (Serial.available()) {
char inChar = (char)Serial.read();
inputString += inChar;
if (inChar == ‘_’) {
stringComplete = true;
}
}
}
Mi problema es que solo ejecuta una vez la selección de encender o apagar el led. Posterior a ello, ya no me ejecuta esta parte:
if (inputString == «LED1ON_») {
inputString = «»;
digitalWrite(8, HIGH);
Serial.print(«L1ON_»);
}
else if (inputString == «LED1OFF_») {
inputString = «»;
digitalWrite(8, LOW);
Serial.print(«L1OFF_»);
}