AVR UART两次读取一个字节

时间:2019-06-28 21:30:41

标签: c avr uart

我目前正在编写UART接收代码,该代码使用AVR ATtiny87从另一台计算机读取和解析命令。 这个想法是检测起始字符并将其存储在缓冲区中,并继续存储UART字节,直到接收到0x0a(FL)。我这样做没有问题,但是由于某种原因,我的代码读取了每个字节两次。以下是我的函数,该函数由内核循环调用。

z

当我发送* H(CR)(FL)时,我希望decode_vehicle_command()函数吐出* H(CR)(FL)。但是,我一直看到** HH(CR)(CR)(FL)(FL)。我可以通过使用RX_buffer-> buffer [2]而不是RX_buffer-> buffer [1]来解决此问题,但是我很好奇我到底在做什么错。

非常感谢您!

2 个答案:

答案 0 :(得分:3)

查看功能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? */
}

答案 1 :(得分: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,您的状态为“正在进行接收”。

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

在状态机中还有其他漏洞,顺便说一句。如果在行尾标记之前输入太多字符会怎样?