Autor Tema: Manejo de buffer rs232 y control de errores en pic 16f876a  (Leído 2871 veces)

0 Usuarios y 1 Visitante están viendo este tema.

Desconectado claudiovega

  • PIC10
  • *
  • Mensajes: 31
Manejo de buffer rs232 y control de errores en pic 16f876a
« en: 19 de Mayo de 2015, 12:24:26 »
Hola,
Tengo varias tarjetas, de fabricación propia, cada una de ellas con un pic 16f876a y un módem xbee xbp09.
Desde un pc con un xbee conectado al puerto serie, envío una misma cadena a todas la tarjetas. En la cadena va un id para que cada pic sepa si el mensaje es para el o no. Si el mensaje es para el responde con su id mas la acción realizada.
El problema es que si pruebo comunicarme con cada tarjeta por separado (sin encender las otras) todo funciona muy bien, pero si enciendo 2 o mas sólo puedo comunicarme con una de ellas, la primera a la cual envíe un mensaje.
Hice la prueba de que sean las tarjetas las que me envíen un mensaje en todo momento y recibo en el pc el mensaje correctamente de todos los pic, pero apenas envío un mensaje a una tarjeta dejo de tener comunicación con todas las demás, no reciben ni envían datos.
Por esto y por el hecho de que esta configuración de red xbee funciona bien con otro sistema que tenemos (hecho en assembler, del cual no entiendo nada) es que creo que debe haber algún problema en el buffer rs232 o en el control de errores de este.
Aquí esta el código del pic en C (ccs compiler).
Código: [Seleccionar]

#include <16F876A.h>
#include <stdlib.h>

#FUSES NOWDT          //No Watch Dog Timer
#FUSES XT                       
#FUSES NOPUT          //No Power Up Timer
#FUSES NOPROTECT      //Code not protected from reading
#FUSES NODEBUG        //No Debug mode for ICD
#FUSES NOBROWNOUT     //No brownout reset
#FUSES NOLVP          //No low voltage prgming, B3(PIC16) or B5(PIC18) used for I/O
#FUSES NOCPD          //No EE protection
#FUSES NOWRT          //Program memory not write protected
#FUSES HS   

#use delay(clock=20000000)
#use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7, STREAM=COM_A, parity=N, bits=8, ERRORS)

char p, term[2], command[48] = "", action[10] = "", values[45] = "", picid[8] = "";
char picsaved[8] = "", pass[8] = "", permited[9] = "";
short newcommand = 0;
int k = 0;
int32 seconds[14], times[14], epoch;
int1 logged;

#bit OERR=0x0018.1
#bit CREN=0x0018.4

#INT_RDA
void usart_modem(void)

disable_interrupts(INT_RDA);

if(OERR)
{
CREN=0;
delay_cycles(2);
CREN=1;
}

newcommand = 0;
if (kbhit(COM_A))
{
p = fgetc(COM_A);
if(p == '#') {
command[k] = '\0';
newcommand = 1;
k = 0;

}else{
command[k] = p;
k++;
}
}

enable_interrupts(INT_RDA);
}

int is_equal(char *p1, char *p2)
{
int *p3;
p3 = strstr(p1,p2);
return (p3);
}

void open(void)
{
int i, j=0;
char numbers[3] = "", letter;
unsigned char number;

for(i = 0; i < strlen(values); i += 3){
numbers[0] = values[i];
numbers[1] = values[i+1];
numbers[2] = '\0';
letter     = values[i+2];
number     = atoi(numbers);
if(letter == 77) number *= 60;
seconds[j] = number;
times[j]   = epoch;
j++;
}
if(seconds[0]  > 0) output_bit(PIN_C0, 1);
if(seconds[1]  > 0) output_bit(PIN_C1, 1);
if(seconds[2]  > 0) output_bit(PIN_C2, 1);
if(seconds[3]  > 0) output_bit(PIN_C3, 1);
if(seconds[4]  > 0) output_bit(PIN_B7, 1);
if(seconds[5]  > 0) output_bit(PIN_B6, 1);
if(seconds[6]  > 0) output_bit(PIN_B5, 1);
if(seconds[7]  > 0) output_bit(PIN_B4, 1);
if(seconds[8]  > 0) output_bit(PIN_B3, 1);
if(seconds[9]  > 0) output_bit(PIN_B2, 1);
if(seconds[10] > 0) output_bit(PIN_B1, 1);
if(seconds[11] > 0) output_bit(PIN_B0, 1);
if(seconds[12] > 0) output_bit(PIN_C5, 1);
if(seconds[13] > 0) output_bit(PIN_C4, 1);
}

