Recepción GPS con PIC16F
Dejando un poco de lado la teoría que hay detrás del sistema GPS, cuya informacion es bastante amplia en sitios de internet como Wikipedia, <Sistema GPS>, paginas del gobierno Americano <Sistema GPS> o fabricantes de receptores <Sistema GPS>, vamos a centrarnos únicamente en el segmento del usuario, donde revisaremos dos modelos de receptores GPS que tengo a mi alcance.
Receptor: NEO-6M
Sensibilidad -156dBm
Inicio Frío 26s, Caliente 1s
Precisión 2.5mts
Altura Max. 50000mts
Velocidad Max. 500m/s
Operación 2.7 – 3.6V 50mA
Frecuencia L1 C/A
SBAS: WAAS, EGNOS, MSAS
Sensibilidad -159dBm
Inicio Frío 35s, Caliente 1s
Precisión 10mts 2D
Altura Max.18000mts
Velocidad Max. 514m/s
Operación 5V 55mA
Dejo los siguientes enlaces con informacion adicional de estos dos receptores:
<Receptor GPS NEO> <Receptor GPS RGM>
- Inicio Frio (Cold start): El receptor cuenta con un almanaque válido, pero necesita actualizar las efemérides y la referencia del tiempo, el proceso puede demorar unos 45 segundos.
- Inicio Caliente (Hot Start): El receptor cuenta con el almanaque y efemérides válidas, además ya posee una referencia del tiempo. Esta situación suele darse en ciudades cuando se pierde cobertura, y proceso suele demorar entre 3 y 5 segundos.
Ahora resumiremos algunas diferencias de los dos receptores, el primero que posee un Chipset U-blox cuenta con hasta 50 canales para capturar satélites a diferencial del Chipset SIRF-III que posee 20, con relación al tiempo de inicio en frío, la precisión y altura maxima de operación los números favorecen al Chipset U-blox. Pero una característica que me resulta muy practica para implementar en el ejemplo, es con el modelo RGM-3600, que opera con voltaje de 5V y además el receptor esta encapsulado con la antena para un uso externo, cuenta una base de imán para sujetarlo en cualquier superficie metálica.
Entonces por el momento los aspectos técnico que debemos tomar en cuenta son el voltaje de alimentación que requiere el receptor, la velocidad de comunicación que utiliza por defecto y los niveles lógicos en las lineas TX - RX, en algunos casos se necesitara convertir estos niveles entre 3.3V y 5.0V.
Sin
importar cual de los modelos se utilizará, el programa del PIC podrá
recibir la informacion de ambos, ya que los mensajes que emiten estos
receptores cumplen con un formato estándar denominado NMEA 0183.
Información del GPS
Un receptor GPS, transmite diferentes mensajes NMEA 0183, algunas de estos son:
- RMC - Recommend Minimum Specific GPS/TRAN Data
- GGA - Global Positioning System Fix Data
- GSA - GPS DOP and Active Satellites
- GSV - GPS Satellites in View
- El tiempo utiliza el formato UTC, y por lo tanto debes tomarlo muy en cuenta en tu aplicación, para hacer la debida corrección con referencia a tu zona.
- El campo de navegación es muy importante, ya que el valor los datos de posicionamiento son validos únicamente si este campo tiene la letra 'A'
- Posterior al asterisco '*' el receptor envía un numero en formato hexadecimal que es la suma exclusiva correlativa de todos los bytes que tiene el mensaje, esto permite realizar una verificación básica del mensaje enviado y el recibido, una diferencia representaría un error de comunicación.
Cuando el receptor GPS y el PIC trabajan con diferentes voltajes de alimentación, por ejemplo 3.3V del GPS y 5.0V del PIC, podría necesitar adaptar los niveles de voltaje en las lineas TXD y RXD, es importante que revise las especificaciones eléctricas VIH/VOL y VOH/VIL de ambos dispositivos. En algún caso tuve que usar un transistor para incrementar el nivel de tensión en la salida del GPS.
El diodo LED conectado al pin RA4 se utilizara para indicar el funcionamiento normal del programa mediante un destello cada segundo.
Muy bien, en este punto toca describir el programa que recibirá la informacion del GPS para lo cual vamos abordar dos enfoques diferentes, considerando las limitaciones que existe en el PIC16F687(ROM 2K y 128 bytes de RAM), para ambos casos la frecuencia del oscilador es Fosc=8MHz. La selección de este PIC es precisamente con el fin de mostrar que un enfoque adecuado en la programación permite optimizar el uso de los recursos.
Una vez energizado y con las conexiones debidamente establecidas, utilice un pequeño programa que replica cada byte recibido por el receptor RXD al transmisor TXD del PIC16F687, y con una terminal serial en mi CUTECOM, ver figura 4, se logra recibir los siguientes mensajes repetidos cada segundo.
Fig4. Recepción GPS en terminal CUTECOM |
Como verán de acuerdo a la figura 4, se recibe bastante informacion del GPS cada segundo, pero no todo es necesariamente útil en una aplicación por esa razón es que trabajaremos con el mensaje RMC y es aquí donde quiero considerar las dos opciones para conseguir los datos que necesitamos:
Fig5. Recepción del mensaje RMC en CUTECOM |
El programa que se describe en la siguiente sección utiliza este método debido a que se requiere menos uso de la memoria RAM.
Fig6. Mensaje final procesado CUTECOM |
La programación del microcontrolador, no es algo simple de explicar con palabras y que a la vez sea entendible, me disculpo si me he saltado con la descripción de algunas lineas en el código, prometo lo mas antes posible elaborar un flujo-grama y actualizar esta publicación para comprender mejor como funciona este programa.
#include <xc.h>
#include <stdio.h>
#include <stdlib.h>
#define LED1pin PORTAbits.RA4 //Led para destello
volatile __bit tick1ms, rmcok; //Banderas
typedef struct //Estructura de datos GPS
{
uint32_t lat, lon;
uint8_t year, month, day;
uint8_t hour, minute, second;
uint8_t valid;
} rmcstruct_t;
rmcstruct_t rmc;
char buffer[12]; //Memoria de datos RAM 12 bytes
void setup(void); //Procedimiento de inicializacion
void taskLED(void);//Tarea para destello LED
void taskGPS(uint8_t data);//Tarea del Programa Receptor
void __interrupt() isr(void)
{
uint8_t res;
if(INTCONbits.T0IF) //Evento cada 1.0ms
{
INTCONbits.T0IF = 0; //Limpia bandera
TMR0 += 131; //Reinicia contador
tick1ms = 1;
}
while(PIR1bits.RCIF) //Evento con recepcion RXD
{
res = RCREG; //Recibe el dato UART
taskGPS(res);//Llama al programa receptor
}
}
void main()
{
setup();//Inicializa el PIC
while(1)
{
if(tick1ms) //Valida cada 1ms
{
tick1ms = 0; //Limpia bandera
taskLED(); //Destello LED
if(rmcok) //Si hay dato GPS decodificado
{
rmcok = 0;
if(rmc.valid) //Verifica si es valido
{
printf("Fecha:%u/%02u/%02u ",rmc.year, rmc.month, rmc.day);
printf("Hora:%02u:%02u:%02u\n",rmc.hour, rmc.minute, rmc.second);
}
RCSTAbits.CREN = 1; //Activa interrupcion del receptor
}
}
}
}
void setup(void)
{
OSCCONbits.IRCF = 0b111; //Ajusta Fosc=8MHz, Tcy=0.5u
while(OSCCONbits.HTS == 0) {}
/* CONFIGURACION PUERTOS*/
ANSEL = 0;
ANSELH = 0;
TRISAbits.TRISA4 = 0; //Salida LED
OPTION_REGbits.nRABPU = 0; //Pull-up
/* CONFIGURACION TIMER0 0.1MS */
OPTION_REGbits.T0CS = 0;//Modo Termporizador
OPTION_REGbits.PSA = 0; //Con prescala
OPTION_REGbits.PS = 0b011; //Prescala 1:16
TMR0 = 131; //256-[(time*Fosc)/(pre*4)] time=0.001 seg
INTCONbits.T0IF = 0; //Limpia bandera
INTCONbits.T0IE = 1; //Activa interrupcion del TMR0
/* CONFIGURA USART A 4800N1 8MHz*/
TXSTAbits.BRGH = 1; //Alta del Generador
TXSTAbits.TXEN = 1; //Activa el transmisor
RCSTAbits.CREN = 1; //Activa el receptor
RCSTAbits.SPEN = 1; //Habilita el modulo USART
SPBRG = 103; //Formula [8MHz/(16 * 4800)] - 1
PIE1bits.RCIE = 1; //Activa interrupcion del receptor
INTCONbits.PEIE = 1; //Activa interrupcion de perifericos
INTCONbits.GIE = 1; //Habilita interrupciones
}
void taskGPS(uint8_t data)//Tarea del Programa receptor GPS
{ //<$GPRMC,215536.000,A,1744.7111,S,06308.9987,W,0.00,0.00,300724,,,A*5B>
static uint8_t state = 0, pos;
switch(state)
{
case 0: //$GPRM
if(data == 'M')
state++;
break;
case 1: //C
if(data == 'C')
state++;
break;
case 2://,
if(data == ',') //Inicio RMC
{
pos = 0;
state++;
}
break;
case 3: //215536.
if(data == '.') //Campo TIME
{
buffer[pos] = 0; //null end
rmc.second = (uint8_t) atoi(&buffer[4]);
buffer[4] = 0; //null end
rmc.minute = (uint8_t) atoi(&buffer[2]);
buffer[2] = 0; //null end
rmc.hour = (uint8_t) atoi(buffer);
state++;
} else buffer[pos] = data;
if(pos++ > 6) state = 0; //Reinicia maquina por error
break;
case 4: //000,
if(data == ',') //Campo, no utilizado
state++;
break;
case 5: //A
if(data == 'A') rmc.valid = 1; //Campo VALID
else rmc.valid = 0;
state++;
break;
case 6: //,
if(data == ',') //Campo no utilizado
state++;
break;
case 7: //1744.7111,
if(data == ',') //Campo LAT, no se utiliza
state++;
break;
case 8: //S,
if(data == ',') //Campo no utilizado
state++;
break;
case 9: //06308.9987,
if(data == ',') //Campo LON, no se utiliza
state++;
break;
case 10: //W,
if(data == ',') //Campo no utilizado
state++;
break;
case 11: //0.00,
if(data == ',') //Campo no utilizado
state++;
break;
case 12: //0.00,
if(data == ',') //Campo no utilizado
{
state++;
pos = 0;
}
break;
case 13: //300724,
if(data == ',') //Campo DATE
{
buffer[pos] = 0; //null end
rmc.year = (uint8_t) atoi(&buffer[4]);
buffer[4] = 0; //null end
rmc.month = (uint8_t) atoi(&buffer[2]);
buffer[2] = 0; //null end
rmc.day = (uint8_t) atoi(buffer);
RCSTAbits.CREN = 0; //Desactiva el receptor
rmcok = 1; //Activa bandera
state = 0; //Reinicia maquina
} else buffer[pos] = data;
if(pos++ > 6) state = 0; //Reiniciar maquina por error
}
}
void taskLED(void) //Tarea para destello led
{
static uint16_t tcnt = 0;
if(tcnt++ > 999)
{
tcnt = 0;
LED1pin = 1;
}
if(tcnt == 200) LED1pin = 0;
}
void putch(char byte)
{
while(PIR1bits.TXIF == 0) {};
TXREG = byte;
}
Funcionamiento del Circuito
El programa descrito anteriormente se ensayo en el microcontrolador con una implementación simple del receptor RGM-3600 y una tarjeta de prueba basada en el PIC16F687, la imagen de la figura 7, muestra el montaje final.
Fig7. Implementacion del circuito PIC |
Se ha demostrado el funcionamiento adecuado del circuito para recibir y decodificar datos de un GPS, sin duda las posibles aplicaciones que hay para este ejemplo son diversas, por lo que únicamente dejo a consideración algunos aspectos si estas en planes de utilizarlo en tu proyecto electrónico.
- Te en claro siempre, que la informacion de tiempo de un GPS estará en formato UTC,
- Considera que para hacer pruebas con este circuito, deberás ubicarte en una zona despejado con vista al exterior, ya que dentro de un edificio el receptor no captara señal de los satélites.
- Si bien en muchas aplicaciones el mensaje RMC tiene la informacion suficiente para la navegación y referencia temporal, hay otro tipo de mensaje que proveen informacion de la recepción y estado de los satélites, que podrían necesitar para ciertas aplicaciones.
- Aunque por defecto la comunicación de un receptor GPS se establece en 4800 8N1, debe revisar las especificaciones del modelo, ya que en algunos casos esto puede variar.
Atentamente, Pablo Zárate Arancibia email: pablinza@me.com / pablinzte@gmail.com, @pablinzar