野火STM32_HAL库版课程笔记-ADC单通道采集电位器应用(轮询)
本文介绍了STM32F10x系列ADC模块的工作原理及配置方法。主要内容包括:1)ADC通道类型区分,规则通道用于常规采集,注入通道用于高优先级任务;2)转换顺序配置方法,通过SQR寄存器设置;3)转换触发方式,支持软件触发和定时器/外部中断触发;4)时钟配置与转换速度计算;5)实际应用示例,通过HAL库实现电位器ADC轮询读取,包括初始化配置、电压值转换公式及串口输出实现。文中还详细说明了Cub
前置介绍
ADC

STM32F10x - 中文手册 - ADC

ADC 框图部分


每个通道对应不同的 GPIO 端口, 具体可以查阅手册.
ADC 还有内部通道, 包括温度传感器 和 电压传感器
每个通道负责采集一个模拟信号.
注入通道与规则通道
规则通道:
正常工作时的通道, 平时读取电位器, 传感器这些模拟型号时使用的都是规则通道.
因为 STM32 的 ADC 实际上可以同时处理很多任务.
那么除了规则通道以外, 就有注入通道留给特殊用途的准备.
注入通道:
注入通道就像插队一样, 当 ADC 正在规则通道里按顺序采集数据的时候,
想要临时测一下某个电压, 这时就可以使用注入通道, 此时就会插队, 抢在规则通道前面, 把自己的电压值转换出来, 转换完成后再继续执行规则通道的任务.
一般情况下是用不到的, 只有需要定时插入测量 或 是一些比规则通道更重要的采集时才会用到.
注入通道必须依附在规则通道的基础上, 才能够工作.
通道转换先后顺序
规则通道是依次转换通道的数据值, 当使用 ADC 采集多个通道的数据, 就会有一个转换先后的顺序需要我们来设定.
这个顺序是由三个规则序列寄存器 (SQR) 来控制的
SQR1 : 13 ~ 16
SQR2 : 7 ~ 12
SQR3 : 1 ~ 6
每个寄存器都用五位来指定一个通道编号
比如:
我们想要第一个转换的通道是通道 16, 那么我们就要在 SQR3 的 SQ1 部分写入 16.
依次, 我们想要第二个通道为 15 , 那么就要在 SQ2 写入 15.
如何开始转换
- 软件控制 (最简单)
在 STM32 的寄存器里, 有个寄存器是 ADCCR2, 这个寄存器里面有一个开关是 ADON
写入 1, 就开始转换.
写入 0, 就停止转换.
- 自动触发 (更高级)
a. 定时器触发, 每秒触发一次 ADC 采集.
b. 外部中断触发, 例如按下按键触发 ADC 采集.
这就需要更多的控制位, 来选择规则通道的触发源.
例如 TIM1, TIM2 时钟部分. 选择规则通道的触发源, 来触发 ADC 转换.
内部模块

这里是采集到的数据经过数据寄存器到达数据总线以外, 还有一个 DMA 请求,
这里的 DMA 也是属于一个 STM32 内部模块.
内部模块它可以在不影响 CPU 工作的前提下, 将数据从一个地方转换到另一个地方.
ADC 时钟 - 转换速度

ADC 的时钟是由 ADCCLK 时钟 和 PCLK2 进行同步的, 并且还提供了一个可编程的预分频器.
可以进行分频. 就是由这个时钟分频产生 最大可以设置到 14MHz.
而 ADC 从模拟电压到数字的转换的时间. 就跟 ADC 的输入时间, 输入时钟, 和采样时间有关.
最快设置成的采样时间是 1.5 个周期.
其采样公式是由采样时间加上 12.5 个周期.
当我们设置 ADC 的时钟是 14MHz, 采样时间是 1.5 个周期加上 12.5 个周期, 一共 14 个周期
正好 14MHz 除以 14 个周期, 那么每一个周期就是 1 微秒.
也就是说 ADC 转换的最大速率是 1MHz.
而我们常用的主频设置为 72MHz, 经过 ADC 的与分频器, 能够分频的最大时钟却不是 14
只能够分频到 12 MHz, 经过这个转换后, 最短的转换时间是 1.17 微秒.
ADC 通道分配图标

