当前位置: 首页 > news >正文

STM32标准库-ADC数模转换器

文章目录

  • 一、ADC
    • 1.1简介
    • 1. 2逐次逼近型ADC
    • 1.3ADC框图
    • 1.4ADC基本结构
      • 1.4.1 信号 “上车点”:输入模块(GPIO、温度、V_REFINT)
      • 1.4.2 信号 “调度站”:多路开关
      • 1.4.3 信号 “加工厂”:ADC 转换器(规则组 + 注入组)
      • 1.4.4信号 “暂存柜”:AD 数据寄存器
      • 1.4.5 信号 “监督员”:模拟看门狗
      • 1.4.6信号 “报警器”:中断输出控制 + NVIC
      • 1.4.7 系统 “动力源”:触发控制 + RCC
      • 1.4.8系统 “总开关”:开关控制
    • 1.5输入通道
    • 1.6转换模式
    • 1.7触发控制
    • 1.8数据对齐
    • 1.9转换时间
    • 1.10校准
    • 1.11硬件电路
  • 二、AD单通道
    • 2.1接线图
    • 2.2代码
    • 2.3ADC 相关 API 函数
        • 1. 时钟配置函数
        • 2. GPIO 配置函数
        • 3. ADC 配置函数
        • 4. ADC 控制函数
        • 5. 状态和数据读取函数
    • 2.4工作现象
  • 三、AD多通道
    • 3.1接线图
    • 3.2代码
    • 3.3AD单通道未提及的关键 API
        • 1. ADC 通道配置函数
        • 2. 采样时间说明
        • 3. ADC 状态标志位
    • 3.4工作现象
        • 1. **光敏传感器(AO 接 ADC 通道,如 PA0)**
        • 2. **声音传感器(AO 接 ADC 通道,如 PA1)**
        • 3. **红外避障传感器(AO 接 ADC 通道,如 PA2)**
        • 4. **电位器(中间引脚接 ADC 通道,如 PA3)**

一、ADC

1.1简介

在这里插入图片描述

1. 2逐次逼近型ADC

在这里插入图片描述

1.3ADC框图

在这里插入图片描述

1.4ADC基本结构

在这里插入图片描述
以下用更通俗的 “信号 journey(旅程)” 逻辑,拆解各模块咋连接、咋配合干活:

1.4.1 信号 “上车点”:输入模块(GPIO、温度、V_REFINT)

  • GPIO(16 路):像 16 个 “小天线”,能接外部五花八门的模拟信号(比如传感器电压、旋钮调节的电平 ),是最常用的信号入口。
  • 温度传感器:专门测温度,把温度变化转成电压信号,相当于 “温度→电信号” 翻译器。
  • V_REFINT:内部精准参考电压,像 “标准尺”,给 ADC 转换当基准(比如转换时拿信号和它比,确定数字值 )。

这些信号要先 “排队上车”,统一交给 多路开关(下面讲它的作用 )。

1.4.2 信号 “调度站”:多路开关

  • 作用:当 “交通调度员”,决定让哪路信号进 ADC 转换器。
  • 逻辑:比如同时有 GPIO、温度传感器的信号,它选 1 路(规则组模式)或几路(注入组模式 ),送往后边的 ADC 转换器。

1.4.3 信号 “加工厂”:ADC 转换器(规则组 + 注入组)

  • 规则组(最多 16 路):常规 “生产线”,按预设顺序、节奏转换信号(比如循环采集 16 路 GPIO ),适合普通、批量的转换需求。
  • 注入组(最多 4 路):“加急生产线”,优先级更高!遇到紧急信号(比如关键传感器超阈值 ),能插队先转换,灵活处理特殊需求。

不管规则组还是注入组,干的事一样:把模拟信号(连续电压 )切成数字信号(0 和 1 组成的编码 )。

