GD32E230实战:5个ADC通道+DMA循环采集,代码直接抄(附避坑点)

张开发
2026/4/21 2:36:26 15 分钟阅读

分享文章

GD32E230实战:5个ADC通道+DMA循环采集,代码直接抄(附避坑点)
GD32E230多通道ADC采集实战DMA循环模式下的高效实现与避坑指南在嵌入式系统开发中模拟信号采集是连接物理世界与数字系统的关键桥梁。GD32E230作为一款高性价比的Cortex-M23内核微控制器其内置的12位ADC配合DMA功能能够实现高效的多通道数据采集。本文将深入解析如何配置5个ADC通道的循环采集系统提供可直接用于项目的完整代码框架并重点剖析那些容易导致采集失败的配置细节。1. 硬件基础与工程准备GD32E230的ADC模块支持多达16个外部通道最高1MSPS的采样率。在我们的场景中我们将使用PA0、PA1、PA4、PA5和PA6五个引脚作为模拟输入源。这些引脚对应的ADC通道分别为引脚ADC通道典型应用场景PA0CH0温度传感器PA1CH1光照强度PA4CH4电池电压检测PA5CH5电位器调节PA6CH6压力传感器硬件连接注意事项确保模拟输入信号在0-VREF范围内通常0-3.3V对于高阻抗信号源建议增加RC滤波电路避免数字信号线与模拟输入线平行走线工程准备需要包含以下关键文件gd32e23x.h gd32e23x_adc.h gd32e23x_dma.h gd32e23x_rcu.h2. 核心配置解析与代码实现2.1 时钟树配置ADC时钟的合理配置直接影响采样精度。GD32E230的ADC时钟由APB2总线分频得到最高不能超过14MHz。推荐配置为12MHz这是平衡速度和精度的最佳选择。/* ADCCLK PCLK2/6 72MHz/6 12MHz */ rcu_adc_clock_config(RCU_ADCCK_APB2_DIV6);2.2 GPIO初始化模拟输入引脚需要配置为模拟模式关闭上下拉电阻void ADC_IO_Init(void) { rcu_periph_clock_enable(RCU_GPIOA); gpio_mode_set(GPIOA, GPIO_MODE_ANALOG, GPIO_PUPD_NONE, GPIO_PIN_0); gpio_mode_set(GPIOA, GPIO_MODE_ANALOG, GPIO_PUPD_NONE, GPIO_PIN_1); gpio_mode_set(GPIOA, GPIO_MODE_ANALOG, GPIO_PUPD_NONE, GPIO_PIN_4); gpio_mode_set(GPIOA, GPIO_MODE_ANALOG, GPIO_PUPD_NONE, GPIO_PIN_5); gpio_mode_set(GPIOA, GPIO_MODE_ANALOG, GPIO_PUPD_NONE, GPIO_PIN_6); }2.3 DMA关键配置DMA是实现高效数据搬运的核心。在多通道ADC采集中必须正确配置内存地址递增dma_parameter_struct dma_config { .periph_addr (uint32_t)(ADC_RDATA), // ADC数据寄存器地址 .periph_inc DMA_PERIPH_INCREASE_DISABLE, // 外设地址不递增 .memory_addr (uint32_t)ADC_Values, // 内存目标数组 .memory_inc DMA_MEMORY_INCREASE_ENABLE, // 内存地址递增 .periph_width DMA_PERIPHERAL_WIDTH_16BIT, .memory_width DMA_MEMORY_WIDTH_16BIT, .direction DMA_PERIPHERAL_TO_MEMORY, .number 5, // 传输5个数据 .priority DMA_PRIORITY_HIGH }; dma_init(DMA_CH0, dma_config); dma_circulation_enable(DMA_CH0); // 开启循环模式2.4 ADC模块配置ADC需要配置为扫描模式和连续转换模式adc_special_function_config(ADC_SCAN_MODE, ENABLE); adc_special_function_config(ADC_CONTINUOUS_MODE, ENABLE); adc_data_alignment_config(ADC_DATAALIGN_RIGHT); adc_resolution_config(ADC_RESOLUTION_12B); // 配置5个通道及其采样时间 adc_channel_length_config(ADC_REGULAR_CHANNEL, 5); adc_regular_channel_config(0, ADC_CHANNEL_0, ADC_SAMPLETIME_55POINT5); adc_regular_channel_config(1, ADC_CHANNEL_1, ADC_SAMPLETIME_55POINT5); adc_regular_channel_config(2, ADC_CHANNEL_4, ADC_SAMPLETIME_55POINT5); adc_regular_channel_config(3, ADC_CHANNEL_5, ADC_SAMPLETIME_55POINT5); adc_regular_channel_config(4, ADC_CHANNEL_6, ADC_SAMPLETIME_55POINT5);3. 常见问题与解决方案3.1 数据错位问题症状各通道数据与预期不对应表现为通道数据乱跳。根本原因DMA内存地址递增未启用ADC通道序列配置与DMA传输长度不匹配数组大小小于实际通道数解决方案// 确保DMA配置中内存递增开启 dma_config.memory_inc DMA_MEMORY_INCREASE_ENABLE; // 确认数组大小足够 #define ADC_CHANNEL_COUNT 5 uint16_t ADC_Values[ADC_CHANNEL_COUNT];3.2 采样值不稳定可能原因及对策电源噪声增加电源滤波电容使用独立的模拟电源信号源阻抗过高在信号输入端增加RC低通滤波减小采样时间降低ADC_SAMPLETIME地线干扰优化PCB布局采用星型接地分离数字地和模拟地3.3 DMA传输不触发排查步骤确认ADC和DMA时钟已使能检查DMA通道是否与ADC匹配验证软件触发是否执行确保ADC校准已完成// 正确的初始化顺序 void ADC_Init_Sequence(void) { ADC_IO_Init(); ADC_DMA_Config(); ADC_Module_Config(); adc_calibration_enable(); // 必须在最后执行校准 }4. 高级应用技巧4.1 定时触发采样避免在主循环中轮询使用定时器触发ADC采样// 定时器中断中触发采样 void TIMER_IRQHandler(void) { if(timer_interrupt_flag_get(TIMER_INT_UP)) { timer_interrupt_flag_clear(TIMER_INT_UP); adc_software_trigger_enable(ADC_REGULAR_CHANNEL); } }4.2 数据滤波处理针对ADC值的常见滤波算法实现移动平均滤波#define FILTER_SIZE 8 uint16_t MovingAverage(uint8_t channel) { static uint16_t buffer[ADC_CHANNEL_COUNT][FILTER_SIZE] {0}; static uint8_t index 0; uint32_t sum 0; buffer[channel][index] ADC_Values[channel]; index (index 1) % FILTER_SIZE; for(uint8_t i0; iFILTER_SIZE; i) { sum buffer[channel][i]; } return sum / FILTER_SIZE; }中值滤波int cmp(const void *a, const void *b) { return (*(uint16_t*)a - *(uint16_t*)b); } uint16_t MedianFilter(uint8_t channel) { static uint16_t samples[ADC_CHANNEL_COUNT][5] {0}; uint16_t temp[5]; // 更新样本 for(uint8_t i4; i0; i--) { samples[channel][i] samples[channel][i-1]; } samples[channel][0] ADC_Values[channel]; // 复制并排序 memcpy(temp, samples[channel], sizeof(temp)); qsort(temp, 5, sizeof(uint16_t), cmp); return temp[2]; // 返回中值 }4.3 低功耗优化在电池供电应用中可配置间断采样模式void ADC_LowPower_Config(void) { adc_special_function_config(ADC_CONTINUOUS_MODE, DISABLE); adc_external_trigger_source_config(ADC_REGULAR_CHANNEL, ADC_EXTTRIG_REGULAR_T1_TRGO); adc_external_trigger_config(ADC_REGULAR_CHANNEL, ENABLE); }配合定时器唤醒可实现μA级平均电流消耗。

更多文章