GPS MTK339: Recomendaciones

Saludos. Recientemente he adquirido un modulo GPS MTK339 diseñado por Adafruit.
He investigado y entiendo la teoria de la trama NMEA, la forma en la que ubican su posicion los modulos GPS.
Actualmente me encuentro en el diseño del software, pero me ha detenido los detalles fisicos.
He visto en la pagina oficial, y toda la informacion es enfocada a Arduino, pero mis planes involucran un PIC18F4550 programado en CCS en comunicacion USART.
Quisiera saber si alguien ha trabajado con este modulo y pudiera proporcionar algun consejo antes de implementarlo fisicamente.
De inicio no entiendo el punto de Voltaje Backup a 3 V y si existe una diferencia con el pin Vin a 5 V ¿Cual se puede usar? ¿Al mismo tiempo o son diferentes?

De antemano se los agradezco
 
He visto en la pagina oficial, y toda la informacion es enfocada a Arduino

La mayoría de las páginas donde se ofrece hardware para desarrollo están invirtiendo horas de esfuerzo para hacerlo compatible con Arduino, debido a que la plataforma es libre y muy sencilla de usar.

De inicio no entiendo el punto de Voltaje Backup a 3 V y si existe una diferencia con el pin Vin a 5 V ¿Cual se puede usar? ¿Al mismo tiempo o son diferentes?

El módulo al parecer se alimenta con 3.3v, pero tiene la batería de respaldo que puede utilizarse para 2 cosas principalmente:

- Mantener el módulo en modo "tibio" (donde permanentemente busca un link con el satélite y disponer de los datos siempre, es decir, no hay que esperar que adquiera señal).

- Mantener el la hora y fecha del RTC interno, pero sería algo redundante ya que el mismo GPS adquiere los datos de fecha y hora del satélite.

El GPS que has adquirido es muy completo, solo sirve para exteriores...es decir no podés conectarle una antena para usarlo en interiores. Le podés configurar varios parámetros, entre los más importantes:

a) - Velocidad de comunicación: Mejor dejar en default a 9.6 Kbps.
b) - Trama NMEA requerida: Lo mejor, ya que podés eliminar las tramas que no necesitas y hacer más
sencillo el programa para el PIC.
c) - El rate del GPS...que en tu caso es de 1 a 10Hz....algo expectacular....teniendo en cuenta que la
mayoría de los GPS comerciales para desarrollo e incluso los domésticos..tienen un rate de entre 1 y
5Hz.

Yo he trabajado con PIC y GPS para un proyecto de la facultad, donde la decodificación básica la hacía de la siguiente manera:

Código:
// Programador: Moyano Jonathan.
// Fecha: 2012.
// Versión del compilador: v4.114
// Versión del programa: v0.1
// Revisión del programa: 0.00

// Definimos el microcontrolador utilizado.
#include <18F4520.h> // Definición de registros internos del PIC18F4520.
// Conversor de 10 bits con justificación a la derecha.
#device ADC=10
// Declaración para trabajar con punteros a constantes.
#device PASS_STRINGS=IN_RAM
// Configuramos velocidad de operación.
#use delay(clock=20000000) // Trabajamos a 20.00Mhz. 

// Configuramos fusibles de programación.

