TODOPIC
Bienvenido(a), Visitante. Por favor, ingresa o regístrate.
¿Perdiste tu email de activación?
03 de Septiembre de 2010, 05:30:11

Ingresar con nombre de usuario, contraseña y duración de la sesión
Buscar:     Búsqueda Avanzada
257111 Mensajes en 28437 Temas por 27916 Usuarios
Último usuario: zororyuzaki
* Inicio Ayuda Buscar Calendario Ingresar Registrarse
Buscar en TodoPIC
+  TODOPIC
|-+  Microcontroladores PIC
| |-+  Lenguaje C para microcontroladores PIC (Moderadores: Modulay, pikman, pocher, vszener, Suky)
| | |-+  Ejemplito 16F876A: Recibiendo del RS232 sobre un Buffer y procesandolo posteriormente.
0 Usuarios y 1 Visitante están viendo este tema. « anterior próximo »
Páginas: [1] Marcar como favorito Imprimir
Autor Tema: Ejemplito 16F876A: Recibiendo del RS232 sobre un Buffer y procesandolo posteriormente.  (Leído 2330 veces)
RedPic
Administrador
DsPIC33
*******
Desconectado Desconectado

Sexo: Masculino
Tibet Tibet

Mensajes: 4876



WWW
« : 01 de Enero de 2006, 02:39:00 »

Este nuevo ejemplito surge del trabajo preparatorio del siguiente que vamos a realizar (ya lo veréis en cuanto esté listo). Como he tenido que desarrollar un metodo de recibir comandos, con argumento (datos) añadidos, y tiene la suficiente enjundia como para publicarlo como artículo separado, he decidido hacerlo así y aquí tenéis el resultado.

Hasta ahora, en los anteriores ejemplitos 16F876A, utilizábamos comandos enviados vía RS232 consistentes en un único carácter, con el que haciamos ejecutar alguna de las funciones que nuestro programa implementaba. Este método es de muy corto alcance por dos motivos fundamentales: Primero porque  eran ejecutados inmediatamente tan pronto eran recibidos y segundo porque no podíamos enviarle datos (una cadena de caracteres) para ser procesados.

En este ejemplito vamos a solucionar exactamente eso. He imaginado un programa que admite dos comándos de alto nivel: uno de lectura "" sin argumentos y otro de escritura "w" que va seguido de un argumento tan largo como deseemos.

Para manejar el envío de ambos comandos asi como el/los argumentos necesarios he implementado lo básico para manejar el buffer en el PIC, a base de teclas únicas, cada una con su función: [INTRO] 0x0D para indicar que hemos terminado de escribir el comando, [RETROCESO] 0x08 para borrar el último caracter enviado y [ESCAPE] 0x1B para borrar todo el contenido actual del buffer. (Como podéis imaginar este miniprograma puede complicarse hasta el infinito y solo tenéis que añadir comandos a vuestra entera discreción)

El programa va entonces recibiendo caracteres, uno tras otro, y guardandolos en el Buffer. Si recibe el comando [INTRO] habilita un flag para que se procese el comando, y tras ser procesado borra el buffer y vuelve a empezar. Las otras dos teclas de [RETROCESO] y [ESCAPE] las usamos para editar el contenido del buffer antes de enviarle la orden de procesado.

He intentado comentar profusamente el programa para que sea meridianamente claro su funcionamiento y hacer así innecesarias mas explicaciones:

Codigo:

// _232_buffered.c

#include <16f876a.h>                          // Definiciones del PIC 16F876A
#fuses XT,NOWDT,NOPROTECT,NOLVP,PUT,BROWNOUT  // Los Fuses de siempre
#use delay(clock=4000000)                     // Oscilador a 4 Mhz
#use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7)// RS232 Estándar

// CONSTANTES /////////////////////////////////////////////////////////////////

int const lenbuff=32;                  // Longitud de buffer, Ajustar
                                       // a lo que desees (o te sea posible)

