Anda di halaman 1dari 11

Ejemplito 16F876A: Recibiendo del RS232 sobre un Buffer y procesandolo

posteriormente.
Este nuevo ejemplito surge del trabajo preparatorio del siguiente que vamos a
realizar (ya lo veris en cuanto est listo). Como he tenido que desarrollar un
metodo de recibir comandos, con argumento (datos) aadidos, y tiene la suficiente
enjundia como para publicarlo como artculo separado, he decidido hacerlo as y
aqu tenis el resultado.
Hasta ahora, en los anteriores ejemplitos 16F876A, utilizbamos comandos
enviados va RS232 consistentes en un nico carcter, con el que haciamos ejecutar
alguna de las funciones que nuestro programa implementaba. Este mtodo es de
muy corto alcance por dos motivos fundamentales: Primero porque eran ejecutados
inmediatamente tan pronto eran recibidos y segundo porque no podamos enviarle
datos (una cadena de caracteres) para ser procesados.
En este ejemplito vamos a solucionar exactamente eso. He imaginado un programa
que admite dos comndos 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 envo de ambos comandos asi como el/los argumentos necesarios
he implementado lo bsico para manejar el buffer en el PIC, a base de teclas nicas,
cada una con su funcin: [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 podis
imaginar este miniprograma puede complicarse hasta el infinito y solo tenis que
aadir comandos a vuestra entera discrecin)
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 Estndar
// CONSTANTES /////////////////////////////////////////////////////////////////
int const lenbuff=32;

// Longitud de buffer, Ajustar


// a lo que desees (o te sea posible)

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


int xbuff=0x00;
char cbuff[lenbuff];
char rcvchar=0x00;
int1 flagcommand=0;

// ndice: siguiente char en cbuff


// Buffer
// ltimo caracter recibido
// Flag para indicar comando disponible

// Declaracin de Funciones ///////////////////////////////////////////////////