1.4.4信号 “暂存柜”:AD 数据寄存器

  • 转换完的数字信号,得找地方 “临时存一下”:
    • 规则组结果:存在 “规则结果 ×1” 里(1 组数据对应 1 个寄存器 )。
    • 注入组结果:存在 “注入结果 ×4” 里(最多存 4 组,方便快速连续处理 )。
  • 就像工厂生产完零件,先放仓库,等 CPU 来 “取货” 处理。

1.4.5 信号 “监督员”:模拟看门狗

  • 作用:当 “质量检测员”,盯着转换后的数字信号,看是否超出你设定的范围(比如温度不能太高 / 太低 )。
  • 触发:一旦超范围,立马发信号(相当于 “报警” ),告诉系统 “这信号有问题!”

1.4.6信号 “报警器”:中断输出控制 + NVIC

  • 中断输出控制:收到模拟看门狗的 “报警” 后,整理信号,决定咋通知系统。
  • NVIC(嵌套向量中断控制器):系统的 “总调度台”,收到中断信号后,暂停当前任务,优先处理 “信号异常” 事件(比如触发紧急程序、记录日志 )。

1.4.7 系统 “动力源”:触发控制 + RCC

  • RCC(时钟控制器):给 ADC 整个系统提供 “心跳”(时钟信号 ),所有模块得跟着时钟节奏干活,否则会乱套。
  • 触发控制:决定啥时候启动 ADC 转换,像 “开关”:可以软件手动触发(程序里写代码启动 ),也能硬件触发(比如定时器定时启动 ),发的信号叫 “START”。

1.4.8系统 “总开关”:开关控制

  • 简单粗暴:控制 ADC 模块整体 “开 / 关”。不用 ADC 时,关掉省点电;要用时,打开干活。

1.5输入通道

在这里插入图片描述

1.6转换模式

在这里插入图片描述

1.7触发控制

在这里插入图片描述

1.8数据对齐

在这里插入图片描述

1.9转换时间

在这里插入图片描述

1.10校准

在这里插入图片描述

1.11硬件电路

在这里插入图片描述

二、AD单通道

2.1接线图

在这里插入图片描述

2.2代码

main.c

#include "stm32f10x.h"                  // Device header
#include "Delay.h"
#include "OLED.h"
#include "AD.h"uint16_t ADValue;			//定义AD值变量
float Voltage;				//定义电压变量int main(void)
{/*模块初始化*/OLED_Init();			//OLED初始化AD_Init();				//AD初始化/*显示静态字符串*/OLED_ShowString(1, 1, "ADValue:");OLED_ShowString(2, 1, "Voltage:0.00V");while (1){ADValue = AD_GetValue();					//获取AD转换的值Voltage = (float)ADValue / 4095 * 3.3;		//将AD值线性变换到0~3.3的范围,表示电压OLED_ShowNum(1, 9, ADValue, 4);				//显示AD值OLED_ShowNum(2, 9, Voltage, 1);				//显示电压值的整数部分OLED_ShowNum(2, 11, (uint16_t)(Voltage * 100) % 100, 2);	//显示电压值的小数部分Delay_ms(100);			//延时100ms,手动增加一些转换的间隔时间}
}

AD.c

