|
|
View previous topic :: View next topic |
Author |
Message |
dream10101tysh
Joined: 17 Apr 2013 Posts: 3
|
RDA_isr() failed to re-enabled |
Posted: Wed Aug 27, 2014 6:54 am |
|
|
Hello,
I use a pic18f458 to receive GPS NMEA data, since it takes a period of time to solve the packet in while-loop, the RDA_isr() is disabled whenever the buffer is full. It is until the packet solved, while-loop re-enables the RDA_isr(). But, according to the test, I just get the first packet and solved. Never receiving the others. I guess the problem is that the RDA_isr is not in service anymore. But, how can I re-enable it successfully?
Thank you.
Code: | #include <18f458.h>
#include <stdlib.h>
#fuses HS,WDT1
#use delay(clock = 20000000)
#use rs232(baud = 9600, xmit = PIN_C6, rcv = PIN_C7)
#define Length 128
int8 gpsMTK1[Length],gMTK1_i=0,len=0,tmp_MTK1[3]={0,0,0},RDA_buf=0;
int8 flg_MTK1=0,data_MTK1=0,no_MTK1=0;
int8 time_hh[2],time_mm[2],time_ss[2];
int8 Latd_MTK1[20],Latm_MTK1[20],Lond_MTK1[20],Lonm_MTK1[20];
int8 n;
#INT_RDA
void RDA_isr(void)
{
if(RDA_buf == 0)
{
gpsMTK1[len] = getc();
len++;
if(len >= 128)
{
RDA_buf = 1;
printf("%c",'Q');
len = 0;
disable_interrupts(INT_RDA);
disable_interrupts(GLOBAL);
}
}
}
void main()
{
for(n=0;n<128;n++) gpsMTK1[n]=0;
enable_interrupts(INT_RDA);
enable_interrupts(GLOBAL);
while(TRUE)
{
if(RDA_buf == 1)
{
for(gMTK1_i = 0 ; gMTK1_i < Length ; gMTK1_i++)
{
tmp_MTK1[0] = tmp_MTK1[1];
tmp_MTK1[1] = tmp_MTK1[2];
tmp_MTK1[2] = gpsMTK1[gMTK1_i];
if(tmp_MTK1[0]=='G' && tmp_MTK1[1]=='A' && tmp_MTK1[2]==',')
{
flg_MTK1 = 1;
data_MTK1 = 0;
no_MTK1 = 0;
}
else if(tmp_MTK1[2]!='*' && flg_MTK1==1)
{
if(tmp_MTK1[2]!=',')
{
if(data_MTK1 == 0)
{
if(no_MTK1<=1) time_hh[no_MTK1] = tmp_MTK1[2];
else if(no_MTK1>=2 && no_MTK1<=3) time_mm[no_MTK1-2] = tmp_MTK1[2];
else if(no_MTK1>=4 && no_MTK1<=5) time_ss[no_MTK1-4] = tmp_MTK1[2];
}
else if(data_MTK1 == 1)
{
if(no_MTK1<=1) Latd_MTK1[no_MTK1] = tmp_MTK1[2];
else if(no_MTK1>=2 && no_MTK1<=9) Latm_MTK1[no_MTK1-2] = tmp_MTK1[2];
}
else if(data_MTK1 == 3)
{
if(no_MTK1 <= 2) Lond_MTK1[no_MTK1] = tmp_MTK1[2];
else if(no_MTK1>=3 && no_MTK1<=9) Lonm_MTK1[no_MTK1-3] = tmp_MTK1[2];
}
no_MTK1++;
}
else
{
no_MTK1 = 0;
data_MTK1++ ;
}
} // else if(tmp_MTK1[2]!='*' && flg_MTK1==1)
} // for-loop
RDA_buf = 0;
flg_MTK1 = 0;
enable_interrupts(INT_RDA);
enable_interrupts(GLOBAL);
printf("%c",'P');
} //if(RDA_buf == 1)
} // while-loop
} // void main()
|
|
|
|
temtronic
Joined: 01 Jul 2010 Posts: 9245 Location: Greensville,Ontario
|
|
Posted: Wed Aug 27, 2014 7:44 am |
|
|
couple of points..
1) it is NEVER a good idea to have a printf(..) inside any ISR..
2) CCS disables the called ISR, so you don't have to...
3)Do you get the 'P' printed out just after the enable ISRs ????
if not,then I think your if..loops might be wrong.
A quick easy test would be to just collect the 128 bytes of data,maybe send them to the PC. Forget about the 'parsing' algorithms until you call receive and display the GPS data string.
It's easier to debug smaller programs !
hth
jay |
|
|
ezflyr
Joined: 25 Oct 2010 Posts: 1019 Location: Tewksbury, MA
|
|
Posted: Wed Aug 27, 2014 7:47 am |
|
|
hi,
The *best* answer is to never disable the int_rda interrupt! Instead, use a interrupt driven circular buffer to receive the NMEA data from the GPS. This technique is illustrated in example program 'ex_sisr.c'.
You also need to add 'Errors' to your #use rs232 declaration. At the moment, it is likely that your hardware UART is overflowing before you have a chance to diasble it, and is locking up. That is why you only receive the 1st NMEA sentence, and then nothing more.
Again, your method is a bit flawed, so check out that example program I mentioned!
John |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19546
|
|
Posted: Thu Aug 28, 2014 12:51 am |
|
|
As an 'add on' to what has already been said, if you absolutely 'must' use the current approach (though it is very much 'not' the way to do things...), the safe way to work, is to set a single bit flag, when you want the data to be ignored, and in the ISR, simply read the character, then if the flag is set 'throw it away'.
The key problem is to understand that the interrupt says 'there is a character waiting, that wants to be read'. Disabling the interrupt stops this read being done, and after just one more character arrives, the UART will go into a 'locked' error state. Since you have nothing to handle this error, the UART will remain locked for ever (ERRORS adds code to clear this).
However then think. This implies characters have been missed. These are lost for ever....
Look in the code library, there is a complete GPS parser there. |
|
|
dream10101tysh
Joined: 17 Apr 2013 Posts: 3
|
|
Posted: Sat Sep 06, 2014 4:52 pm |
|
|
Thanks to all, I try to correct the code with circular buffer, while I don't know why the PIC only display "MDD",and nothing more. Here is my guess:
The "buffer" is filled fully and can not be put into "gpsMTK[len]" respectively. Maybe the RDA_isr() is too frequently that the while loop is not able to complete. But in that case the RDA_buf is always in "1", therefore, RDA_isr() service time is short. I must be able to complete my while-loop and make the RDA_buf=0 at least one time? Why not?
Since I want to retain my main algorithm to solve GPS data, then I use " buffer[BUFFER_SIZE],gpsMTK[BUFFER_SIZE]" in the code. BUFFER_SIZE is 128. Is that the problem? Loading is too heavy?
THANK YOU
Code: | #INT_RDA
void RDA_isr(void)
{
if(RDA_buf == 0)
{
int8 t;
buffer[next_in] = getc();
if(++next_in == BUFFER_SIZE)
{
next_in = 0;
RDA_buf = 1;
}
}
}
int8 bgetc(void)
{
int8 c;
c = buffer[next_out];
next_out = (next_out+1) % BUFFER_SIZE;
printf("%c",'D');
return(c);
}
void main()
{
for(n=0 ; n<BUFFER_SIZE ; n++)
{
buffer[n]=0;
gpsMTK[n]=0;
}
enable_interrupts(INT_RDA);
enable_interrupts(GLOBAL);
while(TRUE)
{
if(RDA_buf == 1)
{ printf("%c",'M');
for(len =0 ; len < BUFFER_SIZE ; len++) gpsMTK[len] = bgetc();
for(gMTK_i = 0 ; gMTK_i < BUFFER_SIZE ; gMTK_i++)
{
tmp_MTK[0] = tmp_MTK[1];
tmp_MTK[1] = tmp_MTK[2];
tmp_MTK[2] = gpsMTK[gMTK_i];
....} RDA_buf = 0; |
|
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19546
|
|
Posted: Sun Sep 07, 2014 12:24 am |
|
|
One simple thing.
The RDA interrupt _must_ always read the character. Otherwise it'll never exit.
Code: |
#INT_RDA
void RDA_isr(void)
{
int8 temp;
temp=getc();
if(RDA_buf == 0)
{
buffer[next_in] = temp;
if(++next_in == BUFFER_SIZE)
{
next_in = 0;
RDA_buf = 1;
}
}
}
|
Note that the actual 'read' always occurs. It _has to_. The RDA interrupt says 'there is a character waiting to be read'. If you exit, without reading this, the interrupt will trigger again immediately, since there is still a 'character waiting to be read'. |
|
|
ezflyr
Joined: 25 Oct 2010 Posts: 1019 Location: Tewksbury, MA
|
|
Posted: Sun Sep 07, 2014 2:21 pm |
|
|
Hi,
You've also modified the example program to get rid of the 'bkbhit' functionality, and thus you are calling 'bgetc' regardless of whether a new character has been placed in the buffer or not.....
'Ex_sisr.c' works, so I recommend not straying too far from it!
John |
|
|
|
|
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
|