STM32F4_模数转换器(ADC)详解

  • Post author:
  • Post category:其他



目录


1. ADC是什么


2. ADC主要特性


3. ADC框图


3.1 ADC开关控制


3.2 ADC时钟


3.3 通道选择


3.4 单次转换模式和连续转换模式


3.5 时序图


3.6 模拟看门狗


4 温度传感器


5. ADC中断


6. ADC初始化结构体


6.1 ADC相关实验配置


7. 相关寄存器


7.1 ADC控制寄存器:ADC_CR1和ADC_CR2


7.2 ADC通用控制寄存器:ADC_CCR


7.3 ADC采样时间寄存器:ADC_SMPR1和ADC_SMPR2


7.4 ADC规则序列寄存器:ADC_SQRx(x取值1~3)


7.5 ADC规则数据寄存器:ADC_DR


7.6 ADC状态寄存器:ADC_SR


8. 库函数配置ADC1的通道5进行AD转换


9. 实验程序


9.1 main.c


9.2 ADC.c


9.3 ADC.h


首先明确,这里提到的ADC不是我们游戏中的ADC,这里提及的ADC是STM32的一种重要外设功能,ADC英文全程:Analog to Digital,又叫做模拟数字转换器。



1. ADC是什么


在高中的物理中,我们学习过电压表、电流表和万用表的使用,这些器件可以用来测量电路中的分路电流、电压值;强大的STM32单片机中也存在着这样的外设,称作模数转换器ADC;

很好理解,模数转换器就是把模拟量转换成数字量;数字对于我们来说是很亲切的,之所以存在这样的外设,也是为了更方便于使用者的理解和操作。

模拟量就如电压值、光敏电阻阻值、热敏电阻阻值等,通过该转换器可以转换为我们肉眼可见的数字。

STM32F4的ADC是12位逐次趋近型模数转换器。具有多达19个复用通道,可测量来自16个外部源、两个内部源通道的信号。

ADC的结果存储在一个左对齐或者右对齐的16位数据寄存器中。

ADC具有模拟看门狗特性,允许应用检测输入电压是否超过了用户自定义的阈值上限或者下限。

STM32F4xx系列一般都有3个ADC,这些ADC可以独立使用,也可以使用双重/三重模样,来提高采样率。STM32F4的ADC是12位逐次逼近型的模拟数字转换器,它有19个通道,可以测16个外部源、2个内部源和Vbat通道的信号。STM32F4的ADC最大的转换速率为2.4Mhz,也就是转换时间为0.41us。



2. ADC主要特性


  • 可配置12位、10位、8位或6位分辨率
  • 在转换结束、注入转换结束以及发生模拟看门狗或溢出事件时产生中断
  • 单次和连续转换模式
  • 用于自动将通道0转换为通道“n”的扫描模式
  • 数据对齐以保持内置数据一致性
  • 可独立设置各通道采样时间
  • 外部触发器选项,可为规则转换和注入转换配置极性
  • ADC电源要求:全速运行时2.4V到3.6V,慢速运行时1.8V



3. ADC框图


1.

电压输入范围

V_{REF+}
表示正模拟参考电压输入,代表ADC高/正参考电压;

V_{DDA}
表示模拟电源输入,代表模拟电源电压等于
V_{DD}

V_{REF-}
表示负模拟参考电压输入,代表ADC低/负参考电压;

V_{SSA}
表示模拟电源接地输入,代表模拟电源接地电压等于
V_{SS}


输入电压:

V_{REF-}
<= VIN <=
V_{REF+}

V_{SSA}

V_{REF-}
接地,把
V_{DDA}

V_{REF+}
接3V3,表示得到ADC的输入电压范围为0-3.3V;

STM32的ADC只能测0-3.3V的电压,如果超过了这个范围,只能在单片机上改变电压的范围(通过相应芯片的转电平作用),以保证能够被STM32的GPIO口识别。

2.

输入通道:

STM32的每个ADC都具有18个通道,其中外部通道16个:


STM32的ADC有16条复用通道。外部16个通道在转换的过程中又分为

规则通道



注入通道


可以将转换分为两组:

规则转换



注入转换

。每个组包含一个转换序列,该序列可按任意顺序在任意通道上完成。

其中

规则通道

由规则序列寄存器ADC_SQRx(x可以取值为1 2 3)来配置,

