Go Down

Topic: Saber codificación del puerto serie  (Read 542 times) previous topic - next topic

victorjam

#15
Aug 02, 2020, 08:48 am Last Edit: Aug 02, 2020, 08:49 am by victorjam
Claro, porque ahora estas escribiendo bytes.

Un byte no tiene codificación solo es un número binario. Si lo envias por Serial, dependerá del receptor lo que quiera interpretar. El terminal por ejemplo, escribe caracteres, solo los que pueda imprimir, los que no los dejará en blanco o hará cualquier cosa.

Mira este programa:

Code: [Select]

#include <EEPROM.h>

void setup() {
  Serial.begin(9600);
  for (int i=0; i<256; i++) {
    Serial.write((unsigned char)i);
    if (i!=0 && i%16==0) Serial.println();
    else Serial.print(' ');
  }
}

void loop() {
 
}


Enviará por el puerto serie los bytes del 0 al 255, he añadido un salto
de línea cada 16 caracteres y he usado el terminal del ide y realTerm, con el siguiente resultado:



RealTerm utiliza ASCII/ANSI, mientras que el terminal usa UTF-8. Como ves el resultado es que cada byte tiene asociado un caracter en el caso de ANSI y los que no tienen un caracter ni los pinta. En el caso del IDE, ocurre tres cuartas de lo mismo, pero en este caso si pinta cuadrados en los caracteres que no tienen esa asociación.

Una cosa buena de las codificaciones es que generalmente los bytes comprendidos entre 0x21 (33) y 0x7F (127) son comunes. No importa si la codificación es tal o cual, será reconocido. Estos caracteres son:

Code: [Select]

