STM32F4_模数转换器(ADC)详解

目录

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框图

STM32F4_模数转换器(ADC)详解_第1张图片

STM32F4_模数转换器(ADC)详解_第2张图片

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个:

STM32F4_模数转换器(ADC)详解_第3张图片

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_模数转换器(ADC)详解_第4张图片

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外设上可用。

STM32F4_模数转换器(ADC)详解_第5张图片

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 时序图

STM32F4_模数转换器(ADC)详解_第6张图片

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

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

3.6 模拟看门狗

STM32F4_模数转换器(ADC)详解_第7张图片

如果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℃
  •         精度:\pm1.5℃

STM32F4_模数转换器(ADC)详解_第8张图片

 读取温度

  •         选择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(开始转换规则组的通道)

STM32F4_模数转换器(ADC)详解_第9张图片

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;

STM32F4_模数转换器(ADC)详解_第10张图片

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)

STM32F4_模数转换器(ADC)详解_第11张图片

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)

STM32F4_模数转换器(ADC)详解_第12张图片

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)

STM32F4_模数转换器(ADC)详解_第13张图片

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)

STM32F4_模数转换器(ADC)详解_第14张图片

STM32F4_模数转换器(ADC)详解_第15张图片

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

STM32F4_模数转换器(ADC)详解_第16张图片

STM32F4_模数转换器(ADC)详解_第17张图片

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

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

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

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

STM32F4_模数转换器(ADC)详解_第18张图片

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

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

你可能感兴趣的:(STM32,stm32,单片机,嵌入式硬件)