View previous topic :: View next topic |
Author |
Message |
opvini
Joined: 27 Apr 2012 Posts: 50 Location: Brazil
|
Unusual problem with delay on while and serial interrupt |
Posted: Fri Apr 27, 2012 10:40 pm |
|
|
Hi guys, I have an unusual problem with the delay on while() and the serial interrupt. The code below doesn't work if the line "delay_ms()", on while(), is not commented. But if the line is commented out, the program woks fine.
I am using the PIC connected to a GSM module, and I call to it, then the serial interrupt should be work, receiving "RING".
Code: |
#include <18f452.h>
#use delay(clock=20000000)
#fuses HS
#use rs232(baud=9600, parity=N, bits=8, xmit=PIN_C6, rcv=PIN_C7)
#define use_portb_lcd true
#include <aev_lcd.c>
void intrda();
void main(){
int ct=0;
enable_interrupts( INT_RDA );
enable_interrupts( GLOBAL );
lcd_init();
printf(lcd_putc, "\fIniciado\n");
while(1){
//delay_ms(20000);
//printf(lcd_putc, "f%d", ++ct);
}
}
#INT_RDA
void intrda(){
char a;
disable_interrupts( INT_RDA );
disable_interrupts( GLOBAL );
output_high(PIN_C3);
a = getc();
printf(lcd_putc, "%c", a);
output_low(PIN_C3);
enable_interrupts( INT_RDA );
enable_interrupts( GLOBAL );
}
|
Why the program works fine without the delay on while() and doesn't work with the delay line?
Thanks!! |
|
|
Mike Walne
Joined: 19 Feb 2004 Posts: 1785 Location: Boston Spa UK
|
|
Posted: Sat Apr 28, 2012 6:13 am |
|
|
In what way does it not work?
You delay is 20 seconds.
Are you sure that you are waiting long enough for it to finish?
Mike |
|
|
Gabriel
Joined: 03 Aug 2009 Posts: 1067 Location: Panama
|
|
Posted: Sat Apr 28, 2012 6:40 am |
|
|
you are printing inside your ISR...thats probably what is causing the hangup.
as usual the general idea is to Get in and get out... _quick_
you are also missing ERRORS in your RS232 .
for hardware serial, having extra long delays should not matter...
you can have the ISR interrupt the delay function... delay is just a well timed loop....
so your problem is not the delay line...
from what i see (read it breifly) ... you are printing each character individually as soon as you get it...
i suggest you fill a buffer (circle buffer) and print that outside of the ISR....
G.- _________________ CCS PCM 5.078 & CCS PCH 5.093 |
|
|
temtronic
Joined: 01 Jul 2010 Posts: 9228 Location: Greensville,Ontario
|
|
Posted: Sat Apr 28, 2012 6:44 am |
|
|
tips...
1) never use printf(..) in an ISR
2) never control the ISRs from within an ISR
3) always add ERRORS to the use rs232(...) statement
4) always use an interrupt driven routine to rcv UART data(ie ex_sisr.c). |
|
|
andrewg
Joined: 17 Aug 2005 Posts: 316 Location: Perth, Western Australia
|
|
Posted: Sat Apr 28, 2012 7:36 am |
|
|
I second temtronic's post, except to change:
Quote: | 2) never enable GLOBAL interrupts from within an ISR |
It's OK to enable/disable specific interrupts from inside an ISR, but not GLOBAL. _________________ Andrew |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19515
|
|
Posted: Sat Apr 28, 2012 8:15 am |
|
|
andrewg wrote: | I second temtronic's post, except to change:
Quote: | 2) never enable GLOBAL interrupts from within an ISR |
It's OK to enable/disable specific interrupts from inside an ISR, but not GLOBAL. |
Spot on.
Key is to understand that the interrupt _hardware_ controls the global interrupt bit, clearing it automatically when the handler is called, and re-enabling it _after_ the code returns from the handler (This is the RETFIE instruction 'return from interrupt - enable'). Enabling _before_ the return, potentially can result in recursive calls to the handler, which the chip doesn't support - uurgh - crash.....
There is no 'point' in enabling and disabling INT_RDA, but it won't kill the code.
Best Wishes |
|
|
opvini
Joined: 27 Apr 2012 Posts: 50 Location: Brazil
|
|
Posted: Sat Apr 28, 2012 10:19 am |
|
|
Hi everbody, thanks a lot for the reply!!!
Well, I agree with everything you spoke, but I have one question yet. Well, why can't I get all the data on the ISR, with getc() and kbhit() (using 0.5s of timeout to flag the end of transmission, using the timed_getc() of CCS, view on help), and after work the data into the ISR?
Code: |
#INT_RDA
void intrda(){
char a, resp[100];
int ct=0;
disable_interrupts( INT_RDA );
output_high(PIN_C3);
// here I receive all the data with just one ISR
while( a = timed_getc() ){ resp[ct] = a; resp[ct++]='\0'; }
// why can not I work the data here, even if the time delay?
// the delay represents the time of one process, for example
delay_ms(2000);
output_low(PIN_C3);
enable_interrupts( INT_RDA );
}
|
Thanks a lot!! |
|
|
Gabriel
Joined: 03 Aug 2009 Posts: 1067 Location: Panama
|
|
Posted: Sat Apr 28, 2012 11:10 am |
|
|
Code: | while( a = timed_getc() ){ resp[ct] = a; resp[ct++]='\0'; } |
you are doing an assignment on the while loop, not a _Comparison_.
below you can see a simple ISR i use in most of my codes with the circular buffer implemented.
Code: | #INT_RDA
void SerialInt()
{
Recieve_String[counter_read]=getchar();
counter_read++;
if(counter_read==Buffer_size)counter_read=0;
} |
you can print the buffer any time you want in the main code and it will contain all characters that have arrived through serial...
make your buffer a global variable...
G _________________ CCS PCM 5.078 & CCS PCH 5.093 |
|
|
opvini
Joined: 27 Apr 2012 Posts: 50 Location: Brazil
|
|
Posted: Sat Apr 28, 2012 11:43 am |
|
|
Hi Gabriel thank you, but I will explain what do I need to do:
I have an GSM module, and the data that the module send to the PIC doesnt have a fixe length. The data can be small or very large, and I just can work with the data after the receive all. The medule send 2 #10#13 chars to end the transmission normaly, but send 4 #10#13 chars when receive a call, and other logical about the number of END_CHARS (#10#13), then, to I signal that the all message was receive, I need work the data according eith this logical. And to optimize the program, I prefer wait all the message and use a flog variable to signal the end of transmission ant then use it on the main(), becouse if I use the logical of time to signal end of transmission (for example if I dont receive anything in 1s, the transmission eded) the program will be STOPED 1s ever that I receive any data...
Sorry my english, I'm from Brazil...
Do you understand ???
Thank you a lot Gabriel! |
|
|
opvini
Joined: 27 Apr 2012 Posts: 50 Location: Brazil
|
|
Posted: Sat Apr 28, 2012 11:52 am |
|
|
Oh, I forgot...
I use the logical about the time_out too, to signal any problem with the communication, for example if I dont receive any data in 1s, the flag timeout is signaled.
Then, I use two logicals to signaled the end of transmission:
1) the END_CHARS (2 #13#10 OR 4 #13#10 if calling, OR 6 #13#10 if reading SMS..)
2) the timeout (to signal any problem with the communication): is different to each action like:
0.5s if is a normal action
2s if reading SMS
5s if send or receiving GPRS data
...
Thank you! |
|
|
opvini
Joined: 27 Apr 2012 Posts: 50 Location: Brazil
|
|
Posted: Mon Apr 30, 2012 4:23 pm |
|
|
Anybody? |
|
|
Gabriel
Joined: 03 Aug 2009 Posts: 1067 Location: Panama
|
|
Posted: Tue May 01, 2012 7:58 am |
|
|
... hi,
The length of the Cell message does not really matter.
Your Circle buffer (which gets filled on the ISR, as I described earlier) should be long enough to hold the entire message (yes, there are more efficient ways).
Now, your GSM module has something called "Unsolicited Messages"... which basically means that the cell will send a short (10 chars? )string indicating somthing happened... like receiving a TXT message or receiving a call.
So, you set up your GSM module properly, clear the buffer and then you can sit there waiting for the unsolicited message.... basically polling your buffer.
You can tell that the cell has sent the pic a msg by ethier setting a flag on the ISR or by polling the circle buffer counter... using the counter poll method you save yourself a flag.
When you notice that the GSM module sent somthing... wait a bit... 2 seconds? and then check your buffer... and then take the appropiate action.
like reading the SMS ...
always give the GSM module enough time to respond... SMS will vary in length yes... so it will take varying times to read... give a delay long enough to cover your worst case...
... you will probably want to use String functions.... to find commands or specific word in your input buffer....
declare your input buffer for example: size 101 characters... but make it circle at possition 100... and initialize position 101 as '\n'.... so your input buffer is always null terminated....
.... in any case... i suggest you get a clear picture on how to work with serial comm first... if you dont get that straight... you wont be able to work with a GSM module.
Basic question... have you even gotten your pic to talk to the module so far?
just plain AT>OK ?
G. _________________ CCS PCM 5.078 & CCS PCH 5.093 |
|
|
opvini
Joined: 27 Apr 2012 Posts: 50 Location: Brazil
|
|
Posted: Tue May 01, 2012 10:56 am |
|
|
Hi Gabriel... thanks again for reply.
My program is communicating with the GSM module with no problem, and synchronous... I am using a flag to indicate the end of transmission and on while() I test this flag, and do actions. But my question is exactly about this. Why the program doesn't work if I process the response of gsm module on ISR (after the message has been fully recovery) the program don't work fine. But if I set a flag on ISR (after the message has been fully recovery too) and process the message on while() it works fine.
The program is working fine, OK, but I really wanted to understand why doesn't work if the process of response is on the ISR... |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19515
|
|
Posted: Tue May 01, 2012 11:11 am |
|
|
opvini wrote: | Hi Gabriel... thanks again for reply.
My program is communicating with the GSM module with no problem, and synchronous... I am using a flag to indicate the end of transmission and on while() I test this flag, and do actions. But my question is exactly about this. Why the program doesn't work if I process the response of gsm module on ISR (after the message has been fully recovery) the program don't work fine. But if I set a flag on ISR (after the message has been fully recovery too) and process the message on while() it works fine.
The program is working fine, OK, but I really wanted to understand why doesn't work if the process of response is on the ISR... |
Probably because characters start to arrive before the 'processing' completes.
Remember the hardware UART only has 2+ characters of buffering. If (for instance) you 'printf' a message in the ISR, that is ten characters long, then the code will effectively have to wait for eight character times, before completing. If meanwhile characters are arriving, then the UART, _will_ overrun. At this point the UART will be _hung_. Unless you add the keyword 'ERRORS' to your RS232 declaration. This adds extra code to clear this condition if it happens. Basically when using the hardware UART, you _must_ have 'ERRORS' in the declaration, unless _you_ yourself deal with the error conditions.
Repeat the 'mantra' - ISR's should _only_ do what they must to handle the hardware condition the interrupt flag signifies. Everything else must be done outside the ISR. Only exceptions to this, are if you know _exactly_ what the implications of staying too long in the ISR are, and handle the effects of this yourself.
Best Wishes |
|
|
Gabriel
Joined: 03 Aug 2009 Posts: 1067 Location: Panama
|
|
Posted: Tue May 01, 2012 1:14 pm |
|
|
.... yeah, what Ttelmah said. _________________ CCS PCM 5.078 & CCS PCH 5.093 |
|
|
|