Continue to Site

Welcome to EDAboard.com

Welcome to our site! EDAboard.com is an international Electronics Discussion Forum focused on EDA software, circuits, schematics, books, theory, papers, asic, pld, 8051, DSP, Network, RF, Analog Design, PCB, Service Manuals... and a whole lot more! To participate you need to register. Registration is free. Click here to register now.

Sending SMS via GSM Modem and PIC controller

Status
Not open for further replies.

tritech

Newbie level 6
Joined
Apr 16, 2013
Messages
14
Helped
0
Reputation
0
Reaction score
0
Trophy points
1,281
Activity points
1,403
PIC : PIC18F4520
PICPLC16v6 Development Board from Mikroelectronika
GSM Modem : Quectel M95

Individually tested serial communication of PIC Board with Hyperterminal -> OK
Checked AT command response in Hyperterminal with GSM Modem -> OK

Now I need to integrate both together.
I wrote a simple code to obtain the OK response if I send AT. But I do not get OK response.

char rcv[10];
void main()
{

UART1_Init(9600);
Delay_ms(2000);
TRISB=0x00;

UART1_Write_Text("at");
UART1_Write(13); //Enter key = CF + LF
UART1_Write(10);
delay_ms(500);

while (1)
{ PORTB.RB0=1; // Endless loop
while(!UART1_Data_Ready()); // If data is received,
rcv[0]=UART1_Read();
rcv[1]=UART1_Read();
rcv[2]='\0';
UART1_Write_Text(rcv);
PORTB.RB0=0;
}
}


I get the response as attt.
Pls let me know the mistake. Thanks
 

I use the following function in my program to send sms using PIC18F4520. It works fine for me. I am not taking any response from the gsm module. If you want response you can just edit the code.
PHP:
void Send_Sms(){
     UART1_Init(9600);
     Delay_ms(100);
     UART1_Write_Text("AT");
     Delay_ms(100);
     UART1_Write_Text("AT+CMGF=1");//set mode as text message
     Delay_ms(100);
     UART1_Write(0x0D);    //enter
     UART1_Write_Text("AT+CMGS=");  
     Delay_ms(100);
     UART1_Write(0x22);
     Delay_ms(100);
     UART1_Write_Text("+919243342000");  //mobile number
     Delay_ms(200);
     UART1_Write(0x22);
     Delay_ms(100);
     UART1_Write(0x0D); // Enter
     Delay_ms(100);
     UART1_Write_Text("Hello this is my txt in all its glory"); //your message
     Delay_ms(600);
     Delay_ms(100);
     UART1_Write(26); //Ctr +Z    --send
     Delay_ms(200);
    }
 
I tried using it directly in the main but still I did not get the sms to my mobile. Am I missing anything?

PHP:
void main ()
{
delay_ms(1000);
     UART1_Init(9600);
     Delay_ms(100);
     UART1_Write_Text("AT");
     Delay_ms(100);
     UART1_Write(0x0D);    //enter
     UART1_Write(0x0A);
     UART1_Write_Text("AT+CMGF=1");//set mode as text message
     Delay_ms(100);
     UART1_Write(0x0D);    //enter
     UART1_Write(0x0A);
     UART1_Write_Text("AT+CMGW=+6597329728");
     Delay_ms(100);
     UART1_Write(0x0D); // Enter
     UART1_Write(0x0A);
     Delay_ms(100);
     UART1_Write_Text("Hello this is my txt in all its glory"); //your message
     Delay_ms(600);
     Delay_ms(100);
     UART1_Write(26); //Ctr +Z    --send
     Delay_ms(200);
     UART1_Write(0x0D);
     UART1_Write(0x0A);
    }
 

Instead of AT+CMGS= you have used AT+CMGW. Try using the code which I have posted above.
 

Managed to send the sms with an increased delay of 1.5 sec. Similarly do you have a function to read sms?
I am sending AT and expecting response OK. But I am not getting it. Tried both UART_Read and UART_Read_Text.
Once I can get this, then I can include the command to read the sms.