#include "stm32f10x.h"                  // Device header/*** 函    数:AD初始化* 参    数:无* 返 回 值:无*/
void AD_Init(void)
{/*开启时钟*/RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);	//开启ADC1的时钟RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);	//开启GPIOA的时钟/*设置ADC时钟*/RCC_ADCCLKConfig(RCC_PCLK2_Div6);						//选择时钟6分频,ADCCLK = 72MHz / 6 = 12MHz/*GPIO初始化*/GPIO_InitTypeDef GPIO_InitStructure;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOA, &GPIO_InitStructure);					//将PA0引脚初始化为模拟输入/*规则组通道配置*/ADC_RegularChannelConfig(ADC1, ADC_Channel_0, 1, ADC_SampleTime_55Cycles5);		//规则组序列1的位置,配置为通道0/*ADC初始化*/ADC_InitTypeDef ADC_InitStructure;						//定义结构体变量ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;		//模式,选择独立模式,即单独使用ADC1ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;	//数据对齐,选择右对齐ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;	//外部触发,使用软件触发,不需要外部触发ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;		//连续转换,失能,每转换一次规则组序列后停止ADC_InitStructure.ADC_ScanConvMode = DISABLE;			//扫描模式,失能,只转换规则组的序列1这一个位置ADC_InitStructure.ADC_NbrOfChannel = 1;					//通道数,为1,仅在扫描模式下,才需要指定大于1的数,在非扫描模式下,只能是1ADC_Init(ADC1, &ADC_InitStructure);						//将结构体变量交给ADC_Init,配置ADC1/*ADC使能*/ADC_Cmd(ADC1, ENABLE);									//使能ADC1,ADC开始运行/*ADC校准*/ADC_ResetCalibration(ADC1);								//固定流程,内部有电路会自动执行校准while (ADC_GetResetCalibrationStatus(ADC1) == SET);ADC_StartCalibration(ADC1);while (ADC_GetCalibrationStatus(ADC1) == SET);
}/*** 函    数:获取AD转换的值* 参    数:无* 返 回 值:AD转换的值,范围:0~4095*/
uint16_t AD_GetValue(void)
{ADC_SoftwareStartConvCmd(ADC1, ENABLE);					//软件触发AD转换一次while (ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC) == RESET);	//等待EOC标志位,即等待AD转换结束return ADC_GetConversionValue(ADC1);					//读数据寄存器,得到AD转换的结果
}

2.3ADC 相关 API 函数

1. 时钟配置函数

c

运行

void RCC_APB2PeriphClockCmd(uint32_t RCC_APB2Periph, FunctionalState NewState);
  • 功能:启用或禁用 APB2 总线上的外设时钟(如 ADC1、GPIOA)。

  • 参数 :

    • RCC_APB2Periph:外设选择(如RCC_APB2Periph_ADC1RCC_APB2Periph_GPIOA)。
    • NewStateENABLEDISABLE

c

运行

void RCC_ADCCLKConfig(uint32_t RCC_PCLK2);
  • 功能:配置 ADC 时钟分频(ADC 时钟必须 ≤ 14MHz)。

  • 参数 :

    • RCC_PCLK2:分频选项(如RCC_PCLK2_Div6表示 72MHz/6=12MHz)。
2. GPIO 配置函数

c

运行

void GPIO_Init(GPIO_TypeDef* GPIOx, GPIO_InitTypeDef* GPIO_InitStruct);
  • 功能:初始化 GPIO 引脚。

  • 参数 :

    • GPIOx:GPIO 端口(如GPIOA)。
    • GPIO_InitStruct:GPIO 配置结构体(模式、引脚、速度)。
3. ADC 配置函数

c

运行

void ADC_RegularChannelConfig(ADC_TypeDef* ADCx, uint8_t ADC_Channel, uint8_t Rank, uint8_t ADC_SampleTime);
  • 功能:配置规则组通道的转换顺序和采样时间。

  • 参数 :

    • ADCx:ADC 外设(如ADC1)。
    • ADC_Channel:通道号(如ADC_Channel_0对应 PA0)。
    • Rank:序列位置(1~16)。
    • ADC_SampleTime:采样周期(如ADC_SampleTime_55Cycles5)。

c

运行

void ADC_Init(ADC_TypeDef* ADCx, ADC_InitTypeDef* ADC_InitStruct);
  • 功能:初始化 ADC 参数。

  • 参数 :

    • ADCx:ADC 外设。
    • ADC_InitStruct:ADC 配置结构体(模式、对齐方式、触发方式等)。
4. ADC 控制函数

c

运行

void ADC_Cmd(ADC_TypeDef* ADCx, FunctionalState NewState);
  • 功能:启用或禁用 ADC。

  • 参数 :

    • ADCx:ADC 外设。
    • NewStateENABLEDISABLE

c

运行

void ADC_SoftwareStartConvCmd(ADC_TypeDef* ADCx, FunctionalState NewState);
  • 功能:软件触发 ADC 转换。

  • 参数 :

    • ADCx:ADC 外设。
    • NewStateENABLE触发一次转换。

