串口收到的两组数据之间,往往会有一定的时间间隔。可以判断这个间隔,来实现无需结束符,无需指定长度,串口可接收不定长数据的功能。如果串口在一定的时间内没有收到新的数据,可以认为一组数据已经接收完毕了。思路是用定时器来设置一个“闹钟”,连续的一段时间没有收到新的数据,闹钟响起,就把已经收到的数据打包,做相应处理。
定时器溢出时间配置
首先修改定时器的溢出时间。本文规定使用5ms的间隔。在某些通信协议中,会规定间隔时间。例如Modbus规定两组数据之间要间隔3.5字符。
实际上,间隔的时间常常与通信的波特率是相关的。在9600波特率下,一个字节的数据共 起始+8数据+结束=10位,一位是104us,所以一个字节的数据是1.04ms,3.5个字节,我们就认为是4ms。有时可能有校验位,稍微保险一点,5ms吧。假如使用115200的波特率,5ms已经算是非常“奢侈”了。
本文使用定时器3来计时,配置的PSC为8399,ARR为49,可得5ms的溢出时间,配置过程可以参考通用定时器章节。
串口接收中断服务函数
我们在串口接收中断服务中,把收到的所有数据都放到数组中去,判断收到的是否是第一个字符,如果是则开启定时器。
其中__HAL_TIM_SET_COUNTER是HAL提供的一个宏定义,类似于函数,功能是通过宏来直接修改寄存器的值。
由于HAL库的串口接收中断在每次执行后都会关闭,所有在串口的中断里要重新手动开启串口接收中断。
另外,由于定时器中断在开启定时器的时候就会执行,所以需要开启定时器之前就把中断标记位清除。
定时器中断服务
一旦定时器发生溢出中断,说明已经到了5ms的时间间隔,可以把数据截断,根据业务需求来做相应处理,我的做法是设着一个标志位,然后在主函数的死循环内不断检测标志位,如果标志位被置1,则把收到的数据发送出去。
功能是串口接收什么就回复什么,但无需结束符,也不用指定长度。当然最长不能超过UART1_Rx_Buf数据的大小。
附上源码