news 2026/5/6 13:57:44

从传感器到屏幕:手把手教你用STM32的ADC读取电位器,并用OLED实时显示电压值

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
从传感器到屏幕:手把手教你用STM32的ADC读取电位器,并用OLED实时显示电压值

从传感器到屏幕:手把手教你用STM32的ADC读取电位器,并用OLED实时显示电压值

在嵌入式开发中,模拟信号的采集与处理是一个基础但极其重要的技能。想象一下,当你旋转一个电位器,屏幕上的数字随之实时变化,这种直观的反馈不仅能带来成就感,更是理解ADC(模数转换器)工作原理的最佳方式。本文将带你一步步实现这个"迷你电压表"项目,从硬件连接到软件编程,完整呈现STM32的ADC模块如何将模拟世界的连续变化转化为数字世界的精确数值。

1. 项目概述与硬件准备

这个项目的核心目标是通过STM32的ADC模块读取电位器的电压值,并将结果实时显示在OLED屏幕上。整个过程涉及三个关键环节:模拟信号采集(ADC)、数据处理(电压换算)和结果展示(OLED显示)。对于初学者来说,这不仅是一个实践ADC的好机会,还能学习到外设驱动和实时数据处理的技巧。

所需硬件清单

  • STM32开发板(如STM32F103C8T6最小系统板)
  • 10kΩ电位器
  • 0.96寸OLED屏幕(I2C接口)
  • 杜邦线若干
  • USB转TTL模块(用于程序下载和调试)

硬件连接非常简单:

  1. 电位器两端分别接3.3V和GND,中间引脚接STM32的ADC输入通道(如PA1)
  2. OLED的SCL接PB6,SDA接PB7(I2C1默认引脚)
  3. 确保所有设备共地

提示:如果使用不同型号的STM32,请查阅数据手册确认ADC和I2C的引脚定义,避免硬件冲突。

2. STM32 ADC模块配置

ADC是将模拟信号转换为数字信号的关键外设。STM32的ADC具有12位分辨率,意味着它能将0-3.3V的输入电压量化为0-4095的数字值。这种转换不是瞬间完成的,而是遵循特定的时序和配置。

2.1 ADC初始化步骤

以下是使用标准外设库配置ADC的典型流程:

// ADC初始化结构体配置 ADC_InitTypeDef ADC_InitStructure; ADC_CommonInitTypeDef ADC_CommonInitStructure; // 1. 使能ADC时钟 RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE); // 2. 配置ADC通用设置 ADC_CommonInitStructure.ADC_Mode = ADC_Mode_Independent; ADC_CommonInitStructure.ADC_Prescaler = ADC_Prescaler_Div4; ADC_CommonInitStructure.ADC_DMAAccessMode = ADC_DMAAccessMode_Disabled; ADC_CommonInitStructure.ADC_TwoSamplingDelay = ADC_TwoSamplingDelay_5Cycles; ADC_CommonInit(&ADC_CommonInitStructure); // 3. 配置ADC特定设置 ADC_InitStructure.ADC_Resolution = ADC_Resolution_12b; ADC_InitStructure.ADC_ScanConvMode = DISABLE; // 单通道不使用扫描模式 ADC_InitStructure.ADC_ContinuousConvMode = ENABLE; // 连续转换模式 ADC_InitStructure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_None; ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right; ADC_InitStructure.ADC_NbrOfConversion = 1; ADC_Init(ADC1, &ADC_InitStructure); // 4. 配置ADC通道 ADC_RegularChannelConfig(ADC1, ADC_Channel_1, 1, ADC_SampleTime_15Cycles); // 5. 使能ADC ADC_Cmd(ADC1, ENABLE); // 6. 执行ADC校准 ADC_StartCalibration(ADC1); while(ADC_GetCalibrationStatus(ADC1));

2.2 关键参数解析

参数选项说明
分辨率12位/10位/8位/6位12位提供最高精度(4096级)
采样时间1.5/7.5/13.5/28.5/41.5/55.5/71.5/239.5周期较长时间提高精度但降低速度
转换模式单次/连续连续模式适合实时监测
触发方式软件/硬件触发本项目使用软件触发

注意:ADC时钟不能超过14MHz,否则会导致精度下降。系统时钟为72MHz时,分频系数应设为6(72/6=12MHz)。

3. 电位器电压读取与计算

配置好ADC后,我们需要编写代码来启动转换并获取结果。由于ADC输出的是原始数字值,还需要通过公式将其转换为实际的电压值。

3.1 读取ADC值的函数实现