注入通道

由注入序列寄存器ADC_JSQR来配置。

一个

规则转换组

最多由16个转换构成。必须在ADC_SQRx寄存器中选择转换序列的规则通道及其顺序。规则转换组中的转换总数必须写入ADC_SQRx寄存器中的L[3:0]位。

一个

注入转换组

最多由4个转换构成。必须在ADC_JSQR寄存器中选择转换序列的注入通道及其顺序。注入转换组中的转换总数必须写入ADC_JSQR寄存器中的L[1:0]位。



顾名思义,两个通道的区别就是


:规则通道就是很规矩的意思,我们一般使用的就是这个规则通道。注入可以理解为插入、插队的意思,是一种不安分的通道,有点类似于中断程序;


注入通道只有在规则通道存在时才会出现。


3.  转换顺序:


输入通道



注入通道

的转换顺序分别由规则序列寄存器ADC_SQRx(x可以取值为1 2 3)和注入序列寄存器ADC_JSQR来配置。


4. 触发源:


触发源

相当于一个信号,用来告诉ADC可以开始转换了。


触发方式

又分为

软件触发



外部事件触发(内部定时器/外部IO)

。分别对应于上图中的左侧TIM和右侧TIM。


5. 转换时间:


转换时间

:Tconv=采样时间+12个周期


采样时间

:ADC需要若干个ADC_CLK周期完成对输入的模拟量进行采样,采样的周期数可通过ADC采样时间寄存器ADC_SMPR1和ADC_SMPR2的SMPx[2:0]位设置,ADC_SMPR2控制的是通道0~9,ADC_SMPR1控制的是通道10~17。每个通道可以分别用不同的时间采样。其中采样周期最小是1.5个,也就是说,我们要达到最快的采样,那么应该设置采样周期为31.5个周期,这里的周期就是1/ADC_CLK。


ADC_CLK

:ADC模拟电路时钟,最大值为14M,由PCLK2提供,还可以进行分频,2/4/6/8,RCC_CFGR的ADCPRE[1:0]设置。PCLK2=72M。


数字时钟

:RCC_APB2ENR,用于访问寄存器。


ag. 最短的转换时间

:Tconv=采样时间+12个周期 (其中PCLK2=72M,ADC_CLK=72/6=12M ,Tconv=1.5+12.5=14=14/12us=1.17us)


6. 数据寄存器:

一切准备就绪后,ADC转换后的数据根据转换组不同,规则组的数据存放在ADC_DR寄存器中,注入组的数据放在JDRx寄存器中。


数据寄存器ADC_DR(ADC regular data register)

位31:16  保留,必须保持复位值

位15:0

DATA[15:0]

:规则数据(Regular data) 这些位为只读。它们包括来自规则通道的转换结果。



该寄存器的1~16位有效,用于存放独立模式转换完成数据。当在双ADC模式(ADC1和ADC2同时使用)下,ADC1放在低16位上,ADC2放在高16位上。


7. 中断:

STM32F4相比于F1增加了DMA溢出标志。由模拟看门狗来检测采样的模拟量信号值的下限和上限。


电压转换:

所谓电压转换就是如何根据数字量去算出模拟量?  也可以说是外部电压假设是2.5V,通过ADC转换成数字量,也就是数字,存放在数据寄存器ADC_DR中,电压转换就是通过数据寄存器中的数字去反推出外部电压。

1. 电压输入范围为:0~3.3V

2. 分辨率为12位

3. 最小精度为:3.3/2^12

4. 设数字量为x,则有模拟量Y=(3.3/2^12)* x



3.1 ADC开关控制


可以通过将ADC控制寄存器ADC_CR2寄存器中的ADON位置1来为ADC供电。首次将ADON位置1时,会将ADC从掉电模式中唤醒。

SWSTART或JSWSTART位置1,启动AD转换。

可通过将ADON位清零来停止转换并使ADC进入掉电模式,在此模式下,ADC几乎不耗电,也可以说进入了低功耗模式。



3.2 ADC时钟



用于模拟电路的时钟

:ADCCLK,所有ADC共用

此时钟来自于经可编程预分频器分频的APB2时钟,该预分频器允许ADC在
f_{PCLK2}/2
、/4、/6或/8下工作。


用于数字接口的时钟

