Haz una pregunta
  Foros de Electrónica » Diseño digital » Microcontroladores y sistemas embebidos » Arduino y Raspberry Pi
Foros Registrarse ¿Olvidaste tu contraseña?

Temas similares

14/09/2014 #1

Avatar de bivalvo

Enviar datos a Arduino desde monitor serial
Hola, buenas a todos.

Leí hace poco que se pueden enviar datos al arduino por puerto serie siempre que se encuentre conectado por USB al PC. Por lo visto se pueden enviar usando el botón "enviar" que aparece arriba a la derecha en el monitor serial del software "arduino". Sabía que existía ese botón pero jamás pensé que tuviera utilidad xD

Mi pregunta es... ¿en qué formato se envía lo que escribo? Por lo que he leído se envían los bytes en bruto pero me parece un poco chocante. ¿No se pueden enviar floats sin necesidad de rebanarse la cabeza intentando averiguar a que serie de bytes corresponden? ¿Cómo recibe por ejemplo (en binario) el arduino el texto "5648"? (sin las comillas)

Gracias por adelantado.
Un saludo, electronicos!
14/09/2014 #2


Los tipos de datos son algo inherente al lenguaje. Las comunicaciones son en bruto, tu defines un protocolo y tratas los datos como sea, por ejemplo mandas 5648f o fl5648 y al tener ese formato, en tu programa arduino lo haces un cast a float. Por esto se definen protocolos de comunicación entre aplicaciones.
14/09/2014 #3

Avatar de Scooter

Envía el contenido del cuadro de texto que tienes al lado.
Como suele ser ASCII, pues ASCII
14/09/2014 #4

Avatar de bivalvo

Sí, pero si inicio comunicación serial con "Serial.begin()" y voy leyendo enteros con "Serial.parseInt()" por ejemplo, leerá el primer byte del buffer y lo tratará como entero. Pero a la hora de meterlo desde el monitor el propio pc tendrá que hacer una conversión de lo que tu escribas para pasarlo a binario. Y esa codificación a binario es la que desconozco. No sé cual usa.

Saludos!

Scooter dijo: Ver Mensaje
Envía el contenido del cuadro de texto que tienes al lado.
Como suele ser ASCII, pues ASCII
y no puedo enviar floats de alguna forma?
gracias
14/09/2014 #5

Avatar de Scooter

Escribes 1653.564 le das a enviar y recibirás esa cadena ASCII, lo puedes filtrar con parsefloat o parseint a conveniencia.
Escribir un float en el teclado podría ser una paranoia total...
14/09/2014 #6

Avatar de bivalvo

Entonces el monitor convierte esa información a binario de punto flotante al enviarlo, ¿no? O sea, genera 32 bits en el buffer con ese número codificado en ellos.
14/09/2014 #7

Avatar de JoaquinFerrero

Para que el cliente y el servidor se entiendan deben ponerse de acuerdo en las reglas (protocolo) de intercambio de información.

Si envías información ASCII por la terminal, el Arduino recibirá los bytes que forman esos caracteres ASCII. Si esos caracteres forman un número en punto flotante, necesitas que el Arduino tengo una subrutina que haga la transformación.

En cambio, si le envías los bytes que forman un número en punto flotante, puedes recogerlos y guardarlos directamente. Eso sí: deben formar un número en punto flotante con el formato en que trabaja Arduino (que no tiene por qué ser el mismo formato de punto flotante del emisor). Si no son iguales, volvemos a necesitar una subrutina de transformación.

Aquí, además, tienes un problema añadido: los bytes que forman los números en punto flotante van en crudo, por lo que debes crear un protocolo para que Arduino sepa cuándo comienza (y termina) la transmisión de cada valor. Poner un carácter de fin de línea a veces es suficiente, pero no siempre.

Por ejemplo, 3.4, como punto flotante en simple precisión, se almacena en los sistemas Linux x86_64 como los 4 bytes siguientes:
Código:
$ perl -E 'print pack "f", 3.4' |hexdump -C
00000000  9a 99 59 40                                       |..Y@|
00000004
Son esos 4 bytes los que tenemos que enviar. Si el receptor sabe que son bytes que forman un número en punto flotante, lo puede reconstruir:
Código:
$ perl -E 'say unpack "f", join "", map { chr hex } qw(9a 99 59 40);'                                                                                                      
3.40000009536743
14/09/2014 #8

Avatar de Scooter