void close(void)
{
if(values[0]  > 0) output_bit(PIN_C0, 0);
if(values[1]  > 0) output_bit(PIN_C1, 0);
if(values[2]  > 0) output_bit(PIN_C2, 0);
if(values[3]  > 0) output_bit(PIN_C3, 0);
if(values[4]  > 0) output_bit(PIN_B7, 0);
if(values[5]  > 0) output_bit(PIN_B6, 0);
if(values[6]  > 0) output_bit(PIN_B5, 0);
if(values[7]  > 0) output_bit(PIN_B4, 0);
if(values[8]  > 0) output_bit(PIN_B3, 0);
if(values[9]  > 0) output_bit(PIN_B2, 0);
if(values[10] > 0) output_bit(PIN_B1, 0);
if(values[11] > 0) output_bit(PIN_B0, 0);
if(values[12] > 0) output_bit(PIN_C5, 0);
if(values[13] > 0) output_bit(PIN_C4, 0);
}

void read_pass(void)
{
int i, address = 12;
for(i = 0; i < 6; i++){
pass[i] = read_eeprom(address + i);
}
pass[i] = '\0';
}

void set_pass(void)
{
int i, address = 12;
for(i = 0; i < 6; i++){
write_eeprom(address + i, values[i]);
}
}

void read_pic(void)
{
int i, address = 22, x;
for(i = 0; i < 7; i++){
x = read_eeprom(address + i);
picsaved[i] = x;
}
picsaved[i] = '\0';
}

void set_pic(void)
{
int i, address = 22;
for(i = 0; i < 7; i++){
write_eeprom(address + i, values[i]);
picsaved[i] = values[i];
}
picsaved[i] = '\0';
}

void auto_off(void)
{
//epoch = secondsSinceYear1(yr, mn, day, hrs, min, sec);
if(seconds[0]  > 0 && (epoch - times[0])  > seconds[0])  output_bit(PIN_C0, 0);
if(seconds[1]  > 0 && (epoch - times[1])  > seconds[1])  output_bit(PIN_C1, 0);
if(seconds[2]  > 0 && (epoch - times[2])  > seconds[2])  output_bit(PIN_C2, 0);
if(seconds[3]  > 0 && (epoch - times[3])  > seconds[3])  output_bit(PIN_C3, 0);
if(seconds[4]  > 0 && (epoch - times[4])  > seconds[4])  output_bit(PIN_B7, 0);
if(seconds[5]  > 0 && (epoch - times[5])  > seconds[5])  output_bit(PIN_B6, 0);
if(seconds[6]  > 0 && (epoch - times[6])  > seconds[6])  output_bit(PIN_B5, 0);
if(seconds[7]  > 0 && (epoch - times[7])  > seconds[7])  output_bit(PIN_B4, 0);
if(seconds[8]  > 0 && (epoch - times[8])  > seconds[8])  output_bit(PIN_B3, 0);
if(seconds[9]  > 0 && (epoch - times[9])  > seconds[9])  output_bit(PIN_B2, 0);
if(seconds[10] > 0 && (epoch - times[10]) > seconds[10]) output_bit(PIN_B1, 0);
if(seconds[11] > 0 && (epoch - times[11]) > seconds[11]) output_bit(PIN_B0, 0);
if(seconds[12] > 0 && (epoch - times[12]) > seconds[12]) output_bit(PIN_C5, 0);
if(seconds[13] > 0 && (epoch - times[13]) > seconds[13]) output_bit(PIN_C4, 0);
}

void clean_values(char v)
{
int x = 0;
for(x = 0; x < 45; x++){
values[x] = v;
}
values[x] = '\0';
}

void clean_command(char v)
{
int x = 0;
for(x = 0; x < 48; x++){
command[x] = v;
}
command[x] = '\0';
}