:(用于寄存器读/写访问)

此时钟等效于APB2时钟。可以通过RCC APB2外设时钟使能寄存器(RCC_APB2ENR)分别为每个ADC使能/禁止数字接口时钟。



3.3 通道选择



STM32的ADC有16条复用通道。外部16个通道在转换的过程中又分为

规则通道



注入通道


可以将转换分为两组:

规则转换



注入转换

。每个组包含一个转换序列,该序列可按任意顺序在任意通道上完成。

一个

规则转换组

最多由16个转换构成。必须在ADC_SQRx寄存器中选择转换序列的规则通道及其顺序。规则转换组中的转换总数必须写入ADC_SQRx寄存器中的L[3:0]位。

一个

注入转换组

最多由4个转换构成。必须在ADC_JSQR寄存器中选择转换序列的注入通道及其顺序。注入转换组中的转换总数必须写入ADC_JSQR寄存器中的L[1:0]位。



顾名思义,两个通道的区别就是


:规则通道就是很规矩的意思,我们一般使用的就是这个规则通道。注入可以理解为插入、插队的意思,是一种不安分的通道,有点类似于中断程序;


注入通道只有在规则通道存在时才会出现。因为注入通道相当于中断,那么当程序正常执行的时候,中断是可以打断你的执行的。因此注入通道的转换可以打断规则通道的转换,在注入通道被转换完成之后,规则通道才得以继续转换。

如果在转换期间修改 ADC_SQRx 或 ADC_JSQR 寄存器,将复位当前转换并向 ADC 发送一 个新的启动脉冲,以转换新选择的组。


温度传感器、
V_{REFINT}
内部通道

对于STM32F40x系列的开发板,温度传感器内部连接到ADC1_IN16。内部参考电压

V_{REFINT}

连接到ADC1_IN17。



注意


: 温度传感器、

V_{REFINT}

只在主ADC1外设上可用。



3.4 单次转换模式和连续转换模式




单次转换模式

下,ADC执行一次转换。CONT位为0时,可以通过以下三种方式启动此模式:

  • 将ADC_CR2寄存器中的SWSTART位置1(仅适用于规则通道)
  • 将JSWSTART位置1(适用于注入通道)
  • 外部触发(适用于规则通道和注入通道)

如果转化了规则通道:

  • 转换数据存储在16位ADC_DR寄存器中
  • EOC(转换结束)标志位置1
  • EOCIE位置1时将产生中断

如果转换了注入通道:

  • 转换数据存储在16位ADC_JCR1寄存器中
  • JEOC(注入转换结束)标志置1
  • JEOCIE位置1时将产生中断



连续转换模式

下,ADC结束一个转换后立即启动一个新的转换。CONT位为1时,可通过外部触发或将ADC_CR2寄存器中的SWSTRT位置1来启动该模式(仅适用于规则通道)

如果转换了规则通道组:

  • 上次转换的数据存储在16位ADC_DR寄存器中
  • EOC(转换结束)标志置1
  • EOCIE位置1时将产生中断

STM32F4的ADC在单次转换模式下,只执行一次转换,该模式可通过ADC_CR2寄存器的ADON位(只适用于规则通道)启动,也可以通过外部触发启动(适用于规则通道和注入通道),这时CONT位为0。

以规则通道为例,一旦所选择的通道转换完成,转换结果将被存储在ADC_DR寄存器中,EOC(转化结束)标志将被置位,如果设置了EOCIE,则会产生中断。然后ADC将停止,直到下次启动。



3.5 时序图


在时序图中, ADC_CLK表示ADC的时钟;ADON是ADC控制寄存器中的最低位,将该位置1表示开启寄存器;SWSTART/JSWSTART用来设置转换模式;

ADC在开始精确转换之前需要一段稳定时间
t_{STAB}
。ADC开始转换并经过15个时钟周期后,EOC标志置1,转换结果存放在16位ADC数据寄存器中。



3.6 模拟看门狗


如果ADC转换的模拟电压低于阈值下限或者高于阈值上限,则AWR模拟看门狗状态位会置1。这些阈值在ADC_HTR或ADC_LTR 16位寄存器的12个最低有效位中进行编程。可以使用ADC_CR1寄存器中的AWDIE位使能中断。



4 温度传感器