STM32F103x8 数据手册 - 引脚功能分配

不同封装的引脚的数量是不同的, 其通道分配也是不同的.
就需要关注这个 LQFP48 的封装 (STM32F103C8T6) 的 ADC 封装在哪里

这里的 ADC12_IN10 到 ADC12_IN13 , 对于我们的封装来说是没有的.
注: 这里的 ADC 并不是 ADC12 ("十二") 的意思, 而是 ADC1 2 的意思. 即可以用在 ADC1, 也可以用在 ADC2.

图中对应封装与 Defualt 栏交错的单元格, 如果是 "-" 就代表在这种封装下, 该 ADC 通道不存在.
实验目标 - 电位器





ADC 读取三种模式

ADC 轮询读取 HAL 库函数

HAL_ADC_Start
启动 ADC 转换, 根据我们设定的模式, 也就是 单次转换 或者是 连续转换
单次转换:
每读取一次就停止, 需要再次启动才能够进行转换.
连续转换:
启动 ADC 转换后, 其就会不停的以它的转换速度进行转换. 随时都可以读取它的最新值.
HAL_ADCEx_Calibration_Start
启动 ADC 校准, 提升采样精度.

HAL_ADC_PollForConversion
等待 ADC 转换完成, 或者说是阻塞读取 ADC , 有两个参数: ADC 句柄 和 阻塞时间
HAL_ADC_GetValue
当前面 ADC 校准, 并且转换完成, 那么我们就可以把转换的值读取出来.
项目配置


这里可以看到 ADC1 除了 0 ~ 9 的通道, 还有温度和电压
而 ADC2 则没有温度和电压.
这里勾选 ADC1 的 IN6

1. ADCs_Common_Settings (ADC 通用设置)
这部分通常用于配置当芯片内有多个 ADC(例如 ADC1 和 ADC2)同时工作时的协同模式。
- Mode (模式): Independent mode (独立模式)
-
- 解释:表示当前的 ADC 独立工作,不与其他 ADC 进行同步或交错转换。如果你只用了一个 ADC,或者不需要多个 ADC 配合采样,通常选这个。
2. ADC_Settings (ADC 基础设置)
这部分配置 ADC 的核心数据格式和工作流程。
- Data Alignment (数据对齐): Right alignment (右对齐)
-
- 解释:STM32 的 ADC 通常是 12 位的,但数据寄存器是 16 位的。
- 右对齐:12 位数据放在寄存器的低 12 位(bit 0-11),高 4 位补 0。这是最常用的模式,读取数据方便。
- (如果是左对齐,数据会放在高 12 位,低 4 位补 0)。
- Scan Conversion Mode (扫描转换模式): Disabled (禁用)
-
- 解释:扫描模式用于一次性自动转换多个通道(例如同时读取温度传感器和电池电压)。
- 禁用:表示只转换一个通道(即下面设置的 Channel 6),转换完就停止。
- Continuous Conversion Mode (连续转换模式): Disabled (禁用)
-
- 禁用:表示单次转换。一旦完成一次转换,ADC 就会停止,直到你再次发出启动指令。
- (如果启用,ADC 会不停地循环转换)。
- Discontinuous Conversion Mode (不连续转换模式): Disabled (禁用)
-
- 解释:这是扫描模式的一个子功能,用于将一组通道分成几组来转换。因为上面“扫描模式”已经禁用了,所以这个自然也是禁用的。
3. ADC_Regular_ConversionMode (ADC 规则转换模式)
这是 ADC 最常用的工作模式,用于处理主要的模拟信号采集。
- Enable Regular Conversions (启用规则转换): Enable (启用)
-
- 解释:开启主要的转换功能。
- Number Of Conversion (转换数量): 1
-
- 解释:因为“扫描模式”是禁用的,所以这里只能转换 1 个通道。
- External Trigger Conversion Source (外部触发源): Regular Conversion launched by software (软件触发规则转换)
-
- 解释:决定由什么信号来启动转换。
- 软件触发:意味着你需要在代码中调用函数(如
HAL_ADC_Start()或HAL_ADC_Start_IT())或者手动置位寄存器来开始转换。它不会自动由定时器或外部引脚触发。
- Rank (排名/顺序): 1
-
- 解释:这是转换序列中的第 1 个位置。
- Channel (通道): Channel 6
-
-
- 解释:具体选择的是 ADC 的第 6 号输入通道(对应芯片引脚,需查阅具体型号的数据手册,通常是 PA6 或其他引脚)。
-
-
- Sampling Time (采样时间): 1.5 Cycles (1.5 个周期)
-
-
- 解释:这是 ADC 内部电容对输入电压进行采样的时间长度。
- 1.5 周期:这是最快的采样速度。适用于信号源阻抗很低(驱动能力强)的情况。如果信号源阻抗高(比如直接接了一个高阻值电位器),采样时间太短会导致电压没充进去,读数不准,那时需要调大这个值(如 55.5 或 239.5 周期)。
-
4. ADC_Injected_ConversionMode (ADC 注入转换模式)
- Enable Injected Conversions (启用注入转换): Disable (禁用)
-
- 解释:注入通道是一种高优先级的转换通道,通常用于在规则转换过程中“插队”进行紧急采样(例如电机控制中的电流保护)。这里不需要,所以关闭。
5. WatchDog (看门狗)
- Enable Analog WatchDog Mode (启用模拟看门狗模式): [未勾选] (禁用)
-
- 解释:模拟看门狗用于监测电压是否超出设定的上下限(例如检测电池是否过压或欠压)。如果超出范围,它会触发中断。这里没有启用该功能。
时钟配置 - ADC

