TODOPIC

Microcontroladores PIC => Lenguaje C para microcontroladores PIC => Mensaje iniciado por: ALFREDOSKY en 05 de Marzo de 2014, 12:40:04

Título: USART, ¿como capturar caracteres y trabajar con su valor numerico?
Publicado por: ALFREDOSKY en 05 de Marzo de 2014, 12:40:04
Hola a todos, estoy atascado en un problema de manejo de datos, uso el dspic30f2010, el modulo USART tanto en RX como en TX y un motor dc; desde pc envio tres caracteres que los trato como hexadecimales, y cada caracter me indica una tarea a realizar, por ejemplo al enviar desde pc al pic la secuencia XXX, los caracteres los trato como:

- el 1er 'X' es un comando de control y no necesito su valor numérico
- el 2do caracter 'X' me indica el angulo de giro del motor , este caracter tiene el rango desde 0 a F (hexadecimal)
- el 3er caracter 'X' me indica la velocidad PWM del motor, también va de 0-F

los últimos 2 caracteres me representan cantidades variables, es decir, por ejemplo si escribo(o envío) 'A8F', voy a mandar girar a la izquierda(caracter A) 200°(caracter 8) y a un pwm del 100%(el caracter F)

Si escribo 'BF7' B:derecha, F:360° y 7:50% pwm y así de la misma manera para otros caracteres hexadecimales.

El problema que tengo es que necesito el valor númerico de esos caracteres, por ejemplo si el PIC recibe 'BF7', el valor de F es 15 en decimal y trabajo con ese valor para los cálculos con números flotantes y enteros y asi con todos los caracteres, lo que he estado haciendo es capturar cada caracter en varios arreglos de tipo char, agregarle un terminador o fin de cadena y convertirlo a entero usando la función atoi(), pero no me funciona; también he probado con -'0' sin usar la función atoi(), pero igual, nada pasa.

Alguien que sepa de estas cosas y me pueda dar un alcance sobre mis posibles errores y propuestas de mejoras seria de gran ayuda.  :mrgreen:
Título: Re: USART, ¿como capturar caracteres y trabajar con su valor numerico?
Publicado por: AngelGris en 05 de Marzo de 2014, 12:48:15
  Yo he utilizado las funciones itoa y atoi con el viejo compilador HiTech y funcionaban bien. En XC8 sólo he probado itoa y también funciona bien.
Título: Re: USART, ¿como capturar caracteres y trabajar con su valor numerico?
Publicado por: rivale en 05 de Marzo de 2014, 12:57:20
el itoa y el atoi no funcionarían porque estas funciones requieren una cadena como argumento y tu solo quieres usar un byte.

una opcion seria usar un switch asi tienes que para:

case '0':
      pwm->0:

break;

case '1'
      pwm-->xxx

break;

y asi sigues.



otra opcion seria que verifiques si tu caracter esta dentro del '0' y el '9', entonces le restas 0x30, y si esta entre la 'A' y la 'F' le restas 0x41

por ejemplo algo asi:

int valor

if(caracter>= '0' && caracter <='9')
{
  valor=caracter-0x30;

}

else if(caracter>='A' && caracter<= 'F')
{
  valor =caracter-0x41;
}


con estas condiciones al final tu variable valor tendría valores numéricos de entre 0 y 16