我们都很清楚传感器的用处,那么显然温度传感器就是用来测量器件的环境温度(
T_{A}
)的。

对应STM32F40x系列的开发板器件(其他的型号开发板对应不同的ADC通道),温度传感器内部连接到ADC1_IN16通道,而ADC1用于将传感器输出电压转换为数字值。


不使用时可以将传感器置于掉电模式。



注意


:必须将TSVREFE位置1才能同时对两个通道进行转换。ADC1_IN16(温度传感器)和ADC1_IN17(VREFINT)。


主要特性

  • 支持的温度范围(可以通过ADC转换成的数字范围):-40℃到125℃
  • 精度:
    \pm
    1.5℃


读取温度

  • 选择ADC1_IN16输入通道
  • 选择一个采样时间,该采样时间要大于数据手册上指定的最低采样时间
  • 在ADC_CCR寄存器中将TSVREFE位置1,以便将温度传感器从掉电模式中唤醒
  • 通过将SWSTART位置1开始ADC转换
  • 读取ADC数据寄存器中生成的
    V_{SENSE}
    数据


计算温度

温度(单位℃)={

V_{SENSE}

V_{25}
/Avg_Slope}+25

其中:
V_{25}
=25℃时的
V_{SENSE}
值          Avg_Slope=温度与
V_{SENSE}
曲线的平均斜率



注意


传感器从掉电模式中唤醒需要一个启动时间,启动时间过后其才能正确输出
V_{SENSE}
。ADC在上电后同样需要一个启动时间,因此,为尽可能减少延迟时间,应同时将ADON和TSVREFE位置1。

温度传感器的输出电压随温度线性变化。



5. ADC中断


当模拟看门狗状态位和溢出状态位分别置1时,规则组和注入组在转换结束时可能会产生中断。可以使用单独的中断使能位以实现灵活性。

ADC_SR寄存器中存在另外两个标志,但这两个标志不存在中断相关性:

  • JSTRT(开始转换注入组的通道)
  • STRT(开始转换规则组的通道)



6. ADC初始化结构体



ADC_InitTypeDef

typedef struct
{
  uint32_t ADC_Resolution;         //ADC分辨率                                        
  FunctionalState ADC_ScanConvMode;     //ADC扫描多通道或者ADC单通道模式选择  通过ADC_CR1的SCAN位来配置
  FunctionalState ADC_ContinuousConvMode;   //ADC单次转换或者连续转换选择 通过ADC_CR2的CON位来配置
  uint32_t ADC_ExternalTrigConvEdge;      //ADC转换触发信号范围选择
  uint32_t ADC_ExternalTrigConv;          //ADC外部触发转换模式选择  通过ADC_CR2的EXTTRIG和EXTSEL位来配置
  uint32_t ADC_DataAlign;                 //ADC数据寄存器对齐格式
  uint8_t  ADC_NbrOfConversion;           //ADC采集通道数
}ADC_InitTypeDef;

typedef struct 
{
  uint32_t ADC_Mode;              //ADC模式 通过ADC_CR1:DUALMOD位来配置                                                 
  uint32_t ADC_Prescaler;              //ADC预分频值                       
  uint32_t ADC_DMAAccessMode;           
  uint32_t ADC_TwoSamplingDelay;        //ADC多通道模式 
}ADC_CommonInitTypeDef;



6.1 ADC相关实验配置



1-独立模式-单通道-

中断读取

  • 初始化ADC用到的GPIO
  • 初始化ADC初始化结构体
  • 配置ADC时钟,配置通道的转换顺序和采样时间
  • 使能ADC转换完成中断,配置中断优先级
  • 使能ADC,准备开始转换
  • 校准ADC   ADC_StartCalibration      ADC_GetCalibrationStatus
  • 软件触发ADC,真正开始转换   ADC_SoftwareStartConvCmd
  • 编写中断服务函数,读取ADC转换数据
  • 编写main函数,把转换的数据打印出来


2-独立模式-单通道-

DMA读取


DMA是一种直接存储器,DMA是不占用CPU的,可以一边读取数据,一边处理数据。

  • 初始化ADC用到的GPIO
  • 初始化ADC初始化结构体
  • 配置ADC时钟,配置通道的转换顺序和采样时间
  • 使能ADC转换完成中断,配置中断优先级


3-独立模式-多通道-

