最近做项目需要用到串口通信,通信速率500Kbps,且不使用中断而使用主线程轮询检测接收数据,在500Kbps高速率不间断的向MCU发送数据时,主线程轮询的方法来查询RI标志位,在执行其他操作时,会导致数据丢失,因此改用UART RX DMA来进行数据缓存,但是实现过程中出现了莫名其妙的问题,请各位大佬帮忙看一看!感谢!
实现思路:
1、配置UART RX DMA指向1024字节的缓存数组,同时配置RX DMA的接收数据中断生成阈值为1024,同样在主循环中检测接收数据完成标志,标志完成后,重新开启RX DMA的接收工作,这样则可以不间断地接收RX的数据,数据从缓存数组0开始到1023,溢出后,继续从缓存数组0开始存放。(DMA在不断接收,UART_DMA_DONE寄存器在不断从0~1023计数)
2、主循环定时检查DMA已经传输的字节数,检测本次传输字节数与上次检查的传输字节数的差值,如果检测到传输成功字节数发生变化,则取本次与上次的差值,这个差值就是上次检测到本次检测时间内接受到的数据量,然后将这些数据取出放进串口状态机内。
串口及DMA初始化代码如下:
- unsigned char xdata Uart_RxBuf[1024];<span style="white-space:pre"> </span>/* 串口DMA接收缓存 */
复制代码
DMA中断处理代码如下(此函数放在主线程中不断轮询):
- void DMARX_ISRHandler()
- {
- if(DMA_UR1R_STA&0x01)
- {
- LED = !LED;
- /* 清除缓存,并重新开始接收数据 */
- DMA_UR1R_STA &= ~0x01;
- DMA_UR1R_CR |= 0x01;
- DMA_UR1R_CR |= 0x20;
- }
- }
复制代码
接收处理代码如下(同样放在主线程中不断轮询):
- volatile unsigned long counter = 0;
- volatile unsigned long lastcounter = 0;
- volatile unsigned long rec_count = 0;
- volatile unsigned long process_length = 0;
-
- void DMARx_Handler()
复制代码
主函数代码如下:
- void main()
- {
- HardwareInit();
- SoftwareInit();
复制代码
rec_count 用于记录从上电到当前时间,串口接收到的数据总量,理论上这种思路只要保证每次轮询间隔时间内缓存足够大,MCU就能不丢失的处理高速率串口数据,但是我用STC32G12K128芯片测试的时候,rec_count总会莫名的多余接收的总字节数,如下图所示
发送78078个字节数据,但是内部记录到的实际接收字节数是00 01 a0 fe换算成十进制就是106750, 这种情况发生在缓存设置成大于256字节时,当缓存设置小于256字节,比如128字节时,记录的数据量就正确,这个代码逻辑放在stm32上测试过,在DMA加持的情况下,能保证发送数据量和接收数据量一致。
|