一 项目背景
项目需要使用一款UART串口编码器,编码器的数据以波特率57600持续向外发送。但这组数据包没有固定的包头和校验尾,仅仅是由多圈圈数和单圈角度组成的六字节数据码,这样接收到的数组无法确定实际的下标,所以这边考虑用串口接收超时中断+DMA来实现。
二 原理说明
【1】UART原理说明:参考【嵌入式】NXP/LPC使用GPIO+定时器模拟UART串口接收
【2】超时中断原理说明:接收的数据包通过逻辑分析仪,如下所示:
由上面的数据可以看到,两个包之间的发送间隔为500us左右,而一个包的发送时间为170us(波特率为57600,那么每位数据是17us,一个包10位数据,就是170us),所以只要在串口收发的过程中加一个定时器,设定超时时间为400us(大于170us,小于500us即可),那么 只要超时了,说明下一次收到的位即为起始位。
STM32中有一个空闲中断(IDLE)的概念,而HC32中没有,取而代之的是串口接收超时中断,两者基本功能是类似的,都是在串口超过一段时间没有接收数据之后触发的一个中断功能。HC32F460的用户手册中对此也有详细说明(我们这边用的是USART4串口,所以相对应的需需要使用 Timer0 Unit2 B 通道):
【3】DMA原理说明:DMA(Direct Memory Access,直接存储器访问) 是单片机的一个外设,它的主要功能是用来搬移数据,但是不需要占用 CPU,即在传输数据的时候, CPU 可以干其他的事情,好像多线程一样。(具体可以参考:串口DMA传输模式)
这边用到DMA,是因为编码器发送数据比较快,若是一直进中断会挤占CPU的资源,所以考虑用DMA改进。
三 设计实现--超时定时器部分
【1】超时定时器初始化( Timer0 Unit2 B 通道 ),这个过程中主要关注一下定时器时间的设置,如下面的 stcTimerCfg.Tim0_CmpValue = 4200 ,它的时钟源是 Tim0_Pclk1 ,在HC32F460中,这个时钟是168MHz的一半,即84MHz,时钟的分频系数为8,根据公式:
T=CmpValue*ClockSource*ClockDivision
其中,T = 400us,ClockSource=1/84MHz,ClockDivision=8,计算出CmpValue=4200:
void Timer0_Config(void)
{
stc_clk_freq_t stcClkTmp;
stc_tim0_base_init_t stcTimerCfg;
stc_tim0_trigger_