/* Programa principal */
void main(void)
{
// Activo todos los pines B como salidas
set_tris_b(0b00000000);
// Activo PIN_C4 y PIN_C7 como entradas
set_tris_c(0b10010000);

// Todos los pines B y C apagados, excepto los que son entradas
output_B(0b00000000);
output_bit(PIN_C0, 0);
output_bit(PIN_C1, 0);
output_bit(PIN_C2, 0);
output_bit(PIN_C5, 0);

// Activo interrupciones
enable_interrupts(GLOBAL);
enable_interrupts(INT_RDA);

epoch = 0;
/*
read_pass();
clean_values(-1);
if(is_equal(values, pass)){
// Password por defecto
strcpy(values, "BUS554");
set_pass();
read_pass();
}

read_pic();

clean_values(-1);
if(is_equal(values, picsaved)){
// Pic Id por defecto
strcpy(values, "ITG0001");
set_pic();
read_pic();
}
*/

//clean_values(0);

strcpy(picsaved, "ITG0002");
strcpy(pass, "BUS554");

while(TRUE)
{
delay_ms(1000);
epoch++;

auto_off();

if(newcommand){
newcommand = 0;
//printf("%s command\r\n", command);

strcpy(term, "|");
strcpy(picid, strtok(command, term));
strcpy(action, strtok(0, term));
strcpy(values, strtok(0, term));

/*
strcpy(permited, "SETPASS");
if(is_equal(permited, action) && logged){
set_pass();
printf("%s\r\n", pass);
}
strcpy(permited, "READPASS");
if(is_equal(permited, action) && logged){
read_pass();
printf("%s\r\n", pass);
}
strcpy(permited, "READPIC");
if(is_equal(permited, action) && logged){
read_pic();
printf("%s read\r\n", picsaved);
}
strcpy(permited, "SETPIC");
if(is_equal(permited, action) && logged){
set_pic();
printf("%s setid\r\n", picsaved);
}
*/
//printf("%s picid %s picsaved\r\n", picid, picsaved);

if(is_equal(picid, picsaved)){
strcpy(permited, "LOGIN");
if(is_equal(permited, action)){
//read_pass();
if(is_equal(values, pass)){
logged = 1;
printf("logged %s\r\n", picsaved);
//printf("logged %s picid %s saved\r\n", picid, picsaved);
}
}
strcpy(permited, "OPEN");
if(is_equal(permited, action)){
open();
printf("%s opened\r\n", picid);
}
strcpy(permited, "CLOSE");
if(is_equal(permited, action)){
close();
printf("%s closed\r\n", picid);
}
strcpy(permited, "EXIT");
if(is_equal(permited, action)){
logged = 0;
printf("%s exited\r\n", picid);
}
}
//clean_command(0);
//clean_values(0);
//enable_interrupts(INT_RDA);
}else{
//printf("%s - %s\r\n", picsaved, pass);
}
}
}

La variable picsaved (id del pic) está fija en este código, pero la cambio, recompilo y grabo con distinto valor para cada pic. Hice esto por que en algún momento pensé que el problema estaba al leer de la eeprom el id del pic.

Desconectado thegame

  • PIC18
  • ****
  • Mensajes: 439
    • Mcu Tronics
Re: Manejo de buffer rs232 y control de errores en pic 16f876a
« Respuesta #1 en: 19 de Mayo de 2015, 13:08:13 »
Hola, porque no agregas el cheque del error FERR: Framing Error bit, para ver si no es por ahi tambien, se supone que la opcion ERRORS deberia solucionar pero es mejor asegurarse.

Tienes activo el bit BRGH??? porque si lo activas, con la frecuencia que tienes (20MHZ) y el baud rate que manejas, tendrias un error de 0.16%, comparado con el 1.73% de no hacerlo.

En la interrupcion porque no sacas el codigo a una funcion activada por una bandera, es decir, en ves de procesar instrucciones dentro de la rutina de interruptcion, solo cambias una bandera, y el estado de la bandera (1 o 0), activa la funcion que se encarga de realizar lo que desees, digo no es que estes tardando mucho en ella, e incluso las desactivas pero no estoy acostumbrado a poner mas de 4 lineas en las interrupciones, cuestion de gustos.

En la erradata de tu PIC no viene nada relacionado con el RS232, solo en la revision B2 tocan el tema de la eeprom, revisalo por si acaso.

saludos.
Nunca se deja de aprender

