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.

Gsm response differs every time with PIC16f877a

Status
Not open for further replies.
This isn't a length issue, there is a fundamental problem with sending and receiving strings.

As far as I can tell, you do not need the Copybuff() routine at all and by duplicating the incoming data all you do is double the amount of RAM being used. What you need is a way to store incoming characters UNTIL a terminator is found. When the terminator is detected, you have time to do whatever you want before sending another command. The incoming storage buffer does not need clearing but you do need a way to 'point' (there is a hint there) to where the data is placed in the buffer and a way to reset the pointer to the start when a new string of characters arrives.

A single routine is all you need to send commands. For example "SendGSM(string);" and it can add it's own terminator so you don't have to add it to every string you send.

First though, tell us how you detect the "OK" message coming back from the modem.

Brian.
 

Instead of your ClearBuff() function there is standard function memset().

Usage.

Code:
memset(buffer,0,sizeof(buffer));
 

... the point I was making is there is no need to double buffer or have a function to clear the buffer at all.

What you do is maintain a pointer (an index to an array) and increment it when a character is received so it saves to the next location in the array and always store a zero in the next location. That means no matter how long the data is, it always has a zero terminator and can be used as an ASCIIZ string. When finished, all you do is reset the pointer to zero so it starts at the beginning of the array again. There may be previous data still in the array but that doesn't matter because it is beyond the terminator and will be ignored by 'C' string functions. It only takes a char sized array and a char sized pointer to do it that way so it is quick and memory efficient.

If I can flow chart it without a chart (!):
1. receive the character
2. see if there is space in the buffer to store it (=check the index < array size)
3. store it in the array[index];
4. increment the index
5. store a zero at array[index]
6. see if the character was a terminator (for example \r or \n)
6a. if it was, the array now contains the received string and any 'C' string function can use it.
6b. if it wasn't the terminator, go to step 1

After step 6a, do whatever you need to do (for example strcmp(), strcpy()...) then reset the index to zero and go back to step 1.

Brian.
 

betwixt i followed your flow chart,

Code:
__interrupt() void ISR(void)
{
    if(RCIF)
    {  
      buf = RCREG;
       
        if(j < 61)
       {
       data[j] = buf;
       j++;
       data[j] = 0;
       if(buf == '\n')
      {
      strcpy(res,data);
      j=0;
      }
}
 
Last edited by a moderator:

Can you burn and test this .hex file? It uses the same AT commands and SMS messages that you have used but written using a different compiler.

Use RealTerm and show me the exact response of Gsm (SIM800) when SMS is received by the device and I will try to fix or help you fix the code.

Test the attached .hex file and reply if it works fine. If it works fine then I will post its c project.

Use winrar 5.7 (free version) to extract the attached file.

Try this.

Code:
__interrupt() void ISR(void)
{
	if((RCIE) && (RCIF))
	{
		if(j < 61)
		{
			data[j++] = RCREG;
			data[j] = 0;
		}
		else
		{
			RCIE = 0;
		}

		j = 0;
		RCIE = 1;
	}

//main code

while(1)
{

	if(j >= 61)
	{
		if(strstr(data,"LOAD1 ON") != 0)	//better to store all strings in
							       // ROM using const char data type as RAM is less.
		{
			RD0 = 1;
		}
		else if(strstr(data,"LOAD1 OFF") != 0)
		{
			RD0 = 0;
		}
	}
}
 

Attachments

  • Gms_Device_Control.rar
    1.9 KB · Views: 46
Last edited:

Please use RealTerm (serial terminal software) and show the exact response of the GSM when a new SMS is received (RealTerm shows CR and LF as it is). Also you have to issue a AT+CMGD command to delete all the SMS in SIM after you check an SMS and control a device that is you should make space for new SMS in your SIM.

I have use 20 MHz HS clock for Gsm project as your dev board has the same.
 

i tested your code for sending sms from gsm modem, i checked the response i.e 'data' in variable window, it is displaying only '\n' and strucked in if(j >= 61),
one more thing i didn't understand why you disable and enable RCIE in ISR
 

For SIM800L they show the response when a new SMS is received here.

https://lastminuteengineers.com/sim800l-gsm-module-arduino-tutorial/

Show the exact response you get on RealTerm (use Printscreen key to capture the screenshot of Desktop) for both: "LOAD1 ON" and "LOAD1 OFF" SMS messages so that I can fix mine and your codes.

Check PM (Private Message).

- - - Updated - - -

Edit:

I had made a mistake with the interrupt flag in my code. Here is the fixed code. Try it.

Code:
__interrupt() void ISR(void)
{
	if((RCIE) && (RCIF))
	{
		if(j < 61)
		{
			data[j++] = RCREG;
			data[j] = 0;
		}
		else
		{
			RCIE = 0;
		}		

		RCIF = 0;
	}

//main code

while(1)
{

	if(j >= 61)
	{
		if(strstr(data,"LOAD1 ON") != 0)	//better to store all strings in
							       // ROM using const char data type as RAM is less.
		{
			RD0 = 1;
		}
		else if(strstr(data,"LOAD1 OFF") != 0)
		{
			RD0 = 0;
		}

		j = 0;
		RCIE = 1;
	}
}

- - - Updated - - -

There was a bug in my code. I have fixed it. Please test the attached .hex file with 20 MHz crystal and 9600 bps baud. If it works fine then I will post my code.
 

Attachments

  • Gms_Device_Control-fixed1.rar
    2 KB · Views: 45

its working fine now, thank you

- - - Updated - - -

thanks everyone for your valuable time and suggestions.
 

You missed the closing ')' in the ISR as well.

RCIE should not be reset, remember that GIE is cleared during an ISR so it would have no effect anyway.
Re-enabling it the main code is not a good idea either as it could lose incoming characters if the main routine took too long.

It is much safer to use the GSM message terminator to reset 'j' and tell the main routine that a full string has been received. It may never happen in real life but imagine a corrupted message such as "fjih%vbbe9LOAD1 ON4456jifjr" was received, the present code would see 'LOAD1 ON' and set RD0. It could even happen if the 'LOAD1' came at the end of one GSM string and 'ON' came in the next. By looking for the terminator inside the ISR you avoid the problem of continuously searching for a match while idle and do it only once when a full string has been received.

Brian.
 

Which code worked? The one I posted as code or the .hex file? Here is the updated code. Try it also.

@betwixt

I didn't use GIE bit to disable interrupts in ISR because if OP uses another interrupt say Timer1 then it will disable timer1 also.


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
41
42
43
44
__interrupt() void ISR(void)
{
    if((RCIE) && (RCIF))
    {
        if(j < 61)
        {
            data[j++] = RCREG;
            data[j] = 0;
        }
        else
        {
            RCIE = 0;
        }       
 
        RCIF = 0;
    }
 
//main code
 
while(1)
{
 
    if(strstr(data,"+CMT: ") != 0)
    {
        if(strstr(data,"LOAD1 ON") != 0)                                {
            RD0 = 1;
        }
        else if(strstr(data,"LOAD1 OFF") != 0)
        {
            RD0 = 0;
        }
 
        if(strstr(data,"LOAD2 ON") != 0)                                {
            RD0 = 1;
        }
        else if(strstr(data,"LOAD2 OFF") != 0)
        {
            RD0 = 0;
        }
 
        j = 0;
        RCIE = 1;
    }
}



or


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
__interrupt() void ISR(void)
{
    if((RCIE) && (RCIF))
    {
        data[j++] = RCREG;
        data[j] = 0;        
        
        RCIF = 0;
    }
 
//main code
 
while(1)
{
    if(strstr(data,"+CMT: ") != 0)
    {
        RCIE = 0;
 
        if(strstr(data,"LOAD1 ON") != 0)                                {
            RD0 = 1;
        }
        else if(strstr(data,"LOAD1 OFF") != 0)
        {
            RD0 = 0;
        }
 
        if(strstr(data,"LOAD2 ON") != 0)                                {
            RD0 = 1;
        }
        else if(strstr(data,"LOAD2 OFF") != 0)
        {
            RD0 = 0;
        }
 
        memset(data,0,sizeof(data));
        j = 0;
        RCIE = 1;
    }
}




Edit:

Add code to send A'AT+CMGD=1,4\r\n" as the last line of code that is after


Code C - [expand]
1
RCIE = 1;



so that all messages in SIM are deleted when a new SMS is received and device controlled and SIM SMS storage will not be full.

If SIM storage is full then Gsm module will not be able to receive new messages.
 
Last edited:

Your code is still not closing the ISR properly - you have main() inside the ISR at the moment!

GIE is AUTOMATICALLY reset during an ISR so none of the interrupts can work, including the timer interrupts. The 16F877A does not allow re-entrant interrupts so it turns the whole interrupt system off until the ISR is finished. Generally it is best practice to never change interrupt settings while processing an interrupt.

The memset() routine is not needed. Consider that a string in 'C' is always terminated by a zero. Each time a character is stored in the buffer, the index is advanced and a new zero stored, that means anything previously in the buffer is overwritten and a new terminator added to it. If the string 'ABC' was received and the buffer previously held 'UVWXYZ' the buffer would look like this:

A, 0x00, W, X, Y, Z
A, B, 0x00, X, Y, Z
A, B, C, 0x00, Y Z
The added zero is in red.
so any string command would start from array[0] and stop at the zero even if previous contents were still there. What needs to be done is to reset the index when the end of the GSM string is detected so the array starts filling from the first location again.

Brian.
 

There was a bug in my code. I have fixed it. Please test the attached .hex file

If it works fine then I will post my code.

@baileychic,

Since OP has stated this question as being solved at post #50 (and I'm particularly tempted to remove all posts after that), there is no need to keep posting here alternative codes differing a lot from the original turning this thread endless, so unless you open your own thread to ask your questions, please avoid stacking issues in a thread that has already been dealt with a solution. In addition: You were already warned to NOT post .hex files with no source codes.
 

Status
Not open for further replies.

Similar threads

Part and Inventory Search

Welcome to EDABoard.com

Sponsor

Back
Top