DMA读取

  • 初始化ADC用到的GPIO
  • 初始化ADC初始化结构体
  • 配置ADC时钟,配置通道的转换顺序和采样时间
  • 使能ADC转换完成中断,配置中断优先级

配置过程相同,只不过初始化IO口时需要初始化多个IO口通道。并且调用函数


ADC_RegularChannelConfig(ADC1, ADC_Channel_5, 1, ADC_SampleTime_480Cycles );


获取多个通道执行多个功能即可。



7. 相关寄存器




7.1 ADC控制寄存器:ADC_CR1和ADC_CR2




ADC控制寄存器1:ADC_CR1(ADC control register 1)


SCAN位

:设置扫描模式位,通过软件将该位置1或者清零可以使能/禁止扫描模式。 在扫描模式下,转换由

规则序列寄存器ADC_SQRx



注入序列寄存器ADC_JSQRx

选中的通道被转换 。

0:禁止扫描模式

1:使能扫描模式

如果设置了EOCIE和JEOCIE,只在最后一个通道转换完毕后才会产生EOC和JEOC中断。


RES位[1:0]

:通过该位来设置分辨率(Resolution)

00:12位(15 ADCCLK周期)

01:10位(13 ADCCLK周期)

10:8位(11 ADCCLK周期)

11:6位(9 ADCCLK周期)



ADC控制寄存器2:ADC_CR2(ADC control register 2)


ADON位

:设置A/D转换器开启或者关闭

0:禁止ADC转换并转至掉电模式

1:使能ADC


CONT位

:该位用来设置连续转换模式或者单次转换模式

0:单次转换模式

1:连续转换模式


ALIGN位

:该位用来设置数据是左对齐还是右对齐

0:右对齐

1:左对齐


EXTEN位

:该位用来设置规则通道的外部触发是否使能

00:禁止触发检测

01:上升沿上的触发检测

10:下降沿上的触发检测

11:上升沿和下降沿上的触发检测


SWSTART位

:用于开始规则通道的转换,我们每次转换(单次转换模式下)都需要向该位写1

0:复位状态

1:开始转换规则通道



7.2 ADC通用控制寄存器:ADC_CCR




ADC通用控制寄存器:ADC_CCR(ADC common control register)


TSVREFE位

:温度传感器和
V_{REFINT}
使能位

0:禁止

1:使能


ADCPRE位

:ADC预分频器,该位由软件置1或者清0,以选择ADC的时钟频率。该时钟为所有ADC所共有。

00:PCLK2    2分频

01:PCLK2    4分频

10:PCLK2    6分频

11:PCLK2    8分频     STM32的ADC最大工作频率为36Mhz,而ADC时钟来自于APB2,APB2频率一般是84Mhz,所以一般的我们置ADCPRE=01,即4分频,这样得到ADCPRE频率为21Mhz。


MULTI位

:该位用来选择ADC的多重模式,本次实验我们使用的是独立模式,将该5位置0即可

  • 所有 ADC 均独立:
  • 00000:独立模式
  • 00001 到 01001:双重模式,ADC1 和 ADC2 一起工作,ADC3 独立
  • 00001:规则同时 + 注入同时组合模式
  • 00010:规则同时 + 交替触发组合模式
  • 00011:Reserved
  • 00101:仅注入同时模式
  • 00110:仅规则同时模式 仅交错模式
  • 01001:仅交替触发模式
  • 10001 到 11001:三重模式:ADC1、ADC2 和 ADC3 一起工作
  • 10001:规则同时 + 注入同时组合模式
  • 10010:规则同时 + 交替触发组合模式
  • 10011:Reserved
  • 10101:仅注入同时模式
  • 10110:仅规则同时模式 仅交错模式
  • 11001:仅交替触发模式



7.3 ADC采样时间寄存器:ADC_SMPR1和ADC_SMPR2




这两个寄存器用于设置通道0~18的采样时间,每个通道占用3个位



ADC采样时间寄存器:ADC_SMPR1(ADC sample time register 1)



ADC采样时间寄存器:ADC_SMPR2(ADC sample time register 2)


采样时间通俗的讲就是收集模拟量的时间,为了保证转换后的数字量更加精准,采样时间通常设置的尽量长一些。由此带来的负面影响会降低ADC的转换效率。