将 ADC Prescaler 设置为 "/6" 六分频, 使 ADC 最终输入频率为 12MHz
给对应 GPIO 引脚打上标签

勾选 Use MicroLIB

代码部分
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include "adc.h"
#include "usart.h"
#include "gpio.h"
/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include <stdio.h> // 使用 printf 函数
#include <string.h> // 使用 strncmp
/* USER CODE END Includes */
/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */
/* USER CODE END PTD */
/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */
/* USER CODE END PD */
/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */
/* USER CODE END PM */
/* Private variables ---------------------------------------------------------*/
/* USER CODE BEGIN PV */
uint32_t adc_val = 0; // 存储原始数字值
float voltage = 0.0f; // 存储转换后的电压值
/* USER CODE END PV */
/* USER CODE BEGIN WHILE */
while (1)
{
// 启动一次 ADC 转换
HAL_ADC_Start(&hadc1);
// HAL_ADC_PollForConversion
if (HAL_ADC_PollForConversion(&hadc1, 50) == HAL_OK)
{
// 读取ADC的值
adc_val = HAL_ADC_GetValue(&hadc1);
// 计算电压值 (参考电压 3.3V, 分辨率 12位)
voltage = (float)adc_val / 4095 * 3.3f;
// 打印结果到串口
printf("ADC原始值: %d, ADC电压值: %.3f \r\n", adc_val, voltage);
}
// 每 500 ms 采样一次
HAL_Delay(500);
/* USER CODE END WHILE */
/* USER CODE BEGIN 4 */
/**
* @brief 重定向 printf 的输出到串口
* @param ch: 要发送的字符
* @param f: 文件指针 (标准库要求的参数, 一般不使用)
* @retval 返回发送的字符
*/
int fputc(int ch, FILE *f)
{
HAL_UART_Transmit(&huart1, (uint8_t *)&ch, 1, HAL_MAX_DELAY);
return ch;
}
/* USER CODE END 4 */
实验现象

电位器从左旋转到右侧, ADC 值改变.
更多推荐


所有评论(0)