第一章:ADC的基本知识
ADC(Analog-to-Digital Converter,模数转换器)是微控制器内部负责把连续变化的模拟电压信号转换为离散数字量的外设。单片机无法直接"理解"电压大小,只有通过 ADC 将模拟量量化成数字后,CPU 才能进行运算、判断和显示。STM32C542RC 内部集成了一路 12 位 SAR(逐次逼近)型 ADC,是片上模拟测量功能的核心。
STM32C542RC 的 ADC 主要特点如下:12 位分辨率,最多支持 12 个外部输入通道和 2 个内部通道(内部温度传感器与内部参考电压 VREFINT),最高转换速率可达 2.25 MSPS(每秒约 225 万次采样)。12 位分辨率意味着输入电压被量化成 0~4095 共 4096 个档位,每一步数字量对应的电压由参考电压 VREF 决定,例如参考电压为 3.3 V 时,每 LSB 约对应 3.3 V / 4095 ≈ 0.806 mV。
输入电压范围:单端输入模式下,ADC 可以测量的电压范围约为 0 V 到 VREF+(开发板上通常接 3.3 V)。当待测信号超过量程时,需要先通过电阻分压等硬件手段把信号降到量程以内,否则会损坏引脚或直接得到饱和值 4095。参考电压越稳定,ADC 的测量结果就越准确,因此在对精度要求高的场合,常为 VREF+ 单独供电或使用外部基准芯片。
转换原理:SAR 型 ADC 的工作过程分为采样保持和逐次逼近两步。采样阶段先将模拟电压保持在一个内部采样电容上,随后通过内部 DAC 与比较器,从最高位到最低位逐位比较逼近,最终得到与输入电压对应的 12 位数字量。转换过程消耗 ADC 时钟周期,采样时间(Sampling Time)越长,对高内阻信号源的采样越准确,但单次转换耗时也越长。
触发与转换方式:ADC 的常规转换组(Regular Group)可以由软件启动,也可以由定时器事件、外部引脚等硬件触发,适合与 PWM 或电机控制同步采样。转换完成后,结果既可以通过轮询(Polling)方式读取,也可以借助 DMA 自动搬运到内存缓冲区,从而释放 CPU 去处理其他任务。
多通道扫描:ADC 支持按顺序扫描多个通道(Sequencer),把多个模拟信号依次转换并把结果依次存入数据寄存器,一次配置后即可循环采集多路电压,常用于多路传感器同时监测。
内部通道与校准:ADC 还能测量内部温度传感器和 VREFINT。通过测量 VREFINT 可以反推实际的 VREF 电压,在缺少外部基准时用于校准;内部温度传感器则可直接读取芯片结温。此外,ADC 自身存在零点偏移和增益误差,STM32C5 的 HAL 库提供了自校准(Calibrate)流程,初始化后执行一次校准可以明显提高转换精度。
第二章:使用STM32CubeMX2的配置过程
STM32CubeMX2 是意法半导体新一代图形化配置工具,通过图形界面完成引脚分配、时钟树配置和外设初始化代码生成。使用 STM32CubeMX2 配置 ADC1 采集单路电压的步骤如下。
第一步,新建工程并选择芯片。打开 STM32CubeMX2,点击 New Project 新建工程,在 MCU 选择器中搜索并选择 STM32C542RC 系列芯片;若使用 NUCLEO-C542RC 开发板,可直接在 Board Selector 中选择对应板卡。
第二步,使能 ADC1 外设。进入 Peripherals 外设配置页面,在 Analog 分类下找到 ADC1,点击 Active 使能该外设,页面会展示 ADC1 的 General information 与 Main features 等配置模块。
第三步,设置 ADC 基本参数。在 Main features 中,将 Resolution(分辨率)设置为 12 bit;Sampling mode(采样模式)选择 Normal;同时确认 Kernel clock source 与 Kernel clock frequency(ADC 内核时钟频率)符合需求,例如 36 MHz。
第四步,配置采样通道。在 Channels 列表中使能 ADC1_IN1(对应 PA1 引脚),将 Sampling time(采样时间)设置为 289 ADC clock cycles,Input mode(输入模式)选择 Single-ended(单端输入)。
第五步,配置常规转换组。在 Group conversions 的 Regular 组中,Use group 选择 Enabled;Trigger event(触发事件)选择 Software start,即由软件启动一次转换;Continuous mode(连续模式)设置为 Disabled,即每次由软件触发单次转换,转换完成后等待下一次启动。
第六步,确认引脚配置。在 System 页面中确认 ADC1_IN1 已分配到 PA1 引脚,GPIO Mode 为 Analog(模拟模式),Pull 选择 No pull-up and no pull-down(无上下拉),保持引脚为纯模拟输入状态。
第七步,时钟配置。进入 Clock Configuration 页面,查看整体时钟树,确认 ADC 内核时钟源和分频系数满足采样要求,生成工程前建议先让时钟求解器自动求解通过。
第八步,生成工程。点击左下角 Click to save 保存工程配置;进入 Project settings,在 IDE Project Generation 中选择工程格式 CMake 与工具链 GCC(也可选择 STM32CubeIDE 或 MDK-ARM),点击 Generate IDE project 生成代码。
第九步,导入 IDE 编译。打开 STM32CubeIDE,通过 File → Import… 选择 STM32 CMake Project,指定 STM32CubeMX2 生成的工程目录,确认芯片型号为 STM32C542RCTx、内核为 Cortex-M33 后点击 Finish 完成导入,编译下载即可运行。
第三章:软件代码捕捉
STM32C5 系列使用新一代 HAL2 库,ADC 采集代码主要由宏定义、通道配置、启动校准、轮询转换与电压换算几部分组成。以下代码基于 STM32CubeMX2 生成的工程,实现 PA1(ADC1_IN1)电压的周期采集,并通过串口打印结果。首先定义满量程与参考电压宏,用于后续的电压换算:
/* 12-bit ADC maximum digital value */ #define ADC_DAC_MAX_VALUE 4095U /* ADC reference voltage, unit: mV */ #define ADC_REF_MV 3300U随后完成 ADC1 句柄获取、通道配置、启动与自校准:
uint32_t adc_value = 0; /* ADC raw value */
uint32_t adc_voltage_mv = 0; /* Converted voltage, unit: mV */
/* Get ADC1 handle */
hal_adc_handle_t *hadc1 = mx_adc1_gethandle();
if (hadc1 == NULL)
{
return (-1);
}
/*
* Configure ADC1 Channel 1.
* This section can be removed if ADC1_IN1 has already
* been added to Regular Sequencer Rank 1 in CubeMX2.
*/
hal_adc_channel_config_t adc_channel_config;
adc_channel_config.group = HAL_ADC_GROUP_REGULAR;
adc_channel_config.sequencer_rank = 1;
adc_channel_config.sampling_time = HAL_ADC_SAMPLING_TIME_289CYCLES;
adc_channel_config.input_mode = HAL_ADC_IN_SINGLE_ENDED;
if (HAL_ADC_SetConfigChannel(hadc1, HAL_ADC_CHANNEL_1,
&adc_channel_config) != HAL_OK)
{
return (-1);
}
//ADC的初始化配置,使能ADC并开启校准
s_adc1_handle = mx_adc1_gethandle();
if (s_adc1_handle == NULL) {
return -1;
}
// // 启动 ADC 并校准(顺序不可颠倒)
if (HAL_ADC_Start(s_adc1_handle) != HAL_OK) {
return 0;
}
if (HAL_ADC_Calibrate(s_adc1_handle) != HAL_OK) {
return 0;
}主循环中启动单次转换,轮询等待转换完成,读取原始值并按公式 Voltage = ADC_Value × VREF / 4095 换算为实际电压:
// 启动一次 Regular 组转换
if (HAL_ADC_REG_StartConv(s_adc1_handle) == HAL_OK) {
// 轮询等待转换完成,超时 100ms
if (HAL_ADC_REG_PollForConv(s_adc1_handle, 100) == HAL_OK) {
// 读取 12 位原始数据
g_adc_raw = HAL_ADC_REG_ReadConversionData(s_adc1_handle);
// 换算为电压(mV)
g_adc_mv = (g_adc_raw * ADC_VREF_MV) / ADC_MAX_VALUE;
}
}
printf("g_adc_raw=%4lu,g_adc_mv = %4lu MV\r\n",g_adc_raw,g_adc_mv);参考电压取 3300 mV、满量程取 4095,均为可配置项,若板级参考电压不同,只需修改 ADC_REF_MV 宏。若需要连续采样多路通道或更高吞吐率,可在 STM32CubeMX2 中开启连续模式并配置 DMA,将转换结果通过 HAL_ADC_REG_StartDMA 直接写入数组,由 DMA 传输完成中断统一处理。
第四章:ADC的应用场景
电池电压与电源监测。通过电阻分压把锂电池或系统电源电压降到 ADC 量程以内,即可实时监测剩余电量与电源跌落,配合阈值判断实现低电量报警或自动关机保护,常用于便携设备、遥控器与仪表产品。
温度采集。使用 NTC 热敏电阻与固定电阻组成分压网络,温度变化会引起分压点电压变化,ADC 读取电压后通过查表或公式即可换算温度,广泛用于电机保护、充电器、环境温控等场景。
模拟传感器数据采集。光敏电阻、电位器、霍尔传感器、气压湿度等模拟输出传感器都依赖 ADC 完成读数,例如用光敏电阻做环境光检测实现屏幕亮度自适应,用电位器做旋钮输入实现音量或参数调节。
电流与功率采样。在功率回路中串入采样电阻,经运算放大器放大后送入 ADC,可采集电机电流与负载功耗,用于过流保护、电源管理或电量计设计。
实验验证图片:

我要赚赏金