// VARIABLES EN RAM ///////////////////////////////////////////////////////////

int  xbuff=0x00;                       // Índice: siguiente char en cbuff
char cbuff[lenbuff];                   // Buffer
char rcvchar=0x00;                     // último caracter recibido
int1 flagcommand=0;                    // Flag para indicar comando disponible

// Declaración de Funciones ///////////////////////////////////////////////////

void inicbuff(void);                   // Borra buffer
int  addcbuff(char c);                 // añade caracter recibido al buffer
void echos(char c);                    // Eco selectivo sobre RS232
void procesa_comando(void);            // Procesa comando

// INTERRUPCIONES /////////////////////////////////////////////////////////////

#int_rda
void serial_isr() {                    // Interrupción recepción serie USART

   rcvchar=0x00;                       // Inicializo caracter recibido                    
   if(kbhit()){                        // Si hay algo pendiente de recibir ...
      rcvchar=getc();                  // lo descargo y ...
      addcbuff(rcvchar);               // lo añado al buffer y ...
      echos(rcvchar);                  // hago eco (si procede).
   }
}

// Desarrollo de Funciones ////////////////////////////////////////////////////

void echos(char c){                    // Echo selectivo ----------------------

      switch(c){
         case 0x0D: printf(" [Ent] " ); // Si he pulsado la tecla [Intro]
                    break;
         case 0x08: printf(" [Del] " ); // Si he pulsado la tecla [Retroceso]
                    break;
         case 0x1B: printf(" [Esc] " ); // Si he pulsado la tecla [Escape]
                    break;
         default:   putc(rcvchar);     // Echo de cualquier otro caracter
      }
}

void inicbuff(void){                   // Inicia a cbuff -------------------
   int i;

   for(i=0;i<lenbuff;i++){             // Bucle que pone a 0 todos los
      cbuff[ i ]=0x00;                   // caracteres en el buffer
   }
   xbuff=0x00;                         // Inicializo el indice de siguiente
                                       // caracter
}

int addcbuff(char c){                  // Añade a cbuff -----------------------

      switch(c){
         case 0x0D:                    // Enter -> Habilita Flag para procesar
            flagcommand=1;             // Comando en Main
            break;
         case 0x08:                    // Del   -> Borra último caracter del Buffer
            if(xbuff>0) cbuff[--xbuff]=0x00;
            break;
         case 0x01B:                   // Esc   -> Borra el Buffer completamente
            inicbuff();
            break;
         default:
            cbuff[xbuff++]=c;          // Añade caracter recibido al Buffer
      }
}


// Programa Principal /////////////////////////////////////////////////////////