c

运行

void ADC_ResetCalibration(ADC_TypeDef* ADCx);
FlagStatus ADC_GetResetCalibrationStatus(ADC_TypeDef* ADCx);
void ADC_StartCalibration(ADC_TypeDef* ADCx);
FlagStatus ADC_GetCalibrationStatus(ADC_TypeDef* ADCx);
  • 功能:ADC 校准流程(复位校准、获取复位状态、开始校准、获取校准状态)。
5. 状态和数据读取函数

c

运行

FlagStatus ADC_GetFlagStatus(ADC_TypeDef* ADCx, uint8_t ADC_FLAG);
  • 功能:检查 ADC 标志位状态(如转换完成标志ADC_FLAG_EOC)。

  • 参数 :

    • ADCx:ADC 外设。
    • ADC_FLAG:标志位类型。

c

运行

uint16_t ADC_GetConversionValue(ADC_TypeDef* ADCx);
  • 功能:获取 ADC 转换结果(0~4095,12 位分辨率)。

  • 参数 :

    • ADCx:ADC 外设。
      AD.h
#ifndef __AD_H
#define __AD_Hvoid AD_Init(void);
uint16_t AD_GetValue(void);#endif

2.4工作现象

  1. 初始化阶段
    • 调用AD_Init()后,ADC1 时钟开启,GPIOA 引脚配置为模拟输入模式,规则组通道 0(PA0)完成配置,ADC 进入就绪状态。
    • 校准过程中,ADC_ResetCalibrationADC_StartCalibration会触发内部校准电路工作,校准完成后标志位自动清除。
  2. 转换阶段
    • 调用AD_GetValue()时,软件触发转换(ADC_SoftwareStartConvCmd),ADC_FLAG_EOC标志位在转换完成后置 1,返回值在 0~4095 范围内(对应输入电压 0~3.3V)。
    • 若输入电压稳定(如接固定电阻分压),多次读取的 ADC 值波动较小(通常≤±3LSB)。
  3. 数据对应关系

在这里插入图片描述

三、AD多通道

3.1接线图

在这里插入图片描述

3.2代码

main.c

#include "stm32f10x.h"                  // Device header
#include "Delay.h"
#include "OLED.h"
#include "AD.h"uint16_t AD0, AD1, AD2, AD3;	//定义AD值变量int main(void)
{/*模块初始化*/OLED_Init();				//OLED初始化AD_Init();					//AD初始化/*显示静态字符串*/OLED_ShowString(1, 1, "AD0:");OLED_ShowString(2, 1, "AD1:");OLED_ShowString(3, 1, "AD2:");OLED_ShowString(4, 1, "AD3:");while (1){AD0 = AD_GetValue(ADC_Channel_0);		//单次启动ADC,转换通道0AD1 = AD_GetValue(ADC_Channel_1);		//单次启动ADC,转换通道1AD2 = AD_GetValue(ADC_Channel_2);		//单次启动ADC,转换通道2AD3 = AD_GetValue(ADC_Channel_3);		//单次启动ADC,转换通道3OLED_ShowNum(1, 5, AD0, 4);				//显示通道0的转换结果AD0OLED_ShowNum(2, 5, AD1, 4);				//显示通道1的转换结果AD1OLED_ShowNum(3, 5, AD2, 4);				//显示通道2的转换结果AD2OLED_ShowNum(4, 5, AD3, 4);				//显示通道3的转换结果AD3Delay_ms(100);			//延时100ms,手动增加一些转换的间隔时间}
}

AD.c

