Go Down

Topic: ñ y letras con tilde en arduino  (Read 352 times) previous topic - next topic

luis2894

Jan 18, 2018, 06:30 pm Last Edit: Jan 20, 2018, 01:48 pm by surbyte Reason: Errores y códgios van con etiquetas.
que tal tengo un problema con las letras ñ y con tilde lo que pasa es lo siguiente yo ingreso letras  una vez que ingreso la letra el programa ingresa a un switch y busca el case , pero cuando ingreso la letra ñ o una vocal con acento no reconoce , necesito ayuda gracias adjunto el código.
Code: [Select]

char input;

void setup(){

 pinMode(5, OUTPUT); // Declaramos que utilizaremos el pin 13 como salida
 pinMode(6,OUTPUT);
 pinMode(7,OUTPUT);
 pinMode(8,OUTPUT);
 pinMode(9,OUTPUT);
 pinMode(10,OUTPUT);
 Serial.begin(9600);
}

void loop(){
 if (Serial.available()>0){

   input=Serial.read();

   switch(input) {
//A  
     case 'a':

     digitalWrite(5, HIGH); //Si el valor de input es 1, se enciende el led
     digitalWrite(6, LOW);
     digitalWrite(7, LOW);
     digitalWrite(8, LOW);
     digitalWrite(9, LOW);
     digitalWrite(10, LOW);
     break;
//B
     case 'b':

     digitalWrite(5, HIGH); //Si el valor de input es 1, se enciende el led
     digitalWrite(6, HIGH);
     digitalWrite(7, LOW);
     digitalWrite(8, LOW);
     digitalWrite(9, LOW);
     digitalWrite(10, LOW);
     break;
//C
     case 'c':

     digitalWrite(5, HIGH); //Si el valor de input es 1, se enciende el led
     digitalWrite(6, LOW);
     digitalWrite(7, LOW);
     digitalWrite(8, HIGH);
     digitalWrite(9, LOW);
     digitalWrite(10, LOW);
     break;
 //D
     case 'd':

     digitalWrite(5, HIGH); //Si el valor de input es 1, se enciende el led
     digitalWrite(6, LOW);
     digitalWrite(7, LOW);
     digitalWrite(8, HIGH);
     digitalWrite(9, HIGH);
     digitalWrite(10, LOW);
     break;

   //E
     case 'e':

     digitalWrite(5, HIGH); //Si el valor de input es 1, se enciende el led
     digitalWrite(6, LOW);
     digitalWrite(7, LOW);
     digitalWrite(8, LOW);
     digitalWrite(9, HIGH);
     digitalWrite(10, LOW);
     break;

case 'á':
    digitalWrite(5,HIGH);
    digitalWrite(6,HIGH);
    digitalWrite(7,HIGH);
    digitalWrite(8,LOW);
    digitalWrite(9,HIGH);
    digitalWrite(10,HIGH);
    break;

    case 'é':
    digitalWrite(5,LOW);
    digitalWrite(6,HIGH);
    digitalWrite(7,HIGH);
    digitalWrite(8,HIGH);
    digitalWrite(9,LOW);
    digitalWrite(10,HIGH);
    break;

    case 'í':
    digitalWrite(5,LOW);
    digitalWrite(6,LOW);
    digitalWrite(7,HIGH);
    digitalWrite(8,HIGH);
    digitalWrite(9,LOW);
    digitalWrite(10,LOW);
    break;

    case 'ó':
    digitalWrite(5,LOW);
    digitalWrite(6,LOW);
    digitalWrite(7,HIGH);
    digitalWrite(8,HIGH);
    digitalWrite(9,LOW);
    digitalWrite(10,HIGH);
    break;

    case 'ú':
    digitalWrite(5,LOW);
    digitalWrite(6,HIGH);
    digitalWrite(7,HIGH);
    digitalWrite(8,HIGH);
    digitalWrite(9,HIGH);
    digitalWrite(10,HIGH);
    break;

    case 'ü':
    digitalWrite(5,HIGH);
    digitalWrite(6,HIGH);
    digitalWrite(7,LOW);
    digitalWrite(8,LOW);
    digitalWrite(9,HIGH);
    digitalWrite(10,HIGH);
    break;

    case 'ñ':
    digitalWrite(5,HIGH);
    digitalWrite(6,HIGH);
    digitalWrite(7,LOW);
    digitalWrite(8,HIGH);
    digitalWrite(9,HIGH);
    digitalWrite(10,HIGH);
    break;
}}}

