极海APM32E030系列是工业级基础拓展型MCU,在APM32F030性能基础上,实现了更高主频、更低功耗、以及更先进的模拟与通信接口。同时配置丰富的片上资源,可满足多行业的应用升级需求,特别是成本敏感型应用。可广泛应用于工业控制、智能家居、仪器仪表、可穿戴设备、医疗及手持设备、小家电、照明灯等领域。
该篇文章主要介绍APM32E030系列ADC使用的一些小心得——从单通道阻塞采样到多通道DMA扫描
APM32E030的硬件资源
APM32E030片内集成1路12-bit ADC,最高1 Msps,支持16个外部通道+2个内部通道(温度传感器、V<sub>),模拟输入范围0~V<sub>(典型3.3 V)。ADC时钟最高14 MHz,由PCLK2分频而来。
典型应用场景
单通道电压监测(阻塞方式)
多通道轮询扫描+DMA,减轻CPU负担
片内温度传感器/参考电压测量,实现温度补偿和电压校准
寄存器/库函数对照
整套官方SDK提供两套接口:
寄存器版apm32e030_adc.h
LL(Low-layer)/HAL版apm32e0xx_ll_adc.h
下文示例以寄存器版为主,关键函数名称与HAL版一一对应,方便迁移。
最小系统单通道阻塞采样
目标:ADC1通道2(PA2)采可调电阻,串口每秒打印一次电压值。
1.GPIO复用
RCM_EnableAPB2PeriphClock(RCM_APB2_PERIPH_ADC1 | RCM_APB2_PERIPH_GPIOA);
GPIO_Config_T t = {
.pin = GPIO_PIN_2,
.mode = GPIO_MODE_AN,
.pupd = GPIO_PUPD_NO,
.speed = GPIO_SPEED_50MHz
};
GPIO_Config(GPIOA, &t);
2.ADC时钟与分辨率
RCM_ConfigADCCLK(RCM_ADCCLK_PCLK2_DIV6); // 72 MHz / 6 = 12 MHz
ADC_Reset();
ADC_Config_T adc = {
.resolution = ADC_RESOLUTION_12B,
.convMode = ADC_CONVERSION_SINGLE,
.dataAlign = ADC_DATA_ALIGN_RIGHT,
.scanDir = ADC_SCAN_DIR_UPWARD,
.extTrigConv = ADC_EXT_TRIG_CONV_T0,
.extTrigEdge = ADC_EXT_TRIG_EDGE_NONE
};
ADC_Config(&adc);
3.通道与采样时间
ADC_ConfigChannel(ADC_CHANNEL_2, ADC_SAMPLE_TIME_239_5); // 最长采样提高精度
4.校准&启动
ADC_ReadCalibrationFactor(); // 加载出厂校准值
ADC_Enable();
while(!ADC_ReadStatusFlag(ADC_FLAG_ADRDY));
5.阻塞读取封装
uint16_t ADC_GetSingle(void)
{
ADC_StartConversion();
while(!ADC_ReadStatusFlag(ADC_FLAG_CC));
return ADC_ReadConversionValue();
}
6.主循环
float v = ADC_GetSingle() * 3.3f / 4096;
printf("V=%.3f\r\n", v);
至此,单通道阻塞采样完成
五、中断方式避免阻塞
使能转换完成中断,采样完成后在ISR中读取结果。
ADC_EnableInterrupt(ADC_INT_CC);
NVIC_EnableIRQRequest(ADC1_IRQn, 2);
ISR:
void ADC1_IRQHandler(void)
{
if (ADC_ReadIntFlag(ADC_INT_CC))
{
adcValue = ADC_ReadConversionValue();
ADC_ClearIntFlag(ADC_INT_CC);
}
}
主循环无需死等,可并行处理其他任务
六、多通道+DMA扫描
目标:一次启动,ADC连续扫描CH0~CH5,DMA将结果写入RAM数组。
1.定义缓冲区
#define ADC_CH_SIZE 6
uint16_t adcBuf[ADC_CH_SIZE];
2.DMA配置
RCM_EnableAHBPeriphClock(RCM_AHB_PERIPH_DMA);
DMA_Config_T dma = {
.peripheralBase = (uint32_t)&ADC->DATA,
.memoryBase = (uint32_t)adcBuf,
.direction = DMA_DIRECTION_PERIPH_TO_MEMORY,
.bufferSize = ADC_CH_SIZE,
.peripheralInc = DMA_PERIPHERAL_INC_DISABLE,
.memoryInc = DMA_MEMORY_INC_ENABLE,
.peripheralDataSize = DMA_PERIPHERAL_DATA_SIZE_HALFWORD,
.memoryDataSize = DMA_MEMORY_DATA_SIZE_HALFWORD,
.mode = DMA_MODE_CIRCULAR,
.priority = DMA_PRIORITY_HIGH
};
DMA_Config(DMA1_Channel1, &dma);
DMA_Enable(DMA1_Channel1);
3.ADC连续扫描模式
adc.convMode = ADC_CONVERSION_CONTINUOUS;
adc.scanDir = ADC_SCAN_DIR_UPWARD;
ADC_Config(&adc);
/* 分别配置 6 个通道,顺序必须与硬件布线对应 */
ADC_ConfigChannel(ADC_CHANNEL_0, ADC_SAMPLE_TIME_71_5);
...
ADC_ConfigChannel(ADC_CHANNEL_5, ADC_SAMPLE_TIME_71_5);
4.启动
ADC_EnableDMA();
ADC_ReadCalibrationFactor();
ADC_Enable();
ADC_StartConversion();
DMA以循环模式自动搬运数据,CPU仅需读取adcBuf[]。
七、内部温度传感器&<sub>使用技巧
通道号:温度=CH16,V&<sub>=CH17
采样时间≥239.5 cycles,确保稳定
温度计算公式(典型):
T=((V25-VTS)/Avg_Slope)+25
V25≈1.34 V,Avg_Slope≈4.3 mV/°C(以数据手册为准)
实测发现V&<sub>读数约1.2 V,若出现偏大/偏小,可通过校准寄存器VREFINT_CAL进行修正