潘多拉STM32L475裸机例程学习 ADC实验

ADC实验

此文章仅限于记录个人知识盲区,没有指导作用,如果有任何疑问,欢迎在评论区提问讨论~

ADC

STM32L475xx 系列有 3 个 ADC,都可以独立工作,其中 ADC1 和 ADC2 还可以组成双重 模式(提高采样率) 。STM32L475 的 ADC 分辨率高达 12 位,每个 ADC 具有多达 20 个的采集 通道,这些通道的 A/D 转换可以单次、连续、扫描或间断模式执行。ADC 的结果可以左对齐 或右对齐方式存储在16 位数据寄存器中。

STM32L475 的 ADC 最大的转换速率为 5.33Mhz,也就是转换时间为 0.188us(12 位分辨率 时)

规则通道组&注入通道组:

规则通道相当于 你正常运行的程序,而注入通道呢,就相当于中断。在你程序正常执行的时候,中断是可以打 断你的执行的。同这个类似,注入通道的转换可以打断规则通道的转换, 在注入通道被转换完成之后,规则通道才得以继续转换。 通过一个形象的例子可以说明:假如你在家里的院子内放了 5 个温度探头,室内放了 3 个 温度探头;你需要时刻监视室外温度即可,但偶尔你想看看室内的温度;因此你可以使用规则 通道组循环扫描室外的 5 个探头并显示 AD 转换结果,当你想看室内温度时,通过一个按钮启 动注入转换组(3 个室内探头)并暂时显示室内温度,当你放开这个按钮后,系统又会回到规则通 道组继续检测室外温度。从系统设计上,测量并显示室内温度的过程中断了测量并显示室外温度的过程,但程序设计上可以在初始化阶段分别设置好不同的转换组,系统运行中不必再变更 循环转换的配置,从而达到两个任务互不干扰和快速切换的结果。可以设想一下,如果没有规 则组和注入组的划分,当你按下按钮后,需要从新配置 AD 循环扫描的通道,然后在释放按钮 后需再次配置 AD 循环扫描的通道。

配置过程

1)开启 PC 口时钟和 ADC1 时钟,设置 PC2 为模拟输入。

2)初始化 ADC,设置 ADC 时钟分频系数,分辨率,模式,扫描方式,对齐方式等信息。

3)开启 AD 转换器。

4)配置通道,读取通道 ADC 值。

HAL库配置函数

1)开启 PC 口时钟和 ADC1 时钟,设置 PC2 为模拟输入。

ADC1通道3在PC2上,所以先使能PORTC得时钟,然后设置PC2为模拟输入。同时把PC2复用为ADC,所以使能ADC1时钟。

 __HAL_RCC_ADC1_CLK_ENABLE();        //使能 ADC1 时钟  
 __HAL_RCC_GPIOA_CLK_ENABLE();   //开启 GPIOA 时钟 

初始化GPIOC为模拟输入

GPIO_InitTypeDef GPIO_Initure; 
GPIO_Initure.Pin=GPIO_PIN_5;              //PA5 
GPIO_Initure.Mode=GPIO_MODE_ANALOG;  //模拟输入 
GPIO_Initure.Pull=GPIO_NOPULL;           //不带上下拉
HAL_GPIO_Init(GPIOA,&GPIO_Initure);  

注意此时配置的是模拟输入而不是复用:GPIO_Initure.Mode=GPIO_MODE_ANALOG

2)初始化 ADC,设置 ADC 时钟分频系数,分辨率,模式,扫描方式,对齐方式等信息。

在 HAL 库中,初始化 ADC 是通过函数 HAL_ADC_Init 来实现的,该函数声明为:

HAL_StatusTypeDef HAL_ADC_Init(ADC_HandleTypeDef* hadc); 

该函数只有一个入口参数 hadc,为 ADC_HandleTypeDef 结构体指针类型,结构体定义为:

typedef struct {   
    ADC_TypeDef     *Instance;   //ADC1/ ADC2/ ADC3   
	ADC_InitTypeDef    Init;   //初始化结构体变量   
	__IO uint32_t     NbrOfCurrentConversionRank; //当前转换序列   
	DMA_HandleTypeDef   *DMA_Handle; //DMA 方式使用                  
	HAL_LockTypeDef    Lock;                        
	__IO HAL_ADC_StateTypeDef  State;                        
	__IO uint32_t     ErrorCode;    
}ADC_HandleTypeDef; 

该结构体定义和其他外设比较类似,我们着重看第二个成员变量 Init 含义,它是结构体 ADC_InitTypeDef 类型,结构体 ADC_InitTypeDef 定义为:

typedef struct {   
    uint32_t ClockPrescaler;//分频系数 2/4/6/8 分频 ADC_CLOCK_SYNC_PCLK_DIV4   	 
    uint32_t Resolution;   //分辨率 12/10/8/6 位:ADC_RESOLUTION_12B   
    uint32_t DataAlign;    //对齐方式:左对齐还是右对齐:ADC_DATAALIGN_RIGHT   
    uint32_t ScanConvMode; //扫描模式 DISABLE       
    uint32_t EOCSelection; //EOC 标志是否设置  DISABLE   
    uint32_t ContinuousConvMode;//开启连续转换模式或者单次转换模式 DISABLE   
    uint32_t DMAContinuousRequests;//开启 DMA 请求连续模式或者单独模式 DISABLE   
    uint32_t NbrOfConversion;  //规则序列中有多少个转换 1   
    uint32_t DiscontinuousConvMode;//不连续采样模式 DISABLE   
    uint32_t NbrOfDiscConversion;//不连续采样通道数 0   
    uint32_t ExternalTrigConv; //外部触发方式 ADC_SOFTWARE_START   
    uint32_t ExternalTrigConvEdge;//外部触发边沿 
}ADC_InitTypeDef; 

3)开启 AD 转换器。

HAL_ADC_Start(&ADC1_Handler); //开启 ADC 

4)配置通道,读取通道 ADC 值。

在上面的步骤完成后,ADC 就算准备好了。接下来我们要做的就是设置规则序列 1 里面的 通道,然后启动 ADC 转换。在转换结束后,读取转换结果值值就是了。 设置规则序列通道以及采样周期的函数是:

设置规则序列通道以及采样周期的函数是:

HAL_StatusTypeDef HAL_ADC_ConfigChannel(ADC_HandleTypeDef* hadc,  ADC_ChannelConfTypeDef* sConfig); 

该函数有两个入口参数,第一个就不用多说了,接下来我们看第二个入口参数 sConfig,它 是 ADC_ChannelConfTypeDef 结构体指针类型,结构体定义如下

typedef struct  {   
    uint32_t Channel;   //ADC 通道   
    uint32_t Rank;    //规则通道中的第几个转换   
    uint32_t SamplingTime;  //采样时间   
    uint32_t Offset;    //备用,暂未用到 
}ADC_ChannelConfTypeDef;  

Channel 用来设置 ADC 通道, Rank 用来设置要配置的通道是规则序列中的第几个转换,SamplingTime 用来设置采样时间。 使用实例为:

ADC1_ChanConf.Channel= ADC_CHANNEL_5;  //通道 5     
ADC1_ChanConf.Rank=1;   //第 1 个序列,序列 1     
ADC1_ChanConf.SamplingTime=ADC_SAMPLETIME_480CYCLES; //采样时间     
ADC1_ChanConf.Offset=0;                     HAL_ADC_ConfigChannel(&ADC1_Handler,&ADC1_ChanConf); //通道配置

配置好通道并且使能ADC后,接下来就是读取ADC值。这里我们采取的是查询方式读取, 所以我们还要等待上一次转换结束。此过程 HAL 库提供了专用函数 HAL_ADC_PollForConversion,函数定义为:

HAL_StatusTypeDef HAL_ADC_PollForConversion(ADC_HandleTypeDef* hadc,  
                                            uint32_t Timeout); 

等待上一次转换结束之后,接下来就是读取 ADC 值,函数为:

 uint32_t HAL_ADC_GetValue(ADC_HandleTypeDef* hadc);
CUBEMX配置

一、 ADCs_Common_Settings

Mode: 设置ADC 工作模式(独立模式或多重模式)
独立模式
<1> Independent mode ADC1 和ADC2 工作在独立模式
双重模式
<2> Dual regular simultaneous + injected simultaneous mode ADC1 和ADC2 工作在同步规则模式和同步注入模式
<3> regular regular simultaneous + alternate trigger mode ADC1 和ADC2 工作在同步规则模式和交替触发模式
<4> Dual injected simultaneous mode only ADC1 和ADC2 工作在同步注入模式
<5> Dual regular simultaneous mode only ADC1 和ADC2 工作在同步规则模式
<6> Dual interleaved mode only ADC1 和ADC2 工作在交叉模式
<7> Dual alternate trigger mode only ADC1 和ADC2 工作在交替触发模式
三重模式
<8> Triple combined regular simultaneous + injected simultaneous mode 工作在同步规则模式和同步注入模式
<9> Triple combined regular simultaneous + alternate trigger mode 工作在同步规则模式和交替触发模式
<10> Triple injected simultaneous mode only ADC1 和ADC2 工作在同步注入模式
<11> Triple regular simultaneous mode only ADC1 和ADC2 工作在同步规则模式
<12> Triple interleaved mode only ADC1 和ADC2 工作在交叉模式
<13> Triple alternate trigger mode only ADC1 和ADC2 工作在交替触发模式

DMA Access Mode :(DMA)直接存储器存取访问模式(在多重模式下才有此项)

Delay between 2 sampling phases: 2个抽样阶段的延迟(在多重模式下才有此项)

