Perdida de datos con la UART del PIC16F876

Hola, tengo un problema con mi proyecto final de de carrera, haber si alguien me puede ayudar a solucionarlo o sugerir algo. Gracias de antemano.

El microcontrolador ha de leer información proveniente de un receptor gps, la ha de procesar e introducir en una trama que posteriormente será enviada al ordenador cada minuto.

Llegué a la conclusión de que el el pic no me lee todos los datos que le envía el gps, se debe saltar alguno y los datos que obtengo en mi aplicación no son los correctos, y no sé a que se debe.

El pic está perfectamente conectado al puerto serie del ordenador y comprobado.

El gps envía información continuamente a 9600 bps, en el protocolo TSIP, que funciona asi:
<DLE> <identificador del paquete> <data string bytes> <DLE> <ETX>, y cuando en el interior de la cedena de cartacteres hay un DLE, se envia otro adicional.

Al final adjunto el codigo fuente en C, a ver si alguien ve algún otro fallo,está hecho para el compilador CCS.

Para ir detectado a que se debía el problema hice varios programas, y llegué a la conclusión de que estaba en la UART, el programa con el que lo probé fué el siguiente, es un programa espejo:

=====================================================
CODIGO DE PRUEBA DE LA UART

#include <16F876.h>
#use delay(clock=4000000)
#fuses XT,NOWDT

set_tris_c(0x80); //Configuro el pin C7 como entrada

#use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7, enable=PIN_B7) //Configura puerto serie
#int_rda
void rda_isr() {
putc(getc()); //Transmite el dato leido cada vez que se produce una interrupción
}

void main(){
enable_interrupts(global);
enable_interrupts(int_rda); //Habilito interrupciones generales y por recepción de datos
while(1){}
}
=====================================================

Si el gps lo conecto al ordenador sin mediar por el pic me lee los datos correctamente, pero la hacerlo a través del PIC nada.

A vista de lo que hay, parece que el pic no es lo suficientemente rápido como para pocesar todos los datos que recibe. No se si sería una posible solución cambiar el cristal de cuarzo del pic de 4Mhz por uno de 20 Mhz (por que creo que con el de 4 le hes suficiente) o cambiar el pic por uno más rápido.

A ver si alguien me puede ayudar. Gracias.

=====================================================
CÓDIGO FUENTE DEL PIC

#include <16F876.h>
#use delay(clock=4000000)
#fuses XT,NOWDT

#define ETX 0x03
#define DLE 0x10

typedef struct{
int8 id;
float latitud;
float longitud;
float altura;
float clock_bias;
float time_of_fix;
}GPS_POSITION;

typedef struct{
int8 frm_num;
int8 no_gps;
float latitud;
float longitud;
float altura;
int8 satelites;
int8 checksum;
}TRAMA;

TRAMA variable;
GPS_POSITION posicion;
int8 I;

set_tris_a(0x00);
set_tris_b(0x00);
set_tris_c(0x80); //Configuro el pin C7 como entrada y los demás salida

int1 escape=FALSE;
int8 matrix[60];

#use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7, enable=PIN_B6) //Configuro puerto serie
#int_rda
void serial_isr() { // Rutina que atiende a la interrupción de la UART
int8 i;
int8 tmpbyte;
tmpbyte=getc(); // Recojo el caracter recibido

if(escape){

switch(tmpbyte){

case (DLE): matrix[i++]=tmpbyte;
break;

case (ETX): switch(matrix[0]){ // En funcion del id del paquete lo copio en un
en un destino

case (0x4A): memcpy(&posicion,matrix,sizeof(GPS_POSITION));
break;

default:break;
}
break;

default: i=0; // El dato que se recibe aquí es un id de paquete
matrix[i++]=tmpbyte;
break;
}

escape=FALSE;

}

else
switch(tmpbyte) {

case DLE:
escape=TRUE;
break;
default:
matrix[i++]=tmpbyte;
break;
}


}


#use rs232(baud=1200, parity=N, xmit=PIN_C6, rcv=PIN_C7, enable=PIN_B7)
void txmt_frame(BYTE *ptr, BYTE len) // Trasmite los datos para transmisor de radio
{

while(len--) // Este protocolo funciona perfectamente
{
switch(*ptr)
{
case (0xC0): putc(0B);
putc(0C);
ptr++;
break;
case (0B): putc(0B);
putc(0D);
ptr++;
break;
default: putc(*ptr);
ptr++;
break;
}
}
putc(0xC0);
}



void main(){

enable_interrupts(global); // Habilito interrupciones general y por recepcion UART
enable_interrupts(int_rda);

variable.frm_num=0;
variable.checksum=0;
variable.latitud=0; //Inicializo variables
variable.longitud=0;
variable.altura=0;

while(1)
{

if(posicion.id==0x4A) // Si el campo tiene ese valor copio en la trama que va a enviarse
{ via radio
variable.latitud=posicion.latitud;
variable.longitud=posicion.longitud;
variable.altura=posicion.altura;
}

else{}

for(I=0;I<sizeof(TRAMA);I++) // Genero un checksum
variable.checksum+=(*((&variable)+I));

txmt_frame(&variable,sizeof(TRAMA)); // Transmito la trama
variable.frm_num++; // Numero de trama
delay_ms(60000); // Espero 1 minuto antes de enviar otra trama
}

}

=============================================
 
Caesar. antes de ponerme a leer tu software, te consulto lo siguiente.

Tienes posibilidad de direccionar lo que sale del GPS a la PC a través del PIC?

Por ejemplo, el GPS manda los datos siempre automáticamente o requiere que el PIC le indique algo?

Si no hace falta que el PIC mande nada y el GPS manda la trama todo el tiempo, entonces podrías conectar el PIN TX a la PC a través de un MAX232, y que haga un 'eco' de todo lo que recibe. De esa forma sabrás qué recibe y que no recibe tu pic.

Por último revisa la configuración del TRISC. En los 16F el TRISC<6> debe estar en 1 para ser pin de usart. (Relee el datasheet). Tú lo has puesto en 0


Saludos
 
Hola maunix, te explico.

El GPS siempre está mandando información, algunos paquetes son de tiempo, otros de posición, velocidad, información de los satélites.... No requiere que el pic envíe comando alguno al gps.

Yo creé una aplicación en labview que me interpretase todo esto, conecto el GPS al PC a través del max232 y la aplicación funciona perfectamente.

Ahora bien, si conecto el GPS al PIC y éste al PC, de forma que lo que reciba el pic del gps lo envíe tal cual al PC (en el protocolo TSIP), recibo datos de posición y todo. Pero eses datos no son correctos, pues da latitudes de 150ºN y valores completamente incoherentes. Y esto se debe a que el PIC no envía todos los datos, se debe saltar algún dato, y al ocurrir esto, el programa del LABVIEW compone los bytes, y como se saltó alguno el PIC da valores incorrectos.

Te explico más acerca del proyecto. El receptor de GPS va a ir colocado en elemento que se desea localizar (vehículo, animal...). Este receptor cada cierto tiempo envía una trama al ordenador donde estoy yo. Todo esto va por un enlace de radiofrecuencia a 433 Mhz.
Entonces el PIC es el encargado de recoger la información del GPS y analizarla, y en función del tipo de información que recibió, meterla en una parte de la trama, que posteriormente se va a enviar.

He mirado el datasheet del pic16f876, yo creo que la configuración del puerto c está correcta, por que para que un bit de un puerto sea salida le hay que poner un 0, y para que sea entrada un 1:


Bit 7 6 5 4 3 2 1 0
Valor 1 0 0 0 0 0 0 0

1000000b=0x80


El pin C7 es el el RX de la UART y el C6 es el de TX, y creo que la configuración que le hay que poner es C6 como 0 y C7 como 1. Y transmitir el PIC transmite.

Yo creé un programa en C que enviase con la función txmt_frame el paquete de información de posición, pero en lugar de que el PIC leyese la información del GPS, la introduje yo en un array. Y me funcionó. Pero he ahí la cuestión, el PIC no lee bien, y no se por qué.

Muchas gracias. Saludos desde España.
 
Caesar^V^ dijo:
Hola maunix, te explico.
He mirado el datasheet del pic16f876, yo creo que la configuración del puerto c está correcta, por que para que un bit de un puerto sea salida le hay que poner un 0, y para que sea entrada un 1:


Bit 7 6 5 4 3 2 1 0
Valor 1 0 0 0 0 0 0 0

1000000b=0x80


El pin C7 es el el RX de la UART y el C6 es el de TX, y creo que la configuración que le hay que poner es C6 como 0 y C7 como 1. Y transmitir el PIC transmite.

Yo haría simplemente un software de ECO para que reciba algo y lo retransmita sin modificar nada.

En cuanto a la configuración de usart, es un error común el que estás cometiendo en los 16F.

Una cosa es setear el puerto para usos 'digitales' de propósito general y otra diferente es usarlo para la USART.

Te subo la parte del datasheet donde te comenta lo que te digo:

Datasheet. ds30292c. Page 95.

Bit SPEN (RCSTA<7>) and bits TRISC<7:6> have to
be set in order to configure pins RC6/TX/CK and
RC7/RX/DT as the Universal Synchronous Asynchronous
Receiver Transmitter.




