Correctly receiving the nmea characters from A2200-A GPS

I have been working on this project for a little while, trying to receive the characters from my GPS and then display these characters on a 16x2 LCD. I am using an interrupt on my UART RX pin which allows the program to enter the interrupt service routine when a character is detected which is working.

In the interrupt service routine the NMEA data is then extracted and stored in a 80 character array and then broken down again into smaller arrays to extract the individual data I am wanting to display. However when I do go to display these characters I see nothing.

The LCD part of the program is working perfectly and I can see on my oscilloscope that characters are being transmitted by the GPS, so the problem might be that I am not storing this information properly and I have set the bit rates correctly?

The microcontroller that I am using is the PIC32mx795f512h, if anyone might know what my problem might be any help would be hugely appreciated.

Below is my main and interrupt service routine

int32_t main(void)
{
#ifndef PIC32_STARTER_KIT
SYSTEMConfig(SYS_FREQ, SYS_CFG_WAIT_STATES | SYS_CFG_PCACHE);

InitApp();             //initialise ports & interrupts
intLCD();              //initialise LCD
clrLCD();
putsLCD("Initialising \n \t TCAS");

// configure for multi-vectored mode
INTConfigureSystem(INT_SYSTEM_CONFIG_MULT_VECTOR);

//UART1 enable for own gps
UARTConfigure(UART1, UART_ENABLE_PINS_TX_RX_ONLY);
UARTSetFifoMode(UART1, UART_INTERRUPT_ON_TX_NOT_FULL | UART_INTERRUPT_ON_RX_NOT_EMPTY);
UARTSetLineControl(UART1, UART_DATA_SIZE_8_BITS | UART_PARITY_NONE | UART_STOP_BITS_1);
UARTSetDataRate(UART1, GetPeripheralClock(), 4800);
UARTEnable(UART1, UART_ENABLE_FLAGS(UART_PERIPHERAL | UART_RX | UART_TX));

// Configure UART1 RX Interrupt
INTEnable(INT_SOURCE_UART_RX(UART1), INT_ENABLED);
INTSetVectorPriority(INT_VECTOR_UART(UART1), INT_PRIORITY_LEVEL_2);
INTSetVectorSubPriority(INT_VECTOR_UART(UART1), INT_SUB_PRIORITY_LEVEL_0);

//UART2 enable for surrounding

PORTSetPinsDigitalOut(IOPORT_F, BIT_5);                    //data transmitter

// enable interrupts
INTEnableInterrupts();

//allow uart >300ms to initialise
Delayms(5000);

gpsINITIALISE();        //initialise GPS to receive data >100ms

//main loop
int check = 0;
while(1)     //wait in here for uart interrupt
{
ValidMsg = NotTrue;     //clear valid message variable
if(check == 0)
{
putsLCD("Resend \n \t message");
sendMessages(); //send for gga message
check = 1;
}
if(ValidMsg = True) //check to see if data is valid in main string
{
putsLCD("Message \n \t Valid");
DisableIntU1RX;   //dissable interrupts on uart 1
createString();   //create character string to transmit to nearby aircraft
EnableIntU2RX;    //enable interrupts on UART2
Delayms(10000);   //wait for data to be received from nearby aircraft
DisableIntU2RX;   //dissable interrupts on uart 2
GPStest();        //display the individual strings

}
if (ValidMsg = NotTrue) //check to see is not valid
{
putsLCD("Message1 \n \t Invalid");
for(s=0; s<80; s++)        //clear received data string
{
GGA[s]=0;
}
sendMessages(); //resend for gga message
}
}
}

// U1RX interrupt, majority of GPS relies within
void __ISR(_UART_1_VECTOR, ipl6) _U1RXInterrupt(void)
{
int parse=0;    // string counter
if(U1STAbits.OERR == 1)
U1STAbits.OERR = 0;

{
c = getcUART1();
while(UARTReceivedDataIsAvailable(UART1)); //check to see if data is available
if(c == '$') //c ==$, hex=0x0024
{
count = 0;
}
if(count < 6)
{
dataTest[count] = c;
count++;
}
else if(count > 5 && count < 80)
{
if(dataTest[4]=='G')     //test data string
{
GGA[count]=c;
ValidMsg = True;    //data is valid
}
else  //error
ValidMsg = NotTrue;    //data is valid
count++;
PORTToggleBits(IOPORT_B, BIT_2);
}
}

//extract data into individual strings
x=0;
for(parse=1;parse<80;parse++)
{

if ((parse >=1) & (parse <6)) //Message Type
{
command[parse-1] = GGA[parse];
}
else if ((parse >6) & (parse < 17)) //Time
{
time[x] = GGA[parse];
x++;
if (parse == 16)
x=0;
}
else if ((parse > 17) & (parse < 27)) //Latitude
{
lat[x] = GGA[parse];
x++;
if (parse == 26)
x=0;
}
else if (parse == 28) //Latitude Dir
latDir = GGA[parse];
else if ((parse > 29) & (parse < 40)) //Longitude
{
lon[x] = GGA[parse];
x++;

if (parse == 39)
x=0;
}
else if (parse == 41) //Longitude Dir
lonDir = GGA[parse];
else if (parse == 43) //Fix Quality

fixQ = GGA[parse];
else if ((parse > 51) & (parse < 55)) //altitude
{
altitude[x] = GGA[parse];
x++;
if(parse == 54)
x=0;
}
}
INTClearFlag(INT_SOURCE_UART_RX(UART1));         // Clear the RX interrupt Flag
}

• it seems that you send you message to valid before you know you known you even receive your message. plus we are also trying to parse your message every time you receive a character so again you are parsing an incomplete message while you valid flag is set – Kvegaoro Sep 19 '14 at 0:49
• The code has a mix of spaces and tabs which seems to mess-up the layout. It might not be worth fixing, but in future maybe try to ensure everything in the code is spaces, with no tabs. – gbulmer Sep 19 '14 at 1:39

A good 'rule of thumb' is to do as little processing inside interrupt service routines (ISR) as possible. It is typically much harder to debug code inside an interrupt service routine than ordinary code.

I would strip all of the decoding from the ISR, and put it into main, or a function called by main.

NMEA message format terminates each message with a carriage-return (0x0D, or '\r') and line-feed (0x0A or '\n'). So I might look for those inside the ISR, and set a flag to indicate a complete message has been found. As easy would be to check the most recent character put into the buffer.

In main(), I'd only do processing when a complete message arrives, signalled by the line-feed.

There is no need to do any processing on the NMEA message while testing. You could print it to the LCD.

It is quite feasible that the code just 'gobbles up' the NME message somewhere. IMHO the code is too messy because of the formatting on this site, to debug by reading it.

Depending on the PIC32 development board you have, I'd print the NMEA message text onto something simpler than the LCD to give independent confirmation of its contents. To help debug this, if you have no debugger, or way to get data out, I'd invest in a cheap USB-UART, and use a PC to print it.

• Thanks I will mirror the data out and display on windows hyperterminal. – brook Sep 21 '14 at 8:33
• Best of luck. Come back if you still want help. I really do recommend simplifying the ISR to make debugging easier. – gbulmer Sep 21 '14 at 13:33