在使用UART接收串口数据时,如果使用接收中断来处理,那么每当RXNE为1时就会中断一次,接收1000个字节的数据就要进中断1000次,很占用CPU时间。举例一种比较常见的应用场景,单片机与GPS模块通讯进行串口通讯,GPS模块每1秒通过串口对外发送报文,单片机接收到完整报文后再一并解析。前述中断的方法显然效率不高,这时想到用DMA来提升效率。假如GPS每秒发送的最大报文长度不会超过1000个字节,此时定义数组GpsRxBuf【1000】来存放GPS模块发来的数据。在配置DMA时,将DMA的源地址设置为单片机所使用的UART的DR寄存器,目的地址设置为&GpsRxBuf[0],传输长度(CNDTR寄存器)设置为1000,模式是非循环模式。这样,DMA模块在每收到1个字节的数据后自动将相应UART的DR寄存器中的值搬移到GpsRxBuf数组中去,第一个字节搬移到GpsRxBuf【0】、此时CNDTR寄存器减1,变为999,第二个字节搬移到GpsRxBuf【1】,CNDTR再减1,变为998……,假如接收到的最后一个字节是第100个字节,此时第100个字节被搬移到GpsRxBuf【99】中,CNDTR减为900。由于此时是最后一个字节,此时会进入UART的IDLE中断(需先配置),程序读出当前DMA的CNDTR的值,此时是900,那么就说明单片机本次从GPS模块接收了(1000 - 900),也就是100个字节的数据,此时禁能DMA,将DMA的CNDTR再次设置为1000,再使能DMA,准备下次接收。但这时有个问题存在,就是再次使能DMA的时候,虽然CNDTR已被重设为1000,只代表下次DMA传输的最大字节数改为1000,但DMA模块内部的目的地址指针并未变,也就是说在下一次收到一个字节数据时,DMA会将数据搬移到GpsRxBuf[100]的位置,而不是GpsRxBuf【0】的位置。但我们所希望的是下一秒再收GPS模块发来的数据,是从头开始,也就是从GpsRxBuf【0】开始存放。不知道大家有没有遇到过这种情况? |