Título: Re: USART, ¿como capturar caracteres y trabajar con su valor numerico?
Publicado por: ALFREDOSKY en 05 de Marzo de 2014, 15:21:50
AngelGris y rivale, gracias por sus prontas respuestas; yo uso el compilador C30 pero no me funciona la funcion atoi(), los  caracteres los convierto a string almacenandolo en 2 arreglos con tamaño de 3 bytes  y le coloco un '/0' como indicador de fin de cadena, pero igual,  la función atoi() no convierte nada  :?; En el caso del 'case' me parece buena alternativa pero algo larga ,tendría que testear cada caracter  :shock:... creo que la resta es la más conveniente  :mrgreen:, lo voy a implementar, gracias nuevamente por las sugerencias   ((:-))
Título: Re: USART, ¿como capturar caracteres y trabajar con su valor numerico?
Publicado por: rivale en 05 de Marzo de 2014, 15:36:56
otro detalle es que el atoi solo convierte cuando están en base 10, es decir, no funcionará si recibe como argumentos letras.
Título: Re: USART, ¿como capturar caracteres y trabajar con su valor numerico?
Publicado por: ALFREDOSKY en 05 de Marzo de 2014, 16:03:46
rivale, tambien uso numeros, el rango es de 0 a F, pero igual, atoi() no me convierte ni los numeros  :x, cosa rara  :(
Título: Re: USART, ¿como capturar caracteres y trabajar con su valor numerico?
Publicado por: rivale en 05 de Marzo de 2014, 17:14:24
el atoi no va a convertir nada si recibe una "F" por ejemplo, pero si recibe un "1", "2", ..."9" debería funcionar, tal vez el problema esta en como generas tu cadena para introducirla al atoi, debería ser algo así


char cad[3];
int num;

cad[0]='2';
cad[1]=0;

num=atoi(cad)


Título: Re: USART, ¿como capturar caracteres y trabajar con su valor numerico?
Publicado por: ALFREDOSKY en 05 de Marzo de 2014, 19:27:19
Asi es rivale, es exactamente lo que hago, pero no lo convierte  :shock:
Título: Re: USART, ¿como capturar caracteres y trabajar con su valor numerico?
Publicado por: rivale en 05 de Marzo de 2014, 19:33:07
Asi es rivale, es exactamente lo que hago, pero no lo convierte  :shock:

que raro, podrías poner tu código de la conversión para ver si hay algo extraño. aunque como solo tienes un rango de 16 valores en hexa, creo que seria mas conveniente usar la resta que te comenté en el primer post
Título: Re: USART, ¿como capturar caracteres y trabajar con su valor numerico?
Publicado por: ALFREDOSKY en 05 de Marzo de 2014, 20:36:33
Código: [Seleccionar]
char BufferRX[4];          //arreglo de 16 bytes
char DataTX[4];            //arreglo de 16 bytes
int i;
int pos = 0;
char comando;
unsigned int RX_data;
int ang;
int pwm;
char PWM[3];
char ANG[3];

//recepcion de comandos
unsigned int check_command_serial()
{
    if (DataRdyUART1())
    {
        RX_data = ReadUART1();
       
        switch (RX_data)
        {
            case 10 : break;                     
            case 13 : if (pos>0)                   
                      {
                        comando = BufferRX[0];
                        pos = 0;                       
                        ANG[0] = BufferRX[1];
                        ANG[1] = 0;
                        PWM[0] = BufferRX[2];
                        PWM[1] = 0;
                        ang = atoi(ANG);
                        pwm = atoi(PWM);
                        pos = 0;
                        BufferRX[pos] = 0;
                        PWM[pos] = 0;
                        ANG[pos] = 0;
                        return 1;
                       }
                      break;
            default :
                      BufferRX[pos] = RX_data;     
                      pos++;                       
                      BufferRX[pos] = 0;                             
                      break;
        }
    }
    return 0;
}
Título: Re: USART, ¿como capturar caracteres y trabajar con su valor numerico?
Publicado por: rivale en 05 de Marzo de 2014, 21:36:45
no se si el c30 es "case sensitive", tienes 2 variables con el mismo nombre
Título: Re: USART, ¿como capturar caracteres y trabajar con su valor numerico?
Publicado por: ALFREDOSKY en 06 de Marzo de 2014, 11:55:57
Cambiaré los nombres y probare, gracias por la sugerencia  :mrgreen:
Título: Re: USART, ¿como capturar caracteres y trabajar con su valor numerico?
Publicado por: ALFREDOSKY en 06 de Marzo de 2014, 18:01:34
Lamentablemente no convierte :8}
Título: Re: USART, ¿como capturar caracteres y trabajar con su valor numerico?
Publicado por: rivale en 06 de Marzo de 2014, 18:07:40
intenta probar la función de atoi directamente, porque puede que no entre al case donde se utiliza
Título: Re: USART, ¿como capturar caracteres y trabajar con su valor numerico?
Publicado por: KALLITOS en 06 de Marzo de 2014, 18:25:35
Hola paisano.

