CCS C Software and Maintenance Offers
FAQFAQ   FAQForum Help   FAQOfficial CCS Support   SearchSearch  RegisterRegister 

ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

CCS does not monitor this forum on a regular basis.

Please do not post bug reports on this forum. Send them to CCS Technical Support

velocity meter with GPS module code help

 
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion
View previous topic :: View next topic  
Author Message
sonealx



Joined: 03 Jun 2010
Posts: 4

View user's profile Send private message

velocity meter with GPS module code help
PostPosted: Wed Aug 11, 2010 7:37 pm     Reply with quote

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

View user's profile Send private message Visit poster's website

PostPosted: Thu Aug 12, 2010 1:06 am     Reply with quote

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

View user's profile Send private message

PostPosted: Thu Aug 12, 2010 5:05 am     Reply with quote

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:
Code:
setup_spi(FALSE);


Code:
return 0;
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.

Code:
               serial_isr();
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

View user's profile Send private message AIM Address

PostPosted: Thu Aug 12, 2010 6:57 am     Reply with quote

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

View user's profile Send private message

PostPosted: Thu Aug 12, 2010 7:09 am     Reply with quote

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

View user's profile Send private message Visit poster's website

PostPosted: Fri Aug 13, 2010 9:25 am     Reply with quote

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

View user's profile Send private message Visit poster's website

PostPosted: Fri Aug 13, 2010 9:33 pm     Reply with quote

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

View user's profile Send private message

PostPosted: Sat Aug 14, 2010 6:37 am     Reply with quote

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

View user's profile Send private message AIM Address

PostPosted: Sat Aug 14, 2010 9:51 am     Reply with quote

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

View user's profile Send private message

PostPosted: Sat Aug 14, 2010 10:14 am     Reply with quote

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
Display posts from previous:   
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion All times are GMT - 6 Hours
Page 1 of 1

 
Jump to:  
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