Correctly receiving the nmea characters from A2200-A GPS

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 16×2 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
 PORTSetPinsDigitalIn(IOPORT_F, BIT_4);                     //data receiver


 // 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;

if(U1STAbits.URXDA) //check if data is ready to be read
    {
        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
} 

Best Answer

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.