我正在尝试编写自己的库,用于通过UART0从我的Arduino UNO向我的计算机发送消息。
除了我想要接收字符串的部分之外,库成功运行。该库的代码是:
#define F_CPU 16000000
#define EVEN_P 0
#define ODD_P 1
#define BAUD_RATE 57600
#include <avr/io.h>
#include <math.h>
#include <avr/io.h>
#include <string.h>
#include <util/delay.h>
// Initialize UART0 communication
void UART0_Init_Custom(unsigned long BaudRate, char AsyncDoubleSpeed, char DataSizeInBits, char ParityEVENorODD, char StopBits)
{
uint16_t UBBR_Value = lrint (F_CPU / 16 / BaudRate - 1 ); // maybe 16L??
// Setting the U2X bit to 1 for double speed asynchronous (default = 0, normal speed)
if (AsyncDoubleSpeed == 1) UCSR0A = (1 << U2X0);
// Upper part of the baud number (bits 8 to 11)
UBRR0H = (unsigned char)(UBBR_Value >> 8);
// Rest of the baud number
UBRR0L = (unsigned char)(UBBR_Value);
// Enable the receiver and transmitter
UCSR0B = (1 << RXEN0) | (1 << TXEN0);
// Set 2 stop bits (default = 1)
if (StopBits == 2) UCSR0C = (1 << USBS0);
// Set parity
if (ParityEVENorODD == EVEN_P) UCSR0C |= (1 << UPM01);
if (ParityEVENorODD == ODD_P) UCSR0C |= (3 << UPM00);
// Set data length (default = 5 bits)
if (DataSizeInBits == 6) UCSR0C |= (1 << UCSZ00); // 6-bit
if (DataSizeInBits == 7) UCSR0C |= (2 << UCSZ00); // 7-bit
if (DataSizeInBits == 8) UCSR0C |= (3 << UCSZ00); // 8-bit
if (DataSizeInBits == 9) UCSR0C |= (7 << UCSZ00); // 9-bit
}
void UART0_Init(unsigned long BaudRate)
{
if (BaudRate == 115200)
{
UART0_Init_Custom((BaudRate/2),1,8,0,2);
}
else
{
UART0_Init_Custom(BaudRate,0,8,0,2);
}
}
// Receive Data UART0
char UART0_GET(void)
{
while (!(UCSR0A & (1 << RXC0)));
return UDR0;
}
// Transmit Data UART0
void UART0_PUT(char data)
{
while (!(UCSR0A & (1 << UDRE0)));
UDR0 = data;
}
// Transmit Data-String UART0
void UART0_PRINT(char* String)
{
while(*String)
{
UART0_PUT(*String++);
}
}
// Receive Data-String UART0
char* UART0_READ(void)
{
char* ReceivedString;
char ReceivedBit;
int StringBit = 0;
memset(&ReceivedString,0,sizeof(ReceivedString));
while ((ReceivedBit=UART0_GET())!=13)
{
UART0_PUT(ReceivedBit);
ReceivedString[StringBit] = ReceivedBit;
StringBit++;
}
ReceivedString[StringBit] = 13;
ReceivedString[StringBit++] = 10;
UART0_PUT(10);
strncpy(ReceivedString, ReceivedString, StringBit+1);
return(ReceivedString);
}
char* Input;
int main(void)
{
UART0_Init(BAUD_RATE);
UART0_PRINT((char*)"Give a message and I will return it\r\n");
while(1)
{
Input = UART0_READ();
UART0_PRINT((char*)"The message was:");
UART0_PRINT(Input);
}
}
运行此代码时,PuTTY会显示一些随机令牌并停止。我不能再插入任何东西了。
答案 0 :(得分:2)
我认为你遇到的主要问题是你没有分配任何存储接收数据的缓冲区(正如@WeatherVane在评论中指出的那样)。
在C中写一个要返回字符串的函数时,你有两个选择:调用者提供一个缓冲区并将指针传递给函数,或者函数分配缓冲区并返回一个指向它的指针。
如果函数要分配它,那么它必须使用malloc
函数在堆上分配它。您无法在函数内部使用局部变量,因为如果您在退出函数后立即执行该变量,则该变量超出范围。从理论上讲,您可以使用静态变量作为缓冲区,但如果您这样做,则一次只能读取一个字符串。
如果调用者要提供缓冲区,那么它可以使用局部变量,静态变量或从堆中分配。
当在堆上分配缓冲区时,无论是谁分配它,调用者必须使用free
函数在完成后释放它。
嵌入式系统通常最大限度地减少堆分配变量的使用 - 请参阅this question以获取有关其原因的一些信息 - 因此您可能最好允许调用者分配缓冲区,如下所示:
void UART0_READ(char* buffer, int buflen)
{
// ... here goes code to read into buffer
}
#define BUFSIZE 100
int main(void)
{
char input[BUFSIZE];
UART0_READ(input, BUFSIZE);
...
}
请注意,我将UART0_READ
函数定义为采用两个参数:缓冲区的地址及其长度。你的程序缺少的另一件事就是防止缓冲区溢出。
在输入例程中,使用例如的buflen参数。如果读取了太多字符,则调用memset,并在循环内部读取字符以提前退出。
缓冲区被定义为调用函数中的本地字符数组。
其他一些说明:
不要忘记添加一个零,超过添加到数组的最后一个字符。这也意味着你必须在读取buflen-1字符后退出循环,这样你才有足够的空间容纳0。
我不确定你打电话给strncpy
的原因?你似乎把字符串复制到自己身上。
在全尺寸操作系统中运行带有散乱指针的程序通常会导致段错误。嵌入式环境通常缺乏检测不正确的内存访问的复杂性,因此您可能会获得较少的可预测行为(例如随机垃圾从串行端口出来)。