void inicbuff(void);
// Borra buffer
int addcbuff(char c);
// aade caracter recibido al buffer
void echos(char c);
// Eco selectivo sobre RS232
void procesa_comando(void);
// Procesa comando
// INTERRUPCIONES /////////////////////////////////////////////////////////////
#int_rda
void serial_isr() {
rcvchar=0x00;
if(kbhit()){
rcvchar=getc();
addcbuff(rcvchar);
echos(rcvchar);
}

// Interrupcin recepcin serie USART


// Inicializo caracter recibido
// Si hay algo pendiente de recibir ...
// lo descargo y ...
// lo aado al buffer y ...
// hago eco (si procede).

}
// Desarrollo de Funciones ////////////////////////////////////////////////////
void echos(char c){

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){
int i;

// Echo selectivo ----------------------

// Inicia a cbuff -------------------

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){

// Aade 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;
// Aade 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 carcter del buffer
" );
printf("[\w] Comando Escribe
" );
printf("[\r] Comando Lee
" );
printf("
" );
enable_interrupts(int_rda);
enable_interrupts(global);

// Habilita Interrupcin RDA


// 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];
flagcommand=0;
printf("
Procesando ... " );

// Argumento de comando (si lo tiene)


// Desactivo flag de comando pendiente.
// Monitorizo procesando ...

for(i=0;i<lenbuff;i++){
arg[ i ]=0x00;
}

// Bucle que pone a 0 todos los


// 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


podis hacer aqui
El post anterior era puramente terico. 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.
}
...

1. // CONTROL DEL BUFFER ORIGINAL DE RED_PIC Y "destrozado por Santipic"

2.
3. // Por el puerto serie me entra esta secuencia de caracteres cada 2
segundos
4. // $GPGGA,194345.0,,,,,0,02,,,,,,,*74 y quiero meterla en el buffer y de ah
poder
5. // recuperla y enviarla otra vez por el puerto serie.
6.
7.
8. #include <18f2550.h>
// Definiciones del PIC 18F2550
9. #fuses HS,NOWDT,NOPROTECT,NOLVP,PUT,BROWNOUT // Los Fuses de
siempre
10. #use delay(clock=8000000)
// Oscilador a 8Mhz
11.
12. #include <stdlib.h>
13.
14. #use rs232(baud=4800, xmit=PIN_C6, rcv=PIN_C7)// RS232 Estndar
15.
16. // CONSTANTES /////////////////////////////////////////////////////////////////
17.
18. int const lenbuff=100;
// Longitud de buffer, Ajustar
19.
// a lo que desees (o te sea posible)
20.
21. // VARIABLES EN RAM ///////////////////////////////////////////////////////////
22.
23. int xbuff=0x00;
// ndice: siguiente char en cbuff
24. char cbuff[lenbuff];
// Buffer
25. char rcvchar=0x00;
// ltimo caracter recibido
26. int1 flagcommand=0;
// Flag para indicar comando disponible
27.
28. // Declaracin de Funciones ///////////////////////////////////////////////////
29.
30. void inicbuff(void);
// Borra buffer
31. int addcbuff(char c);
// aade caracter recibido al buffer
32. void echos(char c);
// Eco selectivo sobre RS232
33. void procesa_comando(void);
// Procesa comando
34.
35. // INTERRUPCIONES /////////////////////////////////////////////////////////////
36.
37. #int_rda
38. void serial_isr() {
// Interrupcin recepcin serie USART
39.
40. rcvchar=0x00;
// Inicializo caracter recibido
41. if(kbhit()){
// Si hay algo pendiente de recibir ...
42.
rcvchar=getc();
// lo descargo y ...
43.
addcbuff(rcvchar);
// lo aado al buffer y ...
44. }
45. }
46.
47. // Desarrollo de Funciones ////////////////////////////////////////////////////
48. int addcbuff(char c){
// Aade a cbuff ----------------------49.
50.
switch(c){
51.
case 0x0D:
// Enter -> Habilita Flag para procesar
52.
flagcommand=1;
// Comando en Main
53.
break;
54.
case 0x08:
// Del -> Borra ltimo caracter del Buffer
55.
if(xbuff>0) cbuff[--xbuff]=0x00;
56.
break;
57.
case 0x01B:
// Esc -> Borra el Buffer completamente
58.
inicbuff();

59.
break;
60.
default:
61.
cbuff[xbuff++]=c;
// Aade caracter recibido al Buffer
62.
}
63. }
64.
65. void inicbuff(void){
// Inicia a \0 cbuff ------------------66. int i;
67.
68. for(i=0;i<lenbuff;i++){
// Bucle que pone a 0 todos los
69.
cbuff[i]=0x00;
// caracteres en el buffer
70. }
71. xbuff=0x00;
// Inicializo el indice de siguiente
72.
// caracter
73. }
74. // Programa Principal /////////////////////////////////////////////////////////
75.
76. void main() {
77. printf("\r\n\** prueba buffer **\r\n\r\n"); // Presenta men
78.
79. enable_interrupts(int_rda);
// Habilita Interrupcin RDA
80. enable_interrupts(global);
// Habilita interrupciones
81.
82. do {
83.
84.
if(flagcommand) procesa_comando();
// Si hay comando pendiente
85.
// de procesar ... lo procesa.
86. } while (TRUE);
87.
88. }
89. // Procesador de Comandos /////////////////////////////////////////////////////
90.
91. void procesa_comando(void){
92.
93. int i, xv;
94. char arg[lenbuff];
// Argumento de comando (si lo tiene)
95. disable_interrupts(int_rda);
96. flagcommand=0;
// Desactivo flag de comando pendiente.
97. printf("\r\nProcesando ... ");
// Monitorizo procesando ...
98.
99.
xbuff=0x00;
//Lo que necesito hacer es scanear el buffer
para
100.
for (cbuff[0];xbuff='$';xbuff=0x4A){ //extraer la cadena de
caracteres que me interesa
101.
printf("\r\nfor ... ");
// Prueba de que pasa por aqu
102.
i=0;
103.
do{
104.
// Extraemos argumento del buffer
105.
arg[0]=xbuff ;
//
106.
}while(cbuff[++i] == 0x4A);
107.
xv = atoi(arg);
108.
printf("Escribiendo %s %u ... ",arg,xv);
109.
}
// Monitorizamos el argunmento.
110.
111.
inicbuff();
// Borro buffer.
112.
113.
printf("Procesado.\r\n\r\n");
// Monitorizo procesado.
114.
enable_interrupts(int_rda);
115.
}
116.

Corrige el erro
1. j=0;
2. printf("Escribiendo ");
3. for (i=0;i<xbuff;i++){
4. if (cbuff[i]=="$")
5.
while((cbuff[i] != 0x4A) & (i<xbuff))
6.
{
7.
salida[j++]=cbuff[i++];
8.
printf ("%c",salida[j-1]);
9.
}
10. i++;
11. }
Cdigo funcionando
1. // CONTROL DEL BUFFER ORIGINAL DE RED_PIC
2.
3. // Por el puerto serie me entra esta secuencia de caracteres cada 2
segundos
4. // $GPGGA,194345.0,,,,,0,02,,,,,,,*74(esta es una trama sin stelite
5. //, sino tendra sobre 70 caracteres)
6. // y quiero meterla en el buffer y de ah poder
7. // recuperla y enviarla otra vez por el puerto serie.
8.
9.
10. #include <18f2550.h>
// Definiciones del PIC 18F2550
11. #fuses HS,NOWDT,NOPROTECT,NOLVP,PUT,BROWNOUT // Los Fuses de
siempre
12. #use delay(clock=8000000)
// Oscilador a 8Mhz
13.
14. #include <stdlib.h>
15.
16. #use rs232(baud=4800, xmit=PIN_C6, rcv=PIN_C7)// RS232 Estndar
17.
18. // CONSTANTES /////////////////////////////////////////////////////////////////
19.
20. int const lenbuff=76;
// Longitud de buffer, Ajustar
21.
// a lo que desees (o te sea posible)
22.
23. // VARIABLES EN RAM ///////////////////////////////////////////////////////////
24.
25. int xbuff=0x00;
// ndice: siguiente char en cbuff
26. char cbuff[lenbuff];
// Buffer
27. char rcvchar=0x00;
// ltimo caracter recibido
28. int1 flagcommand=0;
// Flag para indicar comando disponible
29.
30. // Declaracin de Funciones ///////////////////////////////////////////////////
31.
32. void inicbuff(void);
// Borra buffer
33. int addcbuff(char c);
// aade caracter recibido al buffer
34. void echos(char c);
// Eco selectivo sobre RS232
35. void procesa_comando(void);
// Procesa comando
36.
37. // INTERRUPCIONES /////////////////////////////////////////////////////////////
38.
39. #int_rda
40. void serial_isr() {
// Interrupcin recepcin serie USART
41.
42. rcvchar=0x00;
// Inicializo caracter recibido

43. if(kbhit()){
// Si hay algo pendiente de recibir ...
44.
rcvchar=getc();
// lo descargo y ...
45.
addcbuff(rcvchar);
// lo aado al buffer y ...
46. }
47. }
48.
49. // Desarrollo de Funciones ////////////////////////////////////////////////////
50. int addcbuff(char c){
// Aade a cbuff ----------------------51. switch(c){
52.
case 0x0D:
// Enter -> Habilita Flag para procesar
53.
flagcommand=1;
// Comando en Main
54.
55.
break;
56.
default:
57.
cbuff[xbuff++]=c;
// Aade caracter recibido al Buffer
58.
59.
}
60. }
61.
62. void inicbuff(void){
// Inicia a \0 cbuff ------------------63. int i;
64.
65. for(i=0;i<lenbuff;i++){
// Bucle que pone a 0 todos los
66.
cbuff[i]=0x00;
// caracteres en el buffer
67. }
68. xbuff=0x00;
// Inicializo el indice de siguiente
69.
// caracter
70. }
71. // Programa Principal /////////////////////////////////////////////////////////
72.
73. void main() {
74. printf("\r\n\** prueba buffer **\r\n\r\n"); // Presenta men
75.
76. enable_interrupts(int_rda);
// Habilita Interrupcin RDA
77. enable_interrupts(global);
// Habilita interrupciones
78.
79. do {
80.
if(flagcommand) procesa_comando();
// Si hay comando pendiente
de procesar ... lo procesa.
81.
printf("..\r"); // printf CR
82. } while (TRUE);
83.
84. }
85. // Procesador de Comandos /////////////////////////////////////////////////////
86.
87. void procesa_comando(void){
88.
89. int i, j;
90. char salida[lenbuff];
// Argumento de comando (si lo tiene)
91.
92. disable_interrupts(int_rda);
93. flagcommand=0;
// Desactivo flag de comando pendiente.
94.
95.
j=0;
96.
for (i=0;i<xbuff;i++){
97.
if (cbuff[i] == '$')
98.
while((cbuff[i] != 0x4A) & (i<xbuff))
99.
{
100.
salida[j++]=cbuff[i++];
101.
printf ("%c",salida[j-1]); // Monitorizamos el argunmento.

102.
103.
104.
105.
106.
107.
108.
109.
110.
111.
112.

}
i++;
}
inicbuff();

// Borro buffer.

for(i=0;i<lenbuff;i++){
salida[i]=0x00;
}
}

// Bucle que pone a 0 todos los


// caracteres en el argumento

enable_interrupts(int_rda);

CODIGO PARA CORREGIR


Velocidad_PID_Motor_Serial.c
#include <16f877a.h>
#include <string.h>
#include <stdlib.h>
#fuses NOWDT,HS,NOLVP
#use delay(clock=10M)
#use RS232(baud=9600,XMIT=PIN_C6,RCV=PIN_C7,stream=receptor)
#bit
#bit
#bit
#bit
#bit

RB0=0x06.0
RB1=0x06.1
RC3=0x07.3
RC4=0x07.4
RC7=0x07.7

int i;
int const length=10;
char data;
char cadena[length];
short flagcomand=0;
signed int16 p=0;
#int_RDA
void RDA_isr(void)
{
do
{
data=fgetc(receptor);
if(data=='\0')
{
break;
}
else
{
cadena[i]=data;
i++;
}
}while(kbhit(receptor));
flagcomand=1;
}
void limpiar_buffer()
{

int j;
for(j=0;j<length;j++)
{
cadena[j]=0x00;
}
}
#INT_EXT
// directiva de interrupcion por cambio de estado en RB0
void interrupcion_RB0()
{
if(RB0==1)
{
ext_int_edge(H_TO_L);
if(RB1==1)
{
p=p+1;
}
}
else
{
ext_int_edge(L_TO_H);
if(RB1==1)
{
p=p-1;
}
}
//putc(p);
//puts(p);
printf("\r%Ld",p);
}
void main()
{
//char valorRec[4];
char c;
int d;

//variable donde se recibira desde la cadena

set_tris_b(0xFF);
//configuro portb=in
set_tris_c(0x80);
//solo el Rx esta como entrada
RC3=0;
RC4=0;
//configuracion pwm
setup_ccp1(CCP_PWM);
setup_timer_2(T2_DIV_BY_16,255,1);
//Tpwm=1.63ms--->el ciclo de trabajo sera
de 0-255
set_timer2(0);
set_pwm1_duty(0);
enable_interrupts(INT_RDA);
enable_interrupts(INT_EXT);
//habilito interrupcion RB0
ext_int_edge(L_TO_H);
//configuro interrupcion por flanco de subida
enable_interrupts(GLOBAL);
// habilito interrupcion global

while(TRUE)
{
//gets(valorRec);
c=cadena[0];
if(flagcomand==1)
{

flagcomand=0;
switch(c)
{
case 's':
{
//printf("%3Lu",p);
//putc(p);
//printf("%3u",pv);
//delay_ms(500);
break;
}
case 'i':
{
RC3=0;
RC4=1;
break;
}
case 'd':
{
RC3=1;
RC4=0;
break;
}
default:
{
d=atoi(cadena);
set_pwm1_duty(d);
//putc(p);
//printf("%3Lu",p);
break;
}
}
limpiar_buffer();
}
}
}
Velocidad_PID_Motor_Serial.h
#include <16F877A.h>
#device adc=8
#FUSES NOWDT, HS, NOPUT, NOPROTECT, NODEBUG, NOBROWNOUT, NOLVP,
NOCPD, NOWRT, RESERVED
#use delay(clock=10000000)
#use rs232(baud=9600,parity=N,xmit=PIN_C6,rcv=PIN_C7,bits=8)

Anda mungkin juga menyukai