no puedo cambiar las letras que estoy usando pues tengo que usar todas las letras del abecedario y solo he puesto algunas aqui para que sea mas corta la lectura.


surbyte

#1
Jan 19, 2018, 12:08 am Last Edit: Jan 19, 2018, 12:09 am by surbyte
Lee el privado y edita tu post

Siento comentarte que letras acentuadas o con tildes como ñ no estan permitidas.

rodripelto

Hola,
Efectivamente las letras con tilde, la ñ no son validos, pero para lo que estas haciendo si lo puedes usar.
cambia char input; por int input; Aprovechamos que Serial.read(); devuelve un int que curiosamente es el codigo asci de la letra, ¿por que lo habran hecho así? y luego.

Code: [Select]
   if (Serial.available()>0){
 
    input=Serial.read();
 
    switch(input) {
      case 225:
 
Serial.print("Es la a con tilde");
      break;
      case 241:
 
Serial.print("Es la ñ");
      break;}}


Tabla asci para el resto de las letras.
Si alguna respuesta ha solucionado tu problema, da las gracias marcándola como solucionada.

IgnoranteAbsoluto

Supongo que el problema es porque se está utilizando una codificación UTF-8. Esto implica que no todos los caracteres son de un byte, sólo los "128 primeros" (con valores en decimal del 0 al 127) y estos 128 primeros coinciden con la codificación ASCII, donde tenemos los caracteres que usan nuestros amigos de habla inglesa. Para el resto, que necesitamos de tildes, diéresis y todo tipo de signos que existen, nos tenemos que valer con las otros 128 posibles valores que puede tener un byte. Por ello existen muchísimos "juegos de caracteres" para cubrir "más o menos" las necesidades de cada lengua, o bien usamos un estándar como el UTF-8 (ver el enlace https://es.wikipedia.org/wiki/UTF-8 de la Wikipedia).

La ventaja del UTF-8 es que los 128 primeros caracteres coinciden con el ASCII y ocupan un byte. Pero cuando usamos las tildes y demás "cosas raras" estas son codificadas normalmente en dos bytes. Y ahí radica el problema, como bien señala rodripelto. Pero siento decir que "el problema" no es tan sencillo de solucionar, como él dice.

Efectivamente, Serial.read() retorna un entero de dos bytes, pero no significa que si se le manda un carácter UTF-8 de dos bytes nos lea ese valor. Serial.read() nos devuelve un valor que puede estar entre el -1 y el 255, no menos ni tampoco más. El -1 nos indica que no había ningún byte pendiente en el buffer de recepción del puerto serie, mientras que cualquier otro valor sería el del byte que se ha recibido. Si la función devolviera un byte en lugar de un entero ¿qué valor podría retornar para indicar que no hay dato? El cero es un valor válido para un byte y no se podría usar para indicar que no hay valor válido. Es por esto por lo que retorna un entero y no un byte.

Bueno, si nos hemos leído la entrada de la Wikipedia que habla del UTF-8, sabemos que si se recibe un byte con el bit más significativo a uno es que se trata de parte de un carácter de más de un byte. Así que si detectamos un primer byte con esa característica sabemos que va a venir un segundo byte que nos va a completar el valor UTF-8 del carácter (asumimos que son dos bytes ya que no esperamos caracteres romances). Así que sólo tendríamos que leer el siguiente byte y "añadirlo" al anterior para tener el valor UTF-8 del carácter recibido.

Parece fácil, pero no lo es porque no basta con leer "sin más" el siguiente byte, ya que no suelen llegar el segundo byte inmediatamente después del primero, sino que tarda "un poquito" (dependiendo de la velocidad de transmisión tarda más o menos) porque no es instantáneo. Ese "poquito" es tiempo más que suficiente como para que el Arduino se encuentre con que no hay byte disponible para leer y la función Serial.read() nos de un -1, no siendo este el valor que deseamos. Es por ello que no podemos leer el segundo byte nada más leer el primero. Porque no siempre nos funcionará. Así que habría que hacerlo "en dos pasos".


IgnoranteAbsoluto


¿Posible solución?

Para empezar, guardemos el carácter UTF-8 en un wchar_t en lugar de en un char. Técnicamente el wchar_t es en Arduino un int, pero mejor si "tipamos" a las cosas con su tipo. Llamemos caracterUTF a esa variable de tipo wchar_t. Propongo que caracterUTF tenga el valor -1 si no hay nada o si aún no se ha completado la recepción porque sólo tenemos el primer byte de los dos que compone algunos caracteres, porque el cero es un valor válido para un carácter.

Por otro lado tendremos la variable global byteMasSignificativoUTF que valdrá cero o tendrá el valor primer byte recibido si se trata de un carácter de más de un byte, hasta que se reciba el segundo byte. En la variable datosSerie guardamos temporalmente el byte que se lea del puerto serie. Recordar que -1 nos indica que no hay ningún byte disponible.

El valor de caracterUTF será de 0 a 127 si se ha recibido uno de los caracteres coincidentes con los del ASCII (formado por un solo byte), mientras que tendrá un valor negativo (distinto a -1) si es un carácter "extendido" (formado por dos bytes). El valor será negativo porque el bit más significativo estará a uno.

El formato UTF-8 permite detectar ciertos "errores", pero en la solución propuesta no he tenido en cuenta los posibles errores, asumo que se reciben siempre caracteres UTF-8 válidos.

He modificado el programa para adaptarlo a mi propuesta de solución. El código tiene un par de comentarios indicando cómo funciona.

Code: [Select]
void setup(){

    pinMode(5, OUTPUT); // Declaramos que utilizaremos el pin 13 como salida
    pinMode(6,OUTPUT);
    pinMode(7,OUTPUT);
    pinMode(8,OUTPUT);
    pinMode(9,OUTPUT);
    pinMode(10,OUTPUT);
    Serial.begin(9600);
}

byte byteMasSignificativoUTF = 0;   // Cero para indicar que no se está recibiendo un carácter "extendido"

void loop(){
    wchar_t caracterUTF8 = -1;      // Con -1 indicamos que aún no se ha recibido un carácter válido
    int datoSerie = Serial.read();  // Leemos un byte del puerto serie (-1 nos indica que no hay datos)
    if (datoSerie >= 0) {           // Un valor mayor o igual a cero es que hemos recibido un byte
        if (byteMasSignificativoUTF == 0) {
            // Si no se ha recibido con anterioridad el bit más significativo de un carácter "extendido"
            if ((datoSerie & B11100000) == B11000000) {
                // Se trata del byte más significativo de un carácter extendido, así que lo "guardamos para después"
                byteMasSignificativoUTF = datoSerie;
            }
            else {
                // Asumimos que es un carácter de un solo byte, con lo que ya tenemos el valor del carácter
                caracterUTF8 = datoSerie;
            }
        }
        else {
            // Ya habíamos recibido con anterioridad el byte más significativo, así que "completamos" el carácter recibido
            caracterUTF8 = (byteMasSignificativoUTF << 8) | datoSerie;  // A la parte más significativo le añadimos la parte menos significativa
            byteMasSignificativoUTF = 0;    // Ya no estamos esperando un carácter "extendido" porque ya lo hemos completado
        }
    }

    if (caracterUTF8 != -1) {   // Si tenemos un carácter válido (no poner < 0 ya que los caracteres "extendidos" tienen el bit más significativo a uno)
        switch (caracterUTF8) {
            //A 
            case 'a':

                digitalWrite(5, HIGH);
                digitalWrite(6, LOW);
                digitalWrite(7, LOW);
                digitalWrite(8, LOW);
                digitalWrite(9, LOW);
                digitalWrite(10, LOW);
                break;
                //B
            case 'b':

                digitalWrite(5, HIGH);
                digitalWrite(6, HIGH);
                digitalWrite(7, LOW);
                digitalWrite(8, LOW);
                digitalWrite(9, LOW);
                digitalWrite(10, LOW);
                break;
                //C
            case 'c':

                digitalWrite(5, HIGH);
                digitalWrite(6, LOW);
                digitalWrite(7, LOW);
                digitalWrite(8, HIGH);
                digitalWrite(9, LOW);
                digitalWrite(10, LOW);
                break;
                //D
            case 'd':

                digitalWrite(5, HIGH);
                digitalWrite(6, LOW);
                digitalWrite(7, LOW);
                digitalWrite(8, HIGH);
                digitalWrite(9, HIGH);
                digitalWrite(10, LOW);
                break;

                //E
            case 'e':

                digitalWrite(5, HIGH);
                digitalWrite(6, LOW);
                digitalWrite(7, LOW);
                digitalWrite(8, LOW);
                digitalWrite(9, HIGH);
                digitalWrite(10, LOW);
                break;

            case 'á':
                digitalWrite(5,HIGH);
                digitalWrite(6,HIGH);
                digitalWrite(7,HIGH);
                digitalWrite(8,LOW);
                digitalWrite(9,HIGH);
                digitalWrite(10,HIGH);
                break;

            case 'é':
                digitalWrite(5,LOW);
                digitalWrite(6,HIGH);
                digitalWrite(7,HIGH);
                digitalWrite(8,HIGH);
                digitalWrite(9,LOW);
                digitalWrite(10,HIGH);
                break;

            case 'í':
                digitalWrite(5,LOW);
                digitalWrite(6,LOW);
                digitalWrite(7,HIGH);
                digitalWrite(8,HIGH);
                digitalWrite(9,LOW);
                digitalWrite(10,LOW);
                break;

            case 'ó':
                digitalWrite(5,LOW);
                digitalWrite(6,LOW);
                digitalWrite(7,HIGH);
                digitalWrite(8,HIGH);
                digitalWrite(9,LOW);
                digitalWrite(10,HIGH);
                break;

            case 'ú':
                digitalWrite(5,LOW);
                digitalWrite(6,HIGH);
                digitalWrite(7,HIGH);
                digitalWrite(8,HIGH);
                digitalWrite(9,HIGH);
                digitalWrite(10,HIGH);
                break;

            case 'ü':
                digitalWrite(5,HIGH);
                digitalWrite(6,HIGH);
                digitalWrite(7,LOW);
                digitalWrite(8,LOW);
                digitalWrite(9,HIGH);
                digitalWrite(10,HIGH);
                break;

            case 'ñ':
                digitalWrite(5,HIGH);
                digitalWrite(6,HIGH);
                digitalWrite(7,LOW);
                digitalWrite(8,HIGH);
                digitalWrite(9,HIGH);
                digitalWrite(10,HIGH);
                break;
        }
    }
}


De todas formas, si pueden evitar usar caracteres no ASCII, eviten usarlos.

luis2894

intente el código y salio error crees que hay una manera de convertir identificar el carácter ascii correspondiente y guardarlo en una variable int y a partir de ahí entra al switch.

IgnoranteAbsoluto

¿Qué errores te salen? ¿Puedes poner tu código adjuntandolo como fichero para que no se "altere" la codificación con que lo tienes?

Aunque no te serva de nada te diré que a mi me funciona lo que he puesto.

A decir verdad, el tipo wchar_t no es más que un int.

Go Up