关于UART RX DMA使用方法的问题
最近做项目需要用到串口通信,通信速率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;<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 longcounter = 0;
volatile unsigned longlastcounter = 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加持的情况下,能保证发送数据量和接收数据量一致。
补充一下初始化代码,不知道为什么自动删除了
void UartInit()
{
/* 配置P3.0和P3.1为准双向口 */
P3M0 &= ~0x03;
P3M1 &= ~0x03;
/* 配置USART1映射到P3.0和P3.1 */
P_SW1 &= ~0xC0U;
/* 配置USART1功能 */
SM0 = 0; //数据位8位
SM1 = 1;
SMOD = 0; //波特率不加倍
SMOD0 = 0; //禁用帧错误检测功能
S1BRT = 1; //选择定时器2作为波特率发生器
REN = 1;
ES = 0; //关闭中断
EA = 0; //全局中断关闭
/* 波特率发生器配置 */
T2R = 0; //TIM2停止计时
ET2 = 0; //关闭TIM2中断
TM2PS = 0; //TIM2 36M时钟
T2x12 = 1; //TIM2工作1T模式
T2_CT = 0; //TIM2用作定时器
T2CLKO = 0; //关闭TIM2时钟输出
T2L = 0xEE; //设置自动重载值
T2H = 0xFF;
T2R = 1; //TIM2开始计时
/* 配置USART1 TX DMA */
DMA_UR1T_CFG = 0x0A;
DMA_UR1T_CR |= 0x80;
DMA_UR1T_STA = 0;
DMA_UR1T_AMT = (23&0x00FF);
DMA_UR1T_AMTH = ((23&0xFF00) >> 8);
DMA_UR1T_TXAH = ((unsigned short)&Uart_TxPacket) >> 8;
DMA_UR1T_TXAL = (((unsigned short)&Uart_TxPacket)&0xFF);
/* 配置USART1 RX DMA */
DMA_UR1R_CFG = 0x0F;
DMA_UR1R_STA = 0;
DMA_UR1R_AMT = (1023 & 0xFF);
DMA_UR1R_AMTH = (1023>>8);
// DMA_UR1R_AMT = (1023UL & 0xFF);
// DMA_UR1R_AMTH = ((1023UL & 0xFF00) >> 8);
DMA_UR1R_RXAH = (((unsigned short)&Uart_RxBuf) >> 8);
DMA_UR1R_RXAL = (((unsigned short)&Uart_RxBuf)&0xFF);
DMA_UR1R_CR |= 0xA1;
} 补充一下处理代码,为啥会自动删除呀
void DMARx_Handler()
{
unsigned short DONEH = DMA_UR1R_DONEH;
unsigned short DONE = DMA_UR1R_DONE;
const unsigned short defaultCounter = 1024;
/* 处理DMA接收逻辑 */
counter = ((DONEH << 8) + DONE);
if(counter > lastcounter)
{
process_length = counter - lastcounter;
rec_count += process_length;
}
else if(counter < lastcounter)
{
process_length = ((defaultCounter + counter) - lastcounter);
rec_count += process_length;
}
else
{
process_length = 0;
}
lastcounter = counter;
} 补充主函数代码
void main()
{
HardwareInit();
SoftwareInit();
while(1)
{
DMARx_ISRHandler();
DMARx_Handler();
}
}
【新提醒】4组串口UART使用DMA收发 @32G系列,易用,高效,稳定 !精品实战代码 - DMA支持: QSPI, SPI, I2S, I2C, 4组串口, i8080/MC6800-TFT 国芯技术交流网站 - AI32位8051交流社区 (stcaimcu.com)
用荣誉版主的完整程序 测试下
页:
[1]