CCS C Software and Maintenance Offers
FAQFAQ   FAQForum Help   FAQOfficial CCS Support   SearchSearch  RegisterRegister 

ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

CCS does not monitor this forum on a regular basis.

Please do not post bug reports on this forum. Send them to CCS Technical Support

problem in receiving characters via gsm

 
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion
View previous topic :: View next topic  
Author Message
armma



Joined: 30 Apr 2016
Posts: 7

View user's profile Send private message

problem in receiving characters via gsm
PostPosted: Sat Apr 30, 2016 6:04 am     Reply with quote

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

View user's profile Send private message

PostPosted: Sat Apr 30, 2016 6:13 am     Reply with quote

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

View user's profile Send private message

PostPosted: Sat Apr 30, 2016 6:46 am     Reply with quote

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 .. Smile

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 Embarassed
temtronic



Joined: 01 Jul 2010
Posts: 9226
Location: Greensville,Ontario

View user's profile Send private message

PostPosted: Sat Apr 30, 2016 10:41 am     Reply with quote

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

View user's profile Send private message

PostPosted: Sat Apr 30, 2016 11:15 am     Reply with quote

...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: 19513

View user's profile Send private message

PostPosted: Sat Apr 30, 2016 11:57 am     Reply with quote

Or (of course), both.... Evil or Very Mad

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

View user's profile Send private message

PostPosted: Sat Apr 30, 2016 1:56 pm     Reply with quote

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"...

Shocked Sad

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 Smile
ezflyr



Joined: 25 Oct 2010
Posts: 1019
Location: Tewksbury, MA

View user's profile Send private message

PostPosted: Sat Apr 30, 2016 3:06 pm     Reply with quote

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

View user's profile Send private message

PostPosted: Sat Apr 30, 2016 5:33 pm     Reply with quote

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 Smile

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

View user's profile Send private message

PostPosted: Sat Apr 30, 2016 6:46 pm     Reply with quote

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

View user's profile Send private message

PostPosted: Sat Apr 30, 2016 6:52 pm     Reply with quote

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

View user's profile Send private message

PostPosted: Sun May 01, 2016 7:18 am     Reply with quote

Thanks dyeatman, Smile
I tried to write a program to receive the data using interrupt and the data received correctly Smile
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

View user's profile Send private message

PostPosted: Sun May 01, 2016 7:40 am     Reply with quote

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: 19513

View user's profile Send private message

PostPosted: Sun May 01, 2016 8:45 am     Reply with quote

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.
Display posts from previous:   
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion All times are GMT - 6 Hours
Page 1 of 1

 
Jump to:  
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