ADC转换时间计算:
T_{Conv}
=采样时间+12个周期



7.4 ADC规则序列寄存器:ADC_SQRx(x取值1~3)




ADC规则序列寄存器1:ADC_SQR1(ADC regular sequence register 1)


L位

:规则通道序列长度

0000:1次转换

0001:2次转换

……

1111:16次转换


SQx位

:分别对应规则序列中的第x次转换(x取值13 14 15 16)其余的1~12分别位于ADC规则序列寄存器2和3中



7.5 ADC规则数据寄存器:ADC_DR




ADC规则数据寄存器:ADC_DR(ADC regular data register)


DATA位

: 规则数据位,这些位为只读,它们包括来自规则通道的转换结果。



注意:ADC转换完成后的数字量会存储在该寄存器中,且该寄存器的存储值受ADC_CR2的ALIGN位设置的左对齐还是右对齐控制,所以在读取时需要特别注意。



7.6 ADC状态寄存器:ADC_SR




ADC状态寄存器:ADC_SR(ADC status register)


EOC位

: 通过该位来决定是否此次规则通道的AD转换已完成,如果该位为1,则表示转换已经完成了,这时就可以从ADC_DR中读取转换结果,否则等待转换完成。



8. 库函数配置ADC1的通道5进行AD转换




1. 开启PA口时钟和ADC1时钟,设置PA5为模拟输入

STM32F407ZG的ADC12通道IN5位于引脚PA5上,所以我们要使能GPIOA时钟和ADC1时钟。



RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);     //使能GPIOA时钟



RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);       //使能ADC1时钟



注意:对于IO口复用的ADC我们要设置模式为模拟输入,而不是复用功能。



GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AN;      //模拟输入



2. 设置ADC的通用控制寄存器CCR,配置ADC输入时钟分频,模式为独立模式

在库函数中, 初始化CCR寄存器是通过调用ADC_CommonInit来实现的;

typedef struct 
{
  uint32_t ADC_Mode;              //ADC模式 通过ADC_CR1:DUALMOD位来配置                                                 
  uint32_t ADC_Prescaler;              //ADC预分频值                       
  uint32_t ADC_DMAAccessMode;           //DMA模式禁止或者使能相应的DMA模式
  uint32_t ADC_TwoSamplingDelay;        //ADC两个采样阶段之间的延迟周期数
}ADC_CommonInitTypeDef;


第一个参数ADC_Mode:设置独立模式还是多重模式
第二个参数ADC_Prescaler:设置ADC预分频器,这里设置时一定保证ADC1的时钟频率不超过36MHz
第三个参数ADC_DMAAccessMode:DMA模式禁止或者使能相应的DMA模式
第四个参数ADC_TwoSamplingDelay:设置ADC两个采样阶段之间的延迟周期数



void ADC_CommonInit(ADC_CommonInitTypeDef* ADC_CommonInitStruct)



ADC_CommonInitStructure.ADC_Mode = ADC_Mode_Independent;     //独立模式



ADC_CommonInitStructure.ADC_Prescaler = ADC_Prescaler_Div4;    //ADC预分频值



ADC_CommonInitStructure.ADC_DMAAccessMode = ADC_DMAAccessMode_Disabled;   //ADC的DMA模式禁止或者使能相应DMA模式



ADC_CommonInitStructure.ADC_TwoSamplingDelay = ADC_TwoSamplingDelay_5Cycles;



3. 初始化ADC1参数,设置ADC1的转换分辨率,转换方式,对齐方式,以及规则序列等相关信息



void ADC_Init(ADC_TypeDef* ADCx, ADC_InitTypeDef* ADC_InitStruct)  //初始化ADC函数

typedef struct
{
  uint32_t ADC_Resolution;         //ADC分辨率                                        
  FunctionalState ADC_ScanConvMode;     //ADC扫描多通道或者ADC单通道模式选择  通过ADC_CR1的SCAN位来配置
  FunctionalState ADC_ContinuousConvMode;   //ADC单次转换或者连续转换选择 通过ADC_CR2的CON位来配置
  uint32_t ADC_ExternalTrigConvEdge;      //ADC转换触发信号范围选择
  uint32_t ADC_ExternalTrigConv;          //ADC外部触发转换模式选择  通过ADC_CR2的EXTTRIG和EXTSEL位来配置
  uint32_t ADC_DataAlign;                 //ADC数据寄存器对齐格式
  uint8_t  ADC_NbrOfConversion;           //ADC采集通道数
}ADC_InitTypeDef;

