如何使用ATmega16微控制器从HC05蓝牙模块接收字符串

How to receive strings from HC05 Bluetooth module using ATmega16 microcontroller

我在接收从 HC05 到 ATmega16 的字符串时遇到问题。我能够接收字符但不能接收字符串。

我想用ATmega16和蓝牙模块(HC05)无线控制直流电机。我正在通过 HC05 将定时器 OCR1A 值从串行监视器应用程序发送到 ATmega16,但没有成功。

#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" );
        }
    }
}

预期的结果是当我在串行监视器应用程序中输入数字时,我应该在串行监视器应用程序中返回相同的数字。

在实际结果中,我有时会得到不同的字符,有时会出现空白。

字符串 buff 未终止,因此 UART_SendString( buff ); 将发送接收到的三个字符之后的任何垃圾,直到找到 NUL (0) 字节。

char buff[4] = {0};

将为 NUL 留出空间,并且初始化将确保 buff[3] 是 NUL 终止符。

或者,单独发送三个字符,因为没有终止符,它们不构成有效的 C (ASCIIZ) 字符串。

除了缺少 nul 终止符之外,您的代码还需要输入 完全 形式 nnn!nnn!nnn!...。如果另一端实际上正在发送带有 CR 或 CR+LF 终止符的 - nnn!<newline>nnn!<newline>nnn!<newline>... 您的接收循环将不同步。

一个更安全的解决方案是在收到 '!' 个字符时使用先前收到的 三个 个字符。这可以通过多种方式完成——对于长缓冲区,建议使用 ring-buffer,但对于仅三个字符,在插入新字符时简单地向左移动字符可能就足够有效了——例如:

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" ) ;
}

这还有一个好处,当输入的数字少于三位数字时它会起作用,并且会丢弃任何包含 non-digit 个字符的序列。