问题描述
我正在为 STM32F4 编写软件。 STM32 需要通过 UART 拉入一个字符串。这个字符串的长度是可变的,每秒来自一个传感器。字符串存放在一个固定的缓冲区中,所以缓冲区的内容是不断变化的。
传入的字符串如下所示:"A12941;P2507;T2150;C21;E0;"
UART 的设置:
- 波特率:19200
- 字长:8Bits
- 奇偶校验:无
- 停止出价:1
- 过采样:16 个样本
- 全局中断:已启用
- 无 DMA 设置
uint8_t UART3_rxBuffer[25];
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
HAL_UART_Receive_IT(&huart3,UART3_rxBuffer,25); //restart interrupt reception mode
int main(void)
{
HAL_UART_Receive_IT (&huart3,25);
}
while (1)
{
}
}
stm32f4xx_it.c 中的部分代码
void USART3_IRQHandler(void)
{
/* USER CODE BEGIN USART3_IRQn 0 */
/* USER CODE END USART3_IRQn 0 */
HAL_UART_IRQHandler(&huart3);
/* USER CODE BEGIN USART3_IRQn 1 */
/* USER CODE END USART3_IRQn 1 */
}
这种方式用变量字符串填充缓冲区确实有效,但由于缓冲区在不断补充,因此很难提取字符串的开头和结尾。例如,缓冲区可能如下所示: [0]'E' [1]'0' [2]'/n' [3]'A' [4]'1' [5]'2' [6]'9' [7]'4' [ 8]'1' [9]';' [10]'P'等...... 但我想要一个以“A”开头的缓冲区。
我的问题是,如何在 uart 上正确处理传入的字符串,以便我只有字符串“A12941;P2507;T2150;C21;E0;”?
提前致谢!!
解决方法
我可以看到三种可能性:
-
在中断中完成所有处理。当您到达可变长度消息的末尾时,请执行您需要对信息执行的所有操作,然后更改位置变量以重新从头开始填充缓冲区。
-
并行使用(至少)两个缓冲区。当您在中断上下文中检测到可变长度消息的结尾时,然后开始从位置 0 开始填充不同的缓冲区,并通知主上下文前一个缓冲区已准备好进行处理。
-
串联使用两个缓冲区。让中断以循环方式填充环形缓冲区,不考虑消息何时结束。在主上下文中从上一条消息的末尾扫描以查看您是否还有完整的消息。如果这样做,则将其复制到另一个缓冲区中,使其从缓冲区的开头开始。记录它在下一次的环形缓冲区中完成的位置,然后在线性缓冲区上进行处理。
选项 1 仅适用于您可以在少于发送器发送下一个或两个字节所需的时间内完成所有处理的情况。其他两个选项使用更多的内存并且实现起来有点复杂。只要您足够频繁地轮询新消息,就可以使用循环模式 DMA 实现选项 3,从而避免中断。如果您的主上下文可能不够频繁地轮询,则选项 2 允许将多条消息排队。
,我想分享一个与您的问题相关的示例代码。然而,这并不是您真正要寻找的。您可以根据需要编辑此代码片段。如果我没猜错,您也可以根据选项 3 进行编辑。
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
if (huart->Instance == USART2) {
HAL_UART_Receive_IT(&huart2,&rData,1);
rxBuffer[pos++] = rData;
if (rData == '\n') {
pos = 0;
}
}
在开始之前,在主函数中,在while循环之前,您应该使用“HAL_UART_Receive_IT(&huart2,1);”启用一个字节的中断。如果您的传入数据具有像“\n”这样的限制器,那么您可以保存每帧可能具有不同长度的整个数据。
如果您希望数据框以某个特定字符开头,那么您可以等待保存数据,直到获得该字符。在这种情况下,您可以通过将 '\n' 更改为您的字符来编辑此代码,获得该字符后,您应该开始将以下数据保存到缓冲区内。