当前位置: 首页 > news >正文

GD32F303 定时器触发ADC+DMA实现10ms精准采样与10s中断处理

1. 硬件资源配置与模块选型

在GD32F303上实现精准数据采集,首先要搞定硬件资源的合理分配。我最近在一个工业传感器项目上就用到了这套方案,实测下来稳定性相当不错。先说说ADC的选择——这里用的是ADC2模块,原因很简单:它和定时器4的通道0有硬件级联动,查看数据手册可以看到TIMER4_CH0正好能触发ADC2的常规通道转换。

DMA通道的选择也有讲究。GD32F303的DMA1有多个通道,经过实际测试,DMA1_Channel4最适合这个场景。它不仅能自动搬运ADC数据到内存,还支持循环模式。这里有个坑要注意:DMA传输宽度必须和外设数据宽度匹配,ADC数据是12位的,但DMA要配置为16位传输,否则会丢数据。

时钟配置是很多人容易忽略的关键点。我的经验是先把时钟树理清楚:

  • 系统时钟120MHz
  • APB2总线时钟60MHz
  • ADC时钟设为APB2的6分频(10MHz)
  • 定时器时钟用系统时钟的1分频(120MHz)
static void rcu_config(void) { rcu_periph_clock_enable(RCU_GPIOA); rcu_periph_clock_enable(RCU_DMA1); rcu_periph_clock_enable(ADC_PWM_TMER_RCU); rcu_periph_clock_enable(ADC_RCU); rcu_adc_clock_config(RCU_CKADC_CKAPB2_DIV6); }

2. 定时器精准触发配置

定时器是这里的时间基准,要产生精确的10ms周期信号。我用TIMER4实现这个功能,配置步骤其实挺有技巧的:

  1. 预分频设为11999,这样定时器时钟变成120MHz/(11999+1)=10kHz
  2. 自动重载值设为100-1,产生10kHz/100=100Hz的PWM(周期10ms)
  3. 通道输出模式选PWM0,占空比50%
timer_parameter_struct timer_initpara; timer_initpara.prescaler = 11999; timer_initpara.period = 100-1; timer_init(ADC_PWM_TMER, &timer_initpara); timer_channel_output_mode_config(ADC_PWM_TMER, ADC_PWM_CH, TIMER_OC_MODE_PWM0); timer_channel_output_pulse_value_config(ADC_PWM_TMER, ADC_PWM_CH, 50);

实际调试时发现个问题:如果直接用更新事件触发ADC,会引入约1us的抖动。后来改用通道比较事件触发就稳定多了,这个细节在手册里可不容易注意到。

3. ADC与DMA的协同工作

ADC配置有几个关键点必须掌握:

  • 要开启扫描模式,因为我们用到了多通道
  • 采样时间设置为55.5个周期,这对高阻抗信号源很重要
  • 必须使能外部触发和DMA模式
adc_special_function_config(ADC_NUM_CH, ADC_SCAN_MODE, ENABLE); adc_regular_channel_config(ADC_NUM_CH, 0, ADC_CHANNEL_0, ADC_SAMPLETIME_55POINT5); adc_external_trigger_config(ADC_NUM_CH, ADC_REGULAR_CHANNEL, ENABLE); adc_dma_mode_enable(ADC_NUM_CH);

DMA配置要特别注意内存地址递增:

  • 外设地址固定为ADC数据寄存器
  • 内存地址指向二维数组laser_fre[1024][2]
  • 传输数量是1024*2(双通道)
  • 一定要开循环模式,不然采集一次就停了
dma_init_struct.direction = DMA_PERIPHERAL_TO_MEMORY; dma_init_struct.memory_addr = (uint32_t)laser_fre; dma_init_struct.memory_inc = DMA_MEMORY_INCREASE_ENABLE; dma_init_struct.number = LASWER_FRE_NUME*ADC_CHANNEL_NUMER; dma_circulation_enable(DMA1, DMA_CH4);

4. 中断处理与数据滤波

当DMA传输完1024个数据后(约10秒),会触发中断。这里有个重要技巧:在中断里不要直接处理数据,而是设置标志位,在主循环里处理。因为中断服务函数应该尽可能短。

void DMA1_Channel3_4_IRQHandler(void) { if(dma_interrupt_flag_get(DMA1,DMA_CH4, DMA_INT_FLAG_FTF)) { timer_channel_output_mode_config(ADC_PWM_TMER, ADC_PWM_CH, TIMER_OC_MODE_HIGH); dma_interrupt_flag_clear(DMA1,DMA_CH4, DMA_INT_FLAG_G); Lcd_flag.battery_adc_flag = true; } }

数据滤波我用的是中位值平均滤波法,效果比简单平均好很多。具体实现是:

  1. 对1024个数据排序
  2. 去掉最高和最低的3个值
  3. 对剩下的1018个数据求平均