#include "stm32f10x.h"                  // Device header/*** 函    数:AD初始化* 参    数:无* 返 回 值:无*/
void AD_Init(void)
{/*开启时钟*/RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);	//开启ADC1的时钟RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);	//开启GPIOA的时钟/*设置ADC时钟*/RCC_ADCCLKConfig(RCC_PCLK2_Div6);						//选择时钟6分频,ADCCLK = 72MHz / 6 = 12MHz/*GPIO初始化*/GPIO_InitTypeDef GPIO_InitStructure;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_2 | GPIO_Pin_3;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOA, &GPIO_InitStructure);					//将PA0、PA1、PA2和PA3引脚初始化为模拟输入/*不在此处配置规则组序列,而是在每次AD转换前配置,这样可以灵活更改AD转换的通道*//*ADC初始化*/ADC_InitTypeDef ADC_InitStructure;						//定义结构体变量ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;		//模式,选择独立模式,即单独使用ADC1ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;	//数据对齐,选择右对齐ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;	//外部触发,使用软件触发,不需要外部触发ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;		//连续转换,失能,每转换一次规则组序列后停止ADC_InitStructure.ADC_ScanConvMode = DISABLE;			//扫描模式,失能,只转换规则组的序列1这一个位置ADC_InitStructure.ADC_NbrOfChannel = 1;					//通道数,为1,仅在扫描模式下,才需要指定大于1的数,在非扫描模式下,只能是1ADC_Init(ADC1, &ADC_InitStructure);						//将结构体变量交给ADC_Init,配置ADC1/*ADC使能*/ADC_Cmd(ADC1, ENABLE);									//使能ADC1,ADC开始运行/*ADC校准*/ADC_ResetCalibration(ADC1);								//固定流程,内部有电路会自动执行校准while (ADC_GetResetCalibrationStatus(ADC1) == SET);ADC_StartCalibration(ADC1);while (ADC_GetCalibrationStatus(ADC1) == SET);
}/*** 函    数:获取AD转换的值* 参    数:ADC_Channel 指定AD转换的通道,范围:ADC_Channel_x,其中x可以是0/1/2/3* 返 回 值:AD转换的值,范围:0~4095*/
uint16_t AD_GetValue(uint8_t ADC_Channel)
{ADC_RegularChannelConfig(ADC1, ADC_Channel, 1, ADC_SampleTime_55Cycles5);	//在每次转换前,根据函数形参灵活更改规则组的通道1ADC_SoftwareStartConvCmd(ADC1, ENABLE);					//软件触发AD转换一次while (ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC) == RESET);	//等待EOC标志位,即等待AD转换结束return ADC_GetConversionValue(ADC1);					//读数据寄存器,得到AD转换的结果
}

AD.h

#ifndef __AD_H
#define __AD_Hvoid AD_Init(void);
uint16_t AD_GetValue(uint8_t ADC_Channel);#endif

3.3AD单通道未提及的关键 API

除了之前提到的 ADC API,这段代码还涉及以下未详细说明的函数:

1. ADC 通道配置函数

c

运行

void ADC_RegularChannelConfig(ADC_TypeDef* ADCx, uint8_t ADC_Channel, uint8_t Rank, uint8_t ADC_SampleTime);
  • 功能:配置规则组序列中的通道及其采样时间。

  • 参数 :

    • ADC_Channel:通道号(如ADC_Channel_0~ADC_Channel_17)。
    • Rank:序列位置(1~16,单通道模式下固定为 1)。
    • ADC_SampleTime:采样周期(如ADC_SampleTime_55Cycles5)。
2. 采样时间说明

ADC 采样时间影响转换精度和速度,可选值包括:

c

运行

ADC_SampleTime_1Cycles5   // 1.5个ADC时钟周期(最快)
ADC_SampleTime_7Cycles5   // 7.5个周期
ADC_SampleTime_13Cycles5  // 13.5个周期
ADC_SampleTime_28Cycles5  // 28.5个周期
ADC_SampleTime_41Cycles5  // 41.5个周期
ADC_SampleTime_55Cycles5  // 55.5个周期
ADC_SampleTime_71Cycles5  // 71.5个周期
ADC_SampleTime_239Cycles5 // 239.5个周期(最慢,抗干扰最强)
3. ADC 状态标志位

c

运行

