La forma más fácil de comunicarse con Arduino es usar el puerto serie. También es la herramienta más poderosa para probar y depurar su código.
Material
- Ordenador
- Arduino UNO x2
- Jumper cable M/M x3
Comunicación con el monitor serie
Las funciones de la biblioteca en serie para saber:
- Serial.begin() para inicializar la velocidad de comunicación. La comunicación no funcionará si esto no es correcto
- Serial.print() and Serial.println() para enviar cadenas. El último con un final de línea ‘\ n’
- Serial.write() para enviar un byte a la vez
- Serial.available() para verificar si hay datos en el búfer
- Serial.read() para recibir los datos del puerto
Cargue el siguiente código para probar la comunicación entre la computadora y el Arduino.
char cmd=""; char old_cmd; boolean enable=false; void setup(){ // Initialize serial port Serial.begin(9600); Serial.println("ENTER Commands:"); } void loop(){ old_cmd=cmd; if (Serial.available()){ // Verify that data are available cmd=Serial.read(); // Read data on serial port } if(cmd!=old_cmd){ if(cmd=='O'){ Serial.println("Set to ON"); // Send data to serial port enable=true; }else if(cmd=='F'){ Serial.println("Set to OFF"); // Send data to serial port enable=false; } } if(enable){ Serial.println("System is running"); delay(200); } }
Si escribe O, en la barra de comandos del monitor, debería ver la siguiente pantalla:
Comunicación entre dos Arduinos
Es posible utilizar el puerto serie (Rx0,Tx1) utilizado por el puerto USB para comunicarse entre dos placas Arduino. Para ello, basta con conectar las clavijas de la siguiente manera
- Arduino 1 Rx -> Arduino 2 Tx
- Arduino 1 Tx -> Arduino 2 Rx
- Arduino 1 GND -> Arduino 2 GND
PRECAUCIÓN: Si se utilizan placas diferentes, los niveles de tensión pueden no ser compatibles. En este caso, debes utilizar un convertidor de tensión. Consulta la documentación de cada placa.
Como hemos dicho, los pines 0 y 1 son utilizados por el puerto USB. Para evitar conflictos con el monitor de serie, veremos la biblioteca SoftwareSerial que utiliza otros pines del microcontrolador. Los siguientes ejemplos también son posibles con el puerto serie de hardware. Sólo tienes que sustituir «ArduinoSlave» y «ArduinoMaster» por «Serial» en los siguientes códigos.
En general, las técnicas de intercambio de datos que se comentan a continuación son aplicables a todas las comunicaciones en serie.
Comunicación entre dos Arduinos con SoftwareSerial
Es posible comunicarse entre diferentes dispositivos utilizando un puerto serie como dos Arduinos. Uno será programado como «Maestro» (dar órdenes) y el otro como «Esclavo» (recibir orden y reaccionar).
Un puerto serie está definido por dos cables y una velocidad de comunicación. La biblioteca SoftwareSerial.h se utiliza para definir puertos serie. En este ejemplo, elegimos los pines 2 y 3 como pin de recepción (RX) y transmisión (TX) respectivamente (SoftwareSerial ArduinoSlave (2,3);). La velocidad de comunicación es de 9600bps (ArduinoSlave.begin (9600);
ATENCIÓN : Aquí utilizamos los pines 2 y 3 del Arduino UNO. Dependiendo del microcontrolador utilizado, los pines utilizados para la comunicación en serie pueden ser diferentes. Especialmente para las placas Arduino Mega, Micro, Leonardo. Comprueba la documentación.
Para establecer una comunicación correcta, los paneles deben identificarse adecuadamente y mostrarse en los siguientes esquemas.
En nuestro ejemplo, la placa maestra envía datos y la placa esclava los recibe y los devuelve.
Código «maestro»
#include <SoftwareSerial.h> SoftwareSerial ArduinoSlave(2,3); char cmd=""; char old_cmd; char answer=""; char old_answer; void setup(){ Serial.begin(9600); Serial.println("ENTER Commands:"); ArduinoSlave.begin(9600); } void loop(){ old_cmd=cmd; old_answer=answer; //Read command from monitor if (Serial.available()){ cmd=Serial.read(); } //Read answer from slave if (ArduinoSlave.available()){ answer=ArduinoSlave.read(); } //Send data to slave if(cmd!=old_cmd){ Serial.print("Master sent : "); Serial.println(cmd); ArduinoSlave.write(cmd); } //Send answer to monitor if(answer!=old_answer){ Serial.print("Slave received : "); Serial.println(answer); } }
Código «esclavo»
#include <SoftwareSerial.h> SoftwareSerial ArduinoMaster(2,3); char cmd=""; char old_cmd; void setup(){ ArduinoMaster.begin(9600); } void loop(){ old_cmd=cmd; // Read data from master if (ArduinoMaster.available()){ cmd=ArduinoMaster.read(); } // Send answer to master if(cmd!=old_cmd){ ArduinoMaster.write(cmd); } }
En el monitor en serie de la placa maestra, debería ver la respuesta de la placa esclava.
Con este código puede enviar y recibir un byte a la vez. Los caracteres se codifican siguiendo la tabla ASCII. Consulte la tabla ASCII para ver cómo están codificados. Algunos caracteres no se pueden enviar, como «°» o acentos «é».
Juega con datos
ara algunos proyectos, necesitará obtener más información sobre los diferentes tipos de valor. Una solución rápida es convertir el valor en una cadena y enviarlo con la función print ().
Código maestro
#include <SoftwareSerial.h> SoftwareSerial ArduinoSlave(2,3); String msg; void setup(){ Serial.begin(9600); Serial.println("ENTER Commands:"); ArduinoSlave.begin(9600); } void loop(){ //Read command from monitor readSerialPort(); //Send data to slave if(msg!=""){ Serial.print("Master sent : "); Serial.println(msg); ArduinoSlave.print(msg); msg=""; } } void readSerialPort(){ while (Serial.available()) { delay(10); if (Serial.available() >0) { char c = Serial.read(); //gets one byte from serial buffer msg += c; //add to String } } Serial.flush(); //clean buffer }
Código esclavo
#include <SoftwareSerial.h> SoftwareSerial ArduinoMaster(2,3); String msg; void setup(){ Serial.begin(9600); ArduinoMaster.begin(9600); } void loop(){ readMasterPort(); // Send answer to master if(msg!=""){ ArduinoMaster.print(msg); Serial.print("Master sent : " ); Serial.println(msg); msg=""; } } void readMasterPort(){ while (ArduinoMaster.available()) { delay(10); if (ArduinoMaster.available() >0) { char c = ArduinoMaster.read(); //gets one byte from serial buffer msg += c; //makes the string readString Serial.println(msg); } } ArduinoMaster.flush(); }
Con este código puede enviar cualquier tipo de datos.
Una vez que la comunicación está configurada correctamente y las placas pueden intercambiar datos, puede pensar en cómo usarlo.
Enviar y recibir valor del sensor
Un buen ejemplo de una aplicación es cambiar el brillo de un LED conectado a la placa Slave usando un sensor conectado a la placa Master. A medida que obtenemos los datos en forma de una cadena, tenemos que convertirlos en un entero. La función para realizar la conversión es atoi (). El valor PWM del LED está entre 0 y 255, el valor del sensor entre 0 y 1023 debe convertirse a la función map ().
Código maestro para leer y enviar el valor del sensor
#include <SoftwareSerial.h> SoftwareSerial ArduinoSlave(2,3); String answer; String msg; int intVal=0,oldIntVal=0; void setup(){ Serial.begin(9600); Serial.println("ENTER Commands:"); ArduinoSlave.begin(9600); } void loop(){ //Read sensor intVal=analogRead(A0); //Read answer from slave readSlavePort(); //Send data to slave if(oldIntVal!=intVal){ Serial.print("Master sent : "); Serial.println(intVal); ArduinoSlave.print(intVal); oldIntVal=intVal; } //Send answer to monitor if(answer!=""){ Serial.print("Slave LED PWM value : "); Serial.println(answer); answer=""; } delay(1000); } void readSlavePort(){ while (ArduinoSlave.available()) { delay(10); if (ArduinoSlave.available() >0) { char c = ArduinoSlave.read(); //gets one byte from serial buffer answer += c; //makes the string readString } } }
Código esclavo para recibir y usar el valor del sensor
#include <SoftwareSerial.h> SoftwareSerial ArduinoMaster(2,3); #define ledPin 11 String msg=""; int ledVal=0; int intVal=0,oldIntVal=0; void setup(){ Serial.begin(9600); ArduinoMaster.begin(9600); pinMode(ledPin,OUTPUT); } void loop(){ readMasterPort(); convertMsgToCmd(); // Send answer to master if(intVal!=oldIntVal){ Serial.print("Master sent : " ); Serial.println(intVal); ledVal=map(intVal,0,1023,0,255); Serial.print("led value : "); Serial.println(ledVal); ArduinoMaster.print(ledVal); analogWrite(ledPin,ledVal); oldIntVal=intVal; } } void readMasterPort(){ while (ArduinoMaster.available()) { delay(10); if (ArduinoMaster.available() >0) { char c = ArduinoMaster.read(); //gets one byte from serial buffer msg += c; //makes the string readString } } ArduinoMaster.flush(); } void convertMsgToCmd(){ if (msg.length() >0) { Serial.print("message length : "); Serial.println(msg.length()); char carray1[6]; //magic needed to convert string to a number msg.toCharArray(carray1, sizeof(carray1)); intVal = atoi(carray1); msg=""; } }
Enviar y recibir dos valores de sensor
Para recibir diferentes valores, la idea es definir un separador. En este caso, usamos el carácter «x». Luego, simplemente ubique el carácter en la cadena usando la función indexOf ().
Código maestro para leer y enviar dos valores de sensor
#include <SoftwareSerial.h> SoftwareSerial ArduinoSlave(2,3); String answer; String msg; int intVal1=0,oldIntVal1=0; int intVal2=0,oldIntVal2=0; void setup(){ Serial.begin(9600); Serial.println("ENTER Commands:"); ArduinoSlave.begin(9600); } void loop(){ //Read sensors intVal1=analogRead(A0); intVal2=analogRead(A1); //Send data to slave if(oldIntVal1!=intVal1 || oldIntVal2!=intVal2 ){ Serial.print("Master sent : "); Serial.print(intVal1); Serial.print("x"); Serial.println(intVal2); ArduinoSlave.print(intVal1); ArduinoSlave.print("x"); ArduinoSlave.print(intVal2); oldIntVal1=intVal1; oldIntVal2=intVal2; } delay(1000); //Read answer from slave readSlavePort(); //Send answer to monitor if(answer!=""){ Serial.println("Slave received : "); Serial.println(answer); answer=""; } } void readSerialPort(){ while (Serial.available()) { delay(10); if (Serial.available() >0) { char c = Serial.read(); //gets one byte from serial buffer msg += c; //makes the string readString } } Serial.flush(); } void readSlavePort(){ while (ArduinoSlave.available()) { delay(10); if (ArduinoSlave.available() >0) { char c = ArduinoSlave.read(); //gets one byte from serial buffer answer += c; //makes the string readString } } }
Código esclavo para recibir dos valores de sensor
#include <SoftwareSerial.h> SoftwareSerial ArduinoMaster(2,3); String msg="",m1="",m2=""; int num1=-1,num2=-1; int sep; void setup(){ Serial.begin(9600); ArduinoMaster.begin(9600); } void loop(){ readMasterPort(); convertMsgToMultiCmd(); // Send answer to master if(num1!=-1 && num2!=-1){ Serial.print("Sensor 1 : " ); Serial.println(num1); Serial.print("Sensor 2 : " ); Serial.println(num2); ArduinoMaster.print("Sensor 1 : " ); ArduinoMaster.println(num1); ArduinoMaster.print("Sensor 2 : " ); ArduinoMaster.println(num2); num1=-1; num2=-1; } } void readMasterPort(){ while (ArduinoMaster.available()) { delay(10); if (ArduinoMaster.available() >0) { char c = ArduinoMaster.read(); //gets one byte from serial buffer msg += c; //makes the string readString } } ArduinoMaster.flush(); } void convertMsgToMultiCmd(){ if (msg.length() >0) { Serial.print("message length : "); Serial.println(msg.length()); sep = msg.indexOf('x'); //Serial.println(sep); m1 = msg.substring(0, sep); //get servo id m2 = msg.substring(sep+1, msg.length()); //get servo pos char carray1[6]; //magic needed to convert string to a number m1.toCharArray(carray1, sizeof(carray1)); num1 = atoi(carray1); char carray2[6]; m2.toCharArray(carray2, sizeof(carray2)); num2 = atoi(carray2); msg=""; } }
Enviar y recibir múltiples datos
Es posible que en su aplicación necesite intercambiar una gran cantidad de datos entre dos tarjetas. En este caso, debe cambiar ligeramente la función de conversión. En nuestro ejemplo, suponemos que queremos controlar el estado de un led, la velocidad y la dirección de un motor.
Código maestro para enviar múltiples datos
#include <SoftwareSerial.h> SoftwareSerial ArduinoSlave(2,3); String answer; String msg; int intVal1=0,oldIntVal1=0; int intVal2=0,oldIntVal2=0; void setup(){ Serial.begin(9600); Serial.println("ENTER Commands:"); ArduinoSlave.begin(9600); } void loop(){ //Read command from monitor readSerialPort(); //Read answer from slave readSlavePort(); //Send data to slave if(msg!=""){ Serial.print("Master sent : "); Serial.println(msg); ArduinoSlave.print(msg); msg=""; } //Send answer to monitor if(answer!=""){ Serial.print("Slave received : "); Serial.println(answer); answer=""; } delay(1000); } void readSerialPort(){ while (Serial.available()) { delay(10); if (Serial.available() >0) { char c = Serial.read(); //gets one byte from serial buffer msg += c; //makes the string readString } } Serial.flush(); } void readSlavePort(){ while (ArduinoSlave.available()) { delay(10); if (ArduinoSlave.available() >0) { char c = ArduinoSlave.read(); //gets one byte from serial buffer answer += c; //makes the string readString } } }
Código esclavo para recibir y usar múltiples datos
#include <SoftwareSerial.h> SoftwareSerial ArduinoMaster(2,3); String msg=""; int ledVal=0; int sep; String data[3]; unsigned int data_count=0; void setup(){ Serial.begin(9600); ArduinoMaster.begin(9600); } void loop(){ readMasterPort(); convertMsgToMultiCmd(); //Use data if(data_count==3){ for(int i=0;i<(data_count+1);i++){ switch(i){ case 0: //led status if(data[0]=="ON"){ Serial.println("Switch led ON"); }else if(data[0]=="OFF"){ Serial.println("Switch led OFF"); }else{ Serial.println("Led wrong command"); } break; case 1: //motor PWM Serial.print("Set motor power to : "); Serial.println(stringToInt(data[1])); break; case 2: //motor direction if(data[2]=="forward"){ Serial.println("Motor direction forward"); }else if(data[2]=="backward"){ Serial.println("Motor direction backward"); }else{ Serial.println("Motor wrong command"); } break; } } data_count=0; } } void readMasterPort(){ while (ArduinoMaster.available()) { delay(10); if (ArduinoMaster.available() >0) { char c = ArduinoMaster.read(); //gets one byte from serial buffer msg += c; //makes the string readString } } ArduinoMaster.flush(); } void convertMsgToMultiCmd(){ if (msg.length() >0) { data_count=0; Serial.print("Master sent : "); Serial.println(msg);//Serial.println(msg.length()); do{ sep = msg.indexOf('x'); // expect a string like 0x0021 containing the two servo positions String m1 = msg.substring(0, sep); //get servo id msg = msg.substring(sep+1, msg.length()); //get servo pos data[data_count]=m1; data_count++; } while(sep!=-1); Serial.println("data received : "); for(int i=0;i<(data_count+1);i++) Serial.println(data[i]); msg=""; } } int stringToInt(String s){ char carray1[6]; //magic needed to convert string to a number s.toCharArray(carray1, sizeof(carray1)); return atoi(carray1); }
Una vez que pueda recibir y separar los datos, puede usarlos como desee. Convierta a valor de sensor entero o use una cadena específica para activar acciones.
Con este conocimiento básico, debería poder comunicarse entre sí como un serial servo controller, Bluetooth module u otro microcontrolador como Raspberry Pi .
Si tiene dificultades para establecer una comunicación entre dos dispositivos o si desea decir algo más, deje un comentario o envíenos un mensaje.
Aplicaciones
- Comuníquese con los módulos Arduino y bluetooth HC-06 y HC-05.
- create a serial monitor with Python
Fuentes
Encuentre otros tutoriales y ejemplos en el generador de código automático
Arquitecto de Código
¿Por que usa otros pines para el RX Y TX? Quiero decir, arduino ya tiene predefinidos los pines RX Y TX en el 0 y 1 respectivamente, ¿Hay alguna razón especial?
Los pines RX y TX corresponden al puerto USB. Prefiero mantener estos pines para la comunicación con el PC, debug o otras. Pero puede usar esos pines de la misma manera.