! " # $ % & ' ( ) * + , - . / 0
1 2 3 4 5 6 7 8 9 : ; < = > ? @
A B C D E F G H I J K L M N O P
Q R S T U V W X Y Z [ \ ] ^ _ `
a b c d e f g h i j k l m n o p
q r s t u v w x y z { | }


Pero como ves, no hay acentos, ni ñ, ni caracter raro.

Así que si quieres evitar el problema de la codificación hay dos vias:

Usando texto: obvia tildes y caracteres raros. Así en lo "comandos" que propusiste en la imagen del primer post serían: ok, atras, guardar, etc. Sin usar tildes ni nada por el estilo.

Así no importa si es utf-8 lo que haga arduino con los caracteres, o si es ascii, será lo mismo. E igualmente en el lado del emisor, que lo raro es lo del ide, ya que si fuese utf-8 deberia de mandar en el caso de la ñ 0x3cB1 y envia, parece ser, utf-16.

Usando binario. En este caso lo que mandas son valores binarios, asi que tanto como emisor como receptor deben enteder el idioma, lo que Peter ha dicho que son protocolos. Por ejemplo, el arduino recibe valores binarios y un valor 0x34 es el comando "atrás", entonces el emisor solo debe mandar un byte que es 0x34.






PeterKantTropus

Sin duda se pueden escribir protocolos propios, pero cuando me refería a protocolo, quería decir de utilizar alguno ya desarrollado, como Modbus, MQTT y similares ¿ Para que reinventar la rueda?
Saludos.
//-----------------------******------------------------
if (Codigo_con_delay==True) {
Proyecto=Fracaso;
 } 
//-----------------------******-----------------------

Metaconta

Buenas explicaciones.

Como han dicho arriba, es también depende de como lo interprete en el otro lado.

Es bueno saber que envía Arduino, para poder saber que hacer desde el PC que recibe esos datos, así de simple.

¿Qué envía Arduino para las ñ, Ñ y las letras con tildes?

¿Qué pongo en el PC con todas las codificaciones que hay?

Ahí está la cuestión.

Hay que tenerlo claro para no haber problemas de comunicaciones.

Saludos.

victorjam

#18
Aug 04, 2020, 08:42 am Last Edit: Aug 04, 2020, 08:43 am by victorjam
Arduino no entiende de codificación.

¿Qué ocurre?

Cuando nosotros creamos un sketch, lo que hacemos es escribir un código en un fichero. Ese fichero se guarda con codificación UTF-8. El compilador lee el código fuente con esa codificación, y cuando encuentra un carácter " interpreta que lo hay ahi es una cadena. Así al estar códificado con UTF-8 utiliza los bytes que se corresponden a dicha codificación para crear la cadena.

Cuando se encuentra con un caracter 'ñ', realiza la conversión a entero de 32 bits porque así es como almacena valores enteros.

Pero en realidad, es cosa del compilador. Arduino solo manda valores de 0x00 a 0xFF, un byte.

Así en el lado del PC, debería tener cuidado y leer UTF-8.

En cambio que ocurre si es el PC el que envia.

Pues también dependerá del compilador/programa. Arduino no entiende UTF-8, solo bytes, por lo que cuando le mandas un caracter raro, si ocupa un byte leerá un byte, si ocupa 2 leerá 2. Pero Arduino entenderá solo 1 byte por caracter y si lo reenvias no tendrá codificación ninguna. Aparentemente el terminal del IDE lee UTF-8 pero envia caracteres Unicode (creo que para ser mas exactos ISO-8859-1).



Un ejemplo:

Code: [Select]

void loop() {
  if ( Serial.available() ) {
    String s = Serial.readString();
    Serial.print(s);
  }
}


Ahora teclea en el terminal "áéíóúñ". Dado que el terminal envia Unicode (la ISO dicha), recibes la secuencia de bytes: E1 E9 ED F3 FA F1. Cuando la reenvias al terminal no transforma nada ni hace codificación alguna, solo vuelve a mandar esos bytes, por lo que el terminal muestra ? en todos ellos: envias bytes (aunque sea Unicode) y esperas UTF-8.

Mi recomendación sigue siendo la misma: olvida los caracteres especiales usa solo los ASCII que gracias a dios estan todos presentes en casi cualquier codificación y no tendrás problemas en ningún terminal.

harkonnen

#19
Aug 04, 2020, 11:31 pm Last Edit: Aug 04, 2020, 11:41 pm by harkonnen
https://playground.arduino.cc/Code/UTF-8/
http://www.fileformat.info/info/charset/UTF-8/list.htm
El IDE de arduino crea los ficheros en uft-8.
Los primeros 127 caracteres tanto en ASCCI como en UTF-8 se codifican igual y ocupan un byte.

Los caracteres que no se pueden representar en los primeros 127 caracteres, pasan a ocupar 2, 3 o 4 bytes. Es por eso que en el código de abajo la variable a ocupa 6 bytes, en vez de 4, realmente ocupa 7 ya que las cadenas en C acaban con un byte a cero para indicar el final.
Code: [Select]

char a[]="ñoño";
Serial.println(sizeof(a));



Si imprimimos la cadena por el puerto serie saldrán 6 caracteres, lo cual no pasa nada si el terminal sobre el que imprimimos soporta utf-8, representará las eñes correctamente.

En el sentido contrario, en la recepción, debes tener en cuenta esto. Los caracteres pueden ser de 1, 2, 3, o 4 bytes.

Saludos.

 

Metaconta

Buenas explicaciones.

¿Se puede enviar la ñ?

surbyte

#21
Aug 10, 2020, 03:07 pm Last Edit: Aug 10, 2020, 03:07 pm by surbyte
Y si te dicen :
Quote
Si imprimimos la cadena por el puerto serie saldrán 6 caracteres, lo cual no pasa nada si el terminal sobre el que imprimimos soporta utf-8, representará las eñes correctamente.
por ende en el Monitor Serie del IDE NUNCA veras una ñ pero si usas un terminal que soporte UTF-8 si.

Metaconta

Hola:

Hago un programa que lea el UTF-8 y lo muestro aquí.

Hagan un programa que envíe desde Arduino la mejor ñ o Ñ de su vida a ver si lo lee. Por ahora este en C# es de UTF-8.

Para los que quieran hacer pruebas. Dejo código C# y prueben con Arduino.
Code: [Select]
using System;
using System.IO.Ports;
using System.Threading;

namespace Introducir_datos_puerto_serie_consola_02
{
    class Program
    {
        static bool _continue;
        // Cree un nuevo objeto SerialPort con la configuración predeterminada.
        static SerialPort Puerto_serie = new SerialPort("COM3");

        static void Main(string[] args)
        {
            string nombre;
            string mensaje;
            StringComparer stringComparer = StringComparer.OrdinalIgnoreCase;
            Thread readThread = new Thread(Leer);

            // Título de la ventana.
            Console.Title = "Enviar datos al puerto serie";

            // Tamaño de la ventana, x, y.
            Console.SetWindowSize(70, 25);

            // Color de fondo.
            Console.BackgroundColor = ConsoleColor.Blue;

            // Color de las letras.
            Console.ForegroundColor = ConsoleColor.Yellow;

            // Limpiar pantalla y dejarlo todo gris.
            Console.Clear();

            // Visible el cursor.
            Console.CursorVisible = true;

            Puerto_serie.BaudRate = 115200;
            Puerto_serie.Parity = Parity.None;
            Puerto_serie.StopBits = StopBits.One;
            Puerto_serie.DataBits = 8;
            Puerto_serie.Handshake = Handshake.None;
            Puerto_serie.RtsEnable = true;

            // Establecer los tiempos de espera de lectura / escritura.
            Puerto_serie.ReadTimeout = 500; // 500 // Milisegundos.
            Puerto_serie.WriteTimeout = 500; // 500

            Puerto_serie.Open();
            _continue = true;
            readThread.Start();

            Console.Write("Nombre: ");
            nombre = Console.ReadLine();

            Console.WriteLine("Escriba salir para salir");

            while (_continue)
            {
                mensaje = Console.ReadLine();

                if (stringComparer.Equals("salir", mensaje))
                {
                    _continue = false;
                }
                else
                {
                    Puerto_serie.WriteLine(
                        String.Format("<{0}>: {1}", nombre, mensaje));
                }
            }

            readThread.Join();
            Puerto_serie.Close();

        }

        public static void Leer()
        {
            while (_continue)
            {
                try
                {
                    string mensaje = Puerto_serie.ReadLine();
                    Console.WriteLine(mensaje);
                }
                catch (TimeoutException) { }
            }
        }
    }
}


Si quieren código compilado, avisen y lo subo.

Saludos.

Go Up