AVR UART читает один байт дважды - PullRequest
0 голосов
/ 29 июня 2019

В настоящее время я пишу код приема 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], но мне любопытно, что именно я здесь делаю неправильно.

Спасибо большоемного заранее!

Ответы [ 2 ]

3 голосов
/ 29 июня 2019

Глядя на функцию 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 голос
/ 29 июня 2019

Часть проблемы заключается в том, что вы устанавливаете состояние, а затем воздействуете на него в тот же проход.Измените свой код, чтобы выйти из подпрограммы после обработки определенного символа, или измените второй и третий операторы 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 в процессе".

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

Выесть другие дыры в вашей конечной машине, кстати.Что произойдет, если вы получите слишком много символов перед знаком конца строки?

...