STM32 UART串口数据接收策略
串口是常见的数据通讯接口,需要在不同的应用场景下选择特定的数据接收模式,才能可靠的接收和处理数据。这里介绍常用简化串口即只有TX/RX连接的串口通讯接收策略。

接收传感器数据,选帧方式
典型的应用为传感器按照发送周期,不断的发送串口数据给STM32接收端,由于前后帧数据一般变化小,选择部分帧数据处理即可。这种场景就要用到串口的DMA接收方式,设定特定长度的DMA接收并启动,在接收完成后由DMA完成中断触发,进行数据处理,并重新启动DMA接收。
STM32的UART串口DMA配置为:

使能中断:

如下的帧定义为
FH1 FH2 D7 D6 D5 D4 D3 D2 D1 D0 CRC8
也就是由2个帧头字节,8个数据字节,1个校验字节组成,一帧长度为L=11个字节。
那么DMA接收启动要设置的长度为2L-1, 即21个字节,如
HAL_UART_Receive_DMA(&huart1, uart1_rx_buff, 21);
这样,当DMA接收到21个字节后触发接收完成中断,可以在接收完成中断响应函数里( void HAL_UART_RxCpltCallback(UART_HandleTypeDef huart) )将数据进行转存并设置标识,在主程序循环里识别到有有效数据收到,那么在转存的数据里,有且只有一帧有效数据,可以采用字节滑动法对帧头进行识别,再把后面对应一帧的数据取出来,用校验字节校验,如果校验正确,则进行后续处理。处理完再启动DMA接收。
如果传感器发过来的帧是变长度帧,则以最长的帧作为参考,设置DMA接收长度2L-1, 这样,在接收到的一次DMA完整数据里,可能有几个有效帧,变长度帧会有帧类型识别字节,根据识别字节进行相应处理即可。
接收单帧数据,没有其它逻辑占用MCU时序
典型的应用为主从控制系统,从机保持等待状态,等到主机发送串口指令过来后,才执行操作并做相应的结果返回。在等待主机发送串口信息时,没有其它的运行过程会影响到串口数据的接收。因此,可以先设置中断方式接收一个帧头字节,然后再在主程序里通过轮询进行后续字节的接收,接收时采用接收超时模式完整接收,因此只要把接收的buffer设置到足够包含任何单帧数据长度即可。主程序重新打开接收中断,并在下次接收到串口数据前处理完当前事务。
具体的方式介绍见:《STM32 HAL 串口收发例程(中断配合轮询)》
接收单帧数据,有其它逻辑占用MCU时序
典型的应用为主机系统,一边在执行各种功能代码,同时要接收串口数据,这样就不能采用上述的方式,因为接收到帧头数据后,在主程序里无法保证马上进入轮询接收串口数据,因此要采用如下的方式。
- 主程序while循环之前启动串口通过中断或DMA方式(DMA接收完成中断),接收一个帧头数据,这个帧头数据具有指示后面数据的字节长度意义;
- 在接收完成中断处理函数中,识别当前状态为未接收态,通过接收到帧头后设置状态标识FLAG1, 并判断后面要接收的数据长度,重新使能中断或DMA方式(DMA接收完成中断);
- 在接收完成中断处理函数中,别当前状态为Flag1状态,设置状态标识FLAG2
- 在主程序中,识别到串口Flag1状态,延时特定时间(基于一帧数据接收延时最大值),然后判断串口状态是否为FLAG2,如果是,则进行数据校验和处理,然后重新打开接收一个帧头数据的串口中断或DMA方式(DMA接收完成中断);
- 在主程序中,识别到串口Flag1状态,延时特定时间(基于一帧数据接收延时最大值),然后判断串口状态是否为FLAG2,如果不是,则认为串口接收异常,则对串口接口进行复位,并重新打开接收一个帧头数据的串口中断或DMA方式(DMA接收完成中断);
如采用中断方式打开串口接收一个帧头数据:
HAL_UART_Receive_IT(&huart1, uart1_rxd, 1);
则串口接收完成中断响应函数为:
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
if(huart==&huart1)
{
if(uart1_status==0)
{
switch(uart1_rxd[0])
{
case 0x55:
uart1_status = 0x01;
HAL_UART_Receive_IT(&huart1, uart1_rxd+1, 2);
break;
case 0xAA:
uart1_status = 0x02;
HAL_UART_Receive_IT(&huart1, uart1_rxd+1, 4);
break;
default:
HAL_UART_Receive_IT(&huart1, uart1_rxd, 1);
}
}
else if(uart1_status==0x01)
{
uart1_status = 0xF1;
}
else if(uart1_status==0x02)
{
uart1_status = 0xF2;
}
else ;
}
}
上述代码,在接收到帧头0x55时,设置状态标识为0x01, 然后再使能接收2个字节串口数据,当接收到后,再设置状态标识为0xF1; 在接收到帧头0xAA时,设置状态标识为0x02, 然后再使能接收4个字节串口数据,当接收到后,再设置状态标识为0xF2;
主程序while循环里的代码:
if(uart1_status == 0x01)
{
PY_Delay_us_t(1000000); //To guarantee frame receiving completion
if(uart1_status != 0xF1) //Frame receiving abnormal
{
HAL_UART_MspInit(&huart1);
MX_USART1_UART_Init(); //Re-initialize uart
uart1_status = 0;
HAL_UART_Receive_IT(&huart1, uart1_rxd, 1); //Restart frame head receiving
}
else //Frame receiving normal
{
//Do data verification and processing
}
}
if(uart1_status == 0x02)
{
PY_Delay_us_t(1000000); //To guarantee frame receiving completion
if(uart1_status != 0xF2) //Frame receiving abnormal
{
HAL_UART_MspInit(&huart1);
MX_USART1_UART_Init(); //Re-initialize uart
uart1_status = 0;
HAL_UART_Receive_IT(&huart1, uart1_rxd, 1); //Restart frame head receiving
}
else //Frame receiving normal
{
//Do data verification and processing
}
}
上述代码,可以保证在某次串口数据传输异常时,不会导致后续串口数据的接收继续失败。
GPIO模拟UART串口设计
GPIO模拟串口的实现可以参考:
《STM32 GPIO模拟UART串口:最简延时方式》
《STM32 GPIO模拟UART串口:外部时钟及TIM方式》
USB转TTL串口工具
STM32实现USB转TTL串口工具时,需要通过中断,DMA和缓存方式的配合,实现有效的接收和转发时序。具体介绍见:《STM32实现USB转TTL串口工具》
在不同的场景采用不同的策略,可以实现串口帧数据的有效接收和处理。
UART-CAN融合式高速串口
借用CAN总线物理层收发芯片实现高速UART串口的设计方式:《STM32实现UART-CAN融合式高速串口》
–End–
2万+

被折叠的 条评论
为什么被折叠?



