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:

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
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"
;
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.
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
