STM32F04xx UART — реализовать отклонение ввода для строк длиннее 2 байтов

Я пытаюсь реализовать проверку ввода на стороне STM32. Я надеюсь разрешить строку в форме «x\n», где «x» может быть любым символом.

Чтобы получить изменяющееся количество байтов, я реализовал это вUSART1_IRQHandler

void USART1_IRQHandler(void)
{
    if((USART1->ISR & USART_ISR_RXNE) != RESET) {
        if((1+RX_BUFFER_POS) < RX_BUFFER_SIZE) {
            UART_Buffer[1+RX_BUFFER_POS++] = USART1->RDR; // reading from DR resets RXNE flag, no need to manually clear it!
    }
  }
  HAL_UART_IRQHandler(&huart1);
}

И в основном цикле программы

if((RX_BUFFER_POS + 1) >= 2) {
  if(UART_Buffer[1] == 0x0A && !(UART_Buffer[2])) {
    HAL_UART_Transmit_IT(&huart1, (uint8_t*)OK_BUFFER, OKBUFFERSIZE);
  } else {
    UART_Buffer[2] = 0;
    RX_BUFFER_POS = -1;
    HAL_UART_Transmit_IT(&huart1, (uint8_t*)BAD_BUFFER, BADBUFFERSIZE);
  }
RX_BUFFER_POS = -1;
}

Код правильно отклоняет недопустимую строку символов, я использую «00\n» в качестве примера в первый раз. После этого все строки отбрасываются, в том числе и "действительная" ("x\n") строка.

Я провел некоторую отладку и обнаружил, что после неправильной строки значение RX_BUFFER_POSне сбрасывалось до -1, а зависало на 0. В чем причина этого? Я также обнаружил, что если я добавлю задержку в 1 мс к основному циклу while, проблема будет решена. Это заставляет меня подозревать, что происходит какое-то состояние гонки.

Кстати, я нашел способ исправить отклонение любого персонажа. Если я отправлю строку длиной 7, где "\n" будет последним символом, отказ будет работать еще раз. Когда я отправляю строку, я получаю «ПЛОХО», а также «ОК».

Мой вопрос: почему RX_BUFF_POS не сбрасывается до -1 при получении неправильной строки? Кроме того, поскольку, похоже, возникает состояние гонки, как я могу отследить причину этого?

Для этого уникального случая у меня возникло бы искушение построить крошечный конечный автомат, который временно удерживает полученный символ static charи записывает его в буфер только в том случае, если при следующем прерывании появляется следующая новая строка, в противном случае он отбрасывается. Затем вы можете зайти так далеко, что поместите в буфер только допустимые символы без символов новой строки, поскольку только те, которые сопровождаются таким образом, зайдут так далеко. Но если вашим сообщениям когда-нибудь понадобится стать переменной длины, эту оптимизацию будет нелегко расширить.
Что вы, возможно, (пока) не заметили, так это то, что ваш «RX_BUFFER_POS» изменяется как в ISR, так и в основной программе, но не защищен от прерываний в последней.

Ответы (1)

Как часто запускается основной цикл? Вероятно, он запускается так часто, что запускается между каждым символом, полученным UART. Вы отправляете тестовое сообщение из трех символов. После получения первых двух символов основной цикл выполняет проверку и обнаруживает недопустимое сообщение. Основной цикл устанавливает RX_BUFFER_POS в -1. Но затем приходит третий символ и увеличивает RX_BUFFER_POS до 0.

После того, как вы добавили задержку в основной цикл, возможно, все три символа будут получены до того, как основной цикл выполнит проверку. Если третий символ будет получен до проверки, то RX_BUFFER_POS останется равным -1 и будет работать.

Когда вы отправляете строку из семи символов, я предполагаю, что это семь символов, за которыми следует «\n». В этом случае основной цикл проверяет каждые два символа и отбрасывает первые шесть как недействительные. Затем принимается последний символ, за которым следует «\n», и он проходит проверку. Я подозреваю, что любая строка нечетной длины будет заканчиваться на «ОК». И любая строка четной длины будет заканчиваться RX_BUFFER_POS = 0 вместо -1, потому что после неудачной предыдущей проверки получен один лишний символ.