AVR UART 读取一个字节两次
AVR UART reads a single byte twice
我目前正在编写一个 UART 接收代码,该代码使用 AVR ATtiny87 从另一台机器读取和解析命令。
这个想法是检测起始字符并将其存储在缓冲区中,并继续存储 UART 字节,直到收到 0x0a (FL)。我这样做没有问题,但出于某种原因,我的代码读取每个字节两次。以下是我的函数,由我的内核循环调用。
void vehicle_recv(void) {
uint8_t n = 0;
char byte;
byte = LINDAT; //Reads and stores the content of the UART data register.
if(compass_packet.state == BUFFER_RX_IDLE) {
if(byte == '*' || byte == '#') {
compass_packet.buffer[0] = byte;
compass_packet.index = 1;
compass_packet.state = BUFFER_RX_IN_PROG;
}
}
if(compass_packet.state == BUFFER_RX_IN_PROG) {
compass_packet.buffer[compass_packet.index] = byte;
(compass_packet.index)++;
if(byte == 0x0a) {
compass_packet.buffer[compass_packet.index] = byte;
(compass_packet.index)++;
compass_packet.size = compass_packet.index;
compass_packet.state = BUFFER_RX_DONE;
}
}
if(compass_packet.state == BUFFER_RX_DONE) {
decode_vehicle_command(&compass_packet);
compass_packet.state = BUFFER_RX_IDLE;
}
}
uint8_t decode_vehicle_command(struct compass_comm_packet *RX_buffer) {
debugChar(debug_str);
sendChar(RX_buffer->buffer[0]);
sendCRLF();
sendChar(RX_buffer->buffer[1]);
sendCRLF();
sendChar(RX_buffer->buffer[2]);
sendCRLF();
sendChar(RX_buffer->buffer[3]);
sendCRLF();
sendChar(RX_buffer->buffer[4]);
sendCRLF();
sendChar(RX_buffer->buffer[5]);
sendCRLF();
sendChar(RX_buffer->buffer[6]);
sendCRLF();
sendChar(RX_buffer->buffer[7]);
sendCRLF();
uint8_t return_value = 0;
if(RX_buffer->buffer[0] == '*') {
switch(RX_buffer->buffer[1]) {
case 'H':
strcpy(debug_str, "Heading\r\n");
debugChar(debug_str);
break;
case 'R':
strcpy(debug_str, "Reset\r\n");
debugChar(debug_str);
break;
case 'S':
strcpy(debug_str, "Stop\r\n");
debugChar(debug_str);
break;
case 'C':
strcpy(debug_str, "Calibrate\r\n");
debugChar(debug_str);
break;
}
}
当我发送 *H(CR)(FL) 时,我希望 decode_vehicle_command() 函数输出 *H(CR)(FL)。但是,我一直看到 **HH(CR)(CR)(FL)(FL)。我可以通过使用 RX_buffer->buffer[2] 而不是 RX_buffer->buffer[1] 来非常简单地解决这个问题,但我很好奇我到底做错了什么。
部分问题是您设置了一个状态,然后在同一个通道中对其进行操作。将代码更改为在处理特定字符后退出例程,或者将第二个和第三个 if
语句更改为 else if
.
使用调试器逐句查看我的意思。
将状态设置为空闲,将接收到的字符设置为'*',您将得到以下序列:
if(compass_packet.state == BUFFER_RX_IDLE) {
// TRUE
if(byte == '*' || byte == '#') {
// TRUE
compass_packet.buffer[0] = byte;
compass_packet.index = 1;
compass_packet.state = BUFFER_RX_IN_PROG;
}
}
此时缓冲区中存入了前导字符,索引为1,你的状态为"RX in progress"。
if(compass_packet.state == BUFFER_RX_IN_PROG) {
// TRUE because you just set it in the previous block
compass_packet.buffer[compass_packet.index] = byte;
// here you've now stored the leading character '*' again
(compass_packet.index)++;
if(byte == 0x0a) {
compass_packet.buffer[compass_packet.index] = byte;
(compass_packet.index)++;
compass_packet.size = compass_packet.index;
compass_packet.state = BUFFER_RX_DONE;
}
}
换行终止符也有类似的问题。
尝试:
if(compass_packet.state == BUFFER_RX_IDLE) {
if(byte == '*' || byte == '#') {
compass_packet.buffer[0] = byte;
compass_packet.index = 1;
compass_packet.state = BUFFER_RX_IN_PROG;
}
} else if(compass_packet.state == BUFFER_RX_IN_PROG) {
compass_packet.buffer[compass_packet.index] = byte;
(compass_packet.index)++;
if( byte == 0x0a) {
compass_packet.size = compass_packet.index;
compass_packet.state = BUFFER_RX_DONE;
decode_vehicle_command(&compass_packet);
compass_packet.state = BUFFER_RX_IDLE;
}
}
顺便说一句,你的状态机还有其他漏洞。如果 end-of-line 标记前的字符太多会怎样?
查看函数 vehicle_recv()
,您有:
if(compass_packet.state == BUFFER_RX_IDLE) {
if(byte == '*' || byte == '#') {
compass_packet.buffer[0] = byte;
compass_packet.index = 1;
compass_packet.state = BUFFER_RX_IN_PROG;
}
}
if(compass_packet.state == BUFFER_RX_IN_PROG) {
compass_packet.buffer[compass_packet.index] = byte;
(compass_packet.index)++;
if(byte == 0x0a) {
compass_packet.buffer[compass_packet.index] = byte;
(compass_packet.index)++;
compass_packet.size = compass_packet.index;
compass_packet.state = BUFFER_RX_DONE;
}
}
if(compass_packet.state == BUFFER_RX_DONE) {
decode_vehicle_command(&compass_packet);
compass_packet.state = BUFFER_RX_IDLE;
}
在第一个条件中设置 compass_packet.state = BUFFER_RX_IN_PROG
后,进入第二个条件,因为您刚刚设置了状态。在第二个条件中,您再次将 byte
保存到缓冲区---相同的字节,每个
if(compass_packet.state == BUFFER_RX_IN_PROG) {
compass_packet.buffer[compass_packet.index] = byte;
...
一般来说,我对那些条件句使用 switch
(或 if ... else
);这可能也是你的需要:
switch(compass_packet.state) {
case BUFFER_RX_IDLE:
if(byte == '*' || byte == '#') {
compass_packet.buffer[0] = byte;
compass_packet.index = 1;
compass_packet.state = BUFFER_RX_IN_PROG;
}
break;
case BUFFER_RX_IN_PROG:
compass_packet.buffer[compass_packet.index] = byte;
(compass_packet.index)++;
if(byte == 0x0a) {
compass_packet.buffer[compass_packet.index] = byte;
(compass_packet.index)++;
compass_packet.size = compass_packet.index;
compass_packet.state = BUFFER_RX_DONE;
}
break;
case BUFFER_RX_DONE:
decode_vehicle_command(&compass_packet);
compass_packet.state = BUFFER_RX_IDLE;
break;
default:
/* WTF? */
}
我目前正在编写一个 UART 接收代码,该代码使用 AVR ATtiny87 从另一台机器读取和解析命令。 这个想法是检测起始字符并将其存储在缓冲区中,并继续存储 UART 字节,直到收到 0x0a (FL)。我这样做没有问题,但出于某种原因,我的代码读取每个字节两次。以下是我的函数,由我的内核循环调用。
void vehicle_recv(void) {
uint8_t n = 0;
char byte;
byte = LINDAT; //Reads and stores the content of the UART data register.
if(compass_packet.state == BUFFER_RX_IDLE) {
if(byte == '*' || byte == '#') {
compass_packet.buffer[0] = byte;
compass_packet.index = 1;
compass_packet.state = BUFFER_RX_IN_PROG;
}
}
if(compass_packet.state == BUFFER_RX_IN_PROG) {
compass_packet.buffer[compass_packet.index] = byte;
(compass_packet.index)++;
if(byte == 0x0a) {
compass_packet.buffer[compass_packet.index] = byte;
(compass_packet.index)++;
compass_packet.size = compass_packet.index;
compass_packet.state = BUFFER_RX_DONE;
}
}
if(compass_packet.state == BUFFER_RX_DONE) {
decode_vehicle_command(&compass_packet);
compass_packet.state = BUFFER_RX_IDLE;
}
}
uint8_t decode_vehicle_command(struct compass_comm_packet *RX_buffer) {
debugChar(debug_str);
sendChar(RX_buffer->buffer[0]);
sendCRLF();
sendChar(RX_buffer->buffer[1]);
sendCRLF();
sendChar(RX_buffer->buffer[2]);
sendCRLF();
sendChar(RX_buffer->buffer[3]);
sendCRLF();
sendChar(RX_buffer->buffer[4]);
sendCRLF();
sendChar(RX_buffer->buffer[5]);
sendCRLF();
sendChar(RX_buffer->buffer[6]);
sendCRLF();
sendChar(RX_buffer->buffer[7]);
sendCRLF();
uint8_t return_value = 0;
if(RX_buffer->buffer[0] == '*') {
switch(RX_buffer->buffer[1]) {
case 'H':
strcpy(debug_str, "Heading\r\n");
debugChar(debug_str);
break;
case 'R':
strcpy(debug_str, "Reset\r\n");
debugChar(debug_str);
break;
case 'S':
strcpy(debug_str, "Stop\r\n");
debugChar(debug_str);
break;
case 'C':
strcpy(debug_str, "Calibrate\r\n");
debugChar(debug_str);
break;
}
}
当我发送 *H(CR)(FL) 时,我希望 decode_vehicle_command() 函数输出 *H(CR)(FL)。但是,我一直看到 **HH(CR)(CR)(FL)(FL)。我可以通过使用 RX_buffer->buffer[2] 而不是 RX_buffer->buffer[1] 来非常简单地解决这个问题,但我很好奇我到底做错了什么。
部分问题是您设置了一个状态,然后在同一个通道中对其进行操作。将代码更改为在处理特定字符后退出例程,或者将第二个和第三个 if
语句更改为 else if
.
使用调试器逐句查看我的意思。
将状态设置为空闲,将接收到的字符设置为'*',您将得到以下序列:
if(compass_packet.state == BUFFER_RX_IDLE) {
// TRUE
if(byte == '*' || byte == '#') {
// TRUE
compass_packet.buffer[0] = byte;
compass_packet.index = 1;
compass_packet.state = BUFFER_RX_IN_PROG;
}
}
此时缓冲区中存入了前导字符,索引为1,你的状态为"RX in progress"。
if(compass_packet.state == BUFFER_RX_IN_PROG) {
// TRUE because you just set it in the previous block
compass_packet.buffer[compass_packet.index] = byte;
// here you've now stored the leading character '*' again
(compass_packet.index)++;
if(byte == 0x0a) {
compass_packet.buffer[compass_packet.index] = byte;
(compass_packet.index)++;
compass_packet.size = compass_packet.index;
compass_packet.state = BUFFER_RX_DONE;
}
}
换行终止符也有类似的问题。
尝试:
if(compass_packet.state == BUFFER_RX_IDLE) {
if(byte == '*' || byte == '#') {
compass_packet.buffer[0] = byte;
compass_packet.index = 1;
compass_packet.state = BUFFER_RX_IN_PROG;
}
} else if(compass_packet.state == BUFFER_RX_IN_PROG) {
compass_packet.buffer[compass_packet.index] = byte;
(compass_packet.index)++;
if( byte == 0x0a) {
compass_packet.size = compass_packet.index;
compass_packet.state = BUFFER_RX_DONE;
decode_vehicle_command(&compass_packet);
compass_packet.state = BUFFER_RX_IDLE;
}
}
顺便说一句,你的状态机还有其他漏洞。如果 end-of-line 标记前的字符太多会怎样?
查看函数 vehicle_recv()
,您有:
if(compass_packet.state == BUFFER_RX_IDLE) {
if(byte == '*' || byte == '#') {
compass_packet.buffer[0] = byte;
compass_packet.index = 1;
compass_packet.state = BUFFER_RX_IN_PROG;
}
}
if(compass_packet.state == BUFFER_RX_IN_PROG) {
compass_packet.buffer[compass_packet.index] = byte;
(compass_packet.index)++;
if(byte == 0x0a) {
compass_packet.buffer[compass_packet.index] = byte;
(compass_packet.index)++;
compass_packet.size = compass_packet.index;
compass_packet.state = BUFFER_RX_DONE;
}
}
if(compass_packet.state == BUFFER_RX_DONE) {
decode_vehicle_command(&compass_packet);
compass_packet.state = BUFFER_RX_IDLE;
}
在第一个条件中设置 compass_packet.state = BUFFER_RX_IN_PROG
后,进入第二个条件,因为您刚刚设置了状态。在第二个条件中,您再次将 byte
保存到缓冲区---相同的字节,每个
if(compass_packet.state == BUFFER_RX_IN_PROG) {
compass_packet.buffer[compass_packet.index] = byte;
...
一般来说,我对那些条件句使用 switch
(或 if ... else
);这可能也是你的需要:
switch(compass_packet.state) {
case BUFFER_RX_IDLE:
if(byte == '*' || byte == '#') {
compass_packet.buffer[0] = byte;
compass_packet.index = 1;
compass_packet.state = BUFFER_RX_IN_PROG;
}
break;
case BUFFER_RX_IN_PROG:
compass_packet.buffer[compass_packet.index] = byte;
(compass_packet.index)++;
if(byte == 0x0a) {
compass_packet.buffer[compass_packet.index] = byte;
(compass_packet.index)++;
compass_packet.size = compass_packet.index;
compass_packet.state = BUFFER_RX_DONE;
}
break;
case BUFFER_RX_DONE:
decode_vehicle_command(&compass_packet);
compass_packet.state = BUFFER_RX_IDLE;
break;
default:
/* WTF? */
}