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.