Creo que estan haciendo las cosas mal, las funciones atoi, atol y demas se ejecutan con "caracteres numericos" es decir ASCII, aqui veo que estan usando hexadecimal y por alli no va bien la cosa.

Para que te haces problemas si el valor esperado va de 0x00 a 0x0F entonces calcula directamente:

ang = ((unsigned short)BufferRX[1]*(unsigned short)100)/360;

pwm = ((unsigned short)BufferRX[2]*(unsigned short)100)/0x0f;

Sencillo no?

Ahora si quieres pasar de hexa a decimal o viceversa, en una libreria de ds1307 "creo de RedPic" existen estas funciones:

Código: C++
  1. unsigned char bin2bcd(unsigned char temp)
  2. {
  3. unsigned char retval=0;
  4. while(1)
  5.         {
  6.     if(temp >= 10)
  7.                 {
  8.         temp -= 10;
  9.         retval += 0x10;
  10.         }//
  11.         else   
  12.                 {
  13.         retval += temp;
  14.         break;
  15.         }//
  16.         }//
  17. return(retval);
  18. }//
  19.  
  20. unsigned char bcd2bin(unsigned char bcd_value)
  21. {
  22. unsigned char temp;
  23. temp = bcd_value;
  24. temp >>= 1;
  25. temp &= 0x78;
  26. return(temp + (temp >> 2) + (bcd_value & 0x0f));
  27. }//
Título: Re: USART, ¿como capturar caracteres y trabajar con su valor numerico?
Publicado por: rivale en 06 de Marzo de 2014, 18:32:45
Hola paisano.

Creo que estan haciendo las cosas mal, las funciones atoi, atol y demas se ejecutan con "caracteres numericos" es decir ASCII, aqui veo que estan usando hexadecimal y por alli no va bien la cosa.

Para que te haces problemas si el valor esperado va de 0x00 a 0x0F entonces calcula directamente:



por lo que entendí, Alfredo esta enviando valores del 0 al F, pero en ascii, es decir, 0x30-0x39  y 0x41-0x46

por ejemplo si escribo(o envío) 'A8F', voy a mandar girar a la izquierda(caracter A) 200°(caracter 8) y a un pwm del 100%(el caracter F)

Si escribo 'BF7' B:derecha, F:360° y 7:50% pwm y así de la misma manera para otros caracteres hexadecimales.

Título: Re: USART, ¿como capturar caracteres y trabajar con su valor numerico?
Publicado por: ALFREDOSKY en 06 de Marzo de 2014, 19:27:00
Hola KALLITOS, como dice rivale, en realidad uso valores ascii, no hexadecimales, pero yo los trato como hexadecimal solo de manera visual, por ejemplo, para el caso del angulo de giro del motor, puede dar una vuelta completa, 360° ó 10° ó 50° etc, esto dependerá del byte ingresado, el rango es de 0-F, son 16 posiciones, 360/16=22.5°, si escribo '0' debe girar 22.5° a la izquierda o la derecha dependiendo de otro caracter(o byte), si escribo '7' sera 180° de giro, está codificado de forma rústica  :lol: soloamente para pruebas...así de esta manera cada digito significará un ángulo específico; lo mismo sucede con el pwm, igual otro byte que puede variar de 0-F, 100/16 = 6.25, si escribo 'F' entonces el pwm sera de 100%, si escribo '9' sera del 60% aprox. esa es la idea de usar los valores decimales porque uso el modulo QEI y necesito hacer cálculos numéricos  :tongue:   
Título: Re: USART, ¿como capturar caracteres y trabajar con su valor numerico?
Publicado por: rivale en 06 de Marzo de 2014, 19:30:33
una pregunta alfredo, y porque usas esos valores en ascii?, porque no usas directamente el valor entero de 0x00-0x0F?.


