摘要:在实际项目中经常用到串口接收一些不定长的数据,怎么判断这一帧数据接收完成了呢?通常使用UART非空中断配合简单的数据协议,在数据中加入帧头、帧尾,在程序中判断是否接收到帧尾来确定数据接收完毕,对每个字节数据都要进行判断,比较消耗系统资源,尤其是在一些实时性要求较高的场合。而串口空闲中断可以大大简化数据接收过程的判断,在这一块起到非常重要的作用。
关于这种方法,可以看以前STM32第五章-串口通讯详解。下面说一下空闲中断+DMA。
一、什么是空闲中断?
空闲中断(IDLE),俗称帧中断,即第一帧数据接收完毕到第二帧数据开始接收期间存在一个空闲状态(每接收一帧数据后空闲标志位置1),检测到此空闲状态后即执行中断程序。空闲中断的优点在于省去了帧头帧尾的检测,进入中断程序即意味着已经接收到一组完整数据,仅需即时对数据处理或将数据转移出缓冲区即可。
串口空闲中断在串口无数据接收的情况下,是不会产生的,产生的条件是当清除空闲标志位后,必须有接收到第一个数据后,才开始触发,一旦接收的数据断流,没有接收到数据,即产生空闲中断。
MM32F3277系列的UART支持空闲中断功能。相关的寄存器包括中断状态寄存器(UART_ISR)、 中断使能寄存器(UART_IER)、 中断清除寄存器(UART_ICR),对应的位如下:
中断状态寄存器(UART_ISR)
中断使能寄存器(UART_IER)
中断清除寄存器(UART_ICR)
二、串口初始化
这里以串口1为例,串口1一般就这打印调试使用。
中断服务函数
这样就可以了。但是串口空闲中断一般是配合DMA的方式。
三、串口DMA
一般串口空闲中断配合MM32F0270 UART使用DMA方式接收数据可以减小CPU的开销。
对于接收定长数据,可以将DMA接收缓冲区的长度设定为待接收数据的长度,这样利用DMA的传输完成中断就可以知道已经接收了一帧数据。
对于接收不定长数据,由于内核在串口接收数据到空闲这段时间,是不受理串口数据的,所以可以使用DMA来协助我们把数据传送到指定的地方,当数据传输完成后,通知内核去处理。
注意每一款单片机的串口DMA通道不一样,一定要看数据手册。MM32F3277的DMA各通道请求映像表如下,其中UART3_RX对应通道3。
再来看以下MM32F0270的DMA各通道请求映像,两款芯片串口对应的通道是不一样的。
通过DMA方式把数据传送到指定的缓存区。当UART接收完一帧数据后,会产生一个空闲中断。这个中断在UART其他任何状态都不产生,只会在接收完一帧数据后才会产生,一帧数据可以是1个字节或者多个字节。
四、DMA初始化
关于DMA的就不用多说了,数据从内存到外设,或者外设到内存,或者内存到内存都不需要CPU的参与,直接存储器访问即可,减轻了CPU的压力。
既然有了增加了DMA,所以我们的串口终端服务函数也要修改一下了。
在中断服务函数中,当发生了空闲中断时要关闭DMA,停止DMA数据传输,然后进行处理数据,在数据处理完成之后在打开DMA,继续接收数据。
调试
打开串口调试助手发送一帧数据,如:666,程序运行至断点1,
UART中断状态寄存器UART_ISR的RXIDLE_INTF位置1,表示进入UART空闲中断。
程序运行至断点2,UART中断状态寄存器UART_ISR的RXIDLE_INTF位清0。
这时串口接收到的数据就自动保存到了DMA初始化中你填写的那个内存基地址所在的内存区域了,想什么时候用就什么时候用。
原作者:果果小师弟
|