找回密码
 立即注册
查看: 20|回复: 3

32G等 DMA 串口接收超时判断的方法

[复制链接]
  • 打卡等级:常住居民I
  • 打卡总天数:63
  • 最近打卡:2025-08-16 09:13:07

5

主题

80

回帖

805

积分

高级会员

积分
805
发表于 昨天 09:34 | 显示全部楼层 |阅读模式

我看官方给出 32G 实现 UART4 下 DMA 软件超时的方法,实际上还是用了串口中断,既然要用串口中断,直接用串口中断不就好了?MCU还是在不停被打断,意义不大。

最近用32G 比较多,开始的时候用RTOS 比如 迟老师的 CosyOS,慢慢开始觉得还是裸机比较爽。

脱离 RTOS 作超时判断比较麻烦一点,刚好在看32G的文档的时候,注意到 DMA_URnR_DONE 和 DMA_URnR_DONEH 寄存器。

这两个寄存器主要是用来记录当前读取了多少,那么如果在规定时间内,检查 DMA_URnR_DONE 和 DMA_URnR_DONEH 的数量大于0而且没有变化,那就不是超时了?

主循环中直接

unsigned int req_length = DMA_UR4R_DONE | (DMA_UR4R_DONEH << 8);

    if (req_length > 0)
    {
        if (modbus_rx_last_count != req_length)
        {
            os_timer_restart_8(&modbus_rx_timeout);
            modbus_rx_last_count = req_length;
        }
        else
        {
            if (os_timer_expired_8(&modbus_rx_timeout))
            {
                // 收到数据了
                DMA_UR4R_CR = 0; // 停止接收
                DMA_UR4R_DONE = 0;
                DMA_UR4R_DONEH = 0;

                IO_RS485_TC = ENABLE_WRITE; // 转入发送状态

                {
                    int resp_length = modbus_response(
                        1,
                        modbus_rx_buffer,
                        req_length,
                        modbus_tx_buffer,
                        &modbus_main_mapping);

                    if (resp_length > 0)
                    {
                        // 需要发送
                        DMA_UR4T_AMT = (resp_length - 1);
                        DMA_UR4T_AMTH = (resp_length - 1) >> 8;
                        DMA_UR4T_STA = 0;
                        DMA_UR4T_CR = 0xC0;
                    }
                    else
                    {
                        // 不需要发送
                        modbus_start_recv();
                    }
                }
            }
        }
    }
}

其中 modbus_rx_timeout 是一个定时器,可以用 os_timer_expired_8 函数来判断是否超时,或者用 os_timer_restart_8(&modbus_rx_timeout); 来重新开始计时。

我实验了一下,没有发现什么问题

我就没有想明白,为什么官方实现的方式要用 串口中断,是不是有什么隐情?还是说官方的那种方式比较稳定,而这个方式不太稳定?请指教

希望这个世界让我装一次B
回复

使用道具 举报 送花

3

主题

2058

回帖

964

积分

等待验证会员

积分
964
发表于 昨天 09:38 | 显示全部楼层
在使用 STC32G 系列单片机进行 UART 通信时,结合 DMA 实现高效数据接收是一种常见需求。然而,在实际应用中,如何有效判断串口接收是否超时,是开发者常遇到的问题之一。

官方文档中提供的 UART4 下 DMA 软件超时判断方法,确实依赖于串口中断机制来实现超时检测。这种设计虽然能够实现基本的超时功能,但其本质仍需依赖中断服务程序(ISR)的触发,导致 MCU 在无数据到来时仍会频繁进入中断处理流程,影响系统效率。

若仅为了实现超时判断而引入串口中断,实则并未充分发挥 DMA 的优势。DMA 的核心价值在于减少 CPU 中断频率,提高数据传输效率。因此,建议在裸机环境下,通过轮询方式结合 DMA 寄存器状态进行超时判断,以实现更高效的系统设计。

STC32G 系列提供了两个关键寄存器:DMAURnRDONE 和 DMAURnRDONEH,它们分别记录当前 DMA 接收通道中已接收的数据字节数。通过读取这两个寄存器的值,可以获取当前接收缓冲区中的数据长度。

在主循环中,可采用如下方式读取接收长度:
  1. c
  2. unsigned int reqlength = DMAUR4RDONE | (DMAUR4RDONEH  0)
  3. {
  4.     if (modbusrxlastcount != reqlength)
  5.     {
  6.         ostimerrestart8(&modbusrxtimeout); // 重置超时计时器
  7.         modbusrxlastcount = reqlength;
  8.     }
  9.     else
  10.     {
  11.         if (ostimerexpired8(&modbusrxtimeout))
  12.         {
  13.             // 超时处理
  14.             DMAUR4RCR = 0; // 停止 DMA 接收
  15.             // ...
  16.         }
  17.     }
  18. }
复制代码

此方法避免了依赖串口中断,实现了基于轮询的超时判断机制,适用于裸机环境下的高效数据接收控制。

需要注意的是,该方案依赖于定时器的精度和主循环的执行频率。在实际应用中,应合理设置超时阈值,并确保主循环能够及时响应数据变化。

综上所述,结合 DMA 寄存器状态和定时器机制,可以在不依赖串口中断的情况下实现有效的 UART 接收超时判断,提升系统性能与稳定性。

[本文内容由国芯人工智能辅助生成,仅供参考]
回复 支持 反对

使用道具 举报 送花

  • 打卡等级:以坛为家I
  • 打卡总天数:269
  • 最近打卡:2025-08-16 11:22:30
已绑定手机

79

主题

2919

回帖

6186

积分

荣誉版主

无情的代码机器

积分
6186
发表于 昨天 11:24 | 显示全部楼层
查询模式中断模式,萝卜白菜各有所爱,选择合适你项目的即可。
三天不学习,赶不上刘少奇~
回复 支持 反对

使用道具 举报 送花

  • 打卡等级:常住居民I
  • 打卡总天数:63
  • 最近打卡:2025-08-16 09:13:07

5

主题

80

回帖

805

积分

高级会员

积分
805
发表于 昨天 21:27 | 显示全部楼层
经过测试发现即使没有什么负载的情况下,偶尔还是会出现丢包的现象,不清楚是什么原因
希望这个世界让我装一次B
回复 支持 反对

使用道具 举报 送花

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|手机版|深圳国芯人工智能有限公司 ( 粤ICP备2022108929号-2 )

GMT+8, 2025-8-17 04:26 , Processed in 0.120139 second(s), 68 queries .

Powered by Discuz! X3.5

© 2001-2025 Discuz! Team.

快速回复 返回顶部 返回列表