二、 ADCs _Settings
<1> Clock Prescaler ADC的时钟分频数
<2> Resolution 分辨率(意思是AD位数)
<3> Data Alignment ADC 数据向左边对齐还是向右边对齐
<4> Scan Conversion Mode ADC工作在扫描模式(多通道)还是单次(单通道)模式。可以设置这个参数为ENABLE 或者DISABLE。
<5> Continuous Conversion Mode ADC模数转换工作在连续模式。可以设置这个参数为 ENABLE或者DISABLE 。
<6> Discontinuous Conversion Mode ADC模数转换工作在不连续模式(单次模式)。可以设置这个参数为 ENABLE或者DISABLE 。
<7> DMA Continuous Requests DMA连续请求
<8> End of Conversion Selection 转换选择结束
三、 ADCs_Regular_ConversionMode (规则通道转换模式)
<1> Number of Conversion ADC转换的通道数量
<2> External Trigger Conversion Source ADC外部触发转换源
<3> External Trigger Conversion Edge ADC外部触发转换边沿(意思是上升沿/下降沿触发)
四、 Rank
<1> Channel ADC转换通道
<2> Sampling Time ADC转换时间
五、 ADC_Injected_ConversionMode(注入通道转换模式)
<1> Number of Conversion ADC转换的注入通道数
注入通道数不为0时,才有下面的配置项
<2> External Trigger Source ADC外部触发转换源
<3> External Trigger Edge ADC外部触发转换边沿(意思是上升沿/下降沿触发)
<4> Injected Conversion Mode ADC注入转换通道模式
六、 Rank(ADC_Injected_ConversionMode的(Number of Conversion )ADC转换的注入通道数不为0时,才能配置注入通道的其他参数)
<1> Channel ADC转换通道
<2> Sampling Time ADC转换时间
<3> Injected Offset ADC注入通道的偏值
七、 WatchDog
<1> Enable Analog WatchDog Mode

如何转换ADC的实际电压值?

如何STM32的ADC模块,得到接入ADC管脚上的实际电压值?

会读到什么值

由于STM32的ADC是12位逐次逼近型的模拟数字转换器,也就是说ADC模块读到的数据是12位的数据。

因此:STM32读到的ADC值,是从0到4095(111111111111)。当把ADC引脚接了GND,读到的就是0;当把ADC引脚接了VDD,读到的就是4095。

读到的值怎么换算成实际的电压值

前面提到了,我们输入GND,读到的值是0,输入VDD,得到的值是4095,那么,当读到2035的时候,怎么求输入电压多少V吗?这个问题,归根接地,就到了数学XY坐标,已知两点坐标值(0,0)(3.3,4095),给出任意X坐标值,求Y值的问题。
在这里插入图片描述
参考电压是什么

讨论这个问题之前,先拿万用表量一下你的VDDA的实际电压是多大?是不是标准的3.300V?应该不是吧?或许是2.296V,或许是3.312V。然后你把VDD连接到ADC引脚之后,得到的是4095;也就是,实际上,当你读出4095这个数据的时候,实际的电压值不是你想象中的3.300V。有些初学者,觉得几毫伏的电压差无所谓,但实际应用中,几毫伏就可能代表很大的实际工况,例如,在一个量程为50克的电子称上。

所以,这时候,芯片厂商就想了一个办法,给ADC模块中引入参考电压,由非常标准的参考电压芯片来接入参考电压引脚。标准的电压芯片,我们一般叫做参考电压芯片,或者叫做基准电压芯片。例如REF3133(输出3.300V)、REF3025(输出2.500V)等等。

ADC引脚的输入电压范围是多大

一般情况下,ADC引脚的输入电压,是从0VDD,如果有REF引脚,一般是0Vref,也有0~2Vref的情况。

如果被测的电压大于ADC的输入电压,例如,要用STM32测量0~5V的电压的话,可以在输入ADC引脚之前,加入电阻分压和放大器电路。

一些问题

ADC的时钟源到底如何选择?

在查询了STM32L475VE的手册后发现该芯片的ADC可选择两个不同的时钟源:

  1. 从系统时钟分支出的特殊时钟源:PLLSAI1 和PLLSAI2

    To select this scheme, bits CKMODE[1:0]of the ADCx_CCR register must be reset.

  2. 系统时钟AHB2

    To select this scheme, bits CKMODE[1:0]of the ADCx_CCR register must be different from “00”

ADVANTAGES:

  • 第一个单独的时钟源可以脱离时钟源AHB2线上分频的限制,得到最高的时钟频率。

    最终的时钟频可由1,2,4,6,8,12,16,32,64,128,256分频得到。

  • 第二个时钟源可以避免由于两个时钟源同步时带来的误差,当实际应用要求ADC精确无误时,可选择第二个时钟源。
    在这里插入图片描述
    总结:需要注意用到的函数:
    ADC_Init();在此函数内初始化ADC,设置通道
    HAL_ADC_MspInit(ADC_HandleTypeDef* hadc); GPIO 初始化都会放在 MSP 初始化函数中
    HAL_ADC_Start(&hadc1); 开启ADC
    HAL_ADC_PollForConversion(&hadc1, 10); 轮询转换
    return (u16)HAL_ADC_GetValue(&hadc1); 返回最近一次ADC规则组的转换结果

  • 0
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值