Saludos
 
Hola maunix, ya he correigo ese error de la configuración de la UART tal y como tu me has dicho.

Y con el mismo programa de prueba que publiqué al principio del tema (que el pic envía lo que recibe tal cual, sin modificar nada), lo probé, y sigo teniendo el mismo problema.

El PIC se salta datos, si por ejemplo el GPS envía 5 datos el pic retransmite 3, y eso a la hora de componer los datos en la aplicación es desastroso.

Ya desesperado probé a cambiar el cristal de cuarzo de 4 Mhz por uno de 20 Mhz, pero nada, el problema sigue persistiendo.

Y ya no se que hacer, por que si el PIC pierde datos simplemente enviando lo que recibe, sin analizar nada, no me quiero ni imaginar lo que hará cuando tenga que analizar el dato que recibió e introducirlo en un array.

Si se te ocurre algo que me pueda solucionar esto te lo agradecería.

Muchas gracias. Saludos.
 
Te propongo lo siguiente que subas tu código pero como un archivo .zip

Cuando me haga un tiempo para verlo, te comento mi opinión al respecto


Saludos
 
el receptor gps tiene una modalidad de envio de tramas automático o manual, es decir q el tiene un pin habilitado para enviar tramas cada vez q uno se lo pida unicamente cuando se envia un uno logico al pin del receptor, deberias habilitar ese modo manual de envio, por lo que alcance a ñeer el protoclo de comunicacion es tsip, por lo q supongo q usas un receptor marca trimble, lo mas aprobable es q posea el pin q te menciono,
 
Una cosita que me hace un poco de "ruido": estaba viendo proyecto.c la rutina serial_isr y dentro de:
switch (tmpbyte)->if(escape) (rama de sí) en la sección default aparece:

Código:
default:    i=0;
                                 matrix[i++]=tmpbyte;
                                 break;

me parece raro encontrar i=0 en ésta parte. A ver si es como pienso, se debería entrar en esta parte del programa cada vez que se recibe un dato que no indica inicio/fin de trama no?.

Supongo que i es un contador para los bytes que recibís en la trama, y que lo usas para guardar los datos en el array/vector/matriz "matrix".
De ser así estás inicializando siempre el contador a 0 cada vez que recibís un dato que no es encabezado, puede ser eso?.

Si es así yo metería el i=0 en el else del switch(tmpbyte) case DLE que es cuando se inicia la trama no?.

Código:
void serial_isr() {
int8 i;
int8 tmpbyte;


tmpbyte=getc();

      if(escape){

            switch(tmpbyte){

                     case (DLE): matrix[i++]=tmpbyte;
                                 break;

                     case (ETX):   switch(matrix[0]){


                                       case (0x4A): memcpy(&posicion,matrix,sizeof(GPS_POSITION));
                                                    break;

                                       default:break;

                                       }

                                 break;

                     default:    [b]i=0;[/b] //[i]esto es lo que no me cierra[/i]
                                 matrix[i++]=tmpbyte;
                                 break;
                     }

            escape=FALSE;

                 }

      else
            switch(tmpbyte) {

                     case DLE:
                              [b]i=0;[/b] //[i]no debería ir acá?[/i]
                              escape=TRUE;
                              break;
                     default: //[i]esta sección tampoco me queda claro para que está[/i]
                              matrix[i++]=tmpbyte;
                              break;
                             }


}

Bueno, especulé demás, porque hay cosas que no me quedan claras con respecto a la trama: 1) se supone que el pic tiene que tomar los datos que empiecen con un caracter DLE no?,
2) cuando eso pasa se pone el bit escape=1 no?
3) Los datos que interesan son los que ingresa cuando escape = 1?. Porque como marqué arriba, no entiendo por qué en la sección default del switch del else se guardan datos.

Saludos
 
Ya es viejo este post, pero presiento que probablemente se estén perdiendo datos en la parte de la interrupción donde intentas hacer echo cuando recibes el caracter, a lo mejor ese envio le toma tiempo al PIC y pierde datos.
 
Hola, yo tengo el mismo problema que tú, quiero comunicar un pic16f690 con un gps mediante la uart, pero me llegan tramas incompletas, como si no leyese todos los caracteres. Creo que los problemas vienen más por el hardware que por el software, el gps se alimenta a 3.3V y el pic a 5V. Actualmente estoy colocando una resitencia de 330ohm entre ambos dispositivos, como se indica en las especificaciones del gps, no sé si habrá que poner algo más complicado como un divisor de tensión, usar algún zener intermedio, o un convertidor de tensiones.

En fin, ¿solucionaste el problema?
 
Atrás
Arriba