PHP:
char rcv[10];
char myrx[4];
int i;
void main()
{

UART1_Init(9600);
Delay_ms(2000);
TRISB=0x00;
UART1_Write_Text("at");
UART1_Write(13); //Enter key = CF + LF
UART1_Write(10);
delay_ms(500);

while (1)
{
if (PIR1.RCIF == 1)
   PORTB.RB0=1;                   // Endless loop
   
      if(UART1_Data_Ready())    // If data is received,
       rcv[0]=UART1_Read();
  rcv[1]=UART1_Read();
        rcv[2]=UART1_Read();
         rcv[3]=UART1_Read();
         rcv[4]=UART1_Read();
         rcv[5]=UART1_Read();
         rcv[6]=UART1_Read();
         rcv[7]=UART1_Read();
         rcv[8]=UART1_Read();
      //UART1_Read_Text(rcv,"OK",255);     // read the received data,
      //UART1_Write(rcv);       // and send data via UART
     
      UART1_Write_Text(rcv);
      PORTB.RB0=0;
   }
}
 

1. Delay_ms(2000); // don't need such delay for intializing USART port

try this sample code:

Code:
void main(void){
      
      INTCON = 0;
      TRISA = 0x00;
      TRISB=0x00;
      ANSELA = 0x00;
      ANSELB = 0x00;
      
      UART1_Init(9600);
      Delay_ms(10);
      
      UART1_Write_Text("\r\nATE0\r\n"); 
      int i = 0;
      while (1){ // Endless loop
                  
                  PORTB.RB0=1;
                  
                  while (!UART1_Data_Ready()) {   // If data in RCREG, 
                          rcv[i]=UART1_Read();
                    i++;
                  }
                  rcv[i] = 0x00;
                  UART1_Write_Text(rcv);
                  i = 0;
                  PORTB.RB0=0; 
     }
}

EDIT:
1. try posting functions of UART1_Init & UART1_Data_Ready() to see how do you read and set the RCREG & RCIF,etc. Did you use ring buffer for storing GSM OUTPUT?
2. Avoid delay routines as far as possible except required by system. Because, it will give you good result only few times and many times NOT.
 
Last edited:

if so, I am afraid about my sample code posted above: Instead, I will post a small code in 10 minutes without using RCIF interrupt.

- - - Updated - - -

try this modified code.

1. Ensure USART properly initiated
2. Ensure RCIE, PEIE and GIE NOT enabled


Code C - [expand]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
void main(void){
      
      INTCON = 0;
      TRISA = 0x00;
      TRISB=0x00;
      ANSELA = 0x00;
      ANSELB = 0x00;
      
      UART1_Init(9600);
      Delay_ms(10);
      
  //    UART1_Write_Text("\r\nATE0\r\n"); 
      
      char GSM_reply;
      int i = 0;
      
      while (1){ // Endless loop
                  
                  PORTB.RB0=1;
                  
                  GSM_reply = UART1_Read();
                  
                  switch GSM_reply{
                      case 0x0A:
                          break;
                      case 0x0D: // if <CR> character received
                                rcv[i] = 0x00;
                                if (strlen(rcv) > 0){
                                    UART1_Write_Text(rcv);
                                    i = 0;
                                    PORTB.RB0=0; 
                                }
                          break;
                      default:
                              rcv[i] = GSM_reply;
                              i++;
                         break;
                  }
     }
}

 

PHP:
char GSM_reply;
int i = 0;
char rcv[100];
void main(void){

      INTCON = 0;
      TRISA = 0x00;
      TRISB = 0x00;
      //ANSELA = 0x00;
      //ANSELB = 0x00;

      UART1_Init(9600);
      Delay_ms(10);

      UART1_Write_Text("AT\r\n");
      while (1){ // Endless loop

                  PORTB.RB0=1;

                  GSM_reply = UART1_Read();

                  switch (GSM_reply)
                  {
                      case 0x0A:
                          break;
                      case 0x0D: // if <CR> character received
                                rcv[i] = 0x00;
                                if (strlen(rcv) > 0){
                                    UART1_Write_Text(rcv);
                                    i = 0;
                                    PORTB.RB0=0;
                                }
                          break;
                      default:
                              rcv[i] = GSM_reply;
                              i++;
                         break;
                  }
     }
}

Used the above code and still could not get it. At first attempt, it goes to the strlen(rcv)>0, but it comes out since the condition is false, so I do not get the response.
If I comment the UART_Write_text, the default case is executed and NULL stores in each byte.

