news 2026/9/23 9:26:50

使用STM32 HAL库配置ADC单次转换模式详解

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
使用STM32 HAL库配置ADC单次转换模式详解

前言

在嵌入式开发中,ADC(模数转换器)是连接模拟世界与数字世界的重要桥梁。STM32微控制器内置了高性能的ADC模块,而HAL库则为我们提供了简洁高效的配置方式。今天,我将详细介绍如何使用STM32 HAL库配置ADC的单次转换模式。

什么是单次转换模式?

单次转换模式下,ADC只执行一次转换,完成后自动停止并等待下次触发。这种模式适用于不要求连续采样、需要节能或由特定事件触发的应用场景。

硬件准备

  • STM32开发板(本文以STM32F4系列为例)

  • 模拟信号源(如电位器、传感器等)

  • STM32CubeIDE或Keil MDK开发环境

配置步骤详解

1. 引脚与ADC外设初始化

首先,我们需要初始化ADC使用的GPIO引脚和ADC外设本身:

// ADC句柄声明 ADC_HandleTypeDef hadc1; void ADC_Init(void) { GPIO_InitTypeDef GPIO_InitStruct = {0}; // 1. 使能时钟 __HAL_RCC_GPIOA_CLK_ENABLE(); __HAL_RCC_ADC1_CLK_ENABLE(); // 2. 配置GPIO引脚为模拟输入模式 GPIO_InitStruct.Pin = GPIO_PIN_0; // 假设使用PA0(ADC1_IN0) GPIO_InitStruct.Mode = GPIO_MODE_ANALOG; GPIO_InitStruct.Pull = GPIO_NOPULL; HAL_GPIO_Init(GPIOA, &GPIO_InitStruct); // 3. 配置ADC参数 hadc1.Instance = ADC1; hadc1.Init.ClockPrescaler = ADC_CLOCK_SYNC_PCLK_DIV4; hadc1.Init.Resolution = ADC_RESOLUTION_12B; hadc1.Init.DataAlign = ADC_DATAALIGN_RIGHT; hadc1.Init.ScanConvMode = DISABLE; // 单通道,禁用扫描模式 hadc1.Init.EOCSelection = ADC_EOC_SINGLE_CONV; // 每次转换后产生EOC hadc1.Init.ContinuousConvMode = DISABLE; // 禁用连续转换 hadc1.Init.NbrOfConversion = 1; // 1个转换序列 hadc1.Init.DiscontinuousConvMode = DISABLE; hadc1.Init.NbrOfDiscConversion = 0; hadc1.Init.ExternalTrigConv = ADC_SOFTWARE_START; // 软件触发 hadc1.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE; hadc1.Init.DMAContinuousRequests = DISABLE; HAL_ADC_Init(&hadc1); }

2. 配置ADC通道

接下来配置具体的ADC通道参数:

void ADC_ChannelConfig(void) { ADC_ChannelConfTypeDef sConfig = {0}; sConfig.Channel = ADC_CHANNEL_0; // 通道0(对应PA0) sConfig.Rank = 1; // 转换序列中的第一个 sConfig.SamplingTime = ADC_SAMPLETIME_84CYCLES; // 采样时间 if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK) { Error_Handler(); } }

3. 启动转换与读取结果

编写ADC转换函数:

uint16_t ADC_ReadSingleConversion(void) { uint16_t adc_value = 0; // 启动ADC转换 HAL_ADC_Start(&hadc1); // 等待转换完成,超时时间10ms if (HAL_ADC_PollForConversion(&hadc1, 10) == HAL_OK) { // 读取ADC值 adc_value = HAL_ADC_GetValue(&hadc1); } // 停止ADC(单次转换模式会自动停止,这里确保状态正确) HAL_ADC_Stop(&hadc1); return adc_value; }

4. 电压计算函数

将ADC原始值转换为实际电压:

float ADC_ConvertToVoltage(uint16_t adc_value, float vref) { // 12位ADC,最大值为4095(2^12 - 1) return (adc_value * vref) / 4095.0f; }

完整示例代码

#include "main.h" ADC_HandleTypeDef hadc1; void SystemClock_Config(void); static void MX_GPIO_Init(void); static void MX_ADC1_Init(void); int main(void) { uint16_t raw_adc; float voltage; const float VREF = 3.3f; // 参考电压 HAL_Init(); SystemClock_Config(); MX_GPIO_Init(); MX_ADC1_Init(); while (1) { // 读取ADC值 raw_adc = ADC_ReadSingleConversion(); // 转换为电压 voltage = ADC_ConvertToVoltage(raw_adc, VREF); // 输出结果(可通过串口或调试器查看) printf("ADC Raw: %d, Voltage: %.2f V\r\n", raw_adc, voltage); // 延迟1秒 HAL_Delay(1000); } } static void MX_ADC1_Init(void) { ADC_ChannelConfTypeDef sConfig = {0}; hadc1.Instance = ADC1; hadc1.Init.ClockPrescaler = ADC_CLOCK_SYNC_PCLK_DIV4; hadc1.Init.Resolution = ADC_RESOLUTION_12B; hadc1.Init.DataAlign = ADC_DATAALIGN_RIGHT; hadc1.Init.ScanConvMode = DISABLE; hadc1.Init.EOCSelection = ADC_EOC_SINGLE_CONV; hadc1.Init.ContinuousConvMode = DISABLE; hadc1.Init.NbrOfConversion = 1; hadc1.Init.DiscontinuousConvMode = DISABLE; hadc1.Init.NbrOfDiscConversion = 0; hadc1.Init.ExternalTrigConv = ADC_SOFTWARE_START; hadc1.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE; hadc1.Init.DMAContinuousRequests = DISABLE; HAL_ADC_Init(&hadc1); sConfig.Channel = ADC_CHANNEL_0; sConfig.Rank = 1; sConfig.SamplingTime = ADC_SAMPLETIME_84CYCLES; HAL_ADC_ConfigChannel(&hadc1, &sConfig); }

关键参数解析

采样时间选择

采样时间决定了ADC对输入信号采样的时长,需要根据信号源阻抗来设置:

  • 高阻抗信号源 → 需要更长的采样时间

  • 低阻抗信号源 → 可以使用较短的采样时间

触发方式

除了软件触发,还可以配置为硬件触发:

// 例如,使用定时器2的TRGO事件触发 hadc1.Init.ExternalTrigConv = ADC_EXTERNALTRIGCONV_T2_TRGO; hadc1.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_RISING;

调试技巧

  1. 使用断点调试:在HAL_ADC_GetValue()后设置断点,查看ADC原始值

  2. 验证参考电压:使用万用表测量VREF的实际值

  3. 检查时钟配置:确保ADC时钟不超过规格书规定的最大值

  4. 使用内部参考:部分STM32有内部参考电压,可用于校准

常见问题与解决方案

Q1: ADC读数跳动较大

  • ✅ 检查电源稳定性

  • ✅ 增加软件滤波(如移动平均)

  • ✅ 调整采样时间

  • ✅ 添加硬件滤波电路

Q2: 转换速度慢

  • ✅ 减少采样时间

  • ✅ 提高ADC时钟频率

  • ✅ 考虑使用连续转换+DMA模式

Q3: 精度不足

  • ✅ 确保VREF稳定

  • ✅ 避免高噪声环境

  • ✅ 使用过采样技术提高分辨率

性能优化建议

  1. 使用DMA:即使单次转换,配合DMA也能减少CPU开销

  2. 校准ADC:部分STM32支持内部校准,调用HAL_ADCEx_Calibration_Start()

  3. 温度补偿:注意ADC性能随温度变化,高温下可能需重新校准

总结

配置STM32的ADC单次转换模式并不复杂,关键是要理解各个参数的含义,并根据实际应用需求进行优化。单次转换模式在需要节能或事件触发的场景中非常有用。掌握这种基础配置后,你可以进一步探索扫描模式、注入通道、差分输入等高级功能。

希望这篇博客能帮助你更好地理解和使用STM32的ADC功能。如果有任何问题或建议,欢迎在评论区留言讨论!

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

YOLOv8在零售商品识别中的应用实验

YOLOv8在零售商品识别中的应用实验 在一家连锁便利店的智能货架前,摄像头正默默扫描着琳琅满目的商品。几秒钟后,系统自动识别出哪款饮料库存不足、哪个零食被顾客频繁拿起又放回——这样的场景已不再是科幻电影的情节,而是基于YOLOv8等先进目…

作者头像 李华
网站建设 2026/9/22 9:25:20

SOO-BP+MOPSO,恒星振荡优化算法优化BP神经网络+多目标粒子群算法!(Matlab完整源码和数据),恒星振荡优化算法(Stellar oscillation optimizer,SOO)

✅作者简介:热爱科研的Matlab仿真开发者,擅长数据处理、建模仿真、程序设计、完整代码获取、论文复现及科研仿真。🍎 往期回顾关注个人主页:Matlab科研工作室🍊个人信条:格物致知,完整Matlab代码获取及仿真…

作者头像 李华
网站建设 2026/9/21 18:45:47

为什么我认为:现在绝大多数 AI Agent,在工程上都是「不可控 AI」

最近在工程圈里,“AI Agent”这个词几乎被说烂了。 自动决策、自动调度、自动交易、自动运维…… 很多系统在 Demo 阶段表现得非常聪明,也非常稳定。 但作为工程师,我越来越频繁地遇到一个被忽略的问题: 这些系统,在…

作者头像 李华
网站建设 2026/9/20 15:06:15

DeepSeek大模型:从崛起到悬崖,中国AI的破局之路与开发者学习指南

DeepSeek大模型曾以低成本、高性能、开源挑战全球AI巨头,后陷入技术争议、数据泄露、安全攻击等困境。文章分析其当前处境与东山再起之路,包括技术创新、商业模式探索和信任重建。作为中国AI产业代表,DeepSeek的成败关乎整个中国AI能否突破&a…

作者头像 李华
网站建设 2026/9/20 15:07:51

Java程序员转行大模型开发全攻略:从零基础到项目实战,建议收藏备用_大模型入门到精通,收藏这一篇就够了

Java程序员转型大模型开发需学习机器学习基础,掌握TensorFlow等工具,强化数学和编程能力。Java程序员在软件架构方面有优势。AI时代催生多种新岗位,包括AI工程师、数据工程师等,需掌握多领域知识。文章提供学习路线和资源&#xf…

作者头像 李华
网站建设 2026/9/20 15:02:37

AI论文深度解读:DeepSeek-V3.2的技术突破与局限

DeepSeek-V3.2:推动开源大语言模型的前沿探索 摘要翻译 我们推出 DeepSeek-V3.2,这是一款兼顾高计算效率与卓越推理、智能体性能的模型。其核心技术突破如下:(1)DeepSeek 稀疏注意力(DSA)&#…

作者头像 李华