No no no no noooo
El monitor serial es monitor serial única y exclusivamente. Por eso se llama así y no se llama conversor de punto flotante.
Evidentemente en el cable solo hay binario, no puede haber otra cosa. Si ese binario al recibirse en el PC cuadra con cosas ASCII verás esas cosas ASCII sean las que sean.
Para enviar lo mismo pero al revés. Como en el cuadro de texto solo cabe texto; 5671 es el texto "5671" no es el cinco mil seiscientos setenta y uno binario. Se envía el carácter ASCII de cinco, el del seis etc
Cuando llega al arduino esa cadena la puedes convertir a float o int o lo que sea.

Edito, no había visto el comentario de Joaquín Ferrero.
Es mucho mas eficiente mandar el numero binario que en cadena ascii, pero es mucho menos legible. Si lo haces ya no podrás usar sin mas un monitor serie o un terminal. Necesitarás una aplicación especifica y la depuración es mas liosa.
14/09/2014 #9

Avatar de bivalvo

Muchas gracias a ambos, ya lo tengo claro.

¿Cómo se codifican los floats en binario en arduino? Es para hacer la prueba.

De nuevo gracias!
14/09/2014 #10

Avatar de JoaquinFerrero

Se codifican en 4 bytes (los float), pero lo más seguro es que estén en formato numérico de los chips de AVR.

Edito: encontré un hilo (en inglés) sobre este tema de transmitir flotantes.
14/09/2014 #11

Avatar de bivalvo

En IEEE754 he intentado yo meterlos (una vez pasados a ASCII) pero no me los lee correctamente...

Muchas gracias de todas formas
14/09/2014 #12

Avatar de Scooter

Usa parsefloat, va perfectamente.
Vale que la trasnmisión igual son 10bytes en lugar de 6 pero si tu aplicación no es muy intensiva lo mismo te da, y a cambio la comunicación es "legible para los humano"
14/09/2014 #13

Avatar de JoaquinFerrero

Sería interesante ver el código que estás usando...
14/09/2014 #14

Avatar de bivalvo

Ahora mismo estaba probando este, con conversión ASCII - float y funciona. Hay que meter los números en formato X.XX

Es sólo un código de prueba. Realmente mi pregunta era únicamente para saber cómo funcionaban los float a través de la consola para así poder simular comunicación TTL sin necesidad de hacerla físicamente.

Código:
byte parteEntera, primerDecimal, segundoDecimal;
float salida;

void setup(){
  Serial.begin(9600);
}

void loop(){
  if(Serial.available() > 3){
    
      parteEntera = Serial.read();
      Serial.read();
      primerDecimal = Serial.read();
      segundoDecimal = Serial.read();
      
      Serial.print(parteEntera);
      Serial.print(".");
      Serial.print(primerDecimal);
      Serial.println(segundoDecimal);
    
    salida = ((float)(parteEntera)-48.0)+0.1*((float)(primerDecimal)-48.0)+0.01*((float)(segundoDecimal)-48.0);
    
    Serial.println(salida);
    Serial.println("------------------------");
  }
}
14/09/2014 #15

Avatar de JoaquinFerrero

Casi todas las líneas que has escrito las puedes sustituir por un sencillo
Código:
    salida = Serial.parseFloat();
que es lo que recomendaba Scooter, que se encargará de leer la entrada y de traducirla a un número en punto flotante.

Documentación de Serial.parseFloat.

También puedes usar la función básica atof(). Ejemplo.

Pero recordemos que esto es comunicación usando los caracteres ASCII. Si se trata de conectar varios dispositivos por TTL, pues es más eficiente transmitir los flotantes tal cual son, y así te ahorras la conversión en ambos extremos.
14/09/2014 #16

Avatar de bivalvo

Esa es la ventaja de los TTL.

Pero la función parseFloat la estaba usando y es la que me daba lecturas extrañas por ser ASCII lo que se introduce por el monitor serial.

Cuando al buffer llegan datos binarios con estructura de punto flotante, al usar parseFloat se lee tal cual. El problema viene cuando los datos binarios representan caracteres ASCII y al intentar interpretarlos como float da un resultado completamente distinto. Hay que hacer una conversión como la que yo estaba probando. Pero podéis ver fácilmente que para precisión de dos decimales ya es un buen pedacito de código que, insertado en un código que haga otras funciones, va a generar lo que se llama un señor tocho.
15/09/2014 #17

Avatar de JoaquinFerrero

