#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 это будет происходить постоянно.
Чтобы решить эту проблему, у вас есть два варианта:
- Просто не используйте функции HAL вообще в случае UART, кроме функций инициализации. Реализуйте свой собственный обработчик прерываний UART (большая часть кода может быть скопирована из обработчика в HAL), где при получении данных вы помещаете полученные байты в очередь байтов приема, обрабатываемую в вашей задаче RTOS. В этой задаче вы реализуете синтаксический анализ протокола. Это подход, который я использую лично.
- Если вы действительно хотите использовать 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 — это определит конец приема.