STM32C542开发.7--ADC电压采集
概述
本章介绍如何使用 STM32C5 的 ADC1 实现模拟电压采集。ADC配置为 12位分辨率,采用 Regular Group 和软件触发方式,通过 HAL2 的轮询模式启动转换、等待转换完成并读取采样数据。
实验中将上一讲 PA4(DAC1_OUT1)输出的 1.65 V 电压连接至 PA1(ADC1_IN1),ADC读取原始采样值后,根据参考电压将数字量换算为实际电压。
需要样片的可以加群申请:925643491 / 615061293 。
视频教学
https://www.bilibili.com/video/BV1DNby6UExC/
样品申请
https://www.wjx.top/vm/OhcKxJk.aspx#
源码下载
硬件准备
首先需要准备一个开发板,这里我准备的是自己绘制的开发板,需要的可以进行申请。
主控为STM32C542CCT6

参考程序
https://github.com/CoreMaker-lab/STM32C542_SENSOR
https://gitee.com/CoreMaker/STM32C542_SENSOR
ADC配置
打开 STM32CubeMX2,进入 ADC 外设配置界面,配置步骤如下。
- 进入 Peripherals 外设配置页面。
- 在 Analog 分类中选择 ADC1。
- 点击 Active 使能 ADC1 外设。
- ADC 分辨率设置为 12 bit,Sampling mode 选择 Normal;使能 ADC1_IN1 通道,采样时间设置为 289 ADC clock cycles,输入模式选择 Single-ended。
本实验使用 Regular Group 进行普通 ADC 转换,触发方式选择 Software start,Continuous mode 设置为 Single,即每次由软件启动一次 ADC 转换。STM32C5 HAL2 支持软件触发 Regular Group,并可通过轮询方式获取转换结果。

继续向下配置 System 参数。
ADC1 Channel 1 的输入信号 ADC1_IN1 选择 PA1 引脚,GPIO 工作模式设置为 Analog,并选择 No pull-up and no pull-down。STM32C5 的 PA1 支持 ADC1_IN1 模拟输入功能,可用于采集外部模拟电压。

生成项目
- 修改配置后,左下角会提示 Click to save,需要先保存当前工程配置
- 点击左侧 Project settings,进入工程生成设置页面
- 在 IDE Project Generation 中选择工程格式和工具链,本例选择 CMake + GCC,然后点击 Generate IDE project 生成工程

导入STM32CubeIDE
- 打开 STM32CubeIDE,点击菜单栏 File
- 选择 Import...,准备导入 STM32CubeMX2 生成的 CMake 工程

- 在 Import 窗口中展开 Import STM32 Project
- 选择 STM32 CMake Project
- 点击 Next,进入 CMake 工程路径选择页面

- Project name:填写导入到 STM32CubeIDE 中显示的工程名称
- Source directory:选择 STM32CubeMX2 生成的 CMake 工程目录
- 点击 Next,继续完成工程导入

- Toolchain:选择 MCU ARM GCC,表示使用 ARM GCC 工具链进行编译
- MCU:确认芯片型号为 STM32C542CCTx,与前面 STM32CubeMX2 中选择的 MCU 保持一致
- CPU/Core:确认内核为 Cortex-M33,Core 为 0
- 点击 Finish,完成 CMake 工程导入

设置工程编码
- 在 Project Explorer 中选中当前工程
- 点击菜单栏 Project
- 选择 Properties,进入工程属性设置

- 在工程属性中选择 Resource
- Text file encoding 选择 Other
- 编码格式输入 GBK
- 点击 Apply and Close 保存设置

宏定义
该宏定义用于表示 12 位 ADC/DAC 的最大数字量。
c
/* 12-bit ADC/DAC maximum digital value */
#define ADC_DAC_MAX_VALUE 4095U

c
uint32_t adc_value = 0;
uint32_t adc_voltage_mv = 0;
/* 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);
}
/* Activate ADC1 */
if (HAL_ADC_Start(hadc1) != HAL_OK)
{
return (-1);
}
/* ADC self calibration */
if (HAL_ADC_Calibrate(hadc1) != HAL_OK)
{
return (-1);
}
printf("\r\nSTM32C542 ADC Voltage Test\r\n");
初始化
该部分代码主要完成 ADC1 的初始化准备和采样通道配置。首先定义变量用于保存 ADC 原始采样值和换算后的电压值,然后通过 mx_adc1_gethandle() 获取 ADC1 句柄,并将 ADC1 Channel 1 配置到 Regular Group 的 Rank 1,采样时间设置为 289 个 ADC 时钟周期,输入模式选择单端输入。配置完成后调用 HAL_ADC_Start() 启动 ADC,并通过 HAL_ADC_Calibrate() 执行 ADC 自校准,为后续 PA1 电压采集做好准备。ST 官方 STM32C5 HAL2 的 ADC Polling 流程同样包含通道配置、ADC 启动和校准步骤。
c
uint32_t adc_value = 0;
uint32_t adc_voltage_mv = 0;
/* 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);
}
/* Activate ADC1 */
if (HAL_ADC_Start(hadc1) != HAL_OK)
{
return (-1);
}
/* ADC self calibration */
if (HAL_ADC_Calibrate(hadc1) != HAL_OK)
{
return (-1);
}
printf("\r\nSTM32C542 ADC Voltage Test\r\n");

主程序
这段主循环主要实现 ADC1 的周期性电压采集与串口显示。程序通过 HAL_ADC_REG_StartConv() 启动一次规则组转换,再使用 HAL_ADC_REG_PollForConv() 轮询等待转换完成,随后读取 ADC 原始值,并按照参考电压和 12 位满量程 4095 换算成实际电压值。STM32C5 HAL2 官方文档将 StartConv + PollForConv 作为 ADC Polling 模式的标准使用方式。
c
while (1) {
/* Start ADC regular conversion */
if (HAL_ADC_REG_StartConv(hadc1) == HAL_OK)
{
/* Wait for conversion complete */
if (HAL_ADC_REG_PollForConv(hadc1, 100) == HAL_OK)
{
/* Read ADC conversion data */
adc_value =
(uint32_t)HAL_ADC_REG_ReadConversionData(hadc1);
/*
* Convert ADC value to voltage.
*
* Voltage = ADC_Value × VREF / 4095
*/
adc_voltage_mv =
(adc_value * DAC_VREF_MV) / ADC_DAC_MAX_VALUE;
printf("ADC Value: %4lu, Voltage: %4lu mV\r\n",
(unsigned long)adc_value,
(unsigned long)adc_voltage_mv);
}
else
{
printf("ADC conversion timeout!\r\n");
}
}
HAL_Delay(1000);
}

测试结果
将 PA4(DAC1_OUT1)与 PA1(ADC1_IN1)连接,ADC 对上一讲 DAC 输出的 1.65 V 电压进行实时采集,串口输出结果如下图所示。