Also, on using your first code, UART_Data_Ready=0, so it does not execute the loop.
 
Last edited:

The output format of the GSM Module is : <CR><LF>text<CR><LF>. So, when we receive 1st <CR> it will come to strlen line and check for string. But string will be empty. When we receive 2nd <CR>, there will be chars in the rcv buffer. Set break point at UART1_Write_Text(rcv); line only: and check again.

Also, comment the line "UART1_Write_Text("AT\r\n");" and restart the GSM Modem (only) NOT PIC DEMO BOARD (it should be active by default). If so, CPIN: READY, etc will be received at "rcv" buffer (If you enabled unsolicited result code). You can call the GSM Modem from your mobile phone and check the rcv buffer.

Still If it shows empty "rcv", then check the baudrate, etc.

Also, on using your first code, UART_Data_Ready=0, so it does not execute the loop...
Try, change while(!UART_Data_Ready=0) to while(UART_Data_Ready=0).
 
Last edited:

Tried both ways. Still couldn't get OK. Baud Rate is 9600 cos it was tested in Hyperterminal and it is fine.

Code:
void main(void){

      INTCON = 0;
      TRISA = 0x00;
      TRISB=0x00;

      UART1_Init(9600);
      Delay_ms(10);

      UART1_Write_Text("\r\nATE0\r\n");

      while (1){ // Endless loop

                  PORTB.RB0=1;

                  if (UART1_Data_Ready()) {   // If data in RCREG,
                          rcv[i]=UART1_Read();
                    i++;
                  }
                  //rcv[i] = 0x00;
                  UART1_Write_Text(rcv);
                  //i = 0;
                  PORTB.RB0=0;
     }
}

On using the above, I get 0x0D in every byte of rcv.
 

Best suggestion to use my post #9 above:

1. uncomment rcv
2. check the value of "i" before reset to 0. The GSM result should be \r\nOK\r\n. So, "i" value should be 5.