#FUSES NOWDT                    // No utilizamos el perro guardían.
#FUSES HS                       // Oscilador de alta velocidad 20Mhz.
#FUSES FCMEN                    // Monitor de reloj activado.
#FUSES PUT                      // Temporizador de encendido.
#FUSES NOBROWNOUT               // No activamos el reset por bajo voltaje.
#FUSES NOPBADEN                 // Deshabilitamos el módulo conversor ADC del puerto B.
#FUSES NOLPT1OSC                // Timer 1 configurado para una alta potencia de operación.
#FUSES NOMCLR                   // Pin Master Clear deshabilitado.
#FUSES STVREN                   // Si se rebalsa o llena el stack el microcontrolador se resetea.
#FUSES NOLVP                    // No utilizamos bajo voltaje para programación.
#FUSES NOXINST                  // Set de instruccciones ampliado, desactivado.
#FUSES NODEBUG                  // No utilizamos código para debug.
#FUSES NOPROTECT                // Código no protejido contra lecturas.
#FUSES NOCPB                    // Sector de booteo no protejido.
#FUSES NOCPD                    // Sin protección de código en la EEPROM.
#FUSES NOWRT                    // Memoria de programa no protejida contra escrituras.
#FUSES NOWRTC                   // Registros de configuración no protegido contra escritura.
#FUSES NOWRTB                   // Bloque de booteo no protejido contra escritura.
#FUSES NOWRTD                   // Memoria EEPROM no protejida contra escritura.
#FUSES NOEBTR                   // Memoria no protejida contra lectuas de tablas de memoria.
#FUSES NOEBTRB                  // Bloque de booteo no protejido contra lectura de tablas de memoria.

// Configuramos los puertos RS232 utilizados.
// #use rs232(baud=9600, xmit=PIN_C6,rcv=PIN_C7,errors,stream=SIM900)  // RS232 - SIM900.

#use rs232(baud=9600, rcv=PIN_B0, errors,stream=GPS)                   // RS232 - GM20.

#use rs232(baud=9600, xmit=PIN_B7,rcv=PIN_B6,errors,stream=DEBUG)      // RS232 - DEBUG.

// Configuramos los puertos I2C utilizados.
#use i2c(Master, SDA=PIN_D3, SCL=PIN_D2)    // Memoria EEPROM, RTC, sensor de presión, acelerómetro, controlador PID.

/* Definimos el hardware utilizado:

---------
Puerto A:
---------
RA0 <---- TEMP/HMD <-- Temperatura y humedad relativa.
RA1 <---- AN1      <-- Entrada analógica 1: Sensor de tensión de red.
RA2 <---- AN2      <-- Entrada analógica 2: Sensor de carga de batería.
RA3 <---- CLK      --> Pin CLK  @ LCD Serial.
RA4 <---- ENA      --> Pin ENA  @ LCD Serial.
RA5 <---- DATA     --> Pin DATA @ LCD Serial.

---------
Puerto E:
---------

RE0 <---- RELAY1   --> Relé auxiliar 1.
RE1 <---- RELAY2   --> Relé auxiliar 2.
RE2 <---- RELAY3   --> Relé auxiliar 3.

---------
Puerto B:
---------
RB0 <---- MENÚ_ENTER       <-- Botón enter para acceder al menú de configuración.
RB1 <---- EVENTO_EXT_1     <-- Evento externo INT1.
RB2 <---- EVENTO_EXT_2     <-- Evento externo INT2.
RB3 <---- /RESET           --> Reset ENC28J60.
RB4 <---- /CS              --> Chip - select ENC28J60.
RB5 <---- /CS              --> Chip - select SD.
RB6 <---> Pin dedicado a la programación / PGC -> PIN5_pickit2 -> TX
RB7 <---> Pin dedicado a la programación / PGD -> PIN4_pickit2 <- RX

---------
Puerto C:
---------

RC0 <---- EVENTO_EXT_3 <-- Evento externo 3.
RC1 <---- PWRKEY       --> Encendido SIM900.
RC2 <---- INP3         <-- Botón DOWN -> Menú de configuración.
RC3 <---- SCK          --> Reloj Bus SPI -> ENC28J60 & SD.
RC4 <---- SDI          --> Datos Bus SPI <- MISO (PIC) <<<<< MOSI (SO) ENC28J60 & SD.
RC5 <---- SD0          --> Datos Bus SPI -> MOSI (PIC) >>>>> MISO (SI) ENC28J60 & SD.
RC6 <---- TX           --> TX_PIC (RX_SIM900).
RC7 <---- RX           <-- RX_PIC (TX_SIM900).

---------
Puerto D:
---------

RD0 <---- INP1         <-- Botón UP -> Menú de configuración.
RD1 <---- INP2         <-- Botón CANCEL -> Menú de configuración.
RD2 <---- SCL          --> CLOCK puerto I2C.
RD3 <---- SDA         <--> DATOS puerto I2C.
RD4 <---- BUZZER       --> Indicador de estados.
RD5 <---- LED_OK       --> Indicador de estado: OK.
RD6 <---- LED_ROJO     --> Indicador de estado: ERROR.
RD7 <---- EVENTO_EXT_4 <-- Evento externo 4.

*/

