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? */
}