I am having problem in receiving string from HC05 to ATmega16. I am able receive characters but not able to receive strings.
I want to control DC motor wirelessly using ATmega16 and Bluetooth module (HC05). I am sending the timer OCR1A values from serial monitor app to ATmega16 by HC05 but not succeeded.
#define F_CPU 16000000UL
#include<string.h>
#include <avr/io.h>
#include <util/delay.h>
#include <stdlib.h>
#include <stdio.h>
void UART_init()
{
UCSRB |= (1 << RXEN) | (1 << TXEN);
UCSRC |= (1 << URSEL) | (1 << UCSZ0) | (1 << UCS Z1);
UBRRL = 0x67;
}
unsigned char UART_RxChar()
{
while( (UCSRA & (1 << RXC)) == 0 );
return(UDR);
}
void UART_TxChar( char ch )
{
while( !(UCSRA & (1 << UDRE)) ); /* Wait for empty transmit buffer*/
UDR = ch ;
}
void UART_SendString( char* str )
{
unsigned char j = 0;
while( j <= 2 )
{
UART_TxChar( str[j] );
j++;
}
}
int main( void )
{
char buff[3];
char j;
int i = 0, k = 0;
DDRD = (1 << PD5);
UART_init();
while( 1 )
{
buff[0] = UART_RxChar();
buff[1] = UART_RxChar();
buff[2] = UART_RxChar();
j = UART_RxChar();
if( j == '!' )
{
UART_SendString( buff ); // this is to check whether the atmega16 received correct values for timer or not.
UART_SendString( "\n" );
}
}
}
The expected result is when I enter the number in serial monitor app, I should get back the same number on serial monitor app.
In the actual result I am getting different characters sometimes and empty some times.
The string buff
is unterminated, so UART_SendString( buff );
will send whatever junk follows the received three characters until a NUL (0) byte is found.
char buff[4] = {0};
Will have room for the NUL and the initialisation will ensure that buff[3]
is a NUL terminator.
Alternatively, send the three characters individually since without the terminator they do not constitute a valid C (ASCIIZ) string.
Apart from the lack of nul termination, you code requires input of exactly the form nnn!nnn!nnn!...
. If the other end is in fact sending lines with CR or CR+LF terminators - nnn!<newline>nnn!<newline>nnn!<newline>...
your receive loop will get out of sync.
A safer solution is to use the previously received three characters whenever a '!'
character is received. This can be done in a number of ways - for long buffers a ring-buffer would be advised, but for just three characters it is probably efficient enough to simply shift characters left when inserting a new character - for example:
char buff[4] ;
for(;;)
{
memset( buff, '0', sizeof(buff) - 1 ) ;
char ch = 0 ;
while( (ch != '!' )
{
ch = UART_RxChar() ;
if( isdigit(ch) )
{
// Shift left one digit
memmove( buff, &buff[1], sizeof(buff) - 2 ) ;
// Insert new digit at the right
buff[sizeof(buff) - 2] = ch ;
}
else if( ch != '!' )
{
// Unexpected character, reset buffer
memset( buff, '0', sizeof(buff) - 1 ) ;
}
}
UART_SendString( buff ) ;
UART_SendString( "\n" ) ;
}
This also has the advantage that it will work when the number entered is less than three digits, and will discard any sequence containing non-digit characters.