第一个参数ADC_Resolution:设置ADC转换分辨率
第二个参数ADC_ScanConvMode:设置是否打开扫描模式
第三个参数ADC_ContinuousConvMode:设置时单次转换模式还是连续转换模式
第四个参数ADC_ExternalTrigConvEdge:设置外部通道的触发使能和检测方式
第五个参数ADC_ExternalTrigConv:设置ADC外部触发转换模式
第六个参数ADC_DataAlign:设置数据对齐方式  是左对齐还是右对齐
第七个参数ADC_NbrOfConversion:设置规则序列的长度   单次转换



ADC_InitStructure.ADC_Resolution = ADC_Resolution_12b;//12位模式



ADC_InitStructure.ADC_ScanConvMode = DISABLE;//非扫描模式



ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;//关闭连续转换



ADC_InitStructure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_None; //禁止触发检测,使用软件触发



ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;//右对齐



ADC_InitStructure.ADC_NbrOfConversion = 1;//1个转换在规则序列中



ADC_Init(ADC1, &ADC_InitStructure);//ADC初始化


4. 开启AD转换器

开启AD转换器通过ADC_CR2寄存器控制



ADC_Cmd(ADC1, ENABLE);//开启AD转换器


5. 读取ADC值



void ADC_RegularChannelConfig(ADC_TypeDef* ADCx, uint8_t ADC_Channel,  uint8_t Rank, uint8_t ADC_SampleTime);



// 设置规则序列通道及采样周期



ADC_RegularChannelConfig(ADC1, ADC_Channel_5, 1, ADC_SampleTime_480Cycles );   //规则序列中的第一个转换,采样周期设置为480



ADC_SoftwareStartConvCmd(ADC1);          //使能指定的ADC1的软件转换启动功能



ADC_GetConversionValue(ADC1);       //获取转换ADC转换结果数据



FlagStatus ADC_GetFlagStatus(ADC_TypeDef* ADCx, uint8_t ADC_FLAG)    //获取AD转换的状态信息函数



ag.  while(!ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC ));//等待转换结束



9. 实验程序


该实验需要用杜邦线将PA5引脚接到GND或者3.3V上,测其电压原始值和转化后的值,切记不能接5.5V,会损坏开发板的ADC;



9.1 main.c


#include "stm32f4xx.h"
#include "delay.h"
#include "usart.h"
#include "LED.h"
#include "lcd.h"
#include "usmart.h"
#include "Key.h"
#include "ADC.h"

//LCD状态设置函数
void led_set(u8 sta)//只要工程目录下有usmart调试函数,主函数就必须调用这两个函数
{
	LED1=sta;
}
//函数参数调用测试函数
void test_fun(void(*ledset)(u8),u8 sta)
{
	led_set(sta);
}

int main(void)
{
	u16 adcx;
	float temp;
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
	delay_init(168);
	uart_init(115200);
	LED_Init();
	LCD_Init();
	Adc_Init();
	POINT_COLOR=RED;
	LCD_ShowString(30,50,200,16,16,"Explorer STM32F4");
	LCD_ShowString(30,70,200,16,16,"ADC TEST");
	LCD_ShowString(30,90,200,16,16,"ATOM@ALIENTEK");
	LCD_ShowString(30,110,200,16,16,"2023/20/23");
	POINT_COLOR=BLUE;
	LCD_ShowString(30,130,200,16,16,"ADC1_CH5_VAL:");
	LCD_ShowString(30,150,200,16,16,"ADC1_CH5_VOL:0.000V");  //显示小数点
	while(1)
	{
		adcx=Get_Adc_Average(ADC_Channel_5,20);//adc通道5,取20次平均值
		LCD_ShowxNum(134,130,adcx,4,16,0); //显示ADC采样后的原始值
		temp=(float)adcx*(3.3/4096);  //获取计算后带小数的实际电压值,如3.1111
		adcx=temp;  //赋值整数部分给adcx
		LCD_ShowxNum(134,150,adcx,1,16,0);//显示电压值的整数部分
		temp=temp-adcx; //把已经显示的整数部分去掉,留下小数部分 3.1111-3=0.1111
		temp=temp*1000;//把小数部分乘以1000,变成整数打印出来,乘以1000相当于保留3位小数,乘以10000相当于保留四位小数
		LCD_ShowxNum(150,150,temp,3,16,0x80); //显示小数部分
		LED0=!LED0;
		delay_ms(250);
	}
}



