|
|
View previous topic :: View next topic |
Author |
Message |
sonealx
Joined: 03 Jun 2010 Posts: 4
|
velocity meter with GPS module code help |
Posted: Wed Aug 11, 2010 7:37 pm |
|
|
I have GPS module PIC 16F877A and 2x16 lcd. I am trying to do a velocity meter. I use $GPVTG data strings from GPS signals in my code. The hardware is complete. When I give the voltage to my hardware, lcd responds lately. I think this is normal. But the lcd shows the velocity info 3-4 times, then it stops (blank screen). I thought that the problem is in the code. Here is my code:
Code: |
#include <16F877A.h>
#fuses HS,NOWDT,NOPROTECT,NOBROWNOUT,NOLVP,NOPUT,NOWRT,NODEBUG,NOCPD
#use delay (clock=20000000)
#use fast_io(b)
#define use_portb_lcd TRUE
#include<lcd.c>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#use rs232(baud=9600, xmit=PIN_c6, rcv=PIN_c7, parity=N, bits=8)
#define CR 0x0d
int comma = 0;
int dataLen;
int start, end, speedLen=0;
int i;
char speed[20];
char c[];
char charRead;
unsigned int a;
double parseData() // this function parses the $GPVTG data strings to find the speed information
{
dataLen = strlen(c);
for (i=0; i<dataLen; i++)
{
if (c[i] == ',')
comma++;
if (comma == 7)
{
i++;
start = i;
while (c[i] != ',')
{
speedLen++;
i++;
}
end = i-1;
break;
}
}
for (i=start; i<=end; i++)
{
speed[i-start] = c[i];
}
speed[i] = '\0';
return atof(speed);
}
#int_rda //Serial interrupt to collect gps data and detect the $GPVTG data strings
void serial_isr ()
{
charRead=getc();
while (1)
{
if(charRead == '$') /* GPS messages start with $ char */
{
a = 0;
c[a] = charRead;
do
{
charRead = getc();
if( (charRead != '\0') && (isalnum(charRead) || isspace(charRead) || ispunct(charRead)) )
{
a++;
c[a] = charRead;
}
}
while(charRead != CR);
/* By this point, a complete GPS string has been read so save it to file */
/* Append the null terminator to the string read */
c[a+1] = '\0';
if(c[3] == 'V' && c[4] == 'T' && c[5] == 'G')
{
break;
}
}
}
}
int main()
{
while(1)
{
setup_psp(PSP_DISABLED);
setup_spi(SPI_SS_DISABLED);
setup_timer_1(T1_DISABLED);
setup_timer_2(T2_DISABLED, 0, 1);
setup_adc_ports(NO_ANALOGS);
setup_adc(ADC_OFF);
setup_CCP1(CCP_OFF);
setup_CCP2(CCP_OFF);
enable_interrupts(INT_RDA);
enable_interrupts(GLOBAL);
set_tris_b(0x00);
lcd_init();
serial_isr();
lcd_send_byte(0,0x0d);
lcd_gotoxy(1,2);
printf(lcd_putc,"\f SPEED = %f",parseData());
delay_ms(1000);
}
return 0;
}
|
Can anyone tell me what is the problem with the code?? |
|
|
andrewg
Joined: 17 Aug 2005 Posts: 316 Location: Perth, Western Australia
|
|
Posted: Thu Aug 12, 2010 1:06 am |
|
|
I can see several problems:
1. You need to add "errors" to your "#use rs232".
2. You don't provide a size for your c[] array.
3. You shouldn't sit in a loop in your interrupt handler. All your handler should be doing is saving the received character into a buffer. Your mainline should be reading that buffer and doing the processing. _________________ Andrew |
|
|
ckielstra
Joined: 18 Mar 2004 Posts: 3680 Location: The Netherlands
|
|
Posted: Thu Aug 12, 2010 5:05 am |
|
|
A few other small issues: Code: | setup_psp(PSP_DISABLED);
setup_spi(SPI_SS_DISABLED);
setup_timer_1(T1_DISABLED);
setup_timer_2(T2_DISABLED, 0, 1);
setup_adc_ports(NO_ANALOGS);
setup_adc(ADC_OFF);
setup_CCP1(CCP_OFF);
setup_CCP2(CCP_OFF);
enable_interrupts(INT_RDA);
enable_interrupts(GLOBAL);
set_tris_b(0x00); | There is no need to do this initialization again and again. Save processing power by moving it out of the loop.
Code: | setup_spi(SPI_SS_DISABLED); | This is an error in the CCS code wizard and should be changed to:
One thing different in embedded programming when compared to PC programming is that in embedded environments you have no OS to return to. That is, you can remove the return value as you will never leave the main function.
Here is a serious problem. Why are you calling the interrupt handling function directly? Don't do this.
What you could do is to make it a normal function instead of an interrupt handler by removing the '#int RDA' line. |
|
|
Douglas Kennedy
Joined: 07 Sep 2003 Posts: 755 Location: Florida
|
|
Posted: Thu Aug 12, 2010 6:57 am |
|
|
Well inside your isr you call getc more than once. The way the interrupt works is that it is called whenever and only whenever a char has been received. The hardware is capable of having the last and current character in its buffer but this is not guaranteed. All that is guaranteed is that at least one char is available when the interrupt triggers. If by chance two chars are available then the reading of exactly one char in your isr and then returning will cause automatically an immediate new interrupt to process the second char.
To test for a header label
like $GPVTG try something like this in your isr....
With a global flag set the flag to 1 if $ is the result of your getc
set the flag to 2 if it was 1 and G is the result of getc
set the flag to 3 if it was 2 and P is the result of getc
set the flag to 4 if it was 3 and V is the result of getc
set the flag to 5 if it was 4 and T is the result of getc
set the flag to 6 if it was 5 and G is the result of getc
If the flag is 6 then use getc to place the sentence into your buffer array.
set a global ptr to the position of your sentence in your circular buffer
When the sentence is complete set a global sentence available flag and set a global ptr to the end of your sentence and reset the global flag from 6 to 0. The next sentence will begin at this end address plus one modulo the size of your buffer.
In main you will parse the buffer knowing that your isr will interrupt and process exactly one char at a time as the char is received. The isr will be receiving the next $GPVTG
I highly highly suggest with RS232 that you always use an interrupt and a circular buffer. It is not that it can't be done another way its just that the interrupt and the circular buffer is so robust an approach that you will find it extremely reliable.
Last edited by Douglas Kennedy on Fri Aug 13, 2010 10:15 am; edited 1 time in total |
|
|
sonealx
Joined: 03 Jun 2010 Posts: 4
|
|
Posted: Thu Aug 12, 2010 7:09 am |
|
|
Thank you andrewg and ckielstra for your advice. I changed the code in your advices. but it didnt work again :( here is the changed code:
Code: | #include <16F877A.h>
#fuses HS,NOWDT,NOPROTECT,NOBROWNOUT,NOLVP,NOPUT,NOWRT,NODEBUG,NOCPD
#use delay (clock=20000000)
#use fast_io(b)
#define use_portb_lcd TRUE
#include<lcd.c>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#use rs232(baud=9600, xmit=PIN_c6, rcv=PIN_c7, parity=N, bits=8, ERRORS)
#define CR 0x0d
int comma = 0;
int dataLen;
int start, end, speedLen=0;
int i;
char speed[10];
char c[55];
char charRead;
unsigned int a;
double parseData() // this function parses the $GPVTG data strings to find the speed information
{
dataLen = strlen(c);
for (i=0; i<dataLen; i++)
{
if (c[i] == ',')
comma++;
if (comma == 7)
{
i++;
start = i;
while (c[i] != ',')
{
speedLen++;
i++;
}
end = i-1;
break;
}
}
for (i=start; i<=end; i++)
{
speed[i-start] = c[i];
}
speed[i] = '\0';
return atof(speed);
}
//#int_rda //Serial interrupt to collect gps data
void serial_isr ()
{
charRead=getc();
}
int main()
{
setup_psp(PSP_DISABLED);
setup_spi(FALSE);
setup_timer_1(T1_DISABLED);
setup_timer_2(T2_DISABLED, 0, 1);
setup_adc_ports(NO_ANALOGS);
setup_adc(ADC_OFF);
setup_CCP1(CCP_OFF);
setup_CCP2(CCP_OFF);
// enable_interrupts(INT_RDA);
// enable_interrupts(GLOBAL);
set_tris_b(0x00);
while(1)
{
lcd_init();
serial_isr();
while (1)
{
if(charRead == '$') /* GPS messages start with $ char */
{
a = 0;
c[a] = charRead;
do
{
charRead = getc();
if( (charRead != '\0') && (isalnum(charRead) || isspace(charRead) || ispunct(charRead)) )
{
a++;
c[a] = charRead;
}
}
while(charRead != CR);
/* By this point, a complete GPS string has been read so save it to file */
/* Append the null terminator to the string read */
c[a+1] = '\0';
if(c[3] == 'V' && c[4] == 'T' && c[5] == 'G')
{
break;
}
}
}
lcd_send_byte(0,0x0d);
lcd_gotoxy(1,2);
printf(lcd_putc,"\f HIZ = %f",parseData());
delay_ms(1000);
}
//return 0;
}
|
|
|
|
andrewg
Joined: 17 Aug 2005 Posts: 316 Location: Perth, Western Australia
|
|
Posted: Fri Aug 13, 2010 9:25 am |
|
|
The post from Douglas Kennedy is good except I'd change it a little so that when the flag gets to 6, it starts counting commas, i.e.
set the flag to 7 if it was 6 and , is the result of getc
set the flag to 8 if it was 7 and , is the result of getc
etc
then when you get to the 7th comma:
if the flag is 14 then add the getc characters to your c[] array
if the flag is 15 then set "c array is ready flag"
In your mainline, check the flag, parse and display it, then clear the flag.
Also, make sure your code never accesses past the end of the c[] array, eg c[55], c[56], etc. Add checks to the index variable to ensure that. _________________ Andrew |
|
|
andrewg
Joined: 17 Aug 2005 Posts: 316 Location: Perth, Western Australia
|
|
Posted: Fri Aug 13, 2010 9:33 pm |
|
|
In general, using a circular buffer and simply having the serial ISR put stuff into that buffer is the way to go. CCS include many examples with their compiler and the relevant one in this case is "EX_SISR.C".
The idea is that the serial interrupt handler should be as simple as possible. However, my suggestion was that you can actually perform some simple processing in the interrupt handler using a flag to keep track of where you're up to and only save the velocity field into your buffer for display.
Also, while it isn't important for such a simple task as what you're doing, generally floating point is avoided as much as possible. Floating point is slow and takes up lots of valuable code space.
In fact, for your project the simplest solution is not to parse the velocity data at all but simply copy the velocity field text to a buffer, then copy that text to the display. _________________ Andrew |
|
|
sonealx
Joined: 03 Jun 2010 Posts: 4
|
|
Posted: Sat Aug 14, 2010 6:37 am |
|
|
thank you for helping. But i still dont know how to put the info in a circular buffer after gateflag.i tried some code and CCS didn't happen an error. Do you think that are they true for isr part and in main program part?? if not, can you help me to correct it?? here is the code : Code: |
#include <16F877A.h>
#fuses HS,NOWDT,NOPROTECT,NOBROWNOUT,NOLVP,NOPUT,NOWRT,NODEBUG,NOCPD
#use delay (clock=20000000)
#use fast_io(b)
#define use_portb_lcd TRUE
#include<lcd.c>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#use rs232(baud=9600, xmit=PIN_c6, rcv=PIN_c7, parity=N, bits=8, ERRORS)
#define CR 0x0d
#if __device__ ==77
#device *=16
#define BUFFER_SIZE 96
#else
#define BUFFER_SIZE 40
#endif
byte gps_buff[BUFFER_SIZE]; // implemented as a circular buffer
int gateflag;
short int sentence;
int next_gps_ptr=0,last_read_ptr=0,offset=0,temp;
int comma = 0;
int dataLen;
int start, end, speedLen=0;
int i;
char speed[10];
char c[];
char charRead;
unsigned int a;
double parseData() // this function parses the $GPVTG data strings to find the speed information
{
dataLen = strlen(c);
for (i=0; i<dataLen; i++)
{
if (c[i] == ',')
comma++;
if (comma == 7)
{
i++;
start = i;
while (c[i] != ',')
{
speedLen++;
i++;
}
end = i-1;
break;
}
}
for (i=start; i<=end; i++)
{
speed[i-start] = c[i];
}
speed[i] = '\0';
return atof(speed);
}
#int_rda //Serial interrupt to collect gps data and detect the $GPVTG data strings
void serial_isr ()
{
charRead=getc();
if( (charRead=='$') && (gateflag==0)) gateflag=1;
if( (charRead=='G') && (gateflag==1)) gateflag=2;
if( (charRead=='P') && (gateflag==2)) gateflag=3;
if( (charRead=='V') && (gateflag==3)) gateflag=4;
if( (charRead=='T') && (gateflag==4)) gateflag=5;
if( (charRead=='G') && (gateflag==5)) gateflag=6;
if (gateflag==6) sentence=true;
if(sentence){
gps_buff[next_gps_ptr]=charRead;
if (++next_gps_ptr>sizeof(gps_buff)) next_gps_ptr=0; // circular buffer
if((charRead==10)||(charRead==13)) {sentence=false;}
}
}
int main()
{
setup_psp(PSP_DISABLED);
setup_spi(FALSE);
setup_timer_1(T1_DISABLED);
setup_timer_2(T2_DISABLED, 0, 1);
setup_adc_ports(NO_ANALOGS);
setup_adc(ADC_OFF);
setup_CCP1(CCP_OFF);
setup_CCP2(CCP_OFF);
enable_interrupts(INT_RDA);
enable_interrupts(GLOBAL);
set_tris_b(0x00); // B portunun hepsi çıkış olarak ayarlandı
while(1)
{
lcd_init(); // lcd yi hazır hale getir
while (1)
{
if(charRead == '$') /* GPS messages start with $ char */
{
a = 0;
c[a] = charRead;
do
{
charRead = getc();
if( (charRead != '\0') && (isalnum(charRead) || isspace(charRead) || ispunct(charRead)) )
{
a++;
c[a] = charRead;
}
}
while(charRead != '*');
/* By this point, a complete GPS string has been read so save it to file */
/* Append the null terminator to the string read */
c[a+1] = '\0';
if(c[3] == 'V' && c[4] == 'T' && c[5] == 'G')
{
break;
}
}
}
lcd_send_byte(0,0x0d);
lcd_gotoxy(1,2);
printf(lcd_putc,"\f HIZ = %f",parseData()); // %d x tam sayı olduğu için
delay_ms(1000);
}
return 0;
}
|
thank you.. |
|
|
Douglas Kennedy
Joined: 07 Sep 2003 Posts: 755 Location: Florida
|
|
Posted: Sat Aug 14, 2010 9:51 am |
|
|
With respect you may lack the basic expertise to complete a project like this.
I PM'd you with some of the code you are now cutting and pasting.
Many are disappointed when they cut and paste code and with hope alone expect it to work. Many feel they are just one element of advice or one line of code away from success. Reality is that for all but the most basic things a real understanding is required. Rarely is the loudness of a cry for help or the frequency of the cry sufficient to create success. Success often requires starting small such that a foundation is built that enables greater things to be done. To write a book you must first learn the language in which it is to be written. |
|
|
bkamen
Joined: 07 Jan 2004 Posts: 1615 Location: Central Illinois, USA
|
|
Posted: Sat Aug 14, 2010 10:14 am |
|
|
Douglas Kennedy wrote: | With respect you may lack the basic expertise to complete a project like this.
I PM'd you with some of the code you are now cutting and pasting.
|
A mentor of mine in my teen years (outside of highschool but my one of my best teachers ever) used to bark incessantly to us learning from him, "Get you $h1t straight"... meaning "do your homework".
There's a lot of posts here that give me the impression that proper research has not been done on a somewhat grand scale. (I know I sometimes forget to look at the errata sheets when I'm first troubleshooting a bug and someone helps me out...)
But these are more basic (and in some senses a little scarier) than that.
Quote: |
Many are disappointed when they cut and paste code and with hope alone expect it to work. Many feel they are just one element of advice or one line of code away from success. Reality is that for all but the most basic things a real understanding is required. Rarely is the loudness of a cry for help or the frequency of the cry sufficient to create success. Success often requires starting small such that a foundation is built that enables greater things to be done. To write a book you must first learn the language in which it is to be written. |
Amen. _________________ Dazed and confused? I don't think so. Just "plain lost" will do. :D |
|
|
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum
|
Powered by phpBB © 2001, 2005 phpBB Group
|