Как я могу автоматически вызывать UART_Receive_IT() при получении данных?

#stm32 #uart #freertos

#stm32 #uart #freertos

Вопрос:

Я новичок в STM32 и freertos. Мне нужно написать программу для отправки и получения данных из модуля через порт UART. Я должен отправить (передать) данные в этот модуль (например, M66). Затем я вернусь, чтобы выполнить некоторые другие задачи. как только M66 отправит на это ответ, моя seial-port-receive-функция (HAL_UART_Receive_IT) должна быть вызвана и получить этот ответ. Как я могу этого добиться?

Ответ №1:

Способ HAL_UART_Receive_IT работы заключается в том, что вы настраиваете его на получение указанного объема данных в заданный буфер. Вы предоставляете ему свой буфер, в который он будет считывать полученные данные и количество байтов, которые вы хотите получить. Затем он начинает получать данные. Как только получен именно такой объем данных, вызывается функция обратного HAL_UART_RxCpltCallback вызова (из IRQ), где вы можете делать с этими данными все, что захотите, например, добавлять их в какую-то очередь для последующей обработки в контексте задачи.

Если бы я хотел поделиться своим опытом, связанным с работой с модулем UART от HAL, так это то, что он не самый лучший для общего использования, когда вы не знаете объем данных, которые вы ожидаете получить заранее. В случае упомянутого вами модема M66 это будет происходить постоянно.

Чтобы решить эту проблему, у вас есть два варианта:

  1. Просто не используйте функции HAL вообще в случае UART, кроме функций инициализации. Реализуйте свой собственный обработчик прерываний UART (большая часть кода может быть скопирована из обработчика в HAL), где при получении данных вы помещаете полученные байты в очередь байтов приема, обрабатываемую в вашей задаче RTOS. В этой задаче вы реализуете синтаксический анализ протокола. Это подход, который я использую лично.
  2. Если вы действительно хотите использовать HAL, но также работаете с модулем, который отправляет разное количество данных, вызывайте HAL_UART_Receive_IT и указывайте, что вы хотите получать 1 байт каждый раз. Это сработает, но будет (потенциально намного) медленнее, чем первый подход. Предполагая, что позже вы захотите реализовать некоторую связь tcp / ip (вы упомянули модуль GPRS M66), вы, вероятно, не захотите делать это таким образом.

Комментарии:

1. Спасибо @Jacek … Как я могу реализовать свой собственный обработчик прерываний UART ?… можете ли вы сказать мне, как это сделать?

2. Реализацию HAL можно найти внутри void HAL_UART_IRQHandler(UART_HandleTypeDef *huart) . Вы вызываете эту функцию из ISR, указывая указатель на UART_HandleTypeDef обрабатываемую вами функцию. В вашем случае — реализация вашего собственного обработчика прерываний — вероятно, лучшим подходом было бы скопировать содержимое упомянутой функции и заменить вызовы функций HAL вашими собственными функциями. Применяются все ограничения и рекомендации, когда дело доходит до реализации обработчиков прерываний, например, чтобы они были как можно короче. Вероятно, будет полезно провести собственное исследование.

Ответ №2:

Вы должны попробовать следующий способ.

Включите прерывание UARTX Rx в NVIC. Установите приоритет прерывания. Снять маску с запроса прерывания в EXTI.

Затем используйте функцию обработчика прерываний USARTX, определенную в вашем векторе.

Всякий раз, когда данные поступают из USARTX, эта функция вызывается автоматически, и вы можете скопировать данные из регистра приема данных USARTX.

Ответ №3:

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

Вам необходимо реализовать передачу DMA с функциями определения конца передачи данных. Запустите USART в режиме DMA в циклическом режиме. Вам нужно будет обслуживать два события. Первым из них является прерывание завершения передачи DMA (затем вы копируете данные из текущего хвостового указателя в конец буфера, чтобы избежать переопределения данных) и прерывание ожидания USART — это определит конец приема.