Esta es una de las preguntas que más nos ha llegado en la sección de comentarios o a través del Facebook. Cómo enviar números de más de un dígito a Arduino o palabras enteras sin que la recepción se de caracter por caracter.
A continuación voy a explicar dos métodos para leer números o cadenas de caracteres desde el puerto Serie de Arduino. El primer método será por programación pura y dura al mejor estilo de la vieja escuela. El segundo método será preciso y conciso, una abreviación del primer método. Lo hago de esta forma debido a que hay personas que consultan este espacio para aprender sobre programación y resolver sus dudas sobre ciertas funciones del Arduino. El primer método, el cual llamaré Método Buffer está dirigido a los entusiastas que les gusta ejercitar su lógica y hacer las cosas a su manera. El segundo método, llamado Método Directo será simplemente una función que el Arduino posee que hará lo mismo que el Método Buffer pero mucho más sencillo y simple.
Método Buffer
Resulta que si subimos en nuestro Arduino el siguiente código:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
void setup() { //Iniciamos comunicación con el puerto serie Serial.begin(9600); } void loop() { /* * Evaluamos el momento en el cual recibimos un caracter * a través del puerto serie */ if (Serial.available()>0){ //Imprimimos el caracter que recibimos Serial.println(Serial.read()); } } |
Cuando abrimos el Monitor Serie y escribimos la secuencia numérica 1, 2, 3, 4, 5 obtenemos el siguiente resultado:
- 1 (ENTER)
- 2 (ENTER)
- 3 (ENTER)
- 4 (ENTER)
- 5 (ENTER)
En la pantalla se muestra 49, 50, 51, 52 y 53. Estos son los equivalentes de los números del 1 al 5 en la tabla ASCII, como podemos ver en la siguiente imagen: Debo confesar que el lenguaje Arduino me gusta cada día más y es porque siento que a medida que pasa el tiempo y se mejora el propio lenguaje de programación, este se parece más y más a Java, con el cual estoy muy familiarizado. Arduino se derivó de Processing, el cual nació de Java. De hecho el propio software Arduino IDE, donde se programa Arduino, está escrito en Java. Hago este comentario debido a que para corregir el problema de los caracteres en ASCII podemos utilizar un pequeño truco que inicialmente aprendí en Java y que luego me encontré con que en Arduino es posible hacer lo mismo. Una conversión de un entero a caracter utilizando (char). Modifiquemos el código y veamos el resultado de la conversión de número a caracter:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
void setup() { //Iniciamos comunicación con el puerto serie Serial.begin(9600); } void loop() { /* * Evaluamos el momento en el cual recibimos un caracter * a través del puerto serie */ if (Serial.available()>0){ //Imprimimos el caracter que recibimos, transformándolo a char Serial.println((char)Serial.read()); } } |
El resultado de la misma operación anterior ahora será: Perfecto. Ahora si nos aparecen los mismos caracteres que escribimos. Pero, ¿que tal si escribimos una palabra o un número de más de un dígito? Escribamos Panama Hitek y veamos que pasa.
Para evitar que esto suceda lo que haremos será crear un buffer que almacene los caracteres que se van recibiendo y luego nos imprima el resultado cuando el buffer acabe de recibir la información.
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 |
void setup() { //Iniciamos comunicación con el puerto serie Serial.begin(9600); } void loop() { /* * Evaluamos el momento en el cual recibimos un caracter * a través del puerto serie */ if (Serial.available() > 0) { //Se crea una variable que servirá como buffer String bufferString = ""; /* * Se le indica a Arduino que mientras haya datos * disponibles para ser leídos en el puerto serie * se mantenga concatenando los caracteres en la * variable bufferString */ while (Serial.available() > 0) { bufferString += (char)Serial.read(); } //Se imprime el contenido del buffer Serial.println(bufferString); } } |
Cuando intentamos escribir Panama Hitek obtendremos:
… lo mismo. Esto se debe a que transcurre muy poco tiempo entre el instante en que el Arduino detecta que hay un caracter disponible para ser leído en el Puerto Serie y la entrada en el while. Esto provoca que el Serial.available() del while solo devuelva un valor de 1, lo cual hace que los caracteres se impriman de forma individual. Esto se puede corregir de diferentes formas:
- Aumentando la velocidad de transmisión de datos (los baudios por segundo, el 9600 del Serial.begin())
- Colocando un pequeño delay luego del if(Serial.avaliable()>0)
- Colocando un pequeño delay dentro del while.
Esto último será lo que haremos.
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 |
void setup() { //Iniciamos comunicación con el puerto serie Serial.begin(9600); } void loop() { /* * Evaluamos el momento en el cual recibimos un caracter * a través del puerto serie */ if (Serial.available() > 0) { //Delay para favorecer la lectura de caracteres delay(20); //Se crea una variable que servirá como buffer String bufferString = ""; /* * Se le indica a Arduino que mientras haya datos * disponibles para ser leídos en el puerto serie * se mantenga concatenando los caracteres en la * variable bufferString */ while (Serial.available() > 0) { bufferString += (char)Serial.read(); } //Se imprime el contenido del buffer Serial.println(bufferString); } } |
Y ahora el resultado será:
Nota: El delay utilizado es el suficiente para este aplicación en específico pero puede variar según la cantidad de caracteres que se desee leer. Ahora si queremos enviar números de más de un dígito a Arduino necesitaremos utilizar una conversión de String a int. Para ello utilizamos el comando toInt():
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 |
void setup() { //Iniciamos comunicación con el puerto serie Serial.begin(9600); } void loop() { /* * Evaluamos el momento en el cual recibimos un caracter * a través del puerto serie */ if (Serial.available() > 0) { //Delay para favorecer la lectura de caracteres delay(20); //Se crea una variable que servirá como buffer String bufferString = ""; /* * Se le indica a Arduino que mientras haya datos * disponibles para ser leídos en el puerto serie * se mantenga concatenando los caracteres en la * variable bufferString */ while (Serial.available() > 0) { bufferString += (char)Serial.read(); } //Se transforma el buffer a un número entero int num = bufferString.toInt(); //Se imprime el número que se recibe Serial.print("Numero recibido: "); Serial.println(num); //Se calcula la raíz cuadrada del número recibido num = sqrt(num); //Se imprime el resultado Serial.print("Raiz cuadrada: "); Serial.println(num); } } |
El código presentado recibe un número cualquiera, lo transforma a número y calcula la raíz cuadrada del mismo y la muestra en pantalla.
Método Directo
Arduino posee un método llamado readString() dentro de la clase Serial que permite leer cadenas de caracteres. De igual forma posee un método llamado setTimeOut() para definir el tiempo que debe esperar el código antes de imprimir la cadena de caracteres y dar por terminada la recepción de paquetes de datos.
El código sería:
1 2 3 4 5 6 7 8 9 |
void setup() { Serial.begin(9600); } void loop() { if (Serial.available()>0){ Serial.println(Serial.readString()); } } |
El resultado (el escribir Panama Hitek en el Monitor Serie):
Como podemos observar se da un pequeño retraso en la impresión del mensaje en el Monitor Serie. Esto se debe a que por default se espera 1 segundo para terminar de recibir los datos entrantes. Este tiempo se puede modificar con Serial.setTimeout(). El siguiente código incluirá una reducción del timeOut a 100 milisegundos y se repetirá lo mostrado en el Método Buffer donde se calcula la raíz cuadrada de un número introducido por teclado.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
void setup() { //Iniciamos comunicación con el puerto serie Serial.begin(9600); Serial.setTimeout(100); } void loop() { /* * Evaluamos el momento en el cual recibimos un caracter * a través del puerto serie */ if (Serial.available() > 0) { //Se transforma la lectura a un número entero int num = Serial.readString().toInt(); //Se imprime el número que se recibe Serial.print("Numero recibido: "); Serial.println(num); //Se calcula la raíz cuadrada del número recibido num = sqrt(num); //Se imprime el resultado Serial.print("Raiz cuadrada: "); Serial.println(num); } } |
El resultado:
Esperamos que el concepto haya quedado claro y que la información suministrada sea de su comprensión y utilidad.
Saludos.
Excelente información, me resulto muy útil muchas gracias
Gracias a ti por comentar
Buen aporte!! En mi caso quiero guardar el dato que entra por el serial en na variable
estoy usando una tipo int (int limit) escribiendo lo siguiente
limit = Serial.read()// solo el primero de los caracteres
limit = Serial.readstring()//da error de compilacion
Sin embargo si copio su código si que me funciona, es decir se imprime lo que acabo de enviar. Con la excepcion de que el primer caracter o número no se imprime, es decir, si pongo «Zaragoza», imprime «aragoza»
Gracias y un saludo
Para empezar, tienes el segundo método mal escrito (Serial.readstring() => Serial.readString()).
Si deseas hacerlo con Serial.readString() (el cual es un método más sencillo), debes tener en cuenta que esta es un objeto que se basa en cadenas de carácteres y por lo tanto no puedes declararla como entero (int).
String prueba = Serial.readString();
int limit = prueba.toInt();
A la orden
como anexo a arduino los caracteres de las tablas anteriores
Explícate un poco más
Gracias, era lo que necesitaba
como valido los valores ingresados
A qué te refieres?
Disculpen como puedo hacer lo mismo pero en vez de usar el PC ingresar los números mediante un teclado 4×4, hago lo que se muestra acá pero como no hay enter ni nada de eso los números se me siguen mostrando uno debajo del otro y necesito sacar uno sólo de por lo menos unidades decenas y centenas, gracias de antemano.
Hola, como sería para pasar el numero desde vb.net a arduino
No tengo experiencia en .net
Hola, quisiera separar un numero de 6 digitos en dos numeros de 3 digitos, para guardarlos en variables y ocuparlas al mismo tiempo. Gracias
Hola, como seria separar un numero de 6 digitos a dos numeros de tres digitos cada uno, para guardarlos en variables al mismo tiempo. Gracias
Eso es fácil de hacer con Substrings
Muy bueno pero es mas para RECIBIR que para enviar. Yo ando buscando como enviar a un telefono, datos numericos via bluetooth y leerlos desde appinventor
Empácalos en un JSON y envíalos como un solo String
Muy buena la explicación, pero, si lo que quiero enviar no son números enteros sino decimales, por ejemplo 3.46 o 100.52. ¿Que hago en esa situación?
Envíalos como String
Hola quisiera enviar una letra o un numero de a 3 dígitos por separado como podría hacer?
Separados?
muy buena explicacion