UART interrupt problem
-
- Posts: 11
- Joined: 19 Feb 2013 19:21
UART interrupt problem
I am using a ready for PIC board, and have connected a GPS receiver to UART2 (Rx-RB6). Every second the GPS receiver sends a string of characters to the PIC. I want to store the characters from the GPS module in a character array and then search for "$GPGGA" which is the start of the GPS data that I need.
The problem I'm having is with triggering the PIC to store data every time it is sent to UART2, I tried using UART2_Data_Ready() but this did not work. I have noticed that most people use UART interrupts to trigger the PIC to store data. But I cant get it to work. Please help me
My code checks if data is ready to receive if the there is no data it displays "Not ready" to the LCD, if data is revived and it contains the string of characters "$GPGGA" it displays "data found" to the LCD and if data is received but "GPGGA" is not found it displays "no data".
When I run the program the LCD displays "Not ready" thus I can say with reasonable certainty that the interrupt code is not working. My code is below:
/*-------------------------------------------------------define LCD Connections ------------------------------------- */
sbit LCD_RS at LATA2_bit;
sbit LCD_EN at LATA3_bit;
sbit LCD_D4 at LATA4_bit;
sbit LCD_D5 at LATA5_bit;
sbit LCD_D6 at LATE0_bit;
sbit LCD_D7 at LATE1_bit;
sbit LCD_RS_Direction at TRISA2_bit;
sbit LCD_EN_Direction at TRISA3_bit;
sbit LCD_D4_Direction at TRISA4_bit;
sbit LCD_D5_Direction at TRISA5_bit;
sbit LCD_D6_Direction at TRISE0_bit;
sbit LCD_D7_Direction at TRISE1_bit;
/*-------------------------------------------------------gps variables-----------------------------------------------------*/
int i;
unsigned short ready;
char GPSin[1024]; //GPS data dump
char *pointer;
/*----------------------------------------------------------GPS subroutine----------------------------------------------------------------------------*/
GPS (void)
{
if(ready == 1) // If the data in txt array is ready do:
{
ready = 0;
pointer = strstr(GPSin,"$GPGGA");
if(pointer != 0) // If txt array contains "$GPGGA" string
{
Lcd_Out(1,1,"Data Found");
delay_ms(2000); // display for 2 seconds
lcd_Cmd(_LCD_CLEAR); //clear LCD display
}
else
{
Lcd_Out(1,1,"No data"); //LCD test message
delay_ms(2000); // display for 2 seconds
lcd_Cmd(_LCD_CLEAR); //clear LCD display
}
}
else
{
Lcd_Out(1,1,"Not ready"); //LCD test message
delay_ms(2000); // display for 2 seconds
lcd_Cmd(_LCD_CLEAR); //clear LCD display
}
}
/*----------------------------------------------------------Read GPS data interupt--------------------------------------------------------------------*/
void interrupt()
{
if (RCIF_bit == 0) // If interrupt is generated by RCIF
{
GPSin = UART2_Read(); // Read data and store it to txrt string
i++; // Increment string index
if (i == 768) // If index = 768,
{
i = 0; // set it to zero
ready = 1; // Ready for parsing GPS data
}
RCIF_bit = 0; // Set RCIF to 0
}
}
/*--------------------------------------------------------Main program-------------------------------------------------------------------------------*/
void main()
{
ANSELA = 0; // set all pins as digital
ANSELB = 0; // set all pins as digital
ANSELC = 0; // set all pins as digital
ANSELD = 0; // set all pins as digital
C1ON_bit = 0; // Disable comparator
C2ON_bit = 0; // Disable comparator
Lcd_Init(); // Initalise LCD
delay_ms(100);
Lcd_Cmd(_LCD_CURSOR_OFF); // LCD curser off
Uart2_Init(4800); // Initialize UART module and set board rate
Delay_ms(100);
RC1IE_bit = 1; // Enable USART Receiver interrupt
GIE_bit = 1; // Enable Global interrupt
PEIE_bit = 1; // Enable Peripheral interrupt
ready=0;
i=0;
Lcd_Out(1,1,"LCD test"); //LCD test message
delay_ms(2000); // display for 2 seconds
lcd_Cmd(_LCD_CLEAR); //clear LCD display
while(1)
{
GPS(); //GPS recive data subroutine
}
}
The problem I'm having is with triggering the PIC to store data every time it is sent to UART2, I tried using UART2_Data_Ready() but this did not work. I have noticed that most people use UART interrupts to trigger the PIC to store data. But I cant get it to work. Please help me
My code checks if data is ready to receive if the there is no data it displays "Not ready" to the LCD, if data is revived and it contains the string of characters "$GPGGA" it displays "data found" to the LCD and if data is received but "GPGGA" is not found it displays "no data".
When I run the program the LCD displays "Not ready" thus I can say with reasonable certainty that the interrupt code is not working. My code is below:
/*-------------------------------------------------------define LCD Connections ------------------------------------- */
sbit LCD_RS at LATA2_bit;
sbit LCD_EN at LATA3_bit;
sbit LCD_D4 at LATA4_bit;
sbit LCD_D5 at LATA5_bit;
sbit LCD_D6 at LATE0_bit;
sbit LCD_D7 at LATE1_bit;
sbit LCD_RS_Direction at TRISA2_bit;
sbit LCD_EN_Direction at TRISA3_bit;
sbit LCD_D4_Direction at TRISA4_bit;
sbit LCD_D5_Direction at TRISA5_bit;
sbit LCD_D6_Direction at TRISE0_bit;
sbit LCD_D7_Direction at TRISE1_bit;
/*-------------------------------------------------------gps variables-----------------------------------------------------*/
int i;
unsigned short ready;
char GPSin[1024]; //GPS data dump
char *pointer;
/*----------------------------------------------------------GPS subroutine----------------------------------------------------------------------------*/
GPS (void)
{
if(ready == 1) // If the data in txt array is ready do:
{
ready = 0;
pointer = strstr(GPSin,"$GPGGA");
if(pointer != 0) // If txt array contains "$GPGGA" string
{
Lcd_Out(1,1,"Data Found");
delay_ms(2000); // display for 2 seconds
lcd_Cmd(_LCD_CLEAR); //clear LCD display
}
else
{
Lcd_Out(1,1,"No data"); //LCD test message
delay_ms(2000); // display for 2 seconds
lcd_Cmd(_LCD_CLEAR); //clear LCD display
}
}
else
{
Lcd_Out(1,1,"Not ready"); //LCD test message
delay_ms(2000); // display for 2 seconds
lcd_Cmd(_LCD_CLEAR); //clear LCD display
}
}
/*----------------------------------------------------------Read GPS data interupt--------------------------------------------------------------------*/
void interrupt()
{
if (RCIF_bit == 0) // If interrupt is generated by RCIF
{
GPSin = UART2_Read(); // Read data and store it to txrt string
i++; // Increment string index
if (i == 768) // If index = 768,
{
i = 0; // set it to zero
ready = 1; // Ready for parsing GPS data
}
RCIF_bit = 0; // Set RCIF to 0
}
}
/*--------------------------------------------------------Main program-------------------------------------------------------------------------------*/
void main()
{
ANSELA = 0; // set all pins as digital
ANSELB = 0; // set all pins as digital
ANSELC = 0; // set all pins as digital
ANSELD = 0; // set all pins as digital
C1ON_bit = 0; // Disable comparator
C2ON_bit = 0; // Disable comparator
Lcd_Init(); // Initalise LCD
delay_ms(100);
Lcd_Cmd(_LCD_CURSOR_OFF); // LCD curser off
Uart2_Init(4800); // Initialize UART module and set board rate
Delay_ms(100);
RC1IE_bit = 1; // Enable USART Receiver interrupt
GIE_bit = 1; // Enable Global interrupt
PEIE_bit = 1; // Enable Peripheral interrupt
ready=0;
i=0;
Lcd_Out(1,1,"LCD test"); //LCD test message
delay_ms(2000); // display for 2 seconds
lcd_Cmd(_LCD_CLEAR); //clear LCD display
while(1)
{
GPS(); //GPS recive data subroutine
}
}
Re: UART interrupt problem
If you are using UART2 as you have said than you need to change the following:
In main() change this line: to In interrupt() change this: to: and also: to:
Regards
In main() change this line:
Code: Select all
RC1IE_bit = 1; // Enable USART Receiver interrupt
Code: Select all
RC2IE_bit = 1;
Code: Select all
if (RCIF_bit == 0) // If interrupt is generated by RCIF
Code: Select all
if (RC2IF_bit) // or RC2IF_bit == 1
Code: Select all
RCIF_bit = 0; // Set RCIF to 0
Code: Select all
RC2IF_bit = 0;
Regards
-
- Posts: 11
- Joined: 19 Feb 2013 19:21
Re: UART interrupt problem
Thanks my interrupt is now functioning but now I have another problem.
I now know that the data is being received from the GPS module via URART2 and each character is being stored in the character array GPSin because the LCD indicates this. However when I use the strstr function to try and find the string of characters "$GPGGA" it doesn't not find them. This is rather odd because when I connected the GPS module to my computers serial port it transmits the following data every second, you can see that the "$GPPGA" is in there:
$GPRMC,190506.21,A,5050.1380,N,00007.3619,W,000.5,013.2,100313,001.2,W,A*3B
$GPGGA,190506.21,5050.1380,N,00007.3619,W,1,07,01.0,00041.1,M,0045.4,M,,*41
$GPGSA,A,3,24,12,14,17,15,22,,18,,,,,01.8,01.0,01.5*05
$GPGSV,3,1,09,24,73,099,28,12,69,232,33,14,32,309,23,17,26,047,20*79
$GPGSV,3,2,09,15,22,168,24,22,17,274,25,09,17,106,16,18,10,242,29*74
$GPGSV,3,3,09,04,03,091,*4F
This is baffling to me why wont my PIC find the "$GPGGA" string? My LCD displays the message "No data" if the string "GPGGA" is not found. If anyone has any idea's It would be much appropriated
I now know that the data is being received from the GPS module via URART2 and each character is being stored in the character array GPSin because the LCD indicates this. However when I use the strstr function to try and find the string of characters "$GPGGA" it doesn't not find them. This is rather odd because when I connected the GPS module to my computers serial port it transmits the following data every second, you can see that the "$GPPGA" is in there:
$GPRMC,190506.21,A,5050.1380,N,00007.3619,W,000.5,013.2,100313,001.2,W,A*3B
$GPGGA,190506.21,5050.1380,N,00007.3619,W,1,07,01.0,00041.1,M,0045.4,M,,*41
$GPGSA,A,3,24,12,14,17,15,22,,18,,,,,01.8,01.0,01.5*05
$GPGSV,3,1,09,24,73,099,28,12,69,232,33,14,32,309,23,17,26,047,20*79
$GPGSV,3,2,09,15,22,168,24,22,17,274,25,09,17,106,16,18,10,242,29*74
$GPGSV,3,3,09,04,03,091,*4F
This is baffling to me why wont my PIC find the "$GPGGA" string? My LCD displays the message "No data" if the string "GPGGA" is not found. If anyone has any idea's It would be much appropriated
Code: Select all
/*-------------------------------------------------------define LCD Connections ------------------------------------- */
sbit LCD_RS at LATA2_bit;
sbit LCD_EN at LATA3_bit;
sbit LCD_D4 at LATA4_bit;
sbit LCD_D5 at LATA5_bit;
sbit LCD_D6 at LATE0_bit;
sbit LCD_D7 at LATE1_bit;
sbit LCD_RS_Direction at TRISA2_bit;
sbit LCD_EN_Direction at TRISA3_bit;
sbit LCD_D4_Direction at TRISA4_bit;
sbit LCD_D5_Direction at TRISA5_bit;
sbit LCD_D6_Direction at TRISE0_bit;
sbit LCD_D7_Direction at TRISE1_bit;
/*-------------------------------------------------------gps variables-----------------------------------------------------*/
int i;
unsigned short ready;
char GPSin[1024]; //GPS data dump
char *pointer;
/*----------------------------------------------------------GPS subroutine----------------------------------------------------------------------------*/
GPS (void)
{
if(ready == 1) // If the data in txt array is ready do:
{
ready = 0;
pointer = strstr(GPSin,"$GPGGA");
if(pointer != 0) // If txt array contains "$GPGGA" string
{
Lcd_Out(1,1,"Data Found");
delay_ms(2000); // display for 2 seconds
lcd_Cmd(_LCD_CLEAR); //clear LCD display
}
else
{
Lcd_Out(1,1,"No data"); //LCD test message
delay_ms(2000); // display for 2 seconds
lcd_Cmd(_LCD_CLEAR); //clear LCD display
}
}
else
{
Lcd_Out(1,1,"Not ready"); //LCD test message
delay_ms(2000); // display for 2 seconds
lcd_Cmd(_LCD_CLEAR); //clear LCD display
}
}
/*----------------------------------------------------------Read GPS data interupt--------------------------------------------------------------------*/
void interrupt()
{
if (RC2IF_bit==1) // If interrupt is generated by RCIF
{
GPSin[i] = UART2_Read(); // Read data and store it to txrt string
i++; // Increment string index
if ((i>500)&&(i<700)) // If index is greter than 500 characters,
{
ready = 1; // Ready for parsing GPS data
}
if (i>700) // If number of characters is greater then 700 array approching full capacticy
{
i = 0; //reset string index
ready = 0; //Clear ready flag
memset(GPSin,0x00,1023); //clear GPS data dump
}
RC2IF_bit = 0; // Set RCIF to 0
}
}
/*--------------------------------------------------------Main program-------------------------------------------------------------------------------*/
void main()
{
ANSELA = 0; // set all pins as digital
ANSELB = 0; // set all pins as digital
ANSELC = 0; // set all pins as digital
ANSELD = 0; // set all pins as digital
C1ON_bit = 0; // Disable comparator
C2ON_bit = 0; // Disable comparator
Lcd_Init(); // Initalise LCD
delay_ms(100);
Lcd_Cmd(_LCD_CURSOR_OFF); // LCD curser off
Uart2_Init(4800); // Initialize UART module and set board rate
Delay_ms(100);
RC2IE_bit = 1; // Enable USART Receiver interrupt
GIE_bit = 1; // Enable Global interrupt
PEIE_bit = 1; // Enable Peripheral interrupt
ready=0;
i=0;
Lcd_Out(1,1,"LCD test"); //LCD test message
delay_ms(2000); // display for 2 seconds
lcd_Cmd(_LCD_CLEAR); //clear LCD display
while(1)
{
OERR2_bit = 0; // Set OERR to 0
FERR2_bit = 0; // Set FERR to 0
GPS(); //GPS recive data subroutine
}
}
Re: UART interrupt problem
Because you are filling the buffer array much faster than you can display the result (you use 2000ms delays). If you check your interrupt routine you will see that you are setting "ready" flag and shortly after that resetting it while your LCD is still displaying last result. If you just light up some LEDs in your GPS() routine when string "$GPGGA" is found you will debug the code more easily. Also your code is not very efficient since you are wasting 1KB of RAM which is a lot for PIC.
I assume your goal is to extract and parse $GPGGA NMEA sentence. In that case I suggest you try this:
1. Look for '$' which marks start of the sentence
2. Look for sequence of chars 'G','P','G','G','A'. If you get a character not belonging to this sequence then go back to the beginning of the buffer
3. Read characters until you get CRLF (end of NMEA sentence)
4. Mark buffer as ready for parsing
Then in your main() routine you can check the ready flag and tokenize the string using strtok function.
Regards
I assume your goal is to extract and parse $GPGGA NMEA sentence. In that case I suggest you try this:
1. Look for '$' which marks start of the sentence
2. Look for sequence of chars 'G','P','G','G','A'. If you get a character not belonging to this sequence then go back to the beginning of the buffer
3. Read characters until you get CRLF (end of NMEA sentence)
4. Mark buffer as ready for parsing
Then in your main() routine you can check the ready flag and tokenize the string using strtok function.
Regards
Re: UART interrupt problem
You might want to consider also validating the checksum at the end of the message:
Code: Select all
static unsigned char calcChecksum(char *strBuffer, int intLength) {
char* pBuffer = strBuffer + 1;
unsigned char ucChecksum = 0;
while( *pBuffer != '\0' && --intLength > 0 ) {
ucChecksum ^= *pBuffer;
pBuffer++;
}
return ucChecksum;
}
Kind Regards,
Sy
Sy
Re: UART interrupt problem
Hi,
don't you have a Result is not defined in function warning after compile? I mean:
Bonca
don't you have a Result is not defined in function warning after compile? I mean:
Code: Select all
GPS(void) {
...
}
-
- Posts: 11
- Joined: 19 Feb 2013 19:21
Re: UART interrupt problem
@ aCK0
I think I have addressed the problem of filling the text array quicker than I can display the result. I have now connected an LED to PORTD, which should light up When "$" is found in the text array "GPSin". However the LED does not light up, I know the LED works because I wrote some code to flash it on and off before the while(1).
Yes my goal is to extract the $GPGGA NMEA sentence eventually, and I think your suggestion for extracting it will work well, thanks
However I still cant get my head around why my PIC wont find the "$" character in the array
@ Bonca
Thanks for your help I have sorted out that compile warning now
@ Sy
I have looked at the NMEA protocol documentation and once I have worked out a way of find the start of the GPGGA string "$" I could use the checksum to validate the message. thanks
@everyone
Do you have any idea's why the PIC doesn't find the "$" character in the GPSin text array? I've been trying to debug my code all day and cant find the issue
When I run my new code I get the message "Not found" on the LCD, which indictes that GPS data has been stored into the text array but the program doesnt not find "$".
I think I have addressed the problem of filling the text array quicker than I can display the result. I have now connected an LED to PORTD, which should light up When "$" is found in the text array "GPSin". However the LED does not light up, I know the LED works because I wrote some code to flash it on and off before the while(1).
Yes my goal is to extract the $GPGGA NMEA sentence eventually, and I think your suggestion for extracting it will work well, thanks
However I still cant get my head around why my PIC wont find the "$" character in the array
@ Bonca
Thanks for your help I have sorted out that compile warning now
@ Sy
I have looked at the NMEA protocol documentation and once I have worked out a way of find the start of the GPGGA string "$" I could use the checksum to validate the message. thanks
@everyone
Do you have any idea's why the PIC doesn't find the "$" character in the GPSin text array? I've been trying to debug my code all day and cant find the issue
When I run my new code I get the message "Not found" on the LCD, which indictes that GPS data has been stored into the text array but the program doesnt not find "$".
Code: Select all
/*-------------------------------------------------------gps variables-----------------------------------------------------*/
char GPSin[512];//GPS data dump
char *pointer; //pointer to start of desired string in dump
int i;// text array index
unsigned short ready; //ready flag
/*---------------------------------------------------------LCD connections-----------------------------------------------------*/
sbit LCD_RS at LATA2_bit;
sbit LCD_EN at LATA3_bit;
sbit LCD_D4 at LATA4_bit;
sbit LCD_D5 at LATA5_bit;
sbit LCD_D6 at LATE0_bit;
sbit LCD_D7 at LATE1_bit;
sbit LCD_RS_Direction at TRISA2_bit;
sbit LCD_EN_Direction at TRISA3_bit;
sbit LCD_D4_Direction at TRISA4_bit;
sbit LCD_D5_Direction at TRISA5_bit;
sbit LCD_D6_Direction at TRISE0_bit;
sbit LCD_D7_Direction at TRISE1_bit;
/*---------------------------------------------------------------------read GPS data------------------------------------------*/
void interrupt() {
if (RC2IF_bit == 1) // If interrupt is generated by RCIF
{
GPSin[i] = UART2_Read(); // Read data and store it to txrt string
i++; // Increment string index
if (i == 512) // If index = 512 @ full capacity
{
i = 0; // set it to zero
ready = 1; // Ready for parsing GPS data
}
RC2IF_bit = 0; // Set RCIF to 0
}
}
/*------------------------------------------------------------------------main--------------------------------------------------------------*/
void main()
{
ANSELA = 0; // Configure ports as digital I/O
ANSELB = 0;
ANSELC = 0;
ANSELD = 0;
TRISD=0x00;
Lcd_Init(); // Initalise LCD
delay_ms(100);
Lcd_Cmd(_LCD_CURSOR_OFF); // LCD curser off
ready = 0; // Initialize variables
i = 0;
UART2_Init(4800); // Initialize UART module at 4800
RC2IE_bit = 1; // Enable USART Receiver interrupt
GIE_bit = 1; // Enable Global interrupt
PEIE_bit = 1; // Enable Peripheral interrupt
PORTD = 0xFF; //test LED
delay_ms(100);
PORTD=0x00;
while(1)
{
OERR2_bit = 0; // Set OERR to 0
FERR2_bit = 0; // Set FERR to 0
if(ready == 1) // If the data in txt array is ready do:
{
ready = 0;
pointer = strstr(GPSin,"$");
if(pointer != 0) // If txt array contains "$" string we proceed...
{
PORTD = 0xFF; //led flashes on if "$" is found
delay_ms(100);
PORTD=0x00;
}
else
{
Lcd_Out(1,1,"Not Found");// LCD message if data in GPSin does not contain "$"
delay_ms(1000);
lcd_Cmd(_LCD_CLEAR);
}
}
}
}
-
- Posts: 1179
- Joined: 24 Nov 2005 20:07
- Location: Colorado, USA
Re: UART interrupt problem
Here is some code to study.
It helps explain a way to look for the desired string using the first few chars as the search criteria. It does not use interrupts but can be modified to use them later. It's not optimized code by any means but written purely as a simplified study aid.
The function searches for the GGA string, when found stores it in an array and then sends it back out the second serial port. It assumes the PIC you are using has 2 UARTS and has been configured for desired baud rates.
It helps explain a way to look for the desired string using the first few chars as the search criteria. It does not use interrupts but can be modified to use them later. It's not optimized code by any means but written purely as a simplified study aid.
The function searches for the GGA string, when found stores it in an array and then sends it back out the second serial port. It assumes the PIC you are using has 2 UARTS and has been configured for desired baud rates.
Code: Select all
void readGGA (void)
{
unsigned char gpsGGAarray [72] = "$GPGGA";
unsigned char count = 0;
unsigned char inBuffer = 0;
while (1)
{
// GGA search character loop
do
{
while (UART1_Data_Ready() != 1); // wait for byte receive
inBuffer = UART1_Read(); // read in received byte
if (inBuffer == gpsGGAarray [count]) count++; // test receive byte for match, yes? then increment count
else count = 0; // no match? then reset count
} while (count != 6); // keep looping until all 6 consecutive characters match
count = 6; // set counter to use as an array indexer with 5 character offset (as to not erase search string chars declared at top of function)
inBuffer = 0; // clear the buffer
// loop to read in the rest of the string
do // read GGA NMEA string contents
{
while (UART1_Data_Ready() != 1); // wait for byte receive
inBuffer = UART1_Read(); // read in received byte
gpsGGAarray[count] = inBuffer;
count++;// increment array index
}while (inBuffer != '\r'); // loop until string temination character is seen <CR>.
// send out what was received
gpsGGAarray[count] = 0x00; // add null termination char
UART2_Write_Text (gpsGGAarray); // send out received GGA GPS string which should happen once every second
count = 0; // clear counter and buffer for next pass
inBuffer = 0;
}
}//!
Re: UART interrupt problem
I would write an NMEA packet decode routine and test it as a stand alone function, write a simple test application...
main...then some static NMEA strings and pass these to your NMEA decode function, that way you can validate it does everything it is supposed to do without worrying about the communications, then once you are satisfied your decode is 100% correct, then put it together with the communications.
main...then some static NMEA strings and pass these to your NMEA decode function, that way you can validate it does everything it is supposed to do without worrying about the communications, then once you are satisfied your decode is 100% correct, then put it together with the communications.
Kind Regards,
Sy
Sy
Re: UART interrupt problem
Your code should work. Are you sure you are getting characters on UART2 and that the baud rate is correct (most of GPS modules work at 9600bps)? Maybe you should try forwarding data from UART2 to UART1 so you can confirm this in terminal.@everyone
Do you have any idea's why the PIC doesn't find the "$" character in the GPSin text array? I've been trying to debug my code all day and cant find the issue
When I run my new code I get the message "Not found" on the LCD, which indictes that GPS data has been stored into the text array but the program doesnt not find "$".
Also, take a look at your interrupt routine. If you manage your buffer that way then you must take into account that "$GPGGA" can be anywhere in the buffer. For example, it may start at GPSin[500]. In that case, if you mark your buffer as "ready" then you can't parse it for "$GPGGA" in the main routine because it will not contain complete NMEA sentence. You are just complicating things. I see that GPS example from mikroE had some bad influence on you What they did is they just tried to simplify the example. They chose the buffer size to be 768 so they could be sure there will be at least 2 GGA sentences in it (the first one will be complete obviously). I would call that memory/simplicity trade off. You don't have to do that and you should not do that. In the interrupt routine, why don't you first check if you have received '$' and if yes then put it at the beginning of the buffer and then store incoming characters until you get CR. Then you mark your buffer as ready and process it in main routine. And that's it! Simple, isn't it? This way you can obtain every NMEA sentence and do some parsing on them not just GGA. You can also use much smaller buffer (128 chars is more than enough).
The checksum function is really simple, it just XORs all characters between '$' and '*' (excluding them).
If you use strtok function in main routine to extract NMEA sentence and checksum then you can really simplify your life:
Code: Select all
char checksum(char *s) {
char c = 0;
while(*s)
c ^= *s++;
return c;
}
-
- Posts: 11
- Joined: 19 Feb 2013 19:21
Re: UART interrupt problem
I tested this I created a character string containing the NMEA sentences that I revived when I connected the GPS module to my computer and the strstr function found the "$GPGGA" string no problem. It's weird that this doesn't work when I search for "GPGGA" in the string imported from the UART.Sy wrote:I would write an NMEA packet decode routine and test it as a stand alone function, write a simple test application...
main...then some static NMEA strings and pass these to your NMEA decode function, that way you can validate it does everything it is supposed to do without worrying about the communications, then once you are satisfied your decode is 100% correct, then put it together with the communications.
I'm pretty certain that I am getting characters from UART2 and the baud rate is correct I've checked the data sheet. Your right I did base my code on the MikroE GPS example and it has over complicated things. I not very familiar with using interrupts so I have decided to simplify my code my basing it on the code Sparky1039 provided.aCkO wrote:Your code should work. Are you sure you are getting characters on UART2 and that the baud rate is correct (most of GPS modules work at 9600bps)? Maybe you should try forwarding data from UART2 to UART1 so you can confirm this in terminal.
-
- Posts: 11
- Joined: 19 Feb 2013 19:21
Re: UART interrupt problem
In the GPSread loop I have tested each stage step by step by adding:
PORTD=0xFF; //LED on
delay_ms(100);
This way I could observe if the PIC executes each stage in the GPSread loop. I found that the LED would flash on at every stage in the loop up until it got to count++ in the first dowhile, the code seems to get stuck here. This must mean that the PIC finds some of the characters of "$GPGGA" but not all six of them and does not go onto the next dowhile statement This GPS module is proving to be a nightmare to get working
Here is my new code:
PORTD=0xFF; //LED on
delay_ms(100);
This way I could observe if the PIC executes each stage in the GPSread loop. I found that the LED would flash on at every stage in the loop up until it got to count++ in the first dowhile, the code seems to get stuck here. This must mean that the PIC finds some of the characters of "$GPGGA" but not all six of them and does not go onto the next dowhile statement This GPS module is proving to be a nightmare to get working
Here is my new code:
Code: Select all
/*-------------------------------------------------------gps variables-----------------------------------------------------*/
unsigned char GPSin = 0;
unsigned char GPGGA[76] = "$GPGGA";
unsigned char count= 0;
/*---------------------------------------------------------LCD connections-----------------------------------------------------*/
sbit LCD_RS at LATA2_bit;
sbit LCD_EN at LATA3_bit;
sbit LCD_D4 at LATA4_bit;
sbit LCD_D5 at LATA5_bit;
sbit LCD_D6 at LATE0_bit;
sbit LCD_D7 at LATE1_bit;
sbit LCD_RS_Direction at TRISA2_bit;
sbit LCD_EN_Direction at TRISA3_bit;
sbit LCD_D4_Direction at TRISA4_bit;
sbit LCD_D5_Direction at TRISA5_bit;
sbit LCD_D6_Direction at TRISE0_bit;
sbit LCD_D7_Direction at TRISE1_bit;
/*---------------------------------------------------------------------read GPS data------------------------------------------*/
void GPSread(void)
{
PORTD=0x00; //LED off
do
{
while(UART2_Data_Ready() != 1); //wait for data to be ready
GPSin==UART2_Read(); //store chracter of GPS data
if(GPSin ==GPGGA[count]) // look for "$GPGGA" one chracter at a time
{
count++;
}
else // if no chracter found
{
count=0;
}
}while(count !=6); // do until while count not=6 (end of "$GPGGA")
count=6; // set counter to point after $GPGGA
GPSin=0; // clear buffer
do
{
while(UART2_Data_Ready() != 1); //wait until data is ready
GPSin == UART2_Read(); //store charcter of GPGGA string
GPGGA[count] = GPSin; //store in text string
count++;
}while(GPSin != '\r'); // do until deliminator
count = 0; // clear counter and buffer for next pass
GPSin = 0;
}
/*------------------------------------------------------------------------main--------------------------------------------------------------*/
void main()
{
ANSELA = 0; // Configure ports as digital I/O
ANSELB = 0;
ANSELC = 0;
ANSELD = 0;
TRISD=0x00;
Lcd_Init(); // Initalise LCD
delay_ms(100);
Lcd_Cmd(_LCD_CURSOR_OFF); // LCD curser off
UART2_Init(4800); // Initialize UART module at 9600
delay_ms(100);
while(1)
{
GPSread();
}
}
Last edited by archernater on 20 Mar 2013 01:43, edited 2 times in total.
Re: UART interrupt problem
Don't feel intimidated by interrupts. Trust me, it is the right way to go. I have checked your code on real hardware and the LEDs are flashing. If you are using PIC18F45K22 are you sure you connected your GPS module on UART2 RX pin (RD7)? Also check oscillator frequency in project settings and make sure it matches with the crystal on your board.I'm pretty certain that I am getting characters from UART2 and the baud rate is correct I've checked the data sheet. Your right I did base my code on the MikroE GPS example and it has over complicated things. I not very familiar with using interrupts so I have decided to simplify my code my basing it on the code Sparky1039 provided.
Regards
-
- Posts: 11
- Joined: 19 Feb 2013 19:21
Re: UART interrupt problem
I've had the GPS module connected to RB6 the entire time because someone on this forum said that was the right one lol I'll check the oscillator frequency too. Hopefully I'll get it working now. thanksaCkO wrote:Don't feel intimidated by interrupts. Trust me, it is the right way to go. I have checked your code on real hardware and the LEDs are flashing. If you are using PIC18F45K22 are you sure you connected your GPS module on UART2 RX pin (RD7)? Also check oscillator frequency in project settings and make sure it matches with the crystal on your board.I'm pretty certain that I am getting characters from UART2 and the baud rate is correct I've checked the data sheet. Your right I did base my code on the MikroE GPS example and it has over complicated things. I not very familiar with using interrupts so I have decided to simplify my code my basing it on the code Sparky1039 provided.
Regards
Re: UART interrupt problem
It seems you have been looking at the wrong datasheet Just start from your last example with interrupts and follow the directions I posted earlier to improve your code.I've had the GPS module connected to RB6 the entire time because someone on this forum said that was the right one lol I'll check the oscillator frequency too. Hopefully I'll get it working now. thanks
Regards