STM32—ADC详解
⽂章⽬录
⼀.ADC简介
⼆.ADC功能框图讲解
1.电压输⼊范围
2.输⼊通道
3.转换顺序
4.触发源
5.转换时间
7.中断
8.电压转换
三.初始化结构体
四.单通道电压采集
1.头⽂件
2.引脚配置函数
3.NVIC配置函数
4.ADC配置函数
5.中断函数
6.主函数
⼀.ADC简介
STM32f103系列有3个ADC,精度为12位,每个ADC最多有16个外部通道。其中ADC1和ADC2都有16
个外部通道,ADC3⼀般有8个外部通道,各通道的A/D转换可以单次、连续、扫描或间断执⾏,ADC转换的结果可以左对齐或右对齐储存在16位数据寄存器中。ADC的输⼊时钟不得超过14MHz,其时钟频率由PCLK2分频产⽣。
⼆.ADC功能框图讲解
学习STM32开发板上的外设时⾸先要了解其外设的功能框图,如下:
功能框图可以⼤体分为7部分,下⾯⼀⼀讲解:
1.电压输⼊范围
ADC所能测量的电压范围就是VREF- ≤ VIN ≤ VREF+,把 VSSA 和 VREF-接地,把 VREF+和 VDDA 接 3V3,得到ADC 的输⼊电压范围为: 0~3.3V。
2.输⼊通道
ADC的信号输⼊就是通过通道来实现的,信号通过通道输⼊到单⽚机中,单⽚机经过转换后,将模拟信号输出为数字信号。STM32中的ADC有着18个通道,其中外部的16个通道已经在框图中标出,如下:
这16个通道对应着不同的IO⼝,此外ADC1/2/3 还有内部通道: ADC1 的通道 16 连接到了芯⽚内部的温度传感器, Vrefint 连接到了通道 17。 ADC2 的模拟通道 16 和 17 连接到了内部的 VSS。
ADC的全部通道如⽰:
外部的16个通道在转换时⼜分为规则通道和注⼊通道,其中规则通道最多有16路,注⼊通道最多有4路(注⼊通道貌似使⽤不多),下⾯简单介绍⼀下俩种通道:
规则通道
规则通道顾名思义就是,最平常的通道、也是最常⽤的通道,平时的ADC转换都是⽤规则通道实现的。
注⼊通道
注⼊通道是相对于规则通道的,注⼊通道可以在规则通道转换时,强⾏插⼊转换,相当于⼀个“中断通道”吧。当有注⼊通道需要转换时,规则通道的转换会停⽌,优先执⾏注⼊通道的转换,当注⼊通道的转换执⾏完毕后,再回到之前规则通道进⾏转换。
3.转换顺序
知道了ADC的转换通道后,如果ADC只使⽤⼀个通道来转换,那就很简单,但如果是使⽤多个通道进⾏转换就涉及到⼀个先后顺序了,毕竟规则转换通道只有⼀个数据寄存器。多个通道的使⽤顺序分为俩种情况:规则通道的转换顺序和注⼊通道的转换顺序。
规则通道转换顺序
规则通道中的转换顺序由三个寄存器控制:SQR1、SQR2、SQR3,它们都是32位寄存器。SQR寄存器控制着转换通道的数⽬和转换顺序,只要在对应的寄存器位SQx中写⼊相应的通道,这个通道就是第x个转换。具体的对应关系如下:
通过SQR1寄存器就能了解其转换顺序在寄存器上的实现了:
注⼊通道转换顺序
和规则通道转换顺序的控制⼀样,注⼊通道的转换也是通过注⼊寄存器来控制,只不过只有⼀个JSQR寄存器来控制,控制关系如下:
需要注意的是,只有当JL=4的时候,注⼊通道的转换顺序才会按照JSQ1、JSQ2、JSQ3、JSQ4的顺序执⾏。当JL<4时,注⼊通道的转换顺序恰恰相反,也就是执⾏顺序为:JSQ4、JSQ3、JSQ2、JSQ1。
配置转换顺序的函数如⽰:
/**
* @brief Configures for the selected ADC regular channel its corresponding
* rank in the sequencer and its sample time.
* @param ADCx: where x can be 1, 2 or 3 to select the ADC peripheral.
* @param ADC_Channel: the ADC channel to configure.
* This parameter can be one of the following values:
* @arg ADC_Channel_0: ADC Channel0 selected
* @arg ADC_Channel_1: ADC Channel1 selected
* @arg ADC_Channel_2: ADC Channel2 selected
* @arg ADC_Channel_3: ADC Channel3 selected
* @arg ADC_Channel_4: ADC Channel4 selected
* @arg ADC_Channel_5: ADC Channel5 selected
* @arg ADC_Channel_6: ADC Channel6 selected
* @arg ADC_Channel_7: ADC Channel7 selected
* @arg ADC_Channel_8: ADC Channel8 selectedrank函数怎么用
* @arg ADC_Channel_9: ADC Channel9 selected
* @arg ADC_Channel_10: ADC Channel10 selected
* @arg ADC_Channel_11: ADC Channel11 selected
* @arg ADC_Channel_12: ADC Channel12 selected
* @arg ADC_Channel_13: ADC Channel13 selected
* @arg ADC_Channel_14: ADC Channel14 selected
* @arg ADC_Channel_15: ADC Channel15 selected
* @arg ADC_Channel_16: ADC Channel16 selected
* @arg ADC_Channel_17: ADC Channel17 selected
* @param Rank: The rank in the regular group sequencer. This parameter must be between 1 to 16.
* @param ADC_SampleTime: The sample time value to be set for the selected channel.
* This parameter can be one of the following values:
* @arg ADC_SampleTime_1Cycles5: Sample time equal to 1.5 cycles
* @arg ADC_SampleTime_7Cycles5: Sample time equal to 7.5 cycles
* @arg ADC_SampleTime_13Cycles5: Sample time equal to 13.5 cycles
* @arg ADC_SampleTime_28Cycles5: Sample time equal to 28.5 cycles
* @arg ADC_SampleTime_41Cycles5: Sample time equal to 41.5 cycles
* @arg ADC_SampleTime_55Cycles5: Sample time equal to 55.5 cycles
* @arg ADC_SampleTime_71Cycles5: Sample time equal to 71.5 cycles
* @arg ADC_SampleTime_239Cycles5: Sample time equal to 239.5 cycles
* @retval None
*/
void ADC_RegularChannelConfig(ADC_TypeDef* ADCx, uint8_t ADC_Channel, uint8_t Rank, uint8_t ADC_SampleTime)
{
函数内容略;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
4.触发源
ADC转换的输⼊、通道、转换顺序都已经说明了,但ADC转换是怎么触发的呢?就像通信协议⼀样,都要规定⼀个起始信号才能传输信息,ADC也需要⼀个触发信号来实⾏模/数转换。
其⼀就是通过直接配置寄存器触发,通过配置控制寄存器CR2的ADON位,写1时开始转换,写0时停⽌转换。在程序运⾏过程中只要调⽤库函数,将CR2寄存器的ADON位置1就可以进⾏转换,⽐较好理
解。
另外,还可以通过内部定时器或者外部IO触发转换,也就是说可以利⽤内部时钟让ADC进⾏周期性的转换,也可以利⽤外部IO使ADC在需要时转换,具体的触发由控制寄存器CR2决定。
ADC_CR2寄存器的详情如下:
5.转换时间
还有⼀点,就是转换时间的问题,ADC的每⼀次信号转换都要时间,这个时间就是转换时间,转换时间由输⼊时钟和采样周期来决定。
输⼊时钟
由于ADC在STM32中是挂载在APB2总线上的,所以ADC得时钟是由PCLK2(72MHz)经过分频得到的,分频因⼦由 RCC 时钟配置寄存器RCC_CFGR 的位 15:14 ADCPRE[1:0]设置,可以是 2/4/6/8 分频,⼀般配置分频因⼦为8,即8分频得到ADC的输⼊时钟频率为9MHz。
采样周期
采样周期是确⽴在输⼊时钟上的,配置采样周期可以确定使⽤多少个ADC时钟周期来对电压进⾏采样,采样的周期数可通过 ADC采样时间寄存器 ADC_SMPR1 和 ADC_SMPR2 中的 SMP[2:0]位设置,ADC_SMPR2 控制的是通道 0~9, ADC_SMPR1 控制的是通道
10~17。每个通道可以配置不同的采样周期,但最⼩的采样周期是1.5个周期,也就是说如果想最快时间采样就设置采样周期为1.5.
转换时间
转换时间=采样时间+12.5个周期
12.5个周期是固定的,⼀般我们设置 PCLK2=72M,经过 ADC 预分频器能分频到最⼤的时钟只能是 12M,采样周期设置为 1.5 个周期,算出最短的转换时间为 1.17us。
6.数据寄存器
转换完成后的数据就存放在数据寄存器中,但数据的存放也分为规则通道转换数据和注⼊通道转换数据的。
规则数据寄存器
规则数据寄存器负责存放规则通道转换的数据,通过32位寄存器ADC_DR来存放。
当使⽤ADC独⽴模式(也就是只使⽤⼀个ADC,可以使⽤多个通道)时,数据存放在低16位中,当使⽤ADC多模式时⾼16位存放ADC2的数据。需要注意的是ADC转换的精度是12位,⽽寄存器中有16个位来存放数据,所以要规定数据存放是左对齐还是右对齐。
当使⽤多个通道转换数据时,会产⽣多个转换数据,然鹅数据寄存器只有⼀个,多个数据存放在⼀个寄存器中会覆盖数据导致ADC转换错误,所以我们经常在⼀个通道转换完成之后就⽴刻将数据取出来,⽅便下⼀个数据存放。⼀般开启DMA模式将转换的数据,传输在⼀个数组中,程序对数组读操作就可以得到转换的结果。
DMA的使⽤之前在⼀篇博客中介绍过:DMA介绍
注⼊数据寄存器
注⼊通道转换的数据寄存器有4个,由于注⼊通道最多有4个,所以注⼊通道转换的数据都有固定的存放位置,不会跟规则寄存器那样产⽣数据覆盖的问题。 ADC_JDRx 是 32 位的,低 16 位有效,⾼ 16 位保留,数据同样分为左对齐和右对齐,具体是以哪⼀种⽅式存放,由ADC_CR2 的 11 位 ALIGN 设置。
7.中断
从框图中可以知道数据转换完成之后可以产⽣中断,有三种情况:
规则通道转换完成中断
规则通道数据转换完成之后,可以产⽣⼀个中断,可以在中断函数中读取规则数据寄存器的值。这也是单通道时读取数据的⼀种⽅法。
注⼊通道转换完成中断
注⼊通道数据转换完成之后,可以产⽣⼀个中断,并且也可以在中断中读取注⼊数据寄存器的值,达到读取数据的作⽤。
模拟看门狗事件
当输⼊的模拟量(电压)不再阈值范围内就会产⽣看门狗事件,就是⽤来监视输⼊的模拟量是否正常。
以上中断的配置都由ADC_SR寄存器决定:
当然,在转换完成之后也可以产⽣DMA请求,从⽽将转换好的数据从数据寄存器中读取到内存中。
8.电压转换
要知道,转换后的数据是⼀个12位的⼆进制数,我们需要把这个⼆进制数代表的模拟量(电压)⽤数字表⽰出来。⽐如测量的电压范围是0~3.3V,转换后的⼆进制数是x,因为12位ADC在转换时将电压的范围⼤⼩(也就是3.3)分为4096(2^12)份,所以转换后的⼆进制数x代表的真实电压的计算⽅法就是:
y=3.3* x / 4096
三.初始化结构体
每个外设的核⼼就是其对应的初始化结构体了,ADC的初始化结构体如下:
typedef struct
{
uint32_t ADC_Mode; // ADC ⼯作模式选择
FunctionalState ADC_ScanConvMode; // ADC 扫描(多通道)或者单次(单通道)模式选择
FunctionalState ADC_ContinuousConvMode; // ADC 单次转换或者连续转换选择
uint32_t ADC_ExternalTrigConv; // ADC 转换触发信号选择
uint32_t ADC_DataAlign; // ADC 数据寄存器对齐格式
uint8_t ADC_NbrOfChannel; // ADC 采集通道数
} ADC_InitTypeDef;
1
2
3
4
5
6
7
8
9
通过配置初始化结构体来设置ADC的相关信息。
四.单通道电压采集
⽤这个程序来简单熟练⼀下ADC的单通道电压采集吧,程序使⽤了ADC1的通道11,对应的IO⼝是PC^1,因为博主的开发板上PC ^1引脚没有任何复⽤,使⽤中断,在中断中读取转换的电压。
1.头⽂件
为了提⾼⽂件的可移植性,头⽂件中定义了⼀些与ADC和中断相关的量,在移植程序的时候只需要修改头⽂件中的定义即可。
#ifndef __ADC_H
#define __ADC_H
#include "stm32f10x.h"
/* 采⽤ADC1的通道11 引脚为PC^1 模式必须是模拟输⼊*/
#define ADC_GPIO_RCC RCC_APB2Periph_GPIOC
#define ADC_GPIO_PORT GPIOC
#define ADC_GPIO_PIN GPIO_Pin_1
#define ADC_GPIO_MODE GPIO_Mode_AIN
/* 配置与中断有关的信息 */
#define ADC_IRQn ADC1_2_IRQn
#define ADC_RCC RCC_APB2Periph_ADC1
/* 配置ADC初始化结构体的宏定义 */
#define ADCx ADC1
#define ADCx_ContinuousConvMode ENABLE //连续转换模式
#define ADCx_DataAlign ADC_DataAlign_Right //转换结果右对齐
#define ADCx_ExternalTrigConv ADC_ExternalTrigConv_None //不使⽤外部触发转换,采⽤软件触发
#define ADCx_Mode ADC_Mode_Independent //只使⽤⼀个ADC,独⽴模式
#define ADCx_NbrOfChannel 1 //⼀个转换通道
#define ADCx_ScanConvMode DISABLE //禁⽌扫描模式,多通道时使⽤
/* 通道信息和采样周期 */
#define ADC_Channel ADC_Channel_11
#define ADC_SampleTime ADC_SampleTime_55Cycles5
发布评论