USANDO EL PUERTO SERIE DEL ARDUINO
(15/12/13)
En este tutorial vamos a explicar cómo se usa el puerto serie del Arduino, ya que este se usa en varias ocasiones para transmitir y recibir datos de otros dispositivos como un PC o de otro microcontrolador.
El puerto serie del Arduino Uno usa los pins 0(RX) y 1(TX). Estos están conectados al controlador FTDI (ATmega 16u2) que es el que permite la traducción del formato serie TTL a USB. Estos pins no pueden ser utilizados mientras se usa la comunicación serie.
El puerto serie del Arduino utiliza un buffer de 64 bytes. Para entender el uso del buffer normalmente se usa el ejemplo de la sala de espera del médico. Esta sala de espera es el buffer, que tiene una capacidad de 64 pacientes. Cada paciente es 1 byte. El médico va atendiendo cada paciente uno por uno por orden de llegada. La enfermera que deja entrar a los pacientes a la sala de espera son los baudios (la velocidad de recibir datos), cuando más grande sea la velocidad, más gente entra en la sala. Si la sala está completa con 64 pacientes y llegan más, estos serán rechazados (drop o loss).
Para usar el puerto serie del Arduino hay varias funciones de programación que hay que saber:
-begin(velocidad) Abre el puerto serie y establece la velocidad. La velocidad de conexión (baudios o Baud Rate) es la velocidad que llegan los datos al puerto serie. Normalmente se usa 9600bps o 115000bps.
-available() Esta función devuelve el estado del buffer del puerto serie y rebela si hay datos dentro de este.
-read() Lee un carácter del buffer. Es importante entender que lee un solo carácter (byte).
-write() Escribe caracteres a través del puerto serie. A diferencia de read(), escribe tantos caracteres como quieras.
-print() Imprime los datos al puerto serie como texto ASCII.
-println() Imprime los datos al puerto serie como texto ASCII seguido de un retorno de carro (ASCII 13, o ‘\r’) y un carácter de avance de línea (ASCII 10, o ‘\n’). Este comando tiene la misma forma que Serial.print ().
-flush() Vacía el buffer de entrada de datos.
-end() Desactiva la comunicación serie, permitiendo a los pines 0(RX) y 1 (TX) ser usadoscomo entradas o salidas digitales. Para volver a activar la comunicación serie, llamar la función Serial.begin().
Para enviar y recibir datos, el Arduino utiliza el código ASCII
Enviar datos del Arduino al PC
Para empezar, vamos a enviar datos desde el Arduino al PC. El IDE de Arduino tiene un Monitor Serial para comunicarse con el PC.
Vamos a enviar el valor 81 en formato decimal al PC. El programa sería el siguiente:
void setup() { Serial.begin(9600); } void loop() { Serial.println(81); }
Si cargamos el programa al Arduino y abrimos el Monitor Serial, vemos que va imprimiendo el valor 81 constantemente.
También podemos determinar el formato de salida del valor que enviamos (decimal, binario, hexadecimal, octal o byte).
Enviar el valor 81 en formato decimal, podemos hacerlo con el programa anterior o también con este:
void setup() { Serial.begin(9600); } void loop() { Serial.println(81,DEC); //Imprime "81" }
Para enviar el valor 81 en formato hexadecimal:
void setup() { Serial.begin(9600); } void loop() { Serial.println(81,HEX); //Imprime "51" }
Para enviar el valor 81 en formato octal:
void setup() { Serial.begin(9600); } void loop() { Serial.println(81,OCT); //Imprime "121" }
Para enviar el valor 81 en formato binario:
void setup() { Serial.begin(9600); } void loop() { Serial.println(81,BIN); //Imprime "1010001" }
Y para enviar el valor 81 como un byte se tiene que usar la función write()
void setup() { Serial.begin(9600); } void loop() { Serial.write(81); //Imprime "Q", el qual representa el carácter ASCII del valor "81" }
Recibir datos del PC
Ahora vamos a invertir el proceso, vamos a enviar datos del PC al Arduino. El programa básico para recibir datos es el siguiente:
void setup() { Serial.begin(9600); } void loop() { if(Serial.available()>0) //Comprobamos si en el buffer hay datos { int dato=Serial.read(); //Lee cada carácter uno por uno y se almacena en una variable Serial.println(dato); //Imprimimos en la consola el carácter recibido } }
Y aquí se complica un poco la cosa. ¿Por qué? Pues porqué como hemos explicado antes, el buffer del puerto serie recibe los datos byte por byte y en formato decimal, quiere decir, los caracteres recibidos serán números correspondientes al código ASCII (El Arduino ve Símbolos de del tabla ASCII y los traduce a Decimal).
Por ejemplo: Enviamos desde el PC la palabra “ARDUINO”. El buffer lee uno por uno los caracteres recibidos, primero la “A”, después la “R”,…, hasta la “O”, y los captura como carácter decimal correspondiente a la tabla del código ASCII. Quiere decir que el Arduino ve los siguientes valores:
65 82 68 85 73 78 79
Que corresponden a A R D U I N 0
Para solucionar esto podemos usar la función write() en vez de println(). Porque write() envía uno o varios bytes en forma de datos binarios. De esta manera, cuando enviamos desde el PC la palabra “ARDUINO”, en el Monitor Serial imprimirá “ARDUINO”.
void setup() { Serial.begin(9600); } void loop() { if(Serial.available()>0) //Comprobamos si en el buffer hay datos { int dato=Serial.read(); //Lee cada carácter uno por uno y se almacena en una variable Serial.write(dato); //Imprimimos en la consola el carácter recibido } }
Lo que hace la función write() con los valores recibidos (65 82 68 85 73 78 79) es enviarlos al Monitor Serial con su carácter correspondiente de la tabla del código ASCII. Así visualizamos los mismos caracteres que hemos escrito inicialmente en el PC.
Otra forma similar de hacerlo sin cambiar el println() es en vez de usar el tipo de variable int para leer los datos del buffer, usaremos el tipo de variable char que es un tipo de dato que ocupa un byte de memoria y almacena un valor de carácter (almacena el símbolo de la tabla ASCII).
void setup() { Serial.begin(9600); } void loop() { if(Serial.available()>0) //Comprobamos si en el buffer hay datos { char dato=Serial.read(); //Lee cada carácter uno por uno y se almacena en una variable Serial.println(dato); //Imprimimos en la consola el carácter recibido } }
Pero y si queremos usar datos recibidos dentro del programa. Por ejemplo: si queremos enviar el valor 51 desde el PC al Arduino, y este queremos que a este valor 51 le sumemos un valor 2 para que nos salga un valor 53. ¿Cómo lo podemos hacer? Ya que cuando el Arduino reciba el valor 51, lo va a interpretar como un 53(5) y 49(1).
Usaremos un código muy sencillo. Creamos un array tipo char para que almacene los datos en forma de cadena de caracteres (String). Lo que haremos es convertir esta cadena de caracteres a un número entero usando la función atoi(), que no es una función de Arduino sino de C++, pero que está incluido automáticamente en todos los sketches. También usaremos la función memset() (también procedente de C++) para limpiar el array después de cada lectura.
void setup() { Serial.begin(9600); } char cadena[30]; //Creamos un array que almacenará los caracteres que escribiremos en la consola del PC. Le asignamos un tope de caracteres, en este caso 30 byte posicion=0; //Variable para cambiar la posición de los caracteres del array int valor; //Variable del valor entero void loop() { if(Serial.available()) //Nos dice si hay datos dentro del buffer { memset(cadena, 0,sizeof(cadena));//memset borra el contenido del array "cadena" desde la posición 0 hasta el final sizeof while(Serial.available()>0) //Mientras haya datos en el buffer ejecuta la función { delay(5); //Poner un pequeño delay para mejorar la recepción de datos cadena[posicion]=Serial.read();//Lee un carácter del string "cadena" de la "posicion", luego lee el siguiente carácter con "posicion++" posicion++; } valor=atoi(cadena);//Convertimos la cadena de caracteres en enteros Serial.println(valor+2);//Imprimimos el valor sumandole un valor +2 posicion=0;//Ponemos la posicion a 0 } }