Desconectado claudiovega

  • PIC10
  • *
  • Mensajes: 31
Re: Manejo de buffer rs232 y control de errores en pic 16f876a
« Respuesta #2 en: 19 de Mayo de 2015, 13:35:17 »
Gracias thegame,
En una versión anterior de este código no tenía nada relacionado con el control de errores de rs232. El código de la interrupción sólo era esto:
Código: [Seleccionar]
        newcommand = 0;
if (kbhit(COM_A))
{
p = fgetc(COM_A);
if(p == '#') {
command[k] = '\0';
newcommand = 1;
k = 0;

}else{
command[k] = p;
k++;
}
}
No conozco nada acerca del control de errores de rs232, así que si puedes ayudarme con algo de código te estaría muy agradecido.
Respecto de la eeprom, probé antes el código que ahora está comentado y hacía su trabajo.

Desconectado thegame

  • PIC18
  • ****
  • Mensajes: 439
    • Mcu Tronics
Re: Manejo de buffer rs232 y control de errores en pic 16f876a
« Respuesta #3 en: 19 de Mayo de 2015, 15:02:33 »
Ok, tendrias que agregar lo siguiente:

Esto en las definiciones

Código: [Seleccionar]
#bit FERR=0x0018.2  //Declaracion del bit correspondiente a Framing Error
int aux; //Variable auxiliar para limpieza del error


Despues, en la seccion de la interrupcion o en una funcion aparte (como sugeri), colocas la siguiente condicional, puede ir despues de lo que colocaste de OERR:

Código: [Seleccionar]
if(FERR)
{
      aux=fgetc(COMA);  //Se lee el buffer de recepcion y se espera la siguiente recepcion
}

Del datasheet del PIC, cito:

Citar
FERR: Framing Error bit
1 = Framing error (can be updated by reading RCREG register and receive next valid byte)
0 = No framing error


Ahora, que me corrijan los compañeros si me equivoco, pero....porque poner kbhit() si se supone que estas recibiendo por interrupcion, para mi kbhit() se usa cuando NO USAS INTERRUPCIONES, o como se conoce, por "Poleo", pero en fin, de nuevo es cuestion de gustos.

Saludos.
Nunca se deja de aprender

Desconectado claudiovega

  • PIC10
  • *
  • Mensajes: 31
Re: Manejo de buffer rs232 y control de errores en pic 16f876a
« Respuesta #4 en: 19 de Mayo de 2015, 18:34:55 »
En las primeras pruebas que hice con CCS y este pic, sin kbhit() no funcionaba, usando la interrupción. El código sólo era leer un carácter y hacer un eco.
Tengo la impresión siguiente, como todos los pic reciben el mismo mensaje, pero sólo uno lo procesa (lo procesa solo aquel que se indica en el mensaje), la comunicación serial de los demás genera un error.
He puesto el código indicado, sin resultados.

Desconectado thegame

  • PIC18
  • ****
  • Mensajes: 439
    • Mcu Tronics
Re: Manejo de buffer rs232 y control de errores en pic 16f876a
« Respuesta #5 en: 19 de Mayo de 2015, 19:31:40 »
Es extraño, yo he echo lo siguiente cuando trabajo con interrupciones:

Código: [Seleccionar]
#INT_RDA
void recepcion(void)
{
valor=fgetc(usb); //Se recibe por medio de el RS232 emulado con el FT232RL
recep=1; //Bandera de recepcion
}

Sin kbhit(), y funciona sin problemas, pero creo que mas que la recepcion el problema es el tratamiento de la informacion.

No se dispara la bandera de FERR???

Porque no implementas un sistema de descarte para comandos no validos, la recepcion de basura si que puede bloquear la comunicacion, talves con una estructura SWITCH en lugar de IF-ELSE podrias organizar un poco he implementar una condicion de default de tal modo que leas el buffer de recepcion, y asi lo limpies evitando el posible FERR.

algo asi:

