|
|
View previous topic :: View next topic |
Author |
Message |
ferkar
Joined: 14 Jul 2007 Posts: 38
|
gets() does not work proper in interrupt!!! |
Posted: Wed Jul 14, 2010 1:07 am |
|
|
hi everbody,
i am trying to make communicate a 18f452 and PC(visual basic).
at PC side,(by using command button)
mscomm1.output = set+","set2+","+set3+","+";"+chr(13)
at pic side to receive and seperate data(which were seperated by commas)
gets(string); // string[10]
strcpy(term,",;");
ptr = strtok(string, term);
while(ptr!=0) {
receive_buffer(ptr); // *ptr , receive buffer[10]
ptr = strtok(0, term);
i++; // i int8
}
my problem is that:
the above code is working well in main(). however, i would like to get the serial data in interrupt routine. in this case the code works only once or twice.!!!
i did not know how to deal with it.
thanks in advance... |
|
|
FvM
Joined: 27 Aug 2008 Posts: 2337 Location: Germany
|
|
Posted: Wed Jul 14, 2010 1:24 am |
|
|
gets() is waiting for data until the terminating character, it's absolutely unsuitable for interrupt usage.
A reasonable way to achieve what you intend is to write the received serial data to a buffer during interrupt and process the buffer in the main() loop. A ring buffer involving two pointers is the most versatile way. There are geenric examples for buffered UART receive shipped with CCS C, I hope. At least, buffered UART is used with the MODBUS examples. Personally, I use to write it from the scratch, so I don't care much for the examples. |
|
|
ferkar
Joined: 14 Jul 2007 Posts: 38
|
|
Posted: Wed Jul 14, 2010 1:44 am |
|
|
strtok() command seperate the data
and chr(13) is terminating character.
therefore it should work i think... |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19506
|
|
Posted: Wed Jul 14, 2010 3:58 am |
|
|
You need to understand a basic point.
The serial interrupt means that _just one_ character is waiting.
gets, waits for an entire string to arrive.
If you call gets, in an interrupt, the code _will_ be hung inside the interrupt, till the whole string arrives.
This has been covered many hundreds of times here in the forum.
ex_sisr.c, shows how to use serial interrupts to store characters into a buffer.
As a sort of 'semi example', I'm posting a set of code (untested - as typed), to put characters into a buffer like ex_sisr, but add the following features:
1) Handle the buffer maths efficiently, if buffer size is not a binary multiple - a fault in ex_sisr.
2) Offer a 'bgetline' function to get a complete CR terminated line from the buffer.
3) Offer a 'line_waiting' test, to say that a CR terminated line has been received.
There are 'caveats' with it, but with care, it should provide a starting point.
Code: |
////For whatever chip you want....
#include <16f877A.h>
#fuses HS, NOLVP, NOWDT, PUT
#use delay (clock = 20000000)
#use rs232(baud=9600, Bits=8, Parity=N, xmit=PIN_C6, rcv=PIN_C7, ERRORS)
////
//Buffer definitions
#define CR (13)
int8 CR_seen=0;
int1 Overflow=FALSE; //Logic flags for serial handling
#define BUFFER_SIZE 32 //Change this to alter the buffer size
char buffer[BUFFER_SIZE];
int next_in = 0; //Max 255 chars with int here - change if larger needed
int next_out = 0;
#int_rda
void serial_isr(void) {
int temp;
temp=getc();
buffer[next_in]=temp;
if (temp==CR) CR_seen++; //flag if a carriage return
temp=next_in;
if (++next_in==(BUFFER_SIZE)) next_in=0;
if(next_in==next_out) {
next_in=temp; //Buffer overflow
Overflow=TRUE;
}
}
#define bkbhit() (next_in!=next_out) //True is character waiting to be read
#define line_waiting() (CR_seen) //True if _line_ waiting to be read
char bgetc() { //Get single char from buffer - wait if one not ready
char c;
while(!bkbhit()) ;
c=buffer[next_out++];
if (next_out==BUFFER_SIZE) next_out=0;
if ((c==CR)&&(CR_seen>0)) CR_seen--; //If I read a carriage return from buffer
return(c);
}
int1 bgetline(char * str, int MAX) { //Routine to get a line from buffer - returns false if no line...
//MAX is the maximum number of characters to return
int8 ctr;
int8 temp;
MAX--; //make space for null terminator
if (!line_waiting()) {
*str=0; //terminate null string
return 0;
}
for (ctr=0;ctr<MAX;ctr++) {
if ((temp=bgetc())==CR) { //This will give a compiler warning, but is correct.....
*str=0;
return ctr; //Null terminate and exit
}
*(str++)=temp;
}
if (buffer[next_out] == CR) bgetc(); //dump a character if next is CR
*str=0;
return ctr;
} //Returns the number of characters in the 'line'
void main (void) {
int16 dummy;
char line[20];
char chr;
while (TRUE) { //sit looping doing something.....
delay_ms(100);
dummy++;
printf("%ld/n/r",dummy);
//Only use _one_ of the following at a time.
//Now you can test if a character is waiting, and get it like:
if (bkbhit()) chr=bgetc();
//Or wait for a line with:
if (line_waiting()) {
bgetline(line,20);
//here have a line to process
}
//or get a line with:
if (bgetline(line,20)) {
//Here I have a line to process - since bgetline only returns 'true'
//if a line was retrieved.
}
//Now, _caveats_. The code keeps a count of carriage return characters read
//if the buffer overflows, data _will_ be thrown away. If this happens the
//count may become wrong - need to ensure, that either the buffer _is_ big
//enough, or this is handled, by checking the 'overflow' flag....
//Second, the bgetline will return with a line, if the count of characters
//exceeds 'MAX', even if this is not a complete 'line' from the code.
//You need to ensure that the length of the storage is greater than the
//maximum line length you expect (+1), otherwise line parsing will
//become hard.....
}
}
|
Best Wishes |
|
|
|
|
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
|