uint16_t Read_ADC_Value(uint8_t channel) { // 设置转换通道 ADC_RegularChannelConfig(ADC1, channel, 1, ADC_SampleTime_15Cycles); // 启动软件触发转换 ADC_SoftwareStartConv(ADC1); // 等待转换完成 while(ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC) == RESET); // 返回转换结果 return ADC_GetConversionValue(ADC1); }

3.2 电压值计算公式

ADC转换结果与实际电压的关系可以用以下公式表示:

Vactual = (ADC_Value × Vref) / 4095

其中:

  • Vactual是实际电压值(单位:伏特)
  • ADC_Value是ADC读取的原始值(0-4095)
  • Vref是参考电压(通常为3.3V)

在代码中实现:

float Convert_To_Voltage(uint16_t adc_value) { return (adc_value * 3.3f) / 4095.0f; }

提示:为了提高显示稳定性,可以添加简单的软件滤波算法,如移动平均或中值滤波。

4. OLED显示驱动与界面设计

OLED屏幕以其高对比度和低功耗特性,成为嵌入式项目中常用的显示设备。我们将使用I2C接口驱动OLED,显示实时电压值。

4.1 OLED初始化

首先需要初始化I2C外设和OLED屏幕:

void OLED_Init(void) { I2C_Configuration(); // 配置I2C接口 // OLED初始化命令序列 OLED_Write_Command(0xAE); // 关闭显示 OLED_Write_Command(0xD5); // 设置时钟分频 OLED_Write_Command(0x80); OLED_Write_Command(0xA8); // 设置多路复用率 OLED_Write_Command(0x3F); // ... 更多初始化命令 OLED_Write_Command(0xAF); // 开启显示 OLED_Clear(); // 清屏 }

4.2 电压值显示实现

创建一个函数来更新屏幕上的电压值:

void Display_Voltage(float voltage) { char buffer[16]; // 清空显示区域 OLED_Set_Pos(0, 0); OLED_Show_String("Voltage:"); // 格式化电压值字符串 sprintf(buffer, "%.2f V", voltage); // 在指定位置显示 OLED_Set_Pos(2, 0); OLED_Show_String(buffer); // 添加简单的进度条效果 uint8_t length = (uint8_t)(voltage * 30 / 3.3); OLED_Draw_Line(4, 0, 4, length); }

5. 系统整合与优化

将各个模块组合起来,形成完整的应用程序。主程序的主要逻辑包括初始化、ADC读取、电压计算和显示更新。

5.1 主程序框架

int main(void) { // 硬件初始化 System_Init(); ADC_Init(); OLED_Init(); // 显示初始界面 OLED_Show_String(0, 0, "STM32 Voltage Meter"); OLED_Show_String(2, 0, "Voltage: 0.00 V"); while(1) { // 读取ADC值 uint16_t adc_value = Read_ADC_Value(ADC_Channel_1); // 转换为电压值 float voltage = Convert_To_Voltage(adc_value); // 更新显示 Display_Voltage(voltage); // 适当延时,控制刷新率 Delay_ms(100); } }

5.2 性能优化技巧

  • 采样速率控制:根据需求调整采样间隔,避免不必要的处理
  • 显示刷新优化:仅更新变化的部分,减少全屏刷新频率
  • 低功耗考虑:在电池供电应用中,可以间歇性采样和显示
  • 校准功能:添加校准程序补偿电位器和ADC的误差
// 简单的移动平均滤波实现 #define FILTER_SIZE 5 float voltage_filter[FILTER_SIZE]; uint8_t filter_index = 0; float Filter_Voltage(float new_value) { voltage_filter[filter_index] = new_value; filter_index = (filter_index + 1) % FILTER_SIZE; float sum = 0; for(int i = 0; i < FILTER_SIZE; i++) { sum += voltage_filter[i]; } return sum / FILTER_SIZE; }

6. 项目扩展与进阶应用

这个基础项目可以扩展出许多有趣的应用方向,以下是几个可能的扩展思路:

6.1 功能扩展建议

  1. 多通道采集:同时监测多个电位器或传感器
  2. 数据记录:添加SD卡模块记录电压变化历史
  3. 无线传输:通过蓝牙或WiFi将数据发送到手机或电脑
  4. 阈值报警:设置电压阈值,触发LED或蜂鸣器报警

6.2 进阶学习路径

  • 深入理解ADC原理:采样定理、量化误差、信噪比
  • 探索不同传感器:温度、光强、压力等模拟传感器
  • 学习高级滤波算法:卡尔曼滤波、FIR/IIR数字滤波
  • 研究DMA传输:提高ADC采样效率,减少CPU开销
// 使用DMA进行多通道ADC采集的示例代码 void ADC_DMA_Init(void) { DMA_InitTypeDef DMA_InitStructure; // 配置DMA DMA_DeInit(DMA1_Channel1); DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&ADC1->DR; DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)adc_values; 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_M2M = DMA_M2M_Disable; DMA_Init(DMA1_Channel1, &DMA_InitStructure); // 使能DMA DMA_Cmd(DMA1_Channel1, ENABLE); // 配置ADC使用DMA ADC_DMACmd(ADC1, ENABLE); }

在实际项目中,我发现电位器的机械抖动会导致电压值轻微波动。通过实验比较,采用移动平均滤波配合适当的采样间隔(约100ms),能在响应速度和稳定性之间取得良好平衡。对于需要更高精度的应用,可以考虑使用精密多圈电位器或增加硬件滤波电路。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/5/6 13:52:07

Zynq 7020 PS端MIO配置避坑指南:从Vivado到SDK的完整点灯流程

Zynq 7020 PS端MIO实战&#xff1a;从硬件配置到SDK开发的完整点灯指南 在嵌入式开发领域&#xff0c;Xilinx Zynq系列SoC因其独特的ARM处理器与FPGA协同架构而广受欢迎。对于刚接触Zynq 7020的开发者而言&#xff0c;PS&#xff08;Processing System&#xff09;端的MIO&…

作者头像 李华
网站建设 2026/5/6 13:47:28

如何彻底清理Mac应用残留文件:Pearcleaner免费工具终极指南

如何彻底清理Mac应用残留文件&#xff1a;Pearcleaner免费工具终极指南 【免费下载链接】Pearcleaner A free, source-available and fair-code licensed mac app cleaner 项目地址: https://gitcode.com/gh_mirrors/pe/Pearcleaner 你是否曾经在Mac上删除应用后&#x…

作者头像 李华