Código: [Seleccionar]
//-----------------------------------Funcion de recepcion USB---------------------------------------------
void recep_usb(void)
{
//Bandera de recepcion para el puerto USB
if(recep==1)
{
recep=0; //Limpiamos bandera de recepcion
buffer_instruccion[indice_buffer++]=valor; //Agregamos el dato en el buffer

switch(valor)
{
case 'r':
indice_buffer=0; //Reiniciamos el indice del buffer
borrar_buffer(); //Borramos el buffer de recepcion
reset_cpu(); //Reiniciamos el ucc
break;
case 'i':
indice_buffer=0; //Reiniciamos el indice del buffer
borrar_buffer(); //Borramos el buffer de recepcion
fprintf(usb,"\r\nFirmware y Hardware elaborado por Ing. Julio Cesar Cortes Aceves");
fprintf(usb,"\r\nCorreo Electronico: jccortesac@gmail.com");
break;
case 'v':
indice_buffer=0; //Reiniciamos el indice del buffer
borrar_buffer(); //Borramos el buffer de recepcion
fprintf(usb,"\r\nVesion de Firmware: v%s",vfw);
fprintf(usb,"\r\nMCU-Tronics");
fprintf(usb,"\r\nmcu.tronics@gmail.com\r\r");
break;
case 'o':
indice_buffer=0; //Reiniciamos el indice del buffer
borrar_buffer(); //Borramos el buffer de recepcion
open_disparo(); //Llamamos a la funcion de activacion de disparo para barrera y camara
break;
case 'c':
indice_buffer=0; //Reiniciamos el indice del buffer
borrar_buffer(); //Borramos el buffer de recepcion
disparo_camara(); //Llamamos a la funcion de activacion de disparo para barrera y camara
break;
default:
indice_buffer=0; //Reiniciamos el indice del buffer
borrar_buffer(); //Borramos el buffer de recepcion
fprintf(usb,"\r\nComando no reconocido");
}
}
}

ese es un pequeño set de instrucciones que recibo por puerto serie, pero como ves me aseguro que en caso de recibir un parametro invalido, dejo limpios los buffers de recepcion y listos para un nuevo comando, porque al recibir basura o invalidos causa problemas. Se que por ello puedes tener el IF-ELSE, pero no cuesta nada probar.
Nunca se deja de aprender

Desconectado claudiovega

  • PIC10
  • *
  • Mensajes: 31
Re: Manejo de buffer rs232 y control de errores en pic 16f876a
« Respuesta #6 en: 20 de Mayo de 2015, 10:41:55 »
Ok, seguiré tus consejos.
Pregunta: que código pones en la función borrar_buffer()?
Los comando que uso son bastante largos, y tienen esta forma:

ID PIC    |Accion| Abre salidas 1 a la 14, por XX segundos
ITG0004|OPEN|00S00S00S00S01S00S01S00S00S00S00S00S00S00S#

Todos los pics reciben el mismo comando, extraigo el ID de la cadena, lo comparo con el guardado en el pic y si coincide ejecuto el resto. El símbolo # es para saber que le comando termina.

Hay comandos más cortos como el login

ID PIC    |Accion|clave por defecto
ITG0004|LOGIN|BUS554#
« Última modificación: 20 de Mayo de 2015, 10:51:20 por claudiovega »

Desconectado thegame

  • PIC18
  • ****
  • Mensajes: 439
    • Mcu Tronics
Re: Manejo de buffer rs232 y control de errores en pic 16f876a
« Respuesta #7 en: 20 de Mayo de 2015, 12:36:20 »
hola, borrar_buffer() no es mas que un ciclo for, que recorre las posiciones de mi arreglo dejandolas nulas o con '0', esto depende de que tan largo o grande sea tu buffer, porque como me comentas que hay comandos de distintas longitudes pues me suena a que se te esta quedando con basura que se combina con la nueva recepcion y probablemente ahi es donde ya no saben que hacer los PICs o extraen mal la info.

Te recomiendo que dejes limpio el buffer despues de utilizarlo para que no quede nada remanente, ojala te ayude.

saludos
Nunca se deja de aprender

Desconectado claudiovega

  • PIC10
  • *
  • Mensajes: 31
Re: Manejo de buffer rs232 y control de errores en pic 16f876a
« Respuesta #8 en: 20 de Mayo de 2015, 13:03:48 »
Ok, es lo que hago con la función clean_command(), que tengo comentada en el código. Voy a llamarla siempre (fuera del if), para ver si produce algún cambio.
« Última modificación: 20 de Mayo de 2015, 13:08:54 por claudiovega »


 

anything