9.2 ADC.c


#include "stm32f4xx.h"                
#include "ADC.h"
#include "delay.h"

//初始化ADC
void Adc_Init(void)
{
	RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA,ENABLE);//使能GPIOA时钟
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1,ENABLE);// 使能ADC1时钟
	
	//初始化ADC1通道5 IO口
	GPIO_InitTypeDef GPIO_InitStructure;
	GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AN;  //模式为模拟输入
	GPIO_InitStructure.GPIO_Pin=GPIO_Pin_5;  //PA5 通道5
	GPIO_InitStructure.GPIO_PuPd=GPIO_PuPd_NOPULL; //不带上下拉
	GPIO_Init(GPIOA,&GPIO_InitStructure);
	
	RCC_APB2PeriphResetCmd(RCC_APB2Periph_ADC1,ENABLE);   //ADC1复位
	RCC_APB2PeriphResetCmd(RCC_APB2Periph_ADC1,DISABLE);    //复位结束
	
	//初始化CCR通用控制寄存器配置
	ADC_CommonInitTypeDef ADC_CommonInitStructure;
	ADC_CommonInitStructure.ADC_DMAAccessMode=ADC_DMAAccessMode_Disabled; //DMA失能
	ADC_CommonInitStructure.ADC_Mode=ADC_Mode_Independent;  //独立模式
	ADC_CommonInitStructure.ADC_Prescaler=ADC_Prescaler_Div4;  //预分频值设置
	ADC_CommonInitStructure.ADC_TwoSamplingDelay=ADC_TwoSamplingDelay_5Cycles;//两个采样阶段之间延迟5个时钟
	ADC_CommonInit(&ADC_CommonInitStructure);
	
	//初始化ADC1相关参数
	ADC_InitTypeDef ADC_InitStructure;
	ADC_InitStructure.ADC_ContinuousConvMode=DISABLE;  //关闭连续转换
	ADC_InitStructure.ADC_DataAlign=ADC_DataAlign_Right;  //右对齐
	ADC_InitStructure.ADC_ExternalTrigConvEdge=ADC_ExternalTrigConvEdge_None; //禁止触发检测,使用软件触发
	ADC_InitStructure.ADC_NbrOfConversion=1;  //1个转换在规则序列中
	ADC_InitStructure.ADC_Resolution=ADC_Resolution_12b;  //12位模式
	ADC_InitStructure.ADC_ScanConvMode=DISABLE; //非扫描模式
	ADC_Init(ADC1,&ADC_InitStructure); //ADC初始化
	
	ADC_Cmd(ADC1,ENABLE);   //开启AD转换器
}
//获取ADC值
//ch:通道值 0~16
//返回值:转换结果
u16 Get_Adc(u8 ch)
{
	ADC_RegularChannelConfig(ADC1,ch,1,ADC_SampleTime_480Cycles);//设置ADC规则组通道,一个序列,采样时间480
	ADC_SoftwareStartConv(ADC1);//使能指定的ADC1的软件转换启动功能
	while(!ADC_GetFlagStatus(ADC1,ADC_FLAG_EOC));//读取状态寄存器的状态位EOC,等待转换结束
	return ADC_GetConversionValue(ADC1);//返回最近一次的ADC1规则组的转换结果
}
//获取通道ch的转换值,取times次,然后平均
//ch:通道编号  times:获取次数
//返回值:通道ch的times次转换结果平均值
u16 Get_Adc_Average(u8 ch,u8 times)
{
	u32 temp_val=0;
	u8 t;
	for(t=0;t<times;t++)
	{
		temp_val=temp_val+Get_Adc(ch); //取times次通道值进行求和
		delay_ms(5);
	}
	return temp_val/times; //返回平均值
}




9.3 ADC.h


#ifndef _ADC__H_
#define _ADC__H_

void Adc_Init(void);
u16 Get_Adc(u8 ch);
u16 Get_Adc_Average(u8 ch,u8 times);

#endif



版权声明:本文为light_2025原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。