bivalvo dijo: Ver Mensaje
Pero la función parseFloat la estaba usando y es la que me daba lecturas extrañas por ser ASCII lo que se introduce por el monitor serial.
Es que es eso justamente lo que hace: interpreta los caracteres ASCII presentes en el canal Serial para devolver el float que encuentre. La función para la interpretación en el primer carácter que no pertenezca a un flotante (un carácter que no sea '+', '-', un dígito, o el '.').

Entonces, ¿a qué lecturas extrañas te refieres? ¿Quieres decir que el Arduino no te respondía lo que le enviabas?

bivalvo dijo: Ver Mensaje
Cuando al buffer llegan datos binarios con estructura de punto flotante, al usar parseFloat se lee tal cual. El problema viene cuando los datos binarios representan caracteres ASCII y al intentar interpretarlos como float da un resultado completamente distinto.
No, no es así: parseFloat necesita como entrada caracteres ASCII para luego interpretarlos (parse) a un número en punto flotante.

Aquí hay un ejemplo:

Código PHP:
/* Hipotenusa - Interactivo vía Terminal serie
   M. Ray Burnette 20130125
   Arduino Nano 328P target processor
   Binary sketch size: 5,184 bytes (of a 30,720 byte maximum)
*/

#include "math.h"               // incluir la biblioteca matemática

float a;                        // lados del triángulo
float b;
float h;                        // hipotenusa a calcular
char basura ' ';              // variable para eliminar la basura que no nos interesa


void setup() {                  // ejecutar una vez, al principio

    
Serial.begin(9600);         // velocidad inicial a 9600 bps

    
Serial.println("Vamos a calcular la hipotenusa, h");
    
Serial.println("");

    
Serial.flush();             // limpiar el canal serie
}

void loop() {                   // bucle principal

    
Serial.println("Entre un valor para el cateto 'a', pulse ENTRAR");

    while (
Serial.available() == 0) ;    // esperar aquí hasta que haya un carácter disponible
 
    
{
        
// Cateto 'a'
        
Serial.parseFloat();        // esto es nuevo en Arduino 1.0

        
Serial.print("a = ");           // lo devolvemos
        
Serial.println(aDEC);

        while (
Serial.available() > 0)  // .parseFloat() puede dejar algún carácter no numérico
        
{
            
junk Serial.read();       // limpiamos el búfer
        
}
    }

    
Serial.println("Entre un valor para el cateto 'b', pulse ENTRAR");

    while (
Serial.available() == 0) ;

    {
        
// Cateto 'b'
        
Serial.parseFloat();

        
Serial.print("b = ");
        
Serial.println(bDEC);

        while (
Serial.available() > 0)
        {
            
junk Serial.read();
        }
    }

    
sqrt (floata*b*));      // cálculo de la hipotenusa

    
Serial.print("hipotenusa = ");
    
Serial.println(hDEC);
    
Serial.println();

Como ves, parseFloat() ahorra muchas líneas, pero hay que asegurarse de que está leyendo lo que queremos. Los bucles while() están ahí para eliminar del búfer lo que pueda seguir al número flotante, para que no quede nada suelto. Por ejemplo, ahí se desecha el/los carácter/es de fin de línea que sigue al número.
15/09/2014 #18

Avatar de bivalvo

Yo he insertado "3.2" (por ejemplo) en el monitor serial con un parse float y me ha devuelto basura. ¿Hará falta un + o un - delante como dices?

Pero el código que pones es php. ¿Estás seguro de que ambos parse funcionan de la misma forma?
15/09/2014 #19

Avatar de JoaquinFerrero

No es código PHP. He usado el etiquetado PHP de esta web para que salga el código coloreado, nada más.

Prueba este sketch, y cuando te pida el valor de los catetos, metes valores float (sin las comillas, claro). Solo el valor float seguido de Entrar (o Enter, según tu teclado).
15/09/2014 #20

Avatar de bivalvo

Testeado y funciona! Muchas gracias!!

EDITO: ¿Por qué es necesario vaciar el buffer justo después de leer el flotante?
¿Tienes una mejor respuesta a este tema? ¿Quieres hacerle una pregunta a nuestra comunidad y sus expertos? Registrate

Buscar más temas sobre:
Lupa Arduino y Raspberry Pi

Cerrar
Foros de Electrónica » Diseño digital » Microcontroladores y sistemas embebidos » Arduino y Raspberry Pi

Powered by vBulletin® Version 3.8.4
Copyright ©2000 - 2017, Jelsoft Enterprises Ltd.
Search Engine Optimization by vBSEO ©2011, Crawlability, Inc.