Título: Re: USART, ¿como capturar caracteres y trabajar con su valor numerico?
Publicado por: jesalf en 07 de Marzo de 2014, 13:35:56
Hola, bueno yo soy de los que leo y aprendo mucho del foro y ahora tengo la oportunidad de aportar.

yo programo en PCWH, pero igual y la lógica te sirve. Es indispensable agregar las librerías stdlib.h y string.h

char recibe[10];
unsigned op;

#int_RDA                      //declara la funcion para la interrupcion uart
void uart()
{
   recibe=getc();          //recibe cadena completa
   op=recibe;              //convierte el ultimo byte recibido en entero
                              //para comparar y saber cuando llego un retorno de carro
   
   if(op==0X0D)               //Si el úlyimo caracter es un enter
   {
      dato=1;                 //bandera para indicar que tenemos un dato completo
                       
      for(i=2;i<=4;i++)       //obtengo la cadena SP de la cadena recibe
      {
         SP[i-2]=recibe;
      }
       i=0;                   //reinicia contador
   }
   i++;
}

lo que hago es recibir caracter por caracter a través de la interrupción #int_rda en la cadena recibe[]. luego cuando llega un "enter" (que me indica que termina la cadena) entonces levanto la bandera dato=1 y copio el contenido donde está el dato numérico a la cadena SP, en mi caso el formato "SP123". Ojo en como inicio el ciclo for para que corresponda la posición de los caracteres xxx.

luego en la función principal