if (UART1_Data_Ready()).... {
try:
use while(UART_Data_Ready=0) instead of if(UART1_Data_Ready()).

I don't have details of settings of USART and how UART1_Data_Ready() function works. Thats why I could not able to give you correct suggestion.

- - - Updated - - -

if you can able to receive <CR> character you are almost nearer to your result. Try.
 

It runs 2 times on giving while(UART_Data_Ready). But the bytes give value as 0x0A.
uart_data_ready.JPG

Uploaded the data_ready. Board used is PICPLC16v6 from Mikroelectronika.
 

see the url that may help you:

**broken link removed**

You can use this function (taken from the above URL): pl note the delay of 100ms. It may required by system to initiate USART Module. So, it must be 100ms delay.


Code C - [expand]
1
2
3
4
5
6
7
8
9
UART1_Init(4800) ;                          ' initialize UART module
Delay_ms(100);
 
 while (1){
   if (UART1_Data_Ready() = 1){             ' if data is received   
     UART1_Read_Text(output, 'OK', 10) ; ' reads text until 'OK' is found
     UART1_Write_Text(output);              ' sends back text 
   }
}

 

Made delay as 1500 and also added if (PIR1.RCIF == 1).
The individual bytes are 13 10 0 0 13 10. Which means the in between OK is missing.
But i runs only for 2 times
 
Last edited:

My suggested (post #9) code is working code and I also using this code but for HI-TECH C & MPLAB C-18. As I said earlier, delay must be avoided. Keep this in your mind (except it is required by Microcontroller modules like ADC, CLOCK, USART , etc) whenever you write code for microcontroller.

Try to read and understand how the functions work. In Hi-tech C, they provided usart code see and modify ourself based on our requirements, for example, we have to read RCREG for reading the usart data. Once we read the data buffer will be cleared automatically. The function getch() will be used. Likewise you have to know (in microC) usart_read, UART1_Data_Ready functions work. Any MicroC person may help you in this regard. I have used ring buffer (it is mandatory for working with GSM Module/Modem if we need to work without any error in practical applications. It is quite simple though) and store the GSM Module's response using RCIF interrupt.

- - - Updated - - -

you are almost on the line to get successful read from GSM Module.

- - - Updated - - -

Made delay as 1500 and also added if (PIR1.RCIF == 1).

post the modified code here to check.

The individual bytes are 13 10 0 0 13 10. Which means the in between OK is missing.
Almost you reached there.

But i runs only for 2 times
Yes. It is correct (if you used post #9 code). I made a mistake by mentioning as "5".
 

Code:
char GSM_reply;
int i = 0;
char rcv[10];
void main(void){

      INTCON = 0;
      TRISA = 0x00;
      TRISB = 0x00;

      UART1_Init(9600);
      Delay_ms(1500);

      UART1_Write_Text("AT\r\n");
      while (1){ // Endless loop

                  PORTB.RB0=1;
                 GSM_reply = UART1_Read();
                  switch (GSM_reply)
                  {
                      case 0x0A:
                          break;
                      case 0x0D: // if <CR> character received
                                rcv[i] = 0x00;
                                if (strlen(rcv) > 0){
                                    UART1_Write_Text(rcv);
                                    i = 0;
                                    PORTB.RB0=0;
                                }
                          break;
                      default:
                              rcv[i] = GSM_reply;
                              i++;
                         break;
                  }
     }
}


The rcv array receives ATTTTTTT. The same problem I had started with.



The following one gives 0x0D and 0x0A in the first two bytes. Then it does not go into the Data_Ready loop.
Code:
void main(void){

      INTCON = 0;
      TRISA = 0x00;
      TRISB=0x00;

      UART1_Init(9600);
      Delay_ms(1500);

      UART1_Write_Text("\r\nATE0\r\n");
       Delay_ms(1500);
      while (1){ // Endless loop
                 if (PIR1.RCIF == 1)
                  PORTB.RB0=1;

                  while (UART1_Data_Ready()) {   // If data in RCREG,
                          rcv[i]=UART1_Read();
                    i++;
                  }
                  rcv[i] = 0x00;
                  UART1_Write_Text(rcv);
                  //i = 0;
                  PORTB.RB0=0;
     }
}
 
Last edited:

My recommendation to use the first code above NOT LATER ONE. Also, after issuing AT command there should not be any delay. You may missing the reply from GSM reply.

UART1_Write_Text("\r\nATE0\r\n");
Delay_ms(1500);

This should be definitely wrong. remove this delay.

In the first code, just comment the line, as I said earlier, UART1_Write_Text("\r\nATE0\r\n"); and restart the GSM Modem only. PIC development should be ON. See the result. This will ensure that the characters you received are only from GSM Module and NOT your input "UART1_Write_Text("\r\nATE0\r\n");".

see post #11

......Also, comment the line "UART1_Write_Text("AT\r\n");" and restart the GSM Modem (only) NOT PIC DEMO BOARD (it should be active by default). If so, CPIN: READY, etc will be received at "rcv" buffer (If you enabled unsolicited result code). You can call the GSM Modem from your mobile phone and check the rcv buffer....
 

see getch() function in HI-TECH . when we use getch() function it waits until RC interrupt (RCIF) happens. It it happens the data comes into our buffer. If we read the data, RCREG cleared and ready for next data. So, we can able to continuously read the entire data from USART. I don't know about the UART1_Read(), UART1_Data_Ready() function details.


Code C - [expand]
1
2
3
4
5
6
unsigned char getch() {
    /* retrieve one byte */
    while(!RCIF)    /* set when register is not empty */
        continue;
    return RCREG;   
}



For example,

Code C - [expand]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
.
.
.
while(1){
           char GSM_DATA = getch();
        
           switch (GSM_DATA){
                   case 0x0A: // if line feed
                       break;
                   case 0x0D: // if carriage return (enter)
                                     GSM_STRING[i] = 0x00;
 
                                    if (strlen(GSM_STRING) > 0){
                                            i = 0;
                                            parse_GSM_STRING(GSM_STRING); // Process received GSM String
                                            strcpy(GSM_STRING, "");
                                    }
                       break;
                    case 0x3E: 
                                    GREATER_SIGN = 1;
                       break;
                    default:
                                    GSM_STRING[i] = GSM_DATA;
                                    i++;
                       break;
         }
}

 
Last edited:

Status
Not open for further replies.

Part and Inventory Search

Welcome to EDABoard.com

Sponsor

Back
Top