0

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.

Clifford
  • 88,407
  • 13
  • 85
  • 165

1 Answers1

0

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.

Clifford
  • 88,407
  • 13
  • 85
  • 165
  • @NallurisasiKiran : Which part 'is true'? I have included some guessing. The code I posted is intended to be illustrative: I have no means if running or testing it, so I am not gauranteeing that it is correct. You are using a debugger right? If not, you really should. – Clifford Jul 07 '19 at 10:08
  • @NallurisasiKiran I have the arguments to memmove reversed. Will fix. – Clifford Jul 07 '19 at 10:11
  • this is true but the output what i got when i entered 457! is 007, 567! is 007, 333! is 003! and so on. i think there must be a decrement counter till 0 in memmove and buff[sizeof(buff)-2] = ch instead of '2'. – Nalluri sasi Kiran Jul 07 '19 at 10:11
  • ... also I apparently don't know my left from my right! :-) – Clifford Jul 07 '19 at 10:16
  • i am talking about the part of code which you had answered is true. – Nalluri sasi Kiran Jul 07 '19 at 10:16
  • @NallurisasiKiran I meant was it the nul termination, the synchronisation, or both that are "true". I was trying to see where the error in the answer lies, that's all. Never mind though - the memmove was shifting the wrong way I think. Try the correction. – Clifford Jul 07 '19 at 10:20
  • thank you for showing a new approach by the way code worked :-) – Nalluri sasi Kiran Jul 07 '19 at 10:22
  • what if i want to store 100 char size string without using ring buffer. can it be done by pointers? – Nalluri sasi Kiran Jul 27 '19 at 17:17
  • @NallurisasiKiran "pointers" are not the magic here, pointers are a fundamental concept, not a solution. A ring buffer is as likely to use pointers as any other solution. This method is distinct from a ring buffer as it moves the data in memory rather than moving references to the data. It is the use of memmove() that is peculiar to this solution. It is functionally scalable to any size buffer, but decreases performance linearly. By the time it takes longer to move the data than it takes to receive a character, it will fail. For large buffers it is a poor solution. – Clifford Jul 27 '19 at 17:40
  • how to increase the size of the buffer in the above code and i didnt clearly understand left shift and right shift part in the code. can you explain it with some illustrations. – Nalluri sasi Kiran Jul 27 '19 at 18:17
  • @NallurisasiKiran : All the data in the buffer is moved "left", loosing the oldest character, and adding the new character to the end. Because I have used `sizeof(buff)` throughout, the solution can be extended simply by changing the size of `buff`. But be aware, this solution is specifically tailored to receiving a fixed number of characters before the `!`, it is not a general purpose serial buffering solution and not suited to variable length commands. If that is required you need a redesign and probably to post a new question. – Clifford Jul 27 '19 at 18:29
  • @NallurisasiKiran : SO is not a discussion forum, it is a Q&A, we are deviating from the original question. If you have new or different requirements from the original question, post a new question. – Clifford Jul 27 '19 at 18:31