main()...
{
   while(1)
   {
   ....
   
   if(dato==1)
   {
      if(recibe[1]=='S')               //si el primer caracter es x entonces...
      {
         x=atoi(SP);
         printf("SP = %u",x);
         putc(13);
      }

si dato es 1 entonces tengo una cadena completa para procesar... y posteriormente con condiciones obtengo la operación. En este caso si el primer caracter es S, entonces la cadena SP la cambio a entero con x=atoi(SP) y listo!!.

solo tendrías que adaptar tu código para que corresponda a los números de caracteres que estableciste en tu protocolo.

Espero sea de utilidad.

Título: Re: USART, ¿como capturar caracteres y trabajar con su valor numerico?
Publicado por: ALFREDOSKY en 07 de Marzo de 2014, 14:26:05
 jesalf, claro que es de gran utilidad, todo aporte es siempre bienvenido, gracias por el tiempo que te tomas para explicar el programa, ahora tengo una alternativa mas de solución  :-/
; rivale es solo cuestión de prueba, si fueran números en lugar de caracteres, es decir, 10 en vez de 'A' o 14 en vez de 'E' igual la función atoi() no me esta convirtiendo 1 byte, de a dos bytes a mas si me convierte como seria el caso de escribir 11, o 13 etc; y la idea de usar estos caracteres es que este control de motor sera uno de los esclavos de mi red Maestro-Esclavos y  tengo un protocolo que funciona con 4 dígitos hexadecimales, el maestro enviará una cadena digamos: 0B3F que es para una tarea específica, dependiendo del dígito hex recibido y de la posición de éste se hará una tarea. Entiendo que un dígito hex representa medio byte, pero desde pc(simulado como maestro) desde hyperterminal envio esa secuencia, pero como tipo de dato cada dígito no son estrictamente hexadecimales, sino 1 char ó 1 byte; es por esa razón que lo convierto a entero, sobre todo los dígitos numéricos(0,1,2...9)...en el foro me han explicado que los bytes que no son base 10 la funcion atoi() no los va a convertir; cuando integre un pic como maestro este problema de conversión se va acabar por que se trataran como hexadecimales y podre calcular directamente  :mrgreen: , pero por ahora uso hyperterminal y el modulo usart del dspic30f2010  :shock:
Título: Re: USART, ¿como capturar caracteres y trabajar con su valor numerico?
Publicado por: rivale en 07 de Marzo de 2014, 15:11:49
lo que quieres es enviar un solo caracter, si envias del 0x00 al 0x0F también enviarías solo un caracter por dato, con esto, quizás tendrias el problema de que no son caracteres imprimibles, aunque no creo que te afecte

Otra opción es que envies en ascii 0,1,2,3,4,5,6,7,8,9,:,;,<,=,>,?,@


así tienes una secuencia de ascii continuos, entonces a lo que recibas solo le restas 0x30 y ya tienes del 0-15 en entero
Título: Re: USART, ¿como capturar caracteres y trabajar con su valor numerico?
Publicado por: ALFREDOSKY en 07 de Marzo de 2014, 15:22:47
rivale, en realidad envio varios bytes, algo como 'AFC', luego desgloso cada byte interpretandolo como hexadecimal(o sea no se enviará valores que no signifiquen hex, como una secuencia: 1HT), a excepcion del primero(A) que solo lo uso como comando  y represento su valor decimal, por ejemplo: C es 12...por lo que me dices, la mejor opcion sera restar 0x30 para los bytes de base 10 pero para los bytes:A, B, C, D, E Y F supongo que restare 0x31  :lol:
Título: Re: USART, ¿como capturar caracteres y trabajar con su valor numerico?
Publicado por: rivale en 07 de Marzo de 2014, 16:43:24
rivale, en realidad envio varios bytes, algo como 'AFC', luego desgloso cada byte interpretandolo como hexadecimal(o sea no se enviará valores que no signifiquen hex, como una secuencia: 1HT), a excepcion del primero(A) que solo lo uso como comando  y represento su valor decimal, por ejemplo: C es 12...por lo que me dices, la mejor opcion sera restar 0x30 para los bytes de base 10 pero para los bytes:A, B, C, D, E Y F supongo que restare 0x31  :lol:

me refiero a que quieres enviar un byte por instrucción, como dices, en AFC, la C que es un 12 lo envías en un solo byte, lo que quieres es enviar un "C" en vez de un "12".

para la ABCDEF le restarías 0x41
Título: Re: USART, ¿como capturar caracteres y trabajar con su valor numerico?
Publicado por: ALFREDOSKY en 07 de Marzo de 2014, 17:28:22
Exactamente eso, asi es; esa es la idea...ahh si perdon era 41 segun las tabla ascii; hare las pruebas con la sugerencia que me has dado y enseguida lo comento, gracias rivale, gracias a todos por su tiempo  ((:-)), este foro es de mucha ayuda y no me deja de sorprender la ayuda desinteresada que brindan :cheesy:
Título: Re: USART, ¿como capturar caracteres y trabajar con su valor numerico?
Publicado por: KALLITOS en 07 de Marzo de 2014, 18:38:42
Que ganas tienes de complicarte la vida  :D :D.
Para convertir tu "hexadecimal" a decimal, antes del calculo que te puse, haz lo siguiente:

if(isdigit(BufferRX[1]))BufferRX[1]-=48;  -> convierte 0 ASCII a decimal
else if(isalpha(BufferRX[1]))BufferRX[1] -= 55;  -> convierte 'A' en 10 y 'F' en 15, ojo mayusculas, para minusculas sería 87 en lugar de 55


Saludos.
Título: Re: USART, ¿como capturar caracteres y trabajar con su valor numerico?
Publicado por: ALFREDOSKY en 07 de Marzo de 2014, 20:21:53
Jajaja KALLITOS, es un capricho mio hacerlo de esa manera... :lol: , tambien probare tu sugerencia, gracias nuevamente, espero salga, por ahora me han encargado desarrollar i2c y no estoy viendo por ahora el problema que me trajo a postear en el foro, pero para el lunes o martes pruebo todas las sugerencias a ver que tal nos va, saludos! :tongue: