STM32F103 ADC 实战:测量电位器电压并串口输出
STM32F103 ADC 实战:测量电位器电压并串口输出
在 STM32 单片机开发中,ADC(模数转换器)是最常用的外设之一。像电位器、光敏电阻、热敏电阻这类输出模拟电压的器件,都需要通过 ADC 把模拟量转换为数字量,才能被单片机处理。
本文以 STM32F103 为例,完成一个非常经典的小实验:使用 ADC 采集电位器输出电压,并通过串口打印采样值和对应电压。这类实验非常适合作为 ADC 入门,也能为后续做传感器采集打基础。
一、实验目标
- 掌握 STM32F103 ADC 的基本工作原理
- 学会配置 GPIO 为模拟输入模式
- 学会配置 ADC 单通道采样
- 能够读取电位器电压并换算成实际电压值
- 通过 USART 串口输出结果,便于调试观察
二、硬件连接
实验中使用一个三脚电位器,中间滑动端输出可变电压。
- 电位器一端接
3.3V - 电位器另一端接
GND - 中间滑动端接到 STM32F103 的
PA1
这里选择 PA1,对应的 ADC 通道是 ADC_Channel_1。
注意:ADC 输入电压不能超过芯片参考电压范围,通常为 0~3.3V,否则可能导致采样异常,严重时还可能损坏芯片。
三、ADC 基本原理
STM32F103 的 ADC 是 12 位逐次逼近型 ADC,也就是说:
- 输入电压范围:0 ~ 3.3V
- 转换结果范围:0 ~ 4095
- 分辨率:
3.3 / 4096 ≈ 0.000805V
因此,实际电压可以按下面公式换算:
Voltage = ADC_Value * 3.3 / 4095
比如:
- ADC 值为 0,对应 0V
- ADC 值约为 2048,对应约 1.65V
- ADC 值接近 4095,对应约 3.3V
四、配置思路
整个程序可以分成四步:
- 开启 GPIOA 和 ADC1 时钟
- 把 PA1 配置为模拟输入
- 配置 ADC1 为独立模式、单通道、软件触发
- 启动转换并读取结果
如果还要把结果打印出来,就再配置一个串口即可。
五、核心代码实现
1. ADC 初始化
#include "stm32f10x.h"
#include
void ADC1_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
ADC_InitTypeDef ADC_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_ADC1, ENABLE);
// ADC 时钟不能太高,通常需要分频
RCC_ADCCLKConfig(RCC_PCLK2_Div6);
// PA1 配置为模拟输入
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
GPIO_Init(GPIOA, &GPIO_InitStructure);
ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;
ADC_InitStructure.ADC_ScanConvMode = DISABLE;
ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;
ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;
ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
ADC_InitStructure.ADC_NbrOfChannel = 1;
ADC_Init(ADC1, &ADC_InitStructure);
ADC_Cmd(ADC1, ENABLE);
// 复位校准
ADC_ResetCalibration(ADC1);
while(ADC_GetResetCalibrationStatus(ADC1));
// 开始校准
ADC_StartCalibration(ADC1);
while(ADC_GetCalibrationStatus(ADC1));
}
2. 读取指定 ADC 通道
uint16_t ADC_GetValue(uint8_t channel)
{
ADC_RegularChannelConfig(ADC1, channel, 1, ADC_SampleTime_55Cycles5);
ADC_SoftwareStartConvCmd(ADC1, ENABLE);
while(ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC) == RESET);
return ADC_GetConversionValue(ADC1);
}
3. 主函数测试
下面示例中,循环读取电位器电压,并通过串口打印原始 ADC 值与换算后的电压值。
int main(void)
{
uint16_t adc_value;
float voltage;
USART1_Init();
ADC1_Init();
while(1)
{
adc_value = ADC_GetValue(ADC_Channel_1);
voltage = adc_value * 3.3f / 4095.0f;
printf("ADC = %d, Voltage = %.2fV
", adc_value, voltage);
Delay_ms(500);
}
}
六、运行现象
下载程序后,打开串口助手,旋转电位器旋钮,可以看到串口输出的数据不断变化,例如:
ADC = 15, Voltage = 0.01V
ADC = 1024, Voltage = 0.83V
ADC = 2048, Voltage = 1.65V
ADC = 3072, Voltage = 2.48V
ADC = 4090, Voltage = 3.30V
这说明 ADC 已经成功采集到了电位器的模拟电压变化。
七、几个容易出错的点
1. GPIO 没有配置成模拟输入
如果 PA1 没有设置为 GPIO_Mode_AIN,采样值可能不稳定,甚至一直异常。
2. ADC 时钟配置不合适
STM32F1 的 ADC 时钟一般不能超过 14MHz,所以通常要配置分频,例如 RCC_PCLK2_Div6。
3. 忘记做校准
ADC 在启用后最好执行复位校准和启动校准,否则测量值可能误差较大。
4. 参考电压不稳定
如果开发板 3.3V 电源波动比较大,那么 ADC 的换算电压也会跟着受影响。
5. 电位器接线错误
中间脚必须接 ADC 输入端,如果接错脚位,读数可能固定不变。
八、拓展方向
完成单通道采样后,还可以继续做这些扩展:
- 改成 连续转换模式
- 增加 多通道采样
- 结合 DMA 自动搬运数据
- 用 ADC 读取光敏电阻、热敏电阻、摇杆等模拟传感器
- 加入滤波算法,如均值滤波、中值滤波,提高稳定性
九、总结
这篇实验的重点并不复杂,但非常实用。通过它可以掌握 STM32F103 ADC 的基础使用流程:配置模拟输入 → 初始化 ADC → 启动转换 → 读取结果 → 换算电压。
对于刚接触 STM32 的同学来说,电位器测压是一个非常适合练手的项目。等把这个实验吃透后,再去做多通道采样、DMA 采集、传感器融合,就会轻松很多。
如果你也在学习 STM32,建议亲手把这个实验跑一遍,并尝试把串口输出改成 OLED 显示,效果会更直观。
更多推荐


所有评论(0)