Your receiver code still has a mistake in it.
for(int j=0;j<=100;j++)
{
data[j] = serial_Rx();
uart_put(data[j]);
}
In this loop you are still overindexing the data
array, which is only a size of 2. You should increase its size to 101 to match your for
loop. Probably a smaller value will be sufficient too, but the size of the array should match the for
loop.
As I see on hyperterminal, Local Echo is disabled on your module so it will reply to most of the commands with "\r\nOK\r\n"
or "\r\nERROR\r\n"
. (With Local Echo enabled it would return the command too). So the longest message that you could receive is the error message which is 9 characters long.
char data[10]; //9 for data 1 for terminating null character
for(int j=0;j<9;j++)
{
data[j] = serial_Rx();
}
data[9] = '\0'; // close string with a terminating null character
Now, the response is presented in the array as a proper string. It is ready to be processed either by your own functions or by the standard C String library (#include <string.h>
).
Or you can still send the whole string to hyperterminal as well serial_Tx(data)
.
Process the result of the previous code with strstr() function of string.h
if(strstr(data,"OK") != NULL)
{
// it contains "OK"
// do stuff
}
More accurate way to receive serial data is to enable UART receive complete interrupts by setting RXCIE
bit in the UCSRB
register: UCSRB |= (1<<RXCIE);
If you look at the possible responses, the effective information is enclosed between a '\n'
and a '\r'
characters which makes excellent start and end conditions when parsing the GSM's response in the interrupt service routine.
The complete code is the following:
void serial_Init()
{
UCSRB |= (1<<TXEN)|(1<<RXEN)|(1<<RXCIE); // enable receive interrupts
UCSRC |= (1<<UCSZ1)|(1<<UCSZ0)|(1<<URSEL);
UBRRL = 51;
}
void serial_Tx(char *str)
{
for (unsigned int i=0;str[i]!=0;i++)
{
UDR=str[i];
while(!(UCSRA&(1<<UDRE)));
}
}
char serial_Rx()
{
while(!(UCSRA & (1<<RXC)));
return UDR;
}
void uart_put(char data)
{
UDR=data;
while(!(UCSRA&(1<<UDRE)));
}
///////////////////////////////////
// global variables for UART rx
///////////////////////////////////
int buffer_index = 0, started = 0;
unsigned char buffer[250];
unsigned char k;
ISR(USART_RXC_vect)
{
k = UDR;
if(k == '\r' && started == 1) // stop if is has already started and "\r" received
{
started = 2; // finished, ready for further processing
buffer[buffer_index] = '\0'; // terminate string
}
else if(started == 1) // if started save data
{
buffer[buffer_index++] = k;
}
else if(k == '\n') // start saving data at first "\n"
{
started = 1; // set process started
}
}
int main(void)
{
DDRA = 0x00;
DDRC = 0xFF;
PORTA = 0xFF;
serial_Init();
sei();
while(1)
{
if(PINA==0xFE)
{
buffer_index = 0;
started = 0;
serial_Tx("ATD<number>;\r\n");
}
if(started == 2) // check if rx is finished
{
// check if OK
serial_Tx(buffer);
}
}
}
ISR explanation:
So the structure of the messages we are expecting is the following: <\r><\n><data><\r><\n>
. Based on this, we want to start saving the incoming data after the first \n
was detected and keep it up until we reach a \r
.
Now the roles of the used variables:
k
is a temporary variable into which the received chars are loaded, then we can check if it is a \n
, \r
or data char and handle accordingly.
started
is for tracking the different phases:
started = 0
means, we did not receive the first \n
so far, so we keep waiting (else if(k == '\n')
branch ). Once a \n
arrives we set it to 1
indicating that we can start loading the received chars (k
) into our array.
started = 1
means that the start condition has been fulfilled, data can be stored in the array.
started = 2
when the processing has been started, so if the previous value was 1
and we received a \r
(if(k == '\r' && started == 1)
branch). Value 2
stops the loading of the array and indicates to the main function that the complete data is presented in the array.
I have a GSM module connected to an AVR too, so I tested the code of the ISR and get the following result:
This way data
will contain "OK"
or "ERROR"
.
In your code the following function call is wrong:
serial_Tx(data1[i]);
Because data1[i]
has a type of char
but void serial_Tx(char *str)
expects a char*
, this function is for sending strings, not single characters. This way it causes runtime error, hence you won't get the expected output.
Though, it won't generate a compilation error, but the compiler will give a warning like this:
It is recommended to check and fix these warnings, because as you could see they could cause troubles in runtime.
So, replace the function above with the void uart_put(char data)
function, like:
uart_put(data[i]);
and it will work.
Best Answer
Print bytes received from UART ISR on terminal, to see response from AT calling command, if you get 'OK', then number you wrote in AT command is called, if not your number is not called and you doing something wrong.
You always get an answer from GSM module regardless of whether it is all right or not, in the form of array of bytes and before you want to print it somewhere, you need to store all of that data.
No for loop, use while loop in this case