FlagStatus ADC_GetFlagStatus(ADC_TypeDef* ADCx, uint8_t ADC_FLAG);
  • 常用标志位 :

    • ADC_FLAG_EOC:规则组转换完成标志(代码中使用)。
    • ADC_FLAG_AWD:模拟看门狗触发标志(需额外配置)。
    • ADC_FLAG_OVR:数据溢出标志(连续转换模式下可能出现)。

3.4工作现象

  • 初始化后:ADC1 和 GPIOA 时钟开启,PA0~PA3 配置为模拟输入模式,ADC 处于就绪状态但未开始转换(需调用AD_GetValue()触发)。

  • 动态通道选择:每次调用AD_GetValue(channel)时,会临时配置规则组序列 1 为指定通道(如ADC_Channel_2对应 PA2),然后触发单次转换。

  • 转换结果

    :返回值范围为 0~4095,对应输入电压 0~3.3V(假设 VREF 为 3.3V)。例如:

    • 输入 1.65V → 返回值约为 2048(1.65V/3.3V × 4095 ≈ 2048)。
    • 输入悬空(无信号)→ 返回随机值(受噪声影响)。
1. 光敏传感器(AO 接 ADC 通道,如 PA0)
  • 现象 :

    • 光照越强(如手电筒照射),ADC 值 越大(对应电压越高,假设传感器输出与光照正相关);
    • 光照越弱(手遮挡),ADC 值 越小,OLED / 串口数据同步变化。
  • 原理:光敏电阻阻值随光照变化,转换为电压信号被 ADC 采集。

2. 声音传感器(AO 接 ADC 通道,如 PA1)
  • 现象 :

    • 安静时,ADC 值 稳定在低范围(背景噪声小);
    • 拍手 / 说话时,ADC 值 瞬间跳升(声音越强,跳升幅度越大),数据波动明显。
  • 原理:咪头采集声波,转换为电压波动,ADC 捕捉瞬时变化。

3. 红外避障传感器(AO 接 ADC 通道,如 PA2)
  • 现象 :

    • 无遮挡时,ADC 值 接近最大值(红外反射强,输出电压高);
    • 手靠近遮挡时,ADC 值 骤降(反射弱,电压低),响应迅速。
  • 原理:红外发射 + 接收,距离 / 遮挡影响反射强度,转换为电压变化。

4. 电位器(中间引脚接 ADC 通道,如 PA3)
  • 现象 :

    • 顺时针旋转:ADC 值 从 0→4095 线性递增(或递减,取决于接线方向);
    • 逆时针旋转:ADC 值 反向递减 / 递增,变化平滑无跳变。
  • 原理:电位器分压,输出电压与旋转角度线性相关。

相关文章:

  • 基于ffmpeg+sdl的audio player
  • 模型重展UV后绘制纹理
  • [Java 基础]String 类
  • Java NIO详解:新手完全指南
  • 【技巧】dify前端源代码修改第一弹-增加tab页
  • python打卡day49@浙大疏锦行
  • 逻辑回归暴力训练预测金融欺诈
  • 电路图识图基础知识-远程/本地启停电动机(二十一)
  • 记录一篇HTTPS的文章
  • 如何让hustoj支持Java判题
  • 开放词汇检测分割YOLOE从pytorch到caffe
  • Spring状态机
  • Docker简述
  • React Hooks 的原理、常用函数及用途详解
  • Python打卡训练营学习记录Day49
  • 【Elasticsearch】Elasticsearch 在大数据生态圈的地位 实践经验
  • 2025年渗透测试面试题总结-小鹏[社招]车联网工程师(题目+回答)
  • 云南净餐馆备考单选题及答案
  • Ⅳ.计算机二级选择题(函数)
  • 前端开发面试题总结-vue2框架篇(一)
  • 网页设计企业网站设计的功能/怎样做电商 入手
  • 搜索引擎搜索/黄冈网站推广优化找哪家
  • 嘉兴网站推广/百度seo培训班
  • 郑州做网站要/免费网站制作
  • 力杨网站建设/seo建设招商
  • 武汉哪些网站做免费广告/浏览器网站进入口