|
|
View previous topic :: View next topic |
Author |
Message |
pattousai
Joined: 23 Aug 2006 Posts: 37
|
help to understand what is going on in #int_rda code |
Posted: Thu Jul 10, 2008 8:03 pm |
|
|
hi everybody!
First, i will tell what i want to do.
I have a modem connected to a PIC and the receiving sms are routed directly to the terminal, so, when the modem receive a sms, it will send to the pic something like:
+CMT: "08488471617",,"08/07/10,14:43:31-140"
config1=0 config2=20 config3=5,5
what i want to do is extract the numbers.
ok, but i wrote a simple code to just get the string received and print them to a 'debug stream'. the code is:
Code: |
#include <16f628a.h>
#fuses HS, NOMCLR, NOWDT, NOLVP
#use delay(clock=17287200)
#use rs232(baud=9600, xmit=PIN_B2, rcv=PIN_B1, stream=GSM) //hardware usart
#use rs232(baud=9600, xmit=PIN_B3, rcv=PIN_B0, stream=PC)
char msg[80];
char c;
int1 flag1 = true;
#int_rda
void interrupcao_serial()
{
output_high(PIN_A2);
fgets(msg, GSM);
fprintf(PC, "%s", msg)
output_low(PIN_A2);
}
void main()
{
enable_interrupts(GLOBAL);
enable_interrupts(INT_RDA);
fprintf(PC, "Starting the program\r\n");
fprintf(GSM, "AT+CNMI=3,2\r\n");
delay_ms(3000);
while(1){
if( input(PIN_B4) && flag1 ){
fprintf( GSM, "AT\r\n" );
delay_ms(3000);
flag1 = false;
}
if( !input(PIN_B4) && !flag1 ){
flag1 = true;
}
}
}
|
well, once this code enter in the #int_rda, the led in PIN_A2 just don't go off, i.e., the program don't leave the interrupt and just can't do anything else (obviously), but the message is sent to the PC. I tried to turn on another LED between the fprintf and the output_low(PIN_A2), and the led turned on, but the PIN_A2 justn't go off and i really don't understand why
i tried the get_string instead gets and result in the same way. also tried to put "\r\n" (just "\r", just "\n") in the fprintf(PC...) but with no changes
well, that's it... i would like some help to understand what is going on
also... if anyone want to suggest a way to do what i want (described in the begging of the post) i would really appreciate (i wonder how is the best way to catch exactly the numbers)
ops, i almost forgot, i'm using the 4.057 compiler
thanks everybody. |
|
|
Ttelmah Guest
|
|
Posted: Fri Jul 11, 2008 3:00 am |
|
|
Do a search here about interrupts.
General comment, _unless you know -exactly- what the implications are, always ensure that interrupts can be handled in the time 'between' events_.
In your case, there are two big problems. The interrupt triggering, implies there is just _one_ character waiting to receive. You then go and call 'gets', which will sit wait, for an entire _string_ to arrive. Having done this, you then call a print, which will take as long to send the string, as it took to arrive, and for the entire time, any characters arriving _will_be missed.
This sort of handling error, is probably the commonest single posting cause here!.
Now, as a 'example', I'll post a basic interrupt based 'fetch string' approach, which hopefully will get you going.
Code: |
#include <16f628a.h>
#device *=16
#fuses HS, NOMCLR, NOWDT, NOLVP
#use delay(clock=17287200)
#use rs232(baud=9600, xmit=PIN_B2, rcv=PIN_B1, stream=GSM) //hardware usart
#use rs232(baud=9600, xmit=PIN_B3, rcv=PIN_B0, stream=PC)
#define MESSAGE_LENGTH (80)
int buffer_in_use=0;
char message[2][MESSAGE_LENGTH];
int1 message_available=false;
#int_rda
void serial_gets_isr(void) {
char temp_chr;
static int input_locn=0;
output_high(PIN_A2);
temp_chr=fgetc(GSM); //receive the _one_ character
message[buffer_in_use][input_locn++]=temp_chr; //add it to the buffer
if (input_locn>(MESSAGE_LENGTH-1)) input_locn=MESSAGE_LENGTH-1;
//If more than 'buffer' characters arrive, the data will be clipped at the
//size of the buffer.
if (temp_chr=='\n' || temp_chr=='\r' || temp_chr=='\0') {
message_available=true;
message[buffer_in_use][input_locn]='\0'; //null terminate the string
buffer_in_use^=1;
input_locn=0;
}
output_low(PIN_A2);
}
void main()
{
int8 key_ctr=0;
int8 buffer_not_in_use;
enable_interrupts(GLOBAL);
enable_interrupts(INT_RDA);
fprintf(PC, "Starting the program\r\n");
fprintf(GSM, "AT+CNMI=3,2\r\n");
//No delays needed
while(1){
if( input(PIN_B4) ) {
if (++key_ctr >= 4) {
//ensure key is pressed for four loops
fprintf( GSM, "AT\r\n" );
}
}
else {
key_ctr=0;
}
if (message_received) {
//Now, the whole message, is sitting in the buffer 'not' in use
message_received=false; //must clear this ASAP
buffer_not_in_use=buffer_in_use^1; //select the buffer
printf(PC,"%s",&message[buffer_not_in_use][0]);
//print the received message
//Though this may take absolutely 'ages', any arriving characters
//will be stored in the 'other' buffer, while this happens.
//This will only go 'wrong', if two messages arrive in the time it
//takes to printout the first.
//Consider increasing the baud rate on the software RS232 to the
/PC, to minimise this problem...
}
}
}
|
This is 'untried' code (just typed it here), but should be pretty close to right. Basically, I have allocated two receive buffers. The interrupt toggles your 'A2' line for every character received, and then sets a 'message received' flag, when it sees a terminating character (line feed, carriage return, or a binary '0'). It immediately starts writing new characters to the _other_ buffer. Your 'main', gets rid of all delays, and sits looping quickly, testing the input bit, and checking the 'received' flag. When a message is received, it prints it out (from the first buffer). To debounce the input, without delays, I require the line to go 'high' for 4 loops.
Hope you get the idea.
Best Wishes |
|
|
pattousai
Joined: 23 Aug 2006 Posts: 37
|
|
Posted: Fri Jul 11, 2008 1:03 pm |
|
|
thanks for the help, i will try this aprox right away.
Quote: |
//Though this may take absolutely 'ages', any arriving characters
//will be stored in the 'other' buffer, while this happens.
//This will only go 'wrong', if two messages arrive in the time it
//takes to printout the first.
//Consider increasing the baud rate on the software RS232 to the
/PC, to minimise this problem...
|
Well, the print to the PC it's just a test, what i will do is take this incoming string (something like: config1=10 config2=20 config3=30) and extract the numbers (10, 20, 30).
I'm thinking in using tokens to get just config1=10, config2=20 and config3=30, and then check the first 'n' characters. if then are really configx= i will get the other part of the string and put them into a local variable.
So... you think this will take much longer? it seems to me that yes...
thanks again |
|
|
Ttelmah Guest
|
|
Posted: Fri Jul 11, 2008 1:36 pm |
|
|
The 'print', takes basically just on 1mSec/character. If you have a 60 character string, about 60mSec. Copying a number out of the incoming buffer, takes only perhaps a uSec. You can perform something like 4 floating point divisions (normally considered to be a really 'slow' operation), in the time needed to print just one character!....
Serial is _slow_.
Best Wishes |
|
|
pattousai
Joined: 23 Aug 2006 Posts: 37
|
|
Posted: Fri Jul 11, 2008 1:49 pm |
|
|
ok, thanks very much, this really help to put somethings in 'perspective' |
|
|
|
|
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
|