Разбор кругового буфера

Я реализую небольшую библиотеку Zigbee для устройств Atmel XMEGA. Радио Zigbee общается с MCU, используя внутренний USART.

Когда я начал писать библиотеку, я использовал простой подход фиксированного массива вместе с прерываниями для полученных данных. Как только у меня была полная команда (я знаю, что у меня есть полная команда, потому что Zigbee указывает длину кадра - минус начальный разделитель и контрольная сумма в конце), я установил флаг в процедуре обслуживания прерываний и скопировал массив в другой массив в мой основной().

Как только я скопировал массив, другая процедура ZBProcessFrame берет на себя и анализирует фрейм и предпринимает соответствующие действия.

Потенциальная проблема с этим подходом заключается в том, что при копировании массива может появиться другое сообщение и изменить эту общую переменную.

Читая онлайн, кажется, что я могу либо отключить свои прерывания при копировании массива, либо использовать круговой буфер, так как тогда я могу избежать полного копирования массива. Я успешно реализовал 32-байтовый круговой буфер, но теперь моя проблема заключается в том, как я могу определить, где начались фактические данные и сколько байтов появилось с начала разделителя. Мой ISR имеет только следующее:

ISR(Receiver Interrupt)
{
     ring->add(USART_Data);
}

Должен ли я проверить начальный разделитель здесь и установить флаг, чтобы там была действительная команда здесь? Основной() может затем смотреть на флаг непрерывно, и если он поднят, он подразумевает наличие действительной команды.

Является ли это действительным подходом или я должен искать альтернативу?

+1
источник поделиться
2 ответа

Круговой буфер - хороший дизайн. Я бы оставил ISR как можно проще, как и у вас. Если ваш main супер-цикл, я бы добавил вызов новой подпрограммы, такой как ZBReceiveFrame, которая считывает следующий доступный байт (до всех доступных байтов отдельно) из кольцевого буфера и обрабатывает его в государственной машине. Например, первое состояние ожидает разделителя начала кадра и переходит к следующему состоянию, когда оно было получено. Следующее состояние принимает и интерпретирует длину кадра. Следующее состояние принимает тело кадра, а конечное состояние проверяет CRC фрейма (все просто примеры). Все состояния могут быть реализованы в ZBReceiveFrame с помощью оператора switch. Переменная состояния, используемая в ZBReceiveFrame должна быть статической, чтобы состояние запоминалось с одного вызова на другой. Когда конечное состояние идентифицирует действительный фрейм, он устанавливает флаг, чтобы вызвать main чтобы вызвать ZBProcessFrame. Независимо от ZBReceiveFrame обрабатывает ли ZBReceiveFrame один или все доступные символы, зависит от того, насколько критичным по времени является другой материал в main супер-цикле.

Этот метод создает нежелательную связь, что желательно. ISR отвечает только за прием байта в кольцевой буфер и не знает, что такое фрейм. ZBReceiveFrame знает, как читать из кольцевого буфера и ограничивать кадр, но не знает, как интерпретировать данные. И ZBProcessFrame отвечает за интерпретацию данных в кадре, но не знает о кольцевом буфере.

+4
источник

Ваш круговой буфер должен иметь позиции чтения и записи. WR указывает на следующее пустое пространство, а RD - на самый старший полученный байт.

Но это означает, что вам нужно одновременно манипулировать этими двумя переменными: RD никогда не должен превышать WR, например. И поскольку вы не можете сделать это с помощью одной инструкции, вам необходимо отключить прерывания, когда один из них читается или записывается.

Я обычно делал это так:

  • Имейте функцию putByte которая используется из процедуры прерывания. Из ISR ничего не сделано.

  • Имейте функцию getByte которая используется из основной программы. Эта функция временно отключит прерывания. Возвращает специальное значение (-1 или подобное), если буфер пуст.

  • На каждой итерации основного цикла скопируйте доступные байты из кругового буфера в основной буфер. Проверьте полученные данные после того, как круговой буфер пуст, или основной буфер заполнен. Если байт недостаточно, скопируйте больше на следующую итерацию основного цикла. В противном случае - рамка процесса.

Время в ISR должно быть коротким (только копировать байты в круговой буфер), а время блокировки ISR должно быть коротким (при чтении кругового буфера нет ошибок, только копирование в основной буфер)

+1
источник

Посмотрите другие вопросы по меткам или Задайте вопрос