// Definimos macros hardware:

// Entradas.

#define EVENTO_EXTERNO_1  PIN_B1  // Entrada digital 1. (INTERRUPCIÓN)
#define EVENTO_EXTERNO_2  PIN_B2  // Entrada digital 2. (INTERRUPCIÓN)
#define EVENTO_EXTERNO_3  PIN_C0  // Entrada digital 3. (POLLING)
#define EVENTO_EXTERNO_4  PIN_D7  // Entrada digital 4. (POLLING)
#define PULSADOR_ENTER    PIN_B0  // Entrada digital 3. (ENTER) -> (INTERRUPCIÓN)
//#define PULSADOR_UP       PIN_D0  // Entrada digital 4. (UP)
#define PULSADOR_DOWN     PIN_C2  // Entrada digital 5. (DOWN)
#define PULSADOR_CANCEL   PIN_D1  // Entrada digital 6. (CANCEL)

// Salidas.

#define RELE1             PIN_E0 // Relé 1 auxiliar.
#define RELE2             PIN_E1 // Relé 2 auxiliar.
#define RELE3             PIN_E2 // Relé 3 auxiliar.
#define PWRKEY            PIN_C1 // Encendido del módulo GSM SIM900.
#define BUZZER            PIN_D4 // Indicador de estados audible.
#define LED_VERDE_OK      PIN_D0 // Indicador de estado visible [OK].
#define LED_ROJO_ERROR    PIN_D6 // Indicador de estados visible [ERROR].

// Macros de salida:

#define RELE1_ON             output_high(RELE1);
#define RELE1_OFF            output_low(RELE1);
#define RELE2_ON             output_high(RELE2);
#define RELE2_OFF            output_low(RELE2);
#define RELE3_ON             output_high(RELE3);
#define RELE3_OFF            output_low(RELE3);
#define PWRKEY_ON            output_high(PWRKEY);
#define PWRKEY_OFF           output_low(PWRKEY);
#define BUZZER_ON            output_high(BUZZER);
#define BUZZER_OFF           output_low(BUZZER);
#define LED_VERDE_OK_ON      output_high(LED_VERDE_OK);
#define LED_VERDE_OK_OFF     output_low(LED_VERDE_OK);
#define LED_ROJO_ERROR_ON    output_high(LED_ROJO_ERROR);
#define LED_ROJO_ERROR_OFF   output_low(LED_ROJO_ERROR);

// Macros de entrada:

#define ESTADO_EVENTO_EXTERNO_1 input(EVENTO_EXTERNO_1)
#define ESTADO_EVENTO_EXTERNO_2 input(EVENTO_EXTERNO_2)
#define ESTADO_EVENTO_EXTERNO_3 input(EVENTO_EXTERNO_3)
#define ESTADO_EVENTO_EXTERNO_4 input(EVENTO_EXTERNO_4)
#define ESTADO_PULSADOR_ENTER   input(PULSADOR_ENTER)
#define ESTADO_PULSADOR_UP      input(PULSADOR_UP)
#define ESTADO_PULSADOR_DOWN    input(PULSADOR_DOWN)
#define ESTADO_PULSADOR_CANCEL  input(PULSADOR_CANCEL)

No le des importancia a las definiciones de pines y demás...solo lo relativo al GPS.