void main() {

   inicbuff();                                   // Borra buffer al inicio
 
   printf("
** RS232 Buffered **

" );  // Presenta menú
   printf("[Enter] Procesa comando
" );
   printf("[Escape] Borra todo el buffer
" );
   printf("[Delete] Borra último carácter del buffer
" );
   printf("[\w] Comando Escribe
" );
   printf("[\r] Comando Lee
" );
   printf("
" );

   enable_interrupts(int_rda);                   // Habilita Interrupción RDA
   enable_interrupts(global);                    // Habilita interrupciones

   do {
   
      if(flagcommand) procesa_comando();         // Si hay comando pendiente
                                                 // de procesar ... lo procesa.

   } while (TRUE);

}

// Procesador de Comandos /////////////////////////////////////////////////////

void procesa_comando(void){

   int i;
   char arg[lenbuff];                   // Argumento de comando (si lo tiene)

   flagcommand=0;                       // Desactivo flag de comando pendiente.
   printf("
Procesando ... " );       // Monitorizo procesando ...

   for(i=0;i<lenbuff;i++){             // Bucle que pone a 0 todos los
      arg[ i ]=0x00;                     // caracteres en el argumento
   }

   if(cbuff[0]=="\"&&cbuff[1]=="r"){   // Comparo inicio del buffer con comando ""
   
      printf("Leyendo ... " );           // Aqui lo que deseemos hacer con comando ""
     
   }

   if(cbuff[0]=="\"&&cbuff[ 1 ]=="w"){   // Comparo inicio del buffer con comando "w"
      i=2;
      do{                               // Extraemos argumento del buffer
         arg[i-2]=cbuff;             // a partir del 3er byte y hasta .
      }while(cbuff[++i ]!=0x00);
     
      printf("Escribiendo %s ... ",arg);// Aqui lo que deseemos hacer con comando "w"
                                        // Monitorizamos el argunmento.
   }

   inicbuff();                          // Borro buffer.

   printf("Procesado.

" );        // Monitorizo procesado.
}




Si desais descargar el programa c para realizar vuestras propias modificaciones lo podéis hacer aqui

Los resultados vistos en mi monitor de conexión serie son:






En línea

Contra la estupidez los propios dioses luchan en vano. Schiller
Mi Güeb : Picmania
xootraoox
Colaborador
PIC16
*****
Desconectado Desconectado

Sexo: Masculino
Chile Chile

Mensajes: 245



« Respuesta #1 : 03 de Febrero de 2006, 04:31:00 »

hola amigo RedPic,
           Bueno te comento un poco....  estoy usando una parte de este codigo el cual trabaja bastante bien pero tengo un peueño problema a la hora de trabajar con numeros..... imagino obviamente que debe de ser un problema mio..... detallo un poco lo que me pasa.


  resulta que desde visual basic estoy enviando unos comandos junto con unos valores, como por ejemplo 127, bueno lo que hace esa cadena es setear una variable en el pic, con el valor 127 respectivamente, pero resulta que la variable queda siempre con valor 160, sea el valor que sea el que le envie.

tu en tu codigo colocaste una variable llamada arg, en la cual se debiera guardar respectivamente el contenido que le envio (en este caso 127) la cual es de tipo char, por lo que yo pense que podia ser ese el problema por lo que me decidi a copiar la variable arg en otra variable de tipo int, para que los caracteres ahora fuesen numeros, pero no dio resultado ya que sigue cargando cualquier valor menos el que le envio. bueno pegare el trozo de codigo para que lo puedas ver para que me des una mano si es posible ya que llevo 3 noches completas tratando de solucionar este problema sin ningun resultado.

Codigo:
if(cbuff[0]=="\"&&cbuff[1]=="B"){
      i=2;
      do{                                               // Extraemos argumento del buffer
         arg[i-2]=cbuff;                        // a partir del 3er byte y hasta .
      }while(cbuff[++i]!=0x00);
      valor=arg;                                    // donde valor es respectivamente de tipo int
      temp_duty_cycle2=valor;
      printf("-duty cycle = %u", valor);
}


desde ya quedo muy agradecido si me puedez ayudar
despide
En línea
xootraoox
Colaborador
PIC16
*****
Desconectado Desconectado

Sexo: Masculino
Chile Chile

Mensajes: 245



« Respuesta #2 : 03 de Febrero de 2006, 08:07:00 »

bueno este es solo para adjuntar una captura realizada con un analizador de puertos, el cual me permite ver lo que esta pasando atravez de los cables...



En línea
RedPic
Administrador
DsPIC33
*******
Desconectado Desconectado

Sexo: Masculino
Tibet Tibet

Mensajes: 4876



WWW
« Respuesta #3 : 03 de Febrero de 2006, 08:11:00 »

Ahora no puedo mirarte este tema (no tengo mis cacharros a mano) pero en cuanto llegue a casa pruebo el sistema (que yo ya he modificado para otros asuntos) y te contesto sobre la marcha.

En línea

Contra la estupidez los propios dioses luchan en vano. Schiller
Mi Güeb : Picmania
xootraoox
Colaborador
PIC16
*****
Desconectado Desconectado

Sexo: Masculino
Chile Chile

Mensajes: 245



« Respuesta #4 : 03 de Febrero de 2006, 08:28:00 »

te lo agradeceria...... ya que esto me ha hecho salir humo de las orejasMuchas risasMuchas risas
En línea
RedPic
Administrador
DsPIC33
*******
Desconectado Desconectado

Sexo: Masculino
Tibet Tibet

Mensajes: 4876



WWW
« Respuesta #5 : 03 de Febrero de 2006, 12:35:00 »

Bueno, amigo xootraoox, vamos a ver si soy capaz de explicarme claramente para que puedas completar tu desarrollo con éxito:


Tal como está escrito este programa, y como muy bien dices en tu post, en la variable arg recibo los argumentos que acompañan al comando correspondiente.

En tu ejemplo mandas los carácteres A127[newline][return] o lo que es lo mismo los valores hexadecimales 0x5C 0x41 0x31 0x32 0x37 0x0D 0x0A cosa que corresponde al comando A con el argumento 127 teniendo en cuenta que 127 representa un entero.

Pero, y este pero es importante, tú no mandas el entero 127 sino que envias la representacion del mismo mediante un string, una cadena, de tres caracteres ASCII consecutivos, el 1 (0x31) el 2 (0x32) y el 7 (0x37)

Así en arg lo que realmente tienes es [0x31][0x32][0x37][0x00] que es un string estándar de C acabado en .

Hacer la asignación que haces de una variable de tipo entero directamente igual a una de tipo string solo puede dar un resultado indefinido.

Lo que ahora hay que realizar es la conversión de un string cuyo contenido es la representación ASCII de un valor entero a su valor entero.

Para ello me voy al Reference Manual del CCS-C y en la página número 66, como el mago que saca el conejo de su chistera, encuentro:

Codigo:

ATOI( )
ATOL( )
ATOI32()
Syntax: ivalue = atoi(string) or lvalue = atol(string) or i32value = atoi32(string)
Parameters: string is a pointer to a null terminated string of characters.
Returns: ivalue is an 8 bit int.lvalue is a 16 bit int. i32value is a 32 bit int.
Function: Converts the string pointed too by ptr to int representation. Accepts both decimal and hexadecimal argument. If the result cannot be represented, the behavior is undefined.
Availability: All devices.
Requires: #include <stdlib.h>
Examples:
char string[10];
int x;
strcpy(string,"123"Giño;
x = atoi(string);
// x is now 123



Así que ya sabes:

1º coloca arriba del todo de tú codigo el #include <stdlib.h>
2º el codigo que has escrito quedaría así: valor=atoi(arg);

y 3º compila, prueba y me cuentas.


En línea

Contra la estupidez los propios dioses luchan en vano. Schiller
Mi Güeb : Picmania
RedPic
Administrador
DsPIC33
*******
Desconectado Desconectado

Sexo: Masculino
Tibet Tibet

Mensajes: 4876



WWW
« Respuesta #6 : 03 de Febrero de 2006, 01:45:00 »

El post anterior era puramente teórico. Este es absolutamente real.

He realizado los cambios que te propuse:

Codigo:

...
#include <stdlib.h>
...

void procesa_comando(void){
   int i, xv;
...

   if(cbuff[0]=="\"&&cbuff[1]=="w"){   // Comparo inicio del buffer con comando "w"
      i=2;
      do{                               // Extraemos argumento del buffer
         arg[i-2]=cbuff[ i ];             // a partir del 3er byte y hasta .
      }while(cbuff[++i]!=0x00);

      xv = atoi(arg);

      printf("Escribiendo %s %u... ",arg,xv ) ; // Aqui lo que deseemos hacer con comando "w"
                                        // Monitorizamos el argunmento.
   }
...



y el resultado es ...... tatatachán



En línea

Contra la estupidez los propios dioses luchan en vano. Schiller
Mi Güeb : Picmania
xootraoox
Colaborador
PIC16
*****
Desconectado Desconectado

Sexo: Masculino
Chile Chile

Mensajes: 245



« Respuesta #7 : 03 de Febrero de 2006, 02:22:00 »

Amigo RedPic,

          que puedo decirte..... quedo muy agradecido..... yo tratando 3 noches y tu en un instante lo resuelves....... la verdad es que pense que ese era el problema, pero no lo podia solucionar y por mas que buscaaba no me tope con atoi y itoa, aunque el codigo se elevo bastante resulto ser la solucion justa ya que la aplicacion no es muy grandey creo que me alcanzara bien en el micro que estoy usando (16f628).

despide agradecido
En línea
RedPic
Administrador
DsPIC33
*******
Desconectado Desconectado

Sexo: Masculino
Tibet Tibet

Mensajes: 4876



WWW
« Respuesta #8 : 03 de Febrero de 2006, 02:38:00 »

No, hombre, no. Ocurre que tenemos a nuestra disposición este magnifico foro.

Y he seguido de cerca el hilo Itoa y atoi en ccs donde el maestro Pocher ha desplegado su proverbial sapiencia en ayuda de humildes principiantes como nosotros.

En línea

Contra la estupidez los propios dioses luchan en vano. Schiller
Mi Güeb : Picmania
pocher
Moderador Local
DsPIC30
*****
Desconectado Desconectado

Sexo: Masculino
España España

Mensajes: 2500



« Respuesta #9 : 04 de Febrero de 2006, 12:17:00 »

Guau, gracias maestro RedPic pero sigo aprendiendo de todos vosotros.
En línea
I3iT
PIC12
**
Desconectado Desconectado

Sexo: Masculino
Mensajes: 50


« Respuesta #10 : 04 de Febrero de 2006, 06:11:00 »

ummmm

Yo enviaria el 127 como un solo byte, asi "tarda" menos la comunicacion aunque en este caso no influye.

127(d)=7F(h)

Asi pues con enviar el caracter 7F desde el ordenador, al  recibirlo en el PIC lo puedes meter en un char y luego con asignarlo a un int ya tienes el 127...

---------------------------------------------------------

Me a surgido una duda, referente a una aplicación que estube haciendo con comunicaciones RS232.
Yo mandaba al PIC 4 bytes consecutivos desde un programa en VisualBasic, y funciona bien pero de vez en cuando (aleatoriamente) la USART dejaba de recibir datos... si enviaba pero no recibia mas.... y no se muy bien por que??
No empleaba la instrucción kbhit() pero no creo q sea ese el problema.
Es como si se saturara la recepción, eso que ponia la interrupcion de recepción serie la mas prioritaria y solamente guardaba los bytes recibidos en un "char array" y cuando el contador llagaba a 4 activaba un flag para tratar los datos en el main...
A alguien se le ocurre algo?

>Salu2<
En línea
RedPic
Administrador
DsPIC33
*******
Desconectado Desconectado

Sexo: Masculino
Tibet Tibet

Mensajes: 4876



WWW
« Respuesta #11 : 27 de Marzo de 2006, 02:27:00 »

Muy cierto I3iT, sería rapidísimo, un byte en lugar de tres, pero muy dificil de
escribir desde un terminal "tonto" monitor rs232 estilo Hyperterminal de
Windows o similar.

Y si lo escribiesemos en Hex transmitiríamos solo dos, pero tendríamos que
realizar la conversión de dos ASCII-hex a un byte en lugar de tres ASCII-dec
a ese mismo byte.


En línea

Contra la estupidez los propios dioses luchan en vano. Schiller
Mi Güeb : Picmania
TODOPIC
   

 En línea
Páginas: [1] Imprimir 
« anterior próximo »
Ir a:  

Impulsado por MySQL Impulsado por PHP Powered by SMF 1.1.11 | SMF © 2006-2008, Simple Machines LLC XHTML 1.0 válido! CSS válido!
Página creada en 0.122 segundos con 23 consultas.