uint16_t filter_bat(uint16_t barray[LASWER_FRE_NUME][ADC_CHANNEL_NUMER], uint8_t ifilterlen) { // 排序代码... for(i = 3+FILER_MID; i < ifilterlen-3+FILER_MID; i++) { sum = sum + barray[i][0]; } return (sum>>2); }

5. 实际调试中的经验分享

在实验室测试时一切正常,但现场部署后发现有偶发数据异常。后来发现是电源噪声导致的,解决方法有三个:

  1. ADC电源引脚加10uF+0.1uF去耦电容
  2. 采样时间从55.5周期增加到71.5周期
  3. 在软件滤波前先做异常值剔除

还有个时序问题值得注意:定时器、ADC、DMA的启动顺序很重要。正确的顺序应该是:

  1. 初始化所有外设
  2. 开启DMA
  3. 开启ADC
  4. 最后启动定时器

如果顺序不对,可能会丢失前几个采样数据。我在初期调试时就踩过这个坑,后来用逻辑分析仪抓信号才发现问题。

对于需要更高精度的场合,可以校准ADC的偏移误差。GD32F303提供了自校准功能,上电后执行一次校准能显著提高精度:

adc_enable(ADC_NUM_CH); delay_ms(1); // 等待ADC稳定 adc_calibration_enable(ADC_NUM_CH);

6. 性能优化技巧

当采样通道增加到4个时,发现10ms周期不够用了。通过以下优化解决了问题:

  • 将ADC时钟从10MHz提升到14MHz(APB2/4)
  • 使用定时器主从模式,用TIMER4触发TIMER5产生第二组PWM
  • 在DMA中断中使用内存池管理数据

对于需要实时处理数据的场景,可以双缓冲技术:

  1. 配置两个1024点的缓冲区
  2. DMA在半满和全满时各触发一次中断
  3. 主程序交替处理两个半缓冲区
// 双缓冲配置 dma_init_struct.memory0_addr = (uint32_t)buffer1; dma_init_struct.memory1_addr = (uint32_t)buffer2; dma_init_struct.memory_burst_width = DMA_MEMORY_BURST_SINGLE; dma_init_struct.periph_burst_width = DMA_PERIPH_BURST_SINGLE; dma_dual_buffer_mode_enable(DMA1, DMA_CH4);

7. 低功耗设计考虑

在电池供电设备中使用时,我对方案做了低功耗优化:

  1. 采样间隔从10ms调整为可配置(1ms-1s)
  2. 不采样时关闭ADC和定时器时钟
  3. 使用DMA传输完成中断唤醒MCU
  4. 采样期间将系统时钟降到48MHz
void enter_low_power_mode(void) { timer_disable(ADC_PWM_TMER); adc_disable(ADC_NUM_CH); rcu_system_clock_config(RCU_CKSYSSRC_PLL48M); __WFI(); // 等待中断唤醒 }

这套方案经过半年多的现场运行验证,稳定性非常好。最关键的是要确保三点:定时器触发信号的稳定性、DMA配置的正确性以及滤波算法的有效性。对于不同的应用场景,可以灵活调整采样周期、通道数量和滤波参数。

http://www.jsqmd.com/news/823303/

相关文章:

  • 2026贵州履带式潜孔钻机厂家推荐:西南工业动力服务标杆甄选指南 - 深度智识库
  • 3步解锁BurpSuite中文界面:从语言障碍到高效渗透测试
  • 2026汉中哪家高端品牌门窗好:优选口碑品牌派雅门窗(企业简介) - 一个呆呆
  • openclaw-cortex:基于视觉与深度学习的机器人未知物体灵巧抓取系统解析
  • 宁波考点 SCMP 证书关于(含金量和通过率及费用)详细解读 - 众智商学院课程中心
  • OpenWrt下RT5350 LED驱动开发:从GPIO操作到内核模块打包
  • 【DeepSeek MATH竞赛测试权威复盘】:20年AI评测专家独家拆解7大能力断层与提分临界点
  • 2026年中国开发者代码托管平台选型推荐:本土化DevOps平台的价值凸显
  • 2026年别墅外墙装修选购指南:深度解答别墅仿石漆厂家靠谱吗 - 产业观察网
  • AI智能体架构解析:从工具链到自主创意工作流
  • 流量逐利滔天,凰标固守本心:乱世逆流守纯粹创作之道@凤凰标志
  • 常州市明扬物资回收:常州岩棉板拆除回收公司推荐 - LYL仔仔
  • 别怕大模拟!像做开发项目一样拆解CCF-CSP第三题:一个模板引擎的诞生记
  • 基于RAG与向量数据库的智能网页问答机器人构建实战
  • 初创公司如何利用Taotoken以最小成本启动AI功能开发
  • 寻路生成式引擎优化:贵阳本地GEO优化公司推荐与落地实践指南 - 资讯焦点
  • HsMod终极指南:50+功能全面优化你的炉石传说游戏体验
  • Ryzen SDT:AMD处理器深度调试与调优的实用工具
  • 基于Agentify框架构建AI智能体:从核心原理到实战应用
  • 第四章-13-上传、下载
  • 电商下半场拼什么?有鱼生活用“价值共享+文创”给出新答案 - 资讯焦点
  • Taotoken的审计日志功能如何助力企业满足内部合规与安全审查要求
  • 如何快速解决Windows运行库问题:VisualCppRedist AIO终极指南
  • 2026压力变送器品牌排行榜,广东犸力稳居前列口碑俱佳 - 品牌速递
  • 藏细节于肌理,2026贵州高端木作设计打造理想大宅 - 深度智识库
  • Obsidian Importer终极指南:如何快速将10+笔记应用无缝迁移到Obsidian
  • saas产品集成大模型时借助taotoken实现模型冗余与降级方案
  • GitOps不是概念,是SLA保障,DeepSeek如何将发布失败率压至0.02%?
  • 西安 CPPM 证书报考常见问题(含金量 / 通过率和费用) - 众智商学院课程中心
  • 一册凰标立民声:为千万被资本埋没的创作者正名发声@凤凰标志