Código:
// Programa de prueba para ver el funcionamiento del 
// módulo GPS, GM20 de SkyLAB.
// Programador: Moyano Jonathan.
// Año: 2012.

// Incluimos las librerías necesarias.
#include "Plantilla_PIC18F4520.c"
#include "stdlib.h"


// Constantes.

// Variables globales.
char data=0x00;
int const lenbuffGPS=65;                      // Tamaño del buffer de recepción GPS.
int8 cbuffGPS[lenbuffGPS];                    // Buffer de recepcion de datos serie GPS.  
int8 auxGPS[15];
int8 p1, p2; 
int8 hora=0x00;
int8 minutos=0x00;
int8 segundos=0x00;
float latitud=0.00000;
char direccion_NS=0x00;
float longitud=0.00000;
char direccion_EO=0x00;
int8 dia=0x00;
int8 mes=0x00;
int16 anio=0x00;
int8 xbuff=0x00; 

// Declaración de funciones.
int8 StrFnd(char *s, char c, size_t st);
char* StrnmCpy(char *s1, char *s2, size_t n, size_t m);
// Gestión de interrupciones.
        
void main()
{
   while(true){
   
    if(kbhit(GPS)) // Si hay datos disponibles del puerto serie...
    
     {   
     
     data=getchar(GPS);
      switch(data)
      {
        case 10:  
        
                  // Si llegó el caracter de fin de línea..
                  // Determinamos si hay una trama $GPRMC válida..
                  if(cbuffGPS[0]=='$' && cbuffGPS[1]=='G' && cbuffGPS[2]=='P' && cbuffGPS[3]=='R' && cbuffGPS[4]=='M' && cbuffGPS[5]=='C' && cbuffGPS[18]=='A' ){
                

                  // fprintf(DEBUG,"%s \r\n\n",cbuffGPS);  // Imprimimos la trama $GPRMC completa.
                  
                  // Indicador de trama válida recibida.
                  LED_VERDE_OK_ON 
                  delay_ms(200);
                  LED_VERDE_OK_OFF
                  
                  // Decodificación de los datos de hora,fecha,latitud y longitud.
                  
                  // Delimitamos el primer dato.
                  p1 = StrFnd(cbuffGPS, ',', 0);      // Determinamos donde está la primera coma. 
                  p2 = StrFnd(cbuffGPS, ',', p1+1);   // Determinamos donde está la siguiente coma.                  
                  
                  // Determinamos la hora UTC.
                  hora = atoi(StrnmCpy(auxGPS, cbuffGPS, p1+1, p1+2));   
                  minutos = atoi(StrnmCpy(auxGPS, cbuffGPS, p1+3, p1+4)); 
                  segundos = atoi(StrnmCpy(auxGPS, cbuffGPS, p1+5, p1+6)); 
                  // Imprimimos la hora UTC.
                  fprintf(DEBUG,"\r\nHora UTC:\%02d:\%02d:\%02d\r\n", hora,minutos,segundos);
                  
                  // Delimitamos el segundo dato.
                  p1 = StrFnd(cbuffGPS, ',', p2+1);   // Determinamos donde está la tercer coma.
                  p2 = StrFnd(cbuffGPS, ',', p1+1);   // Determinamos donde está la cuarta coma.
                  
                  // Tomamos el valor de latitud y dirección.
                  latitud = atof(StrnmCpy(auxGPS, cbuffGPS, p1+1, p2-1)); 
                  direccion_NS = cbuffGPS[p2+1]; 
                  // Imprimimos el valor de latitud y dirección.
                  fprintf(DEBUG,"Latitud:%f,DIR:%c\r\n",latitud,direccion_NS);
                  
                  // Delimitamos el tercer dato.
                  p1 = StrFnd(cbuffGPS, ',', p2+1);   // Determinamos donde está la quinta coma. 
                  p2 = StrFnd(cbuffGPS, ',', p1+1);   // Determinamos donde está la sexta coma.
                  
                  // Tomamos el valor de longitud y dirección.
                  longitud = atof(StrnmCpy(auxGPS, cbuffGPS, p1+1, p2-1)); 
                  direccion_EO = cbuffGPS[p2+1];
                  // Imprimimos el valor de longitud y dirección.
                  fprintf(DEBUG,"Longitud:%f,DIR:%c\r\n",longitud,direccion_EO);
                  
                  // Delimitamos el último dato.
                  p1 = StrFnd(cbuffGPS, ',', p2+12);   // Determinamos donde está la última coma. 
                  
                  // Tomamos el valor de la fecha.
                  dia  = atoi(StrnmCpy(auxGPS, cbuffGPS, p1+1, p1+2));  
                  mes  = atoi(StrnmCpy(auxGPS, cbuffGPS, p1+3, p1+4));
                  anio = atoi(StrnmCpy(auxGPS, cbuffGPS, p1+5, p1+6)); 
                  // Imprimimos la fecha.
                  fprintf(DEBUG,"Fecha:\%02d/\%02d/\%02lu\r\n\n",dia,mes,anio);
                  
                  }
                  
                  break;
                                    
               default:
               if(data=='$'){xbuff=0;}   // Si llega una trama válida, resetea el contador.                         
               cbuffGPS[xbuff++]=data;   // Caso contrario, sigue leyendo datos y los agrega al buffer.
               if(xbuff>(lenbuffGPS-1)) 
               xbuff=lenbuffGPS;
               break;
 
        }        
        
      }    
   }
}  

int8 StrFnd(char *s, char c, size_t st) 
{ 
   int8 l; 
    
   for (l=st, s+=st ; *s != '\0' ; l++, s++) 
      if (*s == c) 
         return l; 
   return -1; 
} 

char* StrnmCpy(char *s1, char *s2, size_t n, size_t m) 
{ 
   int8 i; 
   char *s; 
    
   for (s=s1, i=n, s2+=n; i<=m; i++) 
      *s++ = *s2++; 
   *s = '\0'; 
    
   return s1; 
}



PD: El programa lo vas a tener que estudiar por tu cuenta, pero básicamente es un parser que analiza la trama y toma los datos relevantes de posición, fecha, hora y fix (solo toma datos válidos). Las funciones son sencillas y está todo comentado, espero te sirva.

Saludos !
 
Última edición:
En efecto todo requiere un esfuerzo extra. Te agradezco mucho tu respuesta.
En cuanto este proyecto vaya avanzando ire posteando los resultados ya que creo que este modulo es nuevo dentro del foro (al menos no lo encontre en el buscador :oops:.

Para futuras consultas, quisiera ir agregando algunos puntos.
-EL modulo breakout de Adafruit tiene un regulador interno de 3.3V, con lo cual podemos alimentar con 5 V sin temor a sobrepasar el voltaje requerido por el chip mtk3339.

-El GPS recibe varias cadenas con inicios de cadena diferente ($GPGGA,GPGSA,GPGS, etc). Son demasiados datos los cuales no nos son reelevantes para un proyecto sencillo.
Las cadenas que nos entregan latitud, longitud, velocidad estimada y posicion son las que inician como $GPMRC y $GPGGA.

Como bien lo realizo en su programa (y se agradece la amabilidad de compartirlo) Moyano Jonathan es identificar la cadena $GPMRC.

Seguire analizando el codigo para seguir adelante.
 
Tengo un problema, en la trama que recibo no encuentro el caracter de fin de linea
Código:
data=getchar(GPS);
      switch(data)
      {
        case 10:


¿Porque es 10? EN el documento que estoy leyendo aqui me indica que los ultimos caracteres varian debido a que los ultimos caracteres sirven para identificar errores en la transmision (cheksum)

Mi duda es como recibir este fin de caracter
 
Última edición:
Atrás
Arriba