View previous topic :: View next topic |
Author |
Message |
Guest
|
rs232 buffer full |
Posted: Sat Sep 09, 2006 11:51 am |
|
|
I have a gps in a com port.
After i received a sentence i stop the rca interrupt to make some calculations and then go back again to main program and enable the rca interrupt.
The problem is because in the time i was making the debug the buffer is full and then when i go back to the main i need to clear the rx buffer.
What is the best way to do this?
thanks |
|
|
Ttelmah Guest
|
|
Posted: Sat Sep 09, 2006 2:34 pm |
|
|
Code: |
while (kbhit()) getc();
enable_interrupts(INT_RDA);
|
You _must_ have the 'errors' statement in your RS232 setup, which will clear the 'overrun' error status bit, when getc is called (otherwise the UART will remain disabled if this is set).
Use the 'fgetc', and 'kbhit(stream)' functions, if you have more than one serial stream.
Best Wishes |
|
|
Douglas Kennedy
Joined: 07 Sep 2003 Posts: 755 Location: Florida
|
|
Posted: Sun Sep 10, 2006 5:30 am |
|
|
This issue comes up often. You will most very likely need a software circular buffer fed by an #NT RDA interrupt service routine (isr).
Do very little other work inside the isr. If the pic cycle time is fast compared to the time to receive a char from your GPS then you can have code ( in the isr) to reject certain sentences from getting into your circular buffer but be very very frugal inside an isr. In your main code read from the circular buffer and do all the parsing of the sentences. Almost any other approach will bring frustration as GPS data is missed. |
|
|
Guest
|
|
Posted: Sun Sep 10, 2006 1:19 pm |
|
|
Both are a good help.
Ttelmah is the answer for my question but i make a search about circular buffer and i see that it is a good way to not loose any data.
but how can i do it?
imagine that i read data from the gps, send to the buffer and then send to the pc the complete sentence.
i see some posts about circular buffers but i dont know what to do...
I understand interrupt function but i dont understand how to treat the circular buffer...
any help?
thanks |
|
|
Douglas Kennedy
Joined: 07 Sep 2003 Posts: 755 Location: Florida
|
|
Posted: Sun Sep 10, 2006 5:38 pm |
|
|
This is not a complete program but you will see there is a circular buffer gps_buff. Two pointers to the buffer are maintained one is the next available position for a char from the GPS to occupy and the other is the last char the main program read. The buffer is said to be circular because when the gps fills the last slot it rolls over and starts from the first slot.
Now of course your code should be reading fast enough to keep the GPS from getting a head and writing over chars your main program hasn't yet read. Buffer size of 64 should be adequate
The getc() you may be familiar with is replaced by gps_getc() for the purpose of the main program getting chars from the gps_buff.
I can't recommend more strongly the lessons learned by hacking through these issues yourself. The sentence filter is removed from the isr. It could be a good exercise to add your own if you need it.
This code was modified from PCM programmers example of a circular buffer that I found very informative several years back. I've included a structure since they are both descriptive and useful in reducing possible confusion of the position of the terms in GPS sentences. The code originally read from the GPS several different sentences and extracted and converted the info into the structure you see below
Code: | struct {
/// status 'A' ok 'V' gps has problem (Ex.loss of signal ) 'X' invalid period
char gll_status;
float gll_lat;
char gll_N_S;
float gll_long;
char gll_E_W;
char xte_status;
float xte_error;
char xte_steer;
char bwc_status;
char bwc_utc[6];
float bwc_lat;
char bwc_N_S;
float bwc_long;
char bwc_E_W;
float bwc_bearing_true;
float bwc_bearing_mag;
float bwc_dist;
} gps; // note a one byte CRC is appended upon transmission
// gps is sent plus a CRC by the isr
short int led2_flag,sentence,PARSING;
byte seconds=0,int_count=0,I2C_CRC=0,GPS_CRC=0;
byte gps_buff[BUFFER_SIZE]; // implemented as a circular buffer
int next_gps_ptr=0,last_read_ptr=0,offset=0,temp;
#int_rda
void gps_isr()
{
char c;
/// will only allow $GPXTE and $GPGLL and $GPBWC data into gps_buff
/// filter will screen $GPXT $GPGL $GPBW
/// note this routine needs to as short as possible since it is called
/// for each char received from GPS
c=getc() ; // get data
if (c=='$') { sentence=true;output_low(LED1);return;} // new sentence
if(sentence){
gps_buff[next_gps_ptr]=c;
if (++next_gps_ptr>sizeof(gps_buff)) next_gps_ptr=0; // circular buffer
if((c==10)||(c==13)) {sentence=false;output_high(LED1);}
}
}
int gps_getc()
{
char c;
int next_char_ptr;
next_char_ptr=last_read_ptr+1;
if (next_char_ptr>sizeof(gps_buff))next_char_ptr=0;
// there is data available if next_gps_ptr != next_char_ptr
wait: // data from gps will allow isr to update gps_ptr
if (next_gps_ptr == next_char_ptr) goto wait; // let gps advance
else {
c=gps_buff[next_char_ptr];
if(c=='*')PARSING=false; // PARSING is reset in main loop
last_read_ptr=next_char_ptr;
if (PARSING) GPS_CRC=GPS_CRC ^ c; // calc between $ and *
}
return(c);
} |
|
|
|
|