|
|
View previous topic :: View next topic |
Author |
Message |
armma
Joined: 30 Apr 2016 Posts: 7
|
problem in receiving characters via gsm |
Posted: Sat Apr 30, 2016 6:04 am |
|
|
Hi ALL ,
In my project i want to use GSM ..
i wrote the code using the procedure in this thread
https://www.ccsinfo.com/forum/viewtopic.php?t=50390
my problem is when i typed the strings via terminal instead of GSM the data received correctly but when i connect the gsm to PIC there is nothing received,although the GSM send the data...
Code: |
#include <16F877a.h>
#include <string.h>
#include <stdlib.h>
#fuses HS,NOWDT,NOPROTECT,NOLVP
#use delay(clock=20000000)
#use rs232(baud=9600,xmit=PIN_C6, rcv=PIN_C7,STREAM=GSM)
#use rs232(baud=9600,xmit=PIN_B6, rcv=PIN_B7,STREAM=PIC)
#define ledbusy_on output_high(pin_A1)
#define ledbusy_off output_low(pin_A1)
#define ledbusy_flashing output_toggle(pin_A1)
#define toggle_device_state_e output_toggle(pin_A2)
#define toggle_device_state_c output_toggle(pin_A3)
#define buffer_size 80
#define NULL '\0'
#DEFINE OK 0
#DEFINE CMTI 1
#DEFINE ERROR 2
#DEFINE ETRIP 3
#DEFINE CTRIP 4
#DEFINE GETP 5
#DEFINE GETBILL 6
unsigned int32 P=0;
UNSIGNED char rcv_string[buffer_size];
unsigned int8 rcv_bytes_num=0;
int1 buffer_full=0;
UNSIGNED CHAR *STRINGS[]={"OK\0","+CMT\0","ERROR\0","ETRIP\0","CTRIP\0","GETP\0","GETBILL\0"};
UNSIGNED CHAR PP[10];
FLOAT CAL_COST(unsigned int32 V){
FLOAT PO;
PO=(FLOAT)(V/1000.0);
IF(PO<1 ) RETURN (PO*0.025);
ELSE IF(PO>=1 && PO <=160) RETURN (PO*0.033);
ELSE IF(PO>=161 && PO <=300)RETURN ((PO+1-161)*0.072+160.0*0.033);
ELSE IF(PO>=301 && PO <=500) RETURN ((PO+1-301)*0.086+140.0*0.072+160.0*0.033);
ELSE IF((PO>=501) && (PO<=600)) RETURN ((PO+1.0-501.0)*0.114+140.0*0.072+160.0*0.033+200.0*0.086);
ELSE IF(PO>=601 && PO <=750) RETURN ((PO+1-601)*0.158+140.0*0.072+160.0*0.033+200.0*0.086+100.0*0.114);
ELSE IF(PO>=751 && PO <=1000) RETURN ((PO+1-751)*0.188+140.0*0.072+160.0*0.033+200.0*0.086+100.0*0.114+150.0*0.158);
ELSE IF(PO>=1001) RETURN ((PO+1-1001)*0.265+140.0*0.072+160.0*0.033+200.0*0.086+100.0*0.114+150.0*0.158+250.0*0.188);
}
void CLEAR_BUFFER()
{
memset(rcv_string,NULL,buffer_size); // Set all elements to NULL
rcv_bytes_num=0; // Reset index
}
VOID SEND_SMS_BILL(){
rcv_bytes_num=0;
FPRINTF(GSM,"AT+CMGS=\"##########\"\r"); // send command and cel #
delay_ms(1500); // Delay long enough for modem response
FPRINTF(GSM,"power=%.3f kW TAX= %.3f JD \r\nCOST=%.3f JD TOTAL COST=%.3f JD",P/1000.0,3.765,CAL_COST(P),CAL_COST(P)+3.765); // Text to reply
FPUTC(0X1A,GSM);
//putc('\r'); // send Ctrl-z
DELAY_MS(2000);CLEAR_BUFFER();
}
void SEND_SMS()
{
rcv_bytes_num=0;
FPRINTF(GSM,"AT+CMGS=\"#######\"\r"); // send command and cel #
delay_ms(1500); // Delay long enough for modem response
FPRINTF(GSM,"power=%.3f Kw",P/1000.0);
FPUTC(0X1A,GSM);
//putc('\r'); // send Ctrl-z
DELAY_MS(2000);CLEAR_BUFFER();
}
#int_rda
void serial_isr() {
buffer_full=0;
rcv_string[rcv_bytes_num]=Fgetc(GSM);
rcv_bytes_num++;
if(rcv_bytes_num==buffer_size){rcv_bytes_num=0;buffer_full=1;}
//FPRINTF(PIC,"%c %u\r\n",rcv_string[rcv_bytes_num],rcv_bytes_num);
}
#INT_EXT //you must use INT_name as a directive before ISR().
void SENDBILL() //ISR name
{
SEND_SMS_BILL();
CLEAR_BUFFER();
}
int1 SEARCH_STRING(int8 index){
if(strstr(rcv_string,STRINGS[index])!=NULL)return (1);
else return (0);
}
INT1 CHECK_COM(){
rcv_bytes_num=0; // Reset buffer counter
Fprintf(GSM,"AT\r"); // Send Attention Command
DELAY_MS(1000); // Delay a maximum of X seconds
rcv_bytes_num=0; // Reset buffer counter
return(SEARCH_STRING(OK));
}
int1 SET_PDU()
{
rcv_bytes_num=0; // Reset buffer counter
Fprintf(GSM,"AT+CMGF=1\r"); // Set modem to TXT mode
DELAY_MS(3000); // Delay a maximum of X seconds
rcv_bytes_num=0; // Reset buffer counter
return(SEARCH_STRING(OK)); // Check for OK response
}
int1 SET_CNMI()
{
rcv_bytes_num=0; // Reset buffer counter
Fprintf(GSM,"%s","AT+CNMI=3,3,0,0\r"); //text part of the command.
DELAY_MS(3000); // Delay a maximum of X seconds
rcv_bytes_num=0; // Reset buffer counter
return(SEARCH_STRING(OK)); // Check for OK response
}
void main() {
//OUTPUT_HIGH(PIN_A0);
ledbusy_off;
output_HIGH(pin_A2);
output_HIGH(pin_A3);
CLEAR_BUFFER();
enable_interrupts(int_rda);
enable_interrupts(global);
//////////////////////////////
IF(CHECK_COM()){
CLEAR_BUFFER();
ledbusy_on;
delay_ms(1000);
}
else{
while(!CHECK_COM())
{
ledbusy_flashing;delay_ms(200);
}
ledbusy_on;CLEAR_BUFFER();
}
////////////////////////////////
if(SET_PDU())
{
CLEAR_BUFFER();ledbusy_on;delay_ms(1000);
}
else
{
while(1){ledbusy_flashing;delay_ms(100);}
}
///////////////////////////////
if(SET_CNMI())
{
CLEAR_BUFFER(); CLEAR_BUFFER();ledbusy_on;delay_ms(1000);
}
else
{
while(1){ledbusy_flashing;delay_ms(100);}
}
enable_interrupts(int_EXT);
ext_int_edge(H_TO_L);
//!OUTPUT_LOW(PIN_A0);
while(1){
//delay_ms(3000);
WHILE(!SEARCH_STRING(CMTI)){
IF(INPUT(PIN_A0)){
FGETS(PP,PIC);
P=atoI32(pp);
if(P==500){SEND_SMS();}
}
}
//WHILE THE RECIVED STRING NOT INCLUDE CMTI WAIT
//delay_ms(500);
if(SEARCH_STRING(ETRIP)){toggle_device_state_e;CLEAR_BUFFER();}
ELSE IF(SEARCH_STRING(CTRIP)){toggle_device_state_c;CLEAR_BUFFER();}
ELSE if(SEARCH_STRING(GETP)){SEND_SMS();CLEAR_BUFFER();}
ELSE if(SEARCH_STRING(GETBILL)){SEND_SMS_BILL();CLEAR_BUFFER();}
}
}
|
|
|
|
ezflyr
Joined: 25 Oct 2010 Posts: 1019 Location: Tewksbury, MA
|
|
Posted: Sat Apr 30, 2016 6:13 am |
|
|
Hi,
Have you read all the previous GSM threads? If you have then you know the first thing we are going to ask is which GSM modem, and how have you interfaced it to the PIC? Post your schematic, and a link to the actual GSM modem you are using!!
It all starts with your hardware. If that isn't right, all the code in the world won't fix the problem! _________________ John
If it's worth doing, it's worth doing in real hardware! |
|
|
armma
Joined: 30 Apr 2016 Posts: 7
|
|
Posted: Sat Apr 30, 2016 6:46 am |
|
|
ezflyr wrote: | Hi,
Have you read all the previous GSM threads? If you have then you know the first thing we are going to ask is which GSM modem, and how have you interfaced it to the PIC? Post your schematic, and a link to the actual GSM modem you are using!!
It all starts with your hardware. If that isn't right, all the code in the world won't fix the problem! |
thank you ezflyr ..
I'm using sm5100b GSM
https://www.sparkfun.com/products/retired/9607
my schematic
https://www.photobox.co.uk/my/photo/full?photo_id=21170394706
i'm using V5.056 Compiler
thanks in advance |
|
|
temtronic
Joined: 01 Jul 2010 Posts: 9243 Location: Greensville,Ontario
|
|
Posted: Sat Apr 30, 2016 10:41 am |
|
|
Probably the 'classic' 5 volt PIC, 3 volt GSM.....
I did see the GSMm being a 3 volt device, can't see your schematic even if I Ctrl C the url......
You need either a 3 volt rated PIC ( xxxLyyyy ) or logic level conversion between PIC and peripheral.
Given the choice , I'd use a 3 volt rated PIC. It's simpler to interface to GSM, a tad faster, and well, zero problems !!
Currently I use the PIC18F46K22 as it has lots of mem,i/o and is good for 3 or 5 volts.
BTW the 16F877 is 'obsolete'..kinda like dinosaurs and me....
Jay |
|
|
Gabriel
Joined: 03 Aug 2009 Posts: 1067 Location: Panama
|
|
Posted: Sat Apr 30, 2016 11:15 am |
|
|
...Or probably inverted tx/rx lines.
99% of my projects are GSM based or have GSM in them at some point.
I cant count the number of times just swapping the uart lines solved all my problems....especially before i got a proper gsm dev board.
G. _________________ CCS PCM 5.078 & CCS PCH 5.093 |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19538
|
|
Posted: Sat Apr 30, 2016 11:57 am |
|
|
Or (of course), both....
However the voltage level is the most likely. On the PIC he is using Vih for the UART, with the chip running at 5v, is 4V. A 3.3v GSM modem is not going to give this without buffering. |
|
|
armma
Joined: 30 Apr 2016 Posts: 7
|
|
Posted: Sat Apr 30, 2016 1:56 pm |
|
|
Thanks All for your answers ...
I have tried all your suggestions and the problem still exist
the pic sends the commands correctly and the GSM responses correctly but the program stuck in check_com function even the GSM respnse by "OK"...
when i use the terminal instead of GSM the program works correctly ...
i have tried to do some modification on check com ,set_pdu and set_cnmi functions and the program works correctly.
the modifications as the following
Code: |
INT1 CHECK_COM(){
rcv_bytes_num=0; // Reset buffer counter
Fprintf(GSM,"AT\r"); // Send Attention Command
DISABLE_INTERRUPTS(INT_RDA);
FGETC(GSM);FGETC(GSM);
ENABLE_INTERRUPTS(INT_RDA);
DELAY(5); // Delay a maximum of X seconds
rcv_bytes_num=0; // Reset buffer counter
return(SEARCH_STRING(OK));
}
int1 SET_PDU()
{
rcv_bytes_num=0; // Reset buffer counter
Fprintf(GSM,"AT+CMGF=1\r"); // Set modem to TXT mode
DISABLE_INTERRUPTS(INT_RDA);
FGETC(GSM);FGETC(GSM);
ENABLE_INTERRUPTS(INT_RDA);
DELAY_MS(3000); // Delay a maximum of X seconds
rcv_bytes_num=0; // Reset buffer counter
return(SEARCH_STRING(OK)); // Check for OK response
}
int1 SET_CNMI()
{
rcv_bytes_num=0; // Reset buffer counter
Fprintf(GSM,"%s","AT+CNMI=3,3,0,0\r"); //text part of the command.
DISABLE_INTERRUPTS(INT_RDA);
FGETC(GSM);FGETC(GSM);
ENABLE_INTERRUPTS(INT_RDA);
DELAY_MS(3000); // Delay a maximum of X seconds
rcv_bytes_num=0; // Reset buffer counter
return(SEARCH_STRING(OK)); // Check for OK response
}
|
the modification was by disabling the interrupt then reading the two characters \r\n which are coming befor the OK response then enabling the interrupt .
when i did these steps the pic received the response "ok" correctly ..
why ? >_<
are the CR & LF cause problem when i receive the data through interrupts ...
regards |
|
|
ezflyr
Joined: 25 Oct 2010 Posts: 1019 Location: Tewksbury, MA
|
|
Posted: Sat Apr 30, 2016 3:06 pm |
|
|
Hi,
Quote: |
I have tried all your suggestions
|
What *exactly* does this mean? You were given many suggestions, so which ones did you implement?
We have to assume your hardware is incorrect until proven otherwise. This is step 1 ---- don't try to skip it! _________________ John
If it's worth doing, it's worth doing in real hardware! |
|
|
armma
Joined: 30 Apr 2016 Posts: 7
|
|
Posted: Sat Apr 30, 2016 5:33 pm |
|
|
ezflyr wrote: | Hi,
Quote: |
I have tried all your suggestions
|
What *exactly* does this mean? You were given many suggestions, so which ones did you implement?
We have to assume your hardware is incorrect until proven otherwise. This is step 1 ---- don't try to skip it! |
Hi ezflyr ,
I tried to invert rx/tx ... also i tried to use logic level conversion between GSM & PIC .. nothing happened
I have test the gsm using the terminal and simple code and it works well .. |
|
|
dyeatman
Joined: 06 Sep 2003 Posts: 1934 Location: Norman, OK
|
|
Posted: Sat Apr 30, 2016 6:46 pm |
|
|
You are all over the map on this, performing getc(gsm) or fgetc(gsm) in multiple places when you should only be doing one fgetc(gsm) inside the INT_RDA routine. You are also messing with the interrupts (see below)
FIRST: Comment out ALL the getc and fgetc statement lines for now EXCEPT the one in the RDA interrupt routine. .
SECOND: Comment out or remove ALL enable/disable_interrupt statements and let the compiler do its job. You need only two enable statements as detailed in the next step (and no disable statements).
THIRD: Have ONE enable interrupts(rda) immediately followed by ONE enable_interrupts(global) at the start of Main and none anywhere else.
FOURTH: Comment out all the delay_ms() statements for now, they will interfere with your character reception.
FIFTH: make sure you have the ERRORS keyword in both the RS232 lines.
SIXTH: Connect an LED with a series 470 ohm resistor to RB5 (if available) then add an LED toggle statement to the RDA routine as shown below to see if the interrupt is even firing and let us know the results.
If the RB5 test LED toggles when the GSM xmits, then characters are coming in and you likely have a coding problem in your program.
If RB5 does not toggle then the MCU is not running or you have a wiring or serial connection problem and you have to get that resolved so the RB5 LED blinks then move to the next step.
Code: | #int_rda
void serial_isr() {
//
// add test led line below
output_toggle (PIN_RB5); // toggle Test Output line RB5
//
buffer_full=0;
rcv_string[rcv_bytes_num]=Fgetc(GSM);
rcv_bytes_num++;
if(rcv_bytes_num==buffer_size){rcv_bytes_num=0;buffer_full=1;}
//FPRINTF(PIC,"%c %u\r\n",rcv_string[rcv_bytes_num],rcv_bytes_num);
}
|
_________________ Google and Forum Search are some of your best tools!!!! |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Sat Apr 30, 2016 6:52 pm |
|
|
Quote: | when i did these steps the pic received the response "ok" correctly.. why ?
are the CR & LF cause problem when i receive the data through interrupts ... |
Did you compile your program and look at the Build results ?
Interrupts are shut down throughout much of your program:
Quote: | >>> Warning 216 "PCM_Test.c" Line 223(1,2): Interrupts disabled during call to prevent re-entrancy: (@delay_ms1)
>>> Warning 216 "PCM_Test.c" Line 223(1,2): Interrupts disabled during call to prevent re-entrancy: (@PSTRINGC7_9600_62_63)
>>> Warning 216 "PCM_Test.c" Line 223(1,2): Interrupts disabled during call to prevent re-entrancy: (@DTOF)
>>> Warning 216 "PCM_Test.c" Line 223(1,2): Interrupts disabled during call to prevent re-entrancy: (@DIVFF)
>>> Warning 216 "PCM_Test.c" Line 223(1,2): Interrupts disabled during call to prevent re-entrancy: (@PSTRINGCN7_9600_62_63)
>>> Warning 216 "PCM_Test.c" Line 223(1,2): Interrupts disabled during call to prevent re-entrancy: (@PRINTF_L32D_9600_62_63FPFPF)
>>> Warning 216 "PCM_Test.c" Line 223(1,2): Interrupts disabled during call to prevent re-entrancy: (CLEAR_BUFFER)
>>> Warning 216 "PCM_Test.c" Line 223(1,2): Interrupts disabled during call to prevent re-entrancy: (SEND_SMS_BILL)
|
Let's look at the check_com() function that you say the program locks up in.
Based on the warning messages, interrupts are shut off during the lines
shown in bold below:
Quote: | INT1 CHECK_COM(){
rcv_bytes_num=0; // Reset buffer counter
Fprintf(GSM,"AT\r"); // Send Attention Command
DELAY_MS(1000); // Delay a maximum of X seconds
rcv_bytes_num=0; // Reset buffer counter
return(SEARCH_STRING(OK));
}
|
So interrupts are shut off for at least 1 second. During that time, you
will get "OK" followed by CR LF. But the UART receiver on the 16F877A
only has a 2-deep receive fifo. If it receives more than 2 incoming
characters without you reading them out of the fifo, the UART receiver
will lock up. You could clear the lock-up condition by adding ERRORS
to your #use rs232() statement for the GSM stream, but you would still
lose some of the bytes.
You could fix your problems by:
1. Get rid of your current #int_rda routine, and replace it with a circular
buffer, as shown in the CCS example file Ex_sisr.c. Look in the Examples
sub-directory where the compiler is installed to find this file.
2. Inside the #int_rda routine, check the incoming bytes. When you see
CR LF, then you know you have a message in the receive buffer. Then
set a global flag = TRUE. In your check_com() routine, poll this flag.
3. When it goes true, then get the message from the Ex_sisr.c buffer by
calling bkbhit(), and if it's true, then call bgetc() to get the characters.
Put them in a local buffer and make sure you put a '\0' at the end of
the command string in place of the CR. This will make the "OK" into
a string. Your string.h functions need to see a string. After you read
the bytes from the receive buffer, remember to clear the global flag.
4. Then you can call your search_string() function.
5. For some reason, in the #int_ext routine you are calling all the
routines listed in the Warnings above. Re-write your code so the
#int_ext routine just sets a global flag. Poll that flag in your main()
code, and call all those routines in main() and not in the #int_ext routine.
This will prevent interrupts from being disabled in large parts of your program. |
|
|
armma
Joined: 30 Apr 2016 Posts: 7
|
|
Posted: Sun May 01, 2016 7:18 am |
|
|
Thanks dyeatman,
I tried to write a program to receive the data using interrupt and the data received correctly
but when i tried to add the other lines in the program the problem appears -_- ..
The problem solved when i removed the calling statements from external interrupt service routine ^^
Hi PCM PROGRAMMER ,
Thanks for your useful notes )
Yes, Idid but i didn't pay attention to those warnings >_<
The first thing i did it before trying your suggestions is removing the calling statements from external interrupt service routine then i compiled the program .. no warnings appear in build results and the problem solved.
is this mean i can't call functions inside ISR if more than ISR exist? |
|
|
dyeatman
Joined: 06 Sep 2003 Posts: 1934 Location: Norman, OK
|
|
Posted: Sun May 01, 2016 7:40 am |
|
|
The cardinal rule for an ISR is to get out as fast as possible.
Since the ISR fires for each character, you need to be out of the ISR well BEFORE the next character comes in which is about 1ms at 9600... _________________ Google and Forum Search are some of your best tools!!!! |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19538
|
|
Posted: Sun May 01, 2016 8:45 am |
|
|
You should not call the same function both inside and outside an ISR.
Generally basic rule is that an ISR, should _just_ handle the hardware event that triggered it. Nothing else.
So for a timer, just increment a clock, or set a flag.
For 'receive data', just read the single character.
For 'transmit data', test if there is more data to send, if so, send it, if not, stop triggering.
Everything else should be done by flags an buffering. So if you want to do loads of things when a timer gets to zero, then in the ISR set a flag to say this has happened, and _get out_. Then in the main code when this flag is set, clear it, and do the jobs required. Similarly for receive data, just receive that one character, store it, and update the counts to say this has been received. You can add a tiny bit of 'complexity' to this, by (for instance), checking for the 'line feed' character, and setting a flag when this is seen.
Then in the external code, when the 'line feed' flag is seen, you know that the buffer where you stored the data has a complete 'line' available.
Now key point then is that since you spend 99% of your time in the external code, each interrupt can immediately be handled when it happens, without other interrupts interfering. Then all you need to do is ensure that the main code keeps checking all the flags and counters, and avoids 'stopping'. So if (for instance) you want a delay, then instead of using 'delay_ms', you setup a counter to be incremented/decremented by an interrupt, and carry on looping checking all the other main tasks, until the counter reaches the limit you require.
This is the basis of 'co-operative multi tasking', which then allows your code to apparently do multiple things at once, despite only being a single processor. |
|
|
|
|
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
|