保姆级教程:用GD32官方库和DMA搞定多路ADC采样(含内部温度与参考电压)

张开发
2026/4/18 11:14:02 15 分钟阅读

分享文章

保姆级教程:用GD32官方库和DMA搞定多路ADC采样(含内部温度与参考电压)
GD32多路ADC采样实战从官方库配置到DMA高效传输在嵌入式开发中ADC模数转换器是连接模拟世界与数字系统的关键桥梁。对于GD32F103系列MCU而言其内置的12位ADC模块支持多达16个外部通道和2个内部通道温度传感器与参考电压配合DMA直接内存访问技术可实现高效的数据采集。本文将手把手带你完成从环境搭建到实战应用的全过程。1. 开发环境准备与基础认知在开始编码前我们需要明确几个关键概念。GD32F103的ADC模块具有以下特性12位分辨率转换时间最短1μs支持单次、连续、扫描和不连续采样模式内置温度传感器通道16和参考电压通道17可配置的采样时间1.5~239.5个ADC时钟周期硬件准备清单GD32F103VET6开发板或兼容型号3.3V稳压电源精度±5%以内万用表用于电压测量杜邦线若干特别注意ADC参考电压必须稳定在2.6-3.6V范围内超出此范围可能导致采样异常。开发软件方面我们需要Keil MDK或IAR Embedded WorkbenchGD32F10x_AddOn插件用于IDE支持GD32F10x标准外设库版本建议≥3.0.0# 示例GD32标准库目录结构 GD32F10x_standard_peripheral_lib/ ├── Firmware/ │ ├── CMSIS/ # Cortex核心支持 │ ├── GD32F10x_std_periph_driver/ # 外设驱动 │ └── Utilities/ # 实用工具 └── Template/ # 项目模板2. ADC基础配置与校准2.1 初始化ADC外设首先配置ADC时钟和基本参数。GD32的ADC时钟最大14MHz通常由APB2总线分频得到void ADC_Config(void) { ADC_InitPara ADC_InitStructure; // 开启ADC1时钟 RCC_APB2PeriphClock_Enable(RCC_APB2Periph_ADC1, ENABLE); // ADC基本参数配置 ADC_InitStructure.ADC_Resolution ADC_Resolution_12b; ADC_InitStructure.ADC_ContinuousConvMode DISABLE; // 单次转换 ADC_InitStructure.ADC_ExternalTrigConv ADC_ExternalTrigConv_None; ADC_InitStructure.ADC_DataAlign ADC_DataAlign_Right; ADC_InitStructure.ADC_ScanDirection ADC_ScanDirection_Upward; ADC_Init(ADC1, ADC_InitStructure); // 使能温度传感器和Vrefint ADC_TempSensorVrefint_Enable(ENABLE); // ADC校准关键步骤 ADC_Calibration_Reset(ADC1); ADC_Calibration_Set(ADC1); while(ADC_GetCalibrationStatus(ADC1)); }2.2 采样时间优化不同信号源需要不同的采样时间可通过以下公式计算采样时间(cycles) 采样周期数 × (1/ADC时钟频率)推荐配置信号类型采样周期数适用场景低阻抗源1.5运放输出、分压网络中阻抗源7.5多数传感器输出高阻抗源239.5直接接高阻传感器设置采样时间的代码示例// 配置通道0采样时间为239.5周期 ADC_Channel_Config(ADC1, ADC_Channel_0, ADC_SampleTime_239_5Cycles);3. DMA传输配置实战3.1 DMA控制器初始化DMA配置需要特别注意数据宽度和内存地址递增void DMA_Config(uint32_t *adc_buffer) { DMA_InitPara DMA_InitStructure; RCC_AHBPeriphClock_Enable(RCC_AHBPeriph_DMA1, ENABLE); DMA_DeInit(DMA1_Channel1); DMA_InitStructure.DMA_PeripheralBaseAddr (uint32_t)ADC1-RDATA; DMA_InitStructure.DMA_MemoryBaseAddr (uint32_t)adc_buffer; DMA_InitStructure.DMA_DIR DMA_DIR_PeripheralSRC; DMA_InitStructure.DMA_BufferSize ADC_CHANNEL_COUNT; DMA_InitStructure.DMA_PeripheralInc DMA_PeripheralInc_Disable; DMA_InitStructure.DMA_MemoryInc DMA_MemoryInc_Enable; DMA_InitStructure.DMA_PeripheralDataSize DMA_PeripheralDataSize_HalfWord; DMA_InitStructure.DMA_MemoryDataSize DMA_MemoryDataSize_HalfWord; DMA_InitStructure.DMA_Mode DMA_Mode_Circular; DMA_InitStructure.DMA_Priority DMA_Priority_High; DMA_InitStructure.DMA_MTOM DMA_MemToMem_Disable; DMA_Init(DMA1_Channel1, DMA_InitStructure); DMA_Channel_Enable(DMA1_Channel1, ENABLE); }3.2 多通道扫描配置配置ADC的规则组实现多通道自动扫描void ADC_MultiChannel_Config(void) { ADC_RegularChannel_Config(ADC1, ADC_Channel_0, 1, ADC_SampleTime_55_5Cycles); // 外部通道1 ADC_RegularChannel_Config(ADC1, ADC_Channel_1, 2, ADC_SampleTime_55_5Cycles); // 外部通道2 ADC_RegularChannel_Config(ADC1, ADC_Channel_2, 3, ADC_SampleTime_55_5Cycles); // 外部通道3 ADC_RegularChannel_Config(ADC1, ADC_Channel_16, 4, ADC_SampleTime_239_5Cycles); // 温度传感器 ADC_RegularChannel_Config(ADC1, ADC_Channel_17, 5, ADC_SampleTime_239_5Cycles); // 内部参考 // 启用扫描模式 ADC_InitStructure.ADC_ContinuousConvMode ENABLE; ADC_InitStructure.ADC_ScanMode ENABLE; ADC_Init(ADC1, ADC_InitStructure); // 启用DMA传输 ADC_DMA_Enable(ADC1, ENABLE); }4. 内部通道特殊处理与数据转换4.1 温度传感器校准GD32内部温度传感器需要特殊处理出厂校准值存储在系统存储器地址0x1FFFF7B8实际温度计算公式温度(℃) ((V25 - Vsense)/Avg_Slope) 25其中V25 温度传感器在25℃时的电压值Vsense 当前测量的温度传感器电压Avg_Slope 温度传感器斜率典型值4.3mV/℃实现代码float Get_Temperature(void) { uint16_t *temp_cal (uint16_t*)0x1FFFF7B8; float V25 1.43f; // 典型值1.43V25℃ float Avg_Slope 0.0043f; float Vsense (float)adc_buffer[3] * 3.3f / 4095.0f; return ((V25 - Vsense) / Avg_Slope) 25.0f; }4.2 参考电压应用内部参考电压Vrefint可用于电源监测float Get_VDD_Voltage(void) { uint16_t *vref_cal (uint16_t*)0x1FFFF7BA; float Vrefint (float)adc_buffer[4] * 3.3f / 4095.0f; float Vrefint_cal *vref_cal * 3.3f / 4095.0f; return (Vrefint_cal * 1.2f) / Vrefint; // 1.2V为标称参考电压 }5. 实战优化与异常处理5.1 电源噪声抑制ADC精度受电源噪声影响显著推荐措施在VDD与地之间并联10μF0.1μF电容使用独立的LDO为模拟部分供电采样期间关闭不必要的数字电路5.2 常见问题排查现象采样值跳动大检查接地是否良好增加采样时间添加RC滤波10kΩ100nF现象内部通道读数异常确保已正确启用温度传感器和Vrefint检查电源电压是否在2.6-3.6V范围内避免I/O口高压注入即使未使用的引脚DMA传输中断处理void DMA1_Channel1_IRQHandler(void) { if(DMA_GetIntStatus(DMA1_INT_TC1)) { DMA_ClearIntPendingBit(DMA1_INT_TC1); // 处理完整数据帧 Process_ADC_Data(); } }在实际项目中我发现GD32的ADC在连续采样模式下间隔插入单次校准能显著改善长期稳定性。具体做法是每1000次采样后重新校准一次这比完全关闭ADC再重新初始化要高效得多。

更多文章