)
GD32实战Timer触发ADC多通道采样DMA传输全流程解析附PWM调试技巧在工业传感器数据采集、电力监测等实时性要求较高的场景中如何实现多通道同步采样和高效数据传输一直是嵌入式开发者面临的挑战。本文将基于GD32系列MCU深入解析Timer触发ADC多通道采样结合DMA传输的完整实现流程并分享PWM输出调试的实用技巧。1. 硬件架构与核心模块交互原理GD32的Timer、ADC和DMA模块协同工作时数据流向和触发逻辑需要精确配置。以下是关键模块的交互关系Timer作为时间基准产生周期性触发信号ADC响应触发信号进行模数转换DMA自动搬运ADC转换结果到内存// 模块交互示意图 Timer触发事件 → ADC启动转换 → DMA搬运数据 → 内存缓冲区时钟配置要点系统时钟SystemCoreClock决定Timer基准频率ADC时钟需不超过14MHzGD32F307为例DMA时钟与总线时钟同步提示使用PWM输出验证时Timer时钟分频需确保PWM频率在可观测范围建议1kHz-10kHz2. 工程配置全流程详解2.1 GPIO初始化配置多通道采样需要正确配置模拟输入引脚PWM验证输出则需要配置复用功能引脚。以PA1PWM输出、PC3和PC5ADC输入为例void gpio_config(void) { rcu_periph_clock_enable(RCU_GPIOC); rcu_periph_clock_enable(RCU_GPIOA); rcu_periph_clock_enable(RCU_AF); // ADC通道配置为模拟输入 gpio_init(GPIOC, GPIO_MODE_AIN, GPIO_OSPEED_MAX, GPIO_PIN_3|GPIO_PIN_5); // PWM输出配置为复用推挽输出 gpio_init(GPIOA, GPIO_MODE_AF_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_1); }2.2 Timer配置与PWM生成配置Timer1产生1kHz PWM信号同时作为ADC触发源void timer1_config(void) { timer_oc_parameter_struct timer_ocintpara; timer_parameter_struct timer_initpara; rcu_periph_clock_enable(RCU_TIMER1); timer_deinit(TIMER1); // 基础定时器配置1kHz PWM timer_initpara.prescaler 119; // 120MHz/(1191) 1MHz timer_initpara.alignedmode TIMER_COUNTER_EDGE; timer_initpara.counterdirection TIMER_COUNTER_UP; timer_initpara.period 999; // 1MHz/(9991) 1kHz timer_initpara.clockdivision TIMER_CKDIV_DIV1; timer_initpara.repetitioncounter 0; timer_init(TIMER1, timer_initpara); // PWM模式配置50%占空比 timer_ocintpara.outputstate TIMER_CCX_ENABLE; timer_ocintpara.ocpolarity TIMER_OC_POLARITY_HIGH; timer_channel_output_config(TIMER1, TIMER_CH_1, timer_ocintpara); timer_channel_output_pulse_value_config(TIMER1, TIMER_CH_1, 500); timer_channel_output_mode_config(TIMER1, TIMER_CH_1, TIMER_OC_MODE_PWM0); timer_auto_reload_shadow_enable(TIMER1); }PWM调试技巧用示波器观察PA1脚波形确认触发周期准确修改period值调整采样频率修改脉冲值验证触发边沿效果2.3 DMA配置与缓冲区管理配置DMA实现ADC数据自动搬运避免CPU干预uint16_t adc_value[100]; // 双通道采样实际包含50组数据 uint32_t dmaHalfIntCnt 0; void dma_config(void) { dma_parameter_struct dma_data_parameter; rcu_periph_clock_enable(RCU_DMA0); dma_deinit(DMA0, DMA_CH0); dma_data_parameter.periph_addr (uint32_t)(ADC_RDATA(ADC0)); dma_data_parameter.periph_inc DMA_PERIPH_INCREASE_DISABLE; dma_data_parameter.memory_addr (uint32_t)(adc_value); dma_data_parameter.memory_inc DMA_MEMORY_INCREASE_ENABLE; dma_data_parameter.periph_width DMA_PERIPHERAL_WIDTH_16BIT; dma_data_parameter.memory_width DMA_MEMORY_WIDTH_16BIT; dma_data_parameter.direction DMA_PERIPHERAL_TO_MEMORY; dma_data_parameter.number 100; dma_data_parameter.priority DMA_PRIORITY_HIGH; dma_init(DMA0, DMA_CH0, dma_data_parameter); dma_circulation_enable(DMA0, DMA_CH0); dma_interrupt_enable(DMA0, DMA_CH0, DMA_INT_FTF|DMA_INT_HTF); dma_channel_enable(DMA0, DMA_CH0); nvic_irq_enable(DMA0_Channel0_IRQn, 0, 0); }数据缓冲区解析双通道采样时数据交替存储adc_value[0] CH13第一次采样值adc_value[1] CH15第一次采样值adc_value[2] CH13第二次采样值以此类推...2.4 ADC多通道采样配置配置ADC0以Timer1触发实现双通道交替采样void adc_config(void) { rcu_periph_clock_enable(RCU_ADC0); adc_deinit(ADC0); // 双ADC规则并行模式 adc_mode_config(ADC_DAUL_REGULAL_PARALLEL); adc_special_function_config(ADC0, ADC_SCAN_MODE, ENABLE); adc_data_alignment_config(ADC0, ADC_DATAALIGN_RIGHT); // 配置两个规则通道 adc_channel_length_config(ADC0, ADC_REGULAR_CHANNEL, 2); adc_regular_channel_config(ADC0, 0, ADC_CHANNEL_13, ADC_SAMPLETIME_55POINT5); adc_regular_channel_config(ADC0, 1, ADC_CHANNEL_15, ADC_SAMPLETIME_55POINT5); // Timer1触发配置 adc_external_trigger_source_config(ADC0, ADC_REGULAR_CHANNEL, ADC0_1_EXTTRIG_REGULAR_T1_CH1); adc_external_trigger_config(ADC0, ADC_REGULAR_CHANNEL, ENABLE); adc_enable(ADC0); delay_1ms(1); adc_calibration_enable(ADC0); adc_dma_mode_enable(ADC0); }关键参数说明参数配置值说明采样模式ADC_DAUL_REGULAL_PARALLEL规则组并行模式触发源ADC0_1_EXTTRIG_REGULAR_T1_CH1Timer1通道1触发采样时间ADC_SAMPLETIME_55POINT555.5个ADC时钟周期3. 调试技巧与性能优化3.1 PWM验证方法用示波器测量PWM输出引脚PA1确认频率是否为预期值本例1kHz检查占空比是否准确50%调整Timer参数观察ADC采样// 修改采样频率示例改为500Hz timer_initpara.period 1999; // 1MHz/(19991) 500Hz3.2 DMA传输优化双缓冲技术配置两个缓冲区交替使用中断优化仅在缓冲区满时处理数据数据对齐根据ADC分辨率选择16/32位传输// 双缓冲配置示例 uint16_t adc_buf1[100], adc_buf2[100]; volatile uint8_t current_buf 0; void DMA0_Channel0_IRQHandler(void) { if(dma_interrupt_flag_get(DMA0, DMA_CH0, DMA_INT_FLAG_FTF)){ dma_interrupt_flag_clear(DMA0, DMA_CH0, DMA_INT_FLAG_FTF); current_buf 1; // 切换到缓冲区2处理 } else if(dma_interrupt_flag_get(DMA0, DMA_CH0, DMA_INT_FLAG_HTF)){ dma_interrupt_flag_clear(DMA0, DMA_CH0, DMA_INT_FLAG_HTF); current_buf 0; // 切换到缓冲区1处理 } }3.3 常见问题排查无ADC数据检查Timer是否成功触发用PWM验证确认DMA通道与ADC匹配测量模拟输入电压是否在有效范围数据错位检查DMA内存地址递增配置确认ADC通道顺序与DMA缓冲区匹配采样率不准确重新计算Timer分频值检查系统时钟配置4. 实际应用案例温度与电压同步监测以工业现场常见的温度传感器PT100和电压监测为例展示完整实现硬件连接PC3接温度传感器信号调理电路PC5接分压电阻网络监测供电电压数据处理void process_adc_data(uint16_t *data) { float temp (data[0] * 3.3f / 4095) * 100; // 假设0-3.3V对应0-100℃ float voltage data[1] * 3.3f / 4095 * 2; // 1:2分压 printf(温度: %.1f℃ 电压: %.2fV\n, temp, voltage); }系统集成在DMA中断中调用数据处理函数添加软件滤波算法如滑动平均在GD32E230平台上实测该系统可实现双通道1kHz采样率CPU占用率5%采样抖动1us