简体   繁体   English

AVR UART 读取一个字节两次

[英]AVR UART reads a single byte twice

I am currently writing a UART receive code that reads and parses commands from another machine using AVR ATtiny87.我目前正在编写一个 UART 接收代码,该代码使用 AVR ATtiny87 从另一台机器读取和解析命令。 The idea is to detect the start character and store it in the buffer, and keep storing the UART byte until 0x0a (FL) is received.想法是检测起始字符并将其存储在缓冲区中,并继续存储 UART 字节,直到收到 0x0a (FL)。 I have no issue with doing so, but for some reason, my code reads each byte twice.我这样做没有问题,但由于某种原因,我的代码每个字节读取两次。 Following is my function, which is called by my kernel loop.以下是我的函数,它由我的内核循环调用。

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

When I send *H(CR)(FL), I expect the decode_vehicle_command() function to spit out *H(CR)(FL).当我发送 *H(CR)(FL) 时,我希望 decode_vehicle_command() 函数吐出 *H(CR)(FL)。 However, I keep seeing **HH(CR)(CR)(FL)(FL).但是,我一直看到 **HH(CR)(CR)(FL)(FL)。 I can work my way around this issue pretty simply by using RX_buffer->buffer[2] instead of RX_buffer->buffer[1], but I am curious what exactly I am doing wrong here.我可以通过使用 RX_buffer->buffer[2] 而不是 RX_buffer->buffer[1] 来解决这个问题,但我很好奇我在这里做错了什么。

Looking at the function vehicle_recv() , you have:查看函数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;
}

After you set the compass_packet.state = BUFFER_RX_IN_PROG inside the first conditional, you enter the second one as you've just set the state to do so.在第一个条件中设置compass_packet.state = BUFFER_RX_IN_PROG ,进入第二个条件,因为您刚刚设置了状态。 Inside the second conditional you are again saving byte to the buffer---the same byte, per在第二个条件中,您再次将byte保存到缓冲区---相同的字节,每个

if(compass_packet.state == BUFFER_RX_IN_PROG) {
    compass_packet.buffer[compass_packet.index] = byte;
    ...

Generally, I use a switch (or if ... else ) for those conditionals;通常,我对这些条件使用switch (或if ... else ); it may be your need too:这也可能是您的需要:

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

Part of the problem is that you set a state and then act on it in the same pass.部分问题在于您设置了一个状态,然后在同一次传递中对其进行操作。 Change your code to either exit the routine once you handle a particular character, or change the second and third if statements to else if .更改代码以在处理特定字符后退出例程,或者将第二个和第三个if语句更改为else if

Step through it with a debugger to see what I mean.用调试器逐步完成它,看看我的意思。

Set the state to idle and the received character to '*' and you'll get the following sequence:将状态设置为空闲并将接收到的字符设置为“*”,您将获得以下序列:

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

At this point the leading character is stored in the buffer, the index is 1 and your state is "RX in progress".此时前导字符存储在缓冲区中,索引为 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;
    }
}

You have a similar problem for the line feed terminating character.换行终止符也有类似的问题。

Try:尝试:

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

You have other holes in your state machine, btw.顺便说一句,您的状态机中还有其他漏洞。 What happens if you get too many characters before the end-of-line mark?如果在行尾标记之前获得太多字符会怎样?

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM