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.

mayasunny

Member level 3
Joined
Mar 21, 2019
Messages
56
Helped
0
Reputation
0
Reaction score
0
Trophy points
6
Activity points
481
hie all, i'm working PIC16f877a micro controller(xc8 compiler,20MHz crystal and 9600 baudrate, Sim800 module), my project is by sending sms to GSM ,make PIc working according to sms, ex: if i sent sms as led on., led should turn on . I succeed in sending sms to GSM but the problem is GSM response is varying each time. please any suggestion to over come this problem.
Code:
#pragma config FOSC = HS        // Oscillator Selection bits (XT oscillator)
#pragma config WDTE = OFF       // Watchdog Timer Enable bit (WDT disabled)
#pragma config PWRTE = ON       // Power-up Timer Enable bit (PWRT enabled)
#pragma config BOREN = ON       // Brown-out Reset Enable bit (BOR enabled)
#pragma config LVP = OFF        // Low-Voltage (Single-Supply) In-Circuit Serial Programming Enable bit (RB3 is digital I/O, HV on MCLR must be used for programming)
#pragma config CPD = OFF        // Data EEPROM Memory Code Protection bit (Data EEPROM code protection off)
#pragma config WRT = OFF        // Flash Program Memory Write Enable bits (Write protection off; all program memory may be written to by EECON control)
#pragma config CP = OFF         // Flash Program Memory Code Protection bit (Code protection off)

#include <xc.h>
#include<string.h>
#define _XTAL_FREQ 20000000
char a[]="AT\r"; 
char echo[]="ATE0\r";
char sim[]="AT+CPIN?\r";                                 // To Check sim status
char mode_text[]="AT+CMGF=1\r";                          // to set text mode
char message_rec[]="AT+CNMI=1,2,0,0,0\r";             // use to set recipient number and mesg
//char mesg[]="AT+CMGR=49\r";                        // mesg we want to send
//char terminator=0x1A;                                    // ctrl Z to send mesg
char buf,data[61],res,res1;
unsigned int i,j;

void UART_Init(int baudRate)
{    
    BRGH=0;
    SYNC=0;
    TXSTA = 0X20;                                      // Asynchronous mode, 8-bit data & enable transmitter
    RCSTA = 0X90;                                      // Enable Serial Port and 8-bit continuous receive           
    SPBRG = 31;                                        // baud rate @20MHz Clock
}

void UART_TxChar(char ch)
{   
    while(TXIF == 0);                                   // Wait till the transmitter register becomes empty
    TXIF = 0;                                           // Clear transmitter flag
    TXREG = ch;                                         // load the char to be transmitted into transmit reg
}    

void UART_str(char *ch)                                 // to write data continously
{
    
    for(i=0;ch[i]!=0;i++)
    {
        UART_TxChar(ch[i]); 
    }
}

__interrupt() void ISR(void)
{
    int j,length = 61;     
    for(j = 0; j < length; j++)
    {  
       while(RCIF == 0);
        {
            buf = RCREG;                                 // Read The Received Data Buffer and clears RCIF flag
        }
       data[j] = buf; RCIE = 0;
    }
   
}

void main(void)
{
    char ch;
    TRISD = 0X00;
    PORTD = 0X00;
    TRISC = 0x80;                                       // Configure Rx pin(rc7) as input and Tx(rc6) as output 
    RCIE = 1;                                           // UART RecIeving Interrupt Enable Bit
    PEIE = 1;                                           // Peripherals Interrupt Enable Bit
    GIE = 1;                                            // Global Interrupt Enable Bit
    UART_Init(9600);                                    // Initialize the UART module with 9600 baud rate
    
    UART_str(a);
    __delay_ms(2);
    UART_str(echo);
     __delay_ms(2);
    UART_str(sim);
    __delay_ms(2);
    UART_str(mode_text);
    __delay_ms(2);
    UART_str(message_rec);
    __delay_ms(2);
 
    while(1)
    {
      
    }
    return;
}
</string.h></xc.h>
 
Last edited by a moderator:

A number of points there:

Check the polarity of the TXIF bit.
Your ISR is entered each time a character is received by the USART so you shouldn't reinitialize the storage inside it.
The 'return;' at the end does nothing. Think about where it returns to.

Restructure it so the ISR captures the character and sets a flag to say one is available but build the data[] string in the main routine.

When posting code, please wrap it in code tags to preserve the original formatting.

Brian.
 
can you explain little bit clear
 

Don`t ever use closed loop routines inside ISR as you're doing ( e.g while, for, etc... ).
 

but how can i check each character without for loop
 

Hi,

not inside the ISR, do it in main loop.
There are many examples and discussions about this topic...
Just do a search.

Klaus
 

sorry klaisST, with that interrupt im getting proper response like "\r\nOK\n\r
 

Hi,

1) coding style:
* Don´t do loops inside the ISR

2) Give useful informations:
* headline: "response differs every time"
* post#1: "response is varying each time."
* post#7: "im getting proper response"

What now? Proper response or varying reponse?

Klaus
 

What you have to understand Mayasunny is the interrupt does not occur when a GSM string has arrived, it occurs when every single character arrives. The reason you see two characters like 'OK' is there is a two character FIFO inside the PIC, it allows a second character to be held while the first one is being processed but it will not allow more than two characters to be processed.

Use the ISR to tell the main program a character is ready but do not try to build the array (data[j]) inside it. What you should do is set a flag inside the ISR to say a character has been received and maybe (your choice) also save the character itself in a variable, then inside your while() loop, you check for that flag, add the character to your array and then clear the flag so it is ready for the next character arriving.

Brian.
 

dear Klaus,
actually im collecting response of gsm with an array data[j], each time i debug the code the value/output of data[j] is varying means some times it showing every command response and sometimes over writing last command response why it is happening.
 

betwixt,
(What you should do is set a flag inside the ISR to say a character has been received and maybe (your choice) also save the character itself in a variable, then inside your while() loop, you check for that flag, add the character to your array and then clear the flag so it is ready for the next character arriving.)

Code:
__interrupt() void ISR(void)
{
    for(j = 0; j < length; j++)
    {  
       while(RCIF == 0);
        {
            buf = RCREG;                                 // Read The Received Data Buffer and clears RCIF flag
        }
       data[j] = buf; 
    }
}
in this case when i read RCREG, it automatically clears RCIF flag, after claring the flag only im adding data(buf) to the array.
 
Last edited by a moderator:

Hi,

after claring the flag only im adding data(buf) to the array.

With this:
data[j] = buf;
You rather move the contents of buf to the array (overwriting existing contents) instead of adding them.

Klaus
 

I Understood what you said, but i dont know how to avoid that over writing
 

Exactly as explained earlier. Like below - note that I have not attempted to compile or debug this but it should show you how it is done:
Code:
#pragma config FOSC = HS        // Oscillator Selection bits (XT oscillator)
#pragma config WDTE = OFF       // Watchdog Timer Enable bit (WDT disabled)
#pragma config PWRTE = ON       // Power-up Timer Enable bit (PWRT enabled)
#pragma config BOREN = ON       // Brown-out Reset Enable bit (BOR enabled)
#pragma config LVP = OFF        // Low-Voltage (Single-Supply) In-Circuit Serial Programming Enable bit (RB3 is digital I/O, HV on MCLR must be used for programming)
#pragma config CPD = OFF        // Data EEPROM Memory Code Protection bit (Data EEPROM code protection off)
#pragma config WRT = OFF        // Flash Program Memory Write Enable bits (Write protection off; all program memory may be written to by EECON control)
#pragma config CP = OFF         // Flash Program Memory Code Protection bit (Code protection off)

#include 
#include
#define _XTAL_FREQ 20000000
char a[]="AT\r"; 
char echo[]="ATE0\r";
char sim[]="AT+CPIN?\r";                                 // To Check sim status
char mode_text[]="AT+CMGF=1\r";                          // to set text mode
char message_rec[]="AT+CNMI=1,2,0,0,0\r";             // use to set recipient number and mesg
//char mesg[]="AT+CMGR=49\r";                        // mesg we want to send
//char terminator=0x1A;                                    // ctrl Z to send mesg
char buf,data[61],res,res1;
unsigned int i,j;
char CharacterReceived = 0;                            // new variable to announce data is available

void UART_Init(int baudRate)
{    
    BRGH=0;
    SYNC=0;
    TXSTA = 0X20;                                      // Asynchronous mode, 8-bit data & enable transmitter
    RCSTA = 0X90;                                      // Enable Serial Port and 8-bit continuous receive           
    SPBRG = 31;                                        // baud rate @20MHz Clock
}

void UART_TxChar(char ch)
{   
    while(TXIF == 0);                                   // Wait till the transmitter register becomes empty
    TXIF = 0;                                           // Clear transmitter flag
    TXREG = ch;                                         // load the char to be transmitted into transmit reg
}    

void UART_str(char *ch)                                 // to write data continously
{
    
    for(i=0;ch[i]!=0;i++)
    {
        UART_TxChar(ch[i]); 
    }
}

__interrupt() void ISR(void)
{
    if(RCIE)                                            // check the USART is the cause of the interrupt
    {
        buf = RCREG;                                    // Read The Received Data Buffer and clears RCIF flag
        CharacterReceived = 1;                          // Flag to say valid data is in 'buf'
        RCIE = 0;                                       // clear the USART interrupt flag
    }
}

void main(void)
{
    char ch;
    TRISD = 0X00;
    PORTD = 0X00;
    TRISC = 0x80;                                       // Configure Rx pin(rc7) as input and Tx(rc6) as output 
    RCIE = 1;                                           // UART RecIeving Interrupt Enable Bit
    PEIE = 1;                                           // Peripherals Interrupt Enable Bit
    GIE = 1;                                            // Global Interrupt Enable Bit
    UART_Init(9600);                                    // Initialize the UART module with 9600 baud rate
    
    UART_str(a);
    __delay_ms(2);
    UART_str(echo);
     __delay_ms(2);
    UART_str(sim);
    __delay_ms(2);
    UART_str(mode_text);
    __delay_ms(2);
    UART_str(message_rec);
    __delay_ms(2);
 
    while(1)
    {
        if(CharacterReceived)
        {
            CharacterReceived = 0;                      // prepare for any new characters arriving
            data[j] = buf;                              // add the character to 'buf'
            j++;                                        // point to the next location in 'data[]'
        }
    }
    return;
}
Note that this should store the incoming characters in 'data[]' but as the strings may have different lengths, you need a way to tell when all the characters from any response have been received. I suggest you modify the code inside the while() loop so it looks for the terminator at the end of the message. It would also be good programming practice to ensure 'j' doesn't get so big that it overwrites the end of the 'data[]' array. This could happen if for example a long corrupted string was received. The best way to do this is to set a maximum size for the data array and then make sure 'j' doesn't exceed it. My way to do it would be:
1. Add the line "#define MAX_GSM_LENGTH 61" near the top of the program,
2. Declare data like "char data[MAX_GSM_LENGTH];"
3. in the while() loop add "if(j < MAX_GSM_LENGTH)" before saving 'buf'".
That way, you can change the value of MAX_GSM_LENGTH if necessary without changing references to the value throughout the program. I used 61 because that is the value you used but it can be anything from 1 to 255.

Brian.
 

i modified the code as per your suggestions but it is receiving only single character that to A
 

Sorry betwixt , i just change the interrupt code as
Code:
__interrupt() void ISR(void)
{
    while(RCIF == 0);
    {
    buf = RCREG;                                    // Read The Received Data Buffer and clears RCIF flag
    CharacterReceived = 1;                          // Flag to say valid data is in 'buf'
    RCIF = 0;                                       // clear the USART interrupt flag
    }
}

and while part as

Code:
if(CharacterReceived)
        {
            CharacterReceived = 0;                      // prepare for any new characters arriving
            if(j < MAX_LENGTH){
            data[j] = buf;                              // add the character to 'buf'
            j++;                                        // point to the next location in 'data[]'
            }
        }

But there is no change in the problem
 

Sorry, I used RCIE instead of RCIF, the ISR should be:
Code:
__interrupt() void ISR(void)
{
    if(RCIF)                                            // check the USART is the cause of the interrupt
    {
        buf = RCREG;                                    // Read The Received Data Buffer and clears RCIF flag
        CharacterReceived = 1;                          // Flag to say valid data is in 'buf'
        RCIF = 0;                                       // clear the USART interrupt flag
    }
}
But that isn't what you put in the ISR anyway - look closely.

Brian.
 

Sorry, I used RCIE instead of RCIF, the ISR should be:
Code:
__interrupt() void ISR(void)
{
    if(RCIF)                                            // check the USART is the cause of the interrupt
    {
        buf = RCREG;                                    // Read The Received Data Buffer and clears RCIF flag
        CharacterReceived = 1;                          // Flag to say valid data is in 'buf'
        RCIF = 0;                                       // clear the USART interrupt flag
    }
}
But that isn't what you put in the ISR anyway - look closely.

Brian.

i can't sir
 

I used "if(RCIF)" you used "while(RCIF == 0);".

There are two problems with what you wrote, the first is a simple error in 'C' language, you added a ';' to the end of the line which makes it wait until RCIF is NOT zero, waiting inside an ISR is guaranteed to cause you problems.
The second is that the ISR is not entered UNTIL an interrupt occurs so if you only have the USART interrupts enabled, RCIF MUST be set before that part of code is ever reached.

The reason for checking if RCIF is set is that there are other sources of interrupts in the 16F877A, for example the timers or other peripherals. You need to be sure the RCIF bit is set to confirm you are there because the USART received something.

Are you using XC8 as the compiler? If you are, try setting a breakpoint in the while() loop and see what is in the variables when you simulate data entering the USART.

Brian.
 

Are you using XC8 as the compiler? If you are, try setting a breakpoint in the while() loop and see what is in the variables when you simulate data entering the USART.

Brian.

it is receiving "\r" 5 times one by one
 

Status
Not open for further replies.

Similar threads

Part and Inventory Search

Welcome to EDABoard.com

Sponsor

Back
Top