Go Down

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

Metaconta

Jul 31, 2020, 02:54 pm Last Edit: Aug 01, 2020, 12:25 am by Metaconta
Hola:

Cuando envío datos al puerto serie, en este caso, el Monitor serie de Arduino IDE 1.8.13 lee bien las tildes.



El problema está, que no se cual codificación usa Arduino sobre los datos que envía al puerto serie.

Es bueno saberlo ya que si envío letras con tilde a pesar que el Monito serie lo lee bien, en otro lado como el Pc, creando tu propio Monitor serie, no lo lee bien. Hay que saber que datos envía para poder codificarlo.

Un ejemplo tipo monitor serie hecho con la consola C#.



Tengo que saber si es en ASCII, Unicode, UTF8 o algo de eso. O como lo envía exactamente para recibirlo e interpretarlo.

Lo comento para tener un mayor control sobre Arduino, el PC y la comunicación por el puerto serie/USB en muchos dispositivos. Que no haya conflicto.

¿Alguna idea?

Saludos.


Metaconta

Buenas:

No, no es ASCII lo que lee el Monitor Serie.

Ya lo averigüé, es UTF-8.

Código C#:

Code: [Select]
       // Detecta cualquier dato entrante.
        private static void DataReceivedHandler(object sender, SerialDataReceivedEventArgs e)
        {
            SerialPort sp = (SerialPort)sender;
            sp.Encoding = Encoding.GetEncoding("utf-8");
            string entradaDatos = sp.ReadExisting(); // Almacena los datos recibidos en la variable tipo string.
            Console.WriteLine("Datos recibido desde Arduino: " + entradaDatos); // Muestra en pantalla los datos recibidos.

        }


Gracias de todas formas campeón.

victorjam

Veo que tienes razón, pero ahora resulta que tengo más dudas, y yo siempre pensando en ASCII...

He hecho un programilla:

Code: [Select]

void setup() {
  Serial.begin(9600);
  Serial.println('ñ');
  Serial.println('ñ', HEX);
}

void loop() {
 
}


Y he visto lo que se recibe en el puerto serie, y la salida es:

Code: [Select]

-15439
FFFFC3B1


Buscando los código de la 'ñ' resulta que para UTF-8 es 0xC3B1 y para UTF-16 es FEFF00F1, así que me mosquea el hecho de que arduino mande dos FF mas...



PeterKantTropus

El -15439 tiene lógica, su representación en binario, complemento a dos, es  1100001110110001, es decir C3B1 en hexa.
//-----------------------******------------------------
if (Codigo_con_delay==True) {
Proyecto=Fracaso;
 } 
//-----------------------******-----------------------

Metaconta

Hola:

Code: [Select]
-15439
FFFFC3B1


¿Te lo soltó en el Monitor serie o en otro programa?

Saludos.

PeterKantTropus

Esto es interesante
Code: [Select]
void setup() {
  Serial.begin(9600);
 char myChar[2] = "ñ";
Serial.println(myChar[0],HEX);
Serial.println(myChar[1],HEX);
 Serial.write(myChar,2 );
  
}

void loop() {

}


Salida
Code: [Select]

 FFFFFFC3
FFFFFFB1
ñ


Al parecer, el problema es Serial.println que no puede aceptar un char sin completar con ff.
//-----------------------******------------------------
if (Codigo_con_delay==True) {
Proyecto=Fracaso;
 } 
//-----------------------******-----------------------

Metaconta

#7
Aug 01, 2020, 12:28 am Last Edit: Aug 01, 2020, 12:29 am by Metaconta
Hola:

Me he dado cuenta que la ñ y Ñ no me la coje, entonces no es SOLUCINADO como puse arriba, pero si me coje las tildes.


Saludos.

victorjam

En este código del post Guardar y leer EEPROM de un array y lee cosas raras:

Code: [Select]


#include <EEPROM.h>

const unsigned char PROGMEM ALFANUMERICO[] =
{
  'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'Ñ', 'O', 'P',
  'Q', 'R', 'S', 'T', 'U', 'V', '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', 'x', 'y',
  'z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '.', ',', '-', '_', ':', ';',
  '¿', '?', '(', ')', '[', ']', '{', '}', '=', '$', '&', '"', ' '
};


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

void loop() {
  // Leemos el array de la memoria flash, byte a byte, lo mostramos por el puerto
  // serie y a la vez lo grabamos en la eeprom.
  for (int i=0; i<80; i++) {
    Serial.print((char)pgm_read_byte(ALFANUMERICO+i));
    EEPROM.update(i, (byte)pgm_read_byte(ALFANUMERICO+i));
    Serial.print(" ");

  }
  Serial.println();
  delay(5000);

  //Leemos el array de la EEPROM y lo mostramos por el puerto serie.
  for (int i=0; i<80; i++) {
    Serial.print((char)EEPROM.read(i));
    Serial.print(" ");
  }
  Serial.println();
}


Hemos declarado el array como unsigned char, por lo tanto es un byte. A la hora de leerlo y grabarlo en memoria lo interpreta como byte. Como el valor UTF-8 de 'ñ' es 0x3CB1, solo lee y guarda la parte baja, es decir, 0xB1.

Se me ocurre que el compilador trata de una manera especial la codificación UTF8. Así cuando ponemos un caracter fuera del ASCII de 7 bits (que es un conjunto de UTF-8), el compilador lo interpreta como un unsinged long (32 bits). A partir que aqui, dependiendo de como lo tratemos lo interpretará de manera diferente:

- Si le preguntamos el tamaño con sizeof('ñ') este será 2.

- Si lo imprimimos como un caracter nos dará FFFFC3B1 o -15439. dependiendo de si usamos HEX o no, usando los 32 bits.

- Si lo usamos en una cadena, por ejemplo "gañan", el tamaño de la cadena es 6. Al imprimirlo por serial sustitye la 'ñ' por dos bytes (utf-8 de la 'ñ') y muestra dos caracteres raros.

Ahora bien, cuando el proceso es al revés, lo enviamos a través del terminal del IDE hacia al Arduino, ocurre algo maravilloso y desconcertante: sólo recibimos un caracter, si mostramos el valor en hex nos da que para la 'ñ' recibimos 0xF1 y para la 'Ñ' nos da 0xD1, que resulta ser el valor UNICODE.

Da que pensar el tema...












Metaconta

#9
Aug 01, 2020, 01:56 pm Last Edit: Aug 01, 2020, 03:44 pm by Metaconta
Buenas:

Tengo que averiguar estas cosas sea como sea, para no tener problemas en el futuro sobre el control del puerto serie cosas como estas.

Tabla Unicode:


Tabla UTF-8:


En decimal según la tabla UTF-8.
Ñ = 209
ñ = 241.

Mejor convertir sabes en binario desde Arduino antes de pasarlo al puerto serie. Para saber que pasa.

Es el momento de capturar los bytes en binario y ver qué valor está realmente llegando, para buscarlo en las tablas de códigos. Procura capturar simultáneamente en un mismo mensaje a la vez una letra acentuada y la ñ, para asegurarnos de tener más información acerca de qué codificación se está usando.

Lógicamente, hay que capturarlos en binario antes de que el serialport los meta en un string, porque para entonces ya les ha aplicado el Encoding y se ha perdido el valor original. Usa alguno de los métodos del SerialPort que reciben bytes en lugar de strings.

Saludos.


Edito:
Code: [Select]
si mostramos el valor en hex nos da que para la 'ñ' recibimos 0xF1 y para la 'Ñ' nos da 0xD1, que resulta ser el valor UNICODE.

No, eso no es el valor UNICODE. Esos dos valores que indicas (F1 y D1) son los códigos de ñ y Ñ en ISO-8859-1 o en Windows ANSI.

Tienes que buscar cómo y dónde estás haciendo la lectura y/o conversión de estos valores, para ver por qué está usando ese Encoding y posiblemente cambiarlo.

> Hemos declarado el array como unsigned char

Nótese que esto solo existe en C o C++, pero no en C#. El tipo equivalente en C# es byte. Si en C# lo declaras como Char, eso es un carácter Unicode (16 bits), lo mismo que si forma parte de un string. Si estás pasando datos de uno a otro, hay que tener presente que en alguno de los pasos intermedios tiene que hacer una conversión usando el Encoding, y si pones el encoding incorrecto (o lo usa por defecto si no has puesto nada) pues entonces salen los bytes incorrectos a partir de los caracteres originales.

victorjam

Code: [Select]

Name:         Latin Small Letter N with Tilde[1]
Unicode Version: 1.1 (June 1993)[2]
Block:         Latin-1 Supplement, U+0080 - U+00FF[3]
Plane:         Basic Multilingual Plane, U+0000 - U+FFFF[3]
Script:                 Latin (Latn) [4]
Category:                 Lowercase Letter (Ll) [1]
Bidirectional Class: Left To Right (L) [1]
Combining Class:         Not Reordered (0) [1]
Character is Mirrored: No [1]
GCGID:                 LN190000[5]
HTML Entity:

    ñ
    &#xF1;
    &ntilde;

UTF-8 Encoding:         0xC3 0xB1
UTF-16 Encoding: 0x00F1
UTF-32 Encoding: 0x000000F1
Uppercase Character: Ñ (U+00D1) [1]
Decomposition:         n (U+006E) - ◌̃ (U+0303)[1]


La verdad que da mucha guerra lo del encoding, lo mejor: binario. Así todos hablan igual y ya esta, los 0 y 1 es la única verdad multiplataforma.



Metaconta

Hola.

Cierto.
Mejor 0 y 1.
¿Cómo envías formato 1 y 0?

Desde el otro lado.
¿Cómo lo recibe?

El truco de Arduino print(variable, BIN?

Saludos.

PeterKantTropus

Se envían en Byte con  Serial.write(  )
//-----------------------******------------------------
if (Codigo_con_delay==True) {
Proyecto=Fracaso;
 } 
//-----------------------******-----------------------

PeterKantTropus

No se aplicación estés intentado programar, pero mejor que trabajar a nivel byte (o binario ) es trabajar con protocolos, son una capa que te aísla del bus de comunicación.
//-----------------------******------------------------
if (Codigo_con_delay==True) {
Proyecto=Fracaso;
 } 
//-----------------------******-----------------------

Metaconta

Con parte de tu código modificado, sigue sin sali rla Ñ y ñ.

Code: [Select]
void loop()
{
  // Leemos el array de la memoria flash, byte a byte, lo mostramos por el puerto
  // serie y a la vez lo grabamos en la eeprom.
  for (int i=0; i<80; i++) {
    Serial.write((char)pgm_read_byte(ALFANUMERICO+i));
    EEPROM.update(i, (byte)pgm_read_byte(ALFANUMERICO+i));
    Serial.write(" ");

  }
  Serial.println();
  delay(5000);

  // Leemos el array de la EEPROM y lo mostramos por el puerto serie.
  for (int i=0; i<80; i++) {
    Serial.write((char)EEPROM.read(i));
    Serial.write(" ");
  }
  Serial.println();
}


Si que cuesta enteneder esto. Si, lo del tema de protocolo es lo que hay que ver. Quiero saber que es lo que envía Arduino.

Go Up