完整教程下载地址:http://www.armbbs.cn/forum.php?mod=viewthread&tid=86980
本章节为大家讲解ADC(Analog-to-digital converters,模数转换器),极具项目使用价值,因为STM32H7的ADC已经高达16位分辨率,支持3.6Msps采样率。
目录
第44章 STM32H7的ADC基础知识和HAL库API
44.1 初学者重要提示
44.2 ADC基础知识
44.2.1 ADC硬件框图
44.2.2 ADC时钟源选择
44.2.3 ADC的采样时间和转换时间
44.2.4 ADC单次转换和连续转换
44.2.5 ADC外部触发采样
44.2.6 ADC多通道连接方式
44.2.7 ADC多通道扫描时序
44.2.8 ADC单端和差分的支持
44.2.9 ADC过采样机制
44.2.10 ADC的Vbat/4,VrefInt和温度采样
44.2.11 ADC校准问题
44.2.12 ADC电气特性(重要)
44.3 ADC的HAL库用法
44.3.1 ADC寄存器结构体ADC_TypeDef
44.3.2 ADC句柄结构体ADC_HandleTypeDef
44.3.3 ADC参数初始化结构体ADC_InitTypeDef
44.3.4 ADC通道配置结构体ADC_ChannelConfTypeDef
44.3.5 ADC过采样结构体ADC_OversamplingTypeDef
44.3.6 ADC模拟看门狗结构体ADC_AnalogWDGConfTypeDef
44.3.7 ADC的状态标志清除问题
44.3.8 ADC初始化流程总结
44.4 源文件stm32h7xx_hal_adc.c
44.4.1 函数HAL_ADC_Init
44.4.2 函数HAL_ADC_ConfigChannel
44.4.3 函数HAL_ADC_Start
44.4.4 函数HAL_ADC_Start_DMA
44.4.5 函数HAL_ADCEx_Calibration_Start
44.5 总结
http://www.armbbs.cn/forum.php?mod=viewthread&tid=89414 。
ADC的几个关键知识点放在开头说:
认识一个外设,最好的方式就是看他的框图,方便我们快速的了解ADC的基本功能,然后再看手册了解细节。框图如下所示(ADC1和ADC2):
相比前面章节讲解的外设,ADC的框图相对较复杂,因为涉及到控制寄存器较多。通过这个框图,我们可以得到如下信息:
INP是差分正向输入,INN是差分反向输入。
ADC_INP[0:5]和ADC_INN[0:5]是快速通道。
ADC_INP[6:19]和ADC_INN[6:19]是慢速通道。
共有21路触发用于规则通道,ADC1和ADC2共用的,而ADC3是独立的。
共有21路触发用于注入通道,ADC1和ADC2共用的,而ADC3是独立的。
每个ADC都支持三个模拟看门狗。
ADC中断。
ADC的AHB时钟。
ADC的内核时钟。
用于ADC的DMA请求。
五条专用的内部通道,内部参考电压 VrefInt,内部温度传感器和VBAT 监测通道 VBAT/4都是连接到 ADC3。另外内部 DAC 通道 1 和通道 2,连接到 ADC2。
ADC有两种时钟源可供选择,可以使用来自AHB总线的系统时钟(属于同步时钟,对应下面框图的adc_hclk),也可以使用PLL2,PLL3,HSE,HSI或者CSI时钟(属于异步时钟,对应下面框图的adc_ker_ck)。
结合上面的框图,ADC的时钟源要注意以下几个问题:
最后特别注意一点,如果STM32H7工作在400MHz,ADC使用AHB做时钟源,超频是不可避免的。ADC1和ADC2位于200MHz的AHB1总线时钟,而ADC3位于200MHz的AHB4下。根据上面的框图,ADCx_CCR寄存器的CKMODE最高可以选择4分频,那么就是50MHz,而ADC数据手册限制最高是36MHz,也就是说已经超频了。
使用AHB作为时钟源的好处就是定时器等外部触发方式的效果好。
STM32H7的ADC采样速度,即转换时间 = 采样时间 + 逐次逼近时间。
采样时间是可配置的,通过ADCx_SMPR1 和 ADCx_SMPR2 寄存器中的 SMP[2:0] 位就可以编程所有ADC通道,可选采样时间值如下:
不同ADC分辨率对应的逐次逼近时间不同,具体数值如下:
比如配置SMP = 110,采用16位分辨率,那么:
ADC的转换时间 =采样时间 + 逐次逼近时间
= 387.5个ADC时钟周期 + 8.5个ADC时钟周期
= 396个ADC时钟周期。
STM32H7的ADC支持单次转换和连续转换。
在单次转换模式下,ADC会将通道的所有转换执行一次。
该模式仅适用于常规通道。
在连续转换模式下,如果发生软件或硬件触发,ADC会执行所有常规通道的转换,随后会自动重启并继续执行每个通道的转换。
STM32H7既可以选择软件触发也可以选择外部硬件触发,并且可以设置触发边沿。
#define ADC_EXTERNALTRIG_T1_CC1 ((uint32_t)0x00000000)
#define ADC_EXTERNALTRIG_T1_CC2 ((uint32_t)ADC_CFGR_EXTSEL_0)
#define ADC_EXTERNALTRIG_T1_CC3 ((uint32_t)ADC_CFGR_EXTSEL_1)
#define ADC_EXTERNALTRIG_T2_CC2 ((uint32_t)(ADC_CFGR_EXTSEL_1 | ADC_CFGR_EXTSEL_0))
#define ADC_EXTERNALTRIG_T3_TRGO ((uint32_t)ADC_CFGR_EXTSEL_2)
#define ADC_EXTERNALTRIG_T4_CC4 ((uint32_t)(ADC_CFGR_EXTSEL_2 | ADC_CFGR_EXTSEL_0))
#define ADC_EXTERNALTRIG_EXT_IT11 ((uint32_t)(ADC_CFGR_EXTSEL_2 | ADC_CFGR_EXTSEL_1))
#define ADC_EXTERNALTRIG_T8_TRGO ((uint32_t)(ADC_CFGR_EXTSEL_2 | ADC_CFGR_EXTSEL_1 |
ADC_CFGR_EXTSEL_0))
#define ADC_EXTERNALTRIG_T8_TRGO2 ((uint32_t) ADC_CFGR_EXTSEL_3)
#define ADC_EXTERNALTRIG_T1_TRGO ((uint32_t)(ADC_CFGR_EXTSEL_3 | ADC_CFGR_EXTSEL_0))
#define ADC_EXTERNALTRIG_T1_TRGO2 ((uint32_t)(ADC_CFGR_EXTSEL_3 | ADC_CFGR_EXTSEL_1))
#define ADC_EXTERNALTRIG_T2_TRGO ((uint32_t)(ADC_CFGR_EXTSEL_3 | ADC_CFGR_EXTSEL_1 | ADC_CFGR_EXTSEL_0))
#define ADC_EXTERNALTRIG_T4_TRGO ((uint32_t)(ADC_CFGR_EXTSEL_3 | ADC_CFGR_EXTSEL_2))
#define ADC_EXTERNALTRIG_T6_TRGO ((uint32_t)(ADC_CFGR_EXTSEL_3 | ADC_CFGR_EXTSEL_2 | ADC_CFGR_EXTSEL_0))
#define ADC_EXTERNALTRIG_T15_TRGO ((uint32_t)(ADC_CFGR_EXTSEL_3 | ADC_CFGR_EXTSEL_2 | ADC_CFGR_EXTSEL_1))
#define ADC_EXTERNALTRIG_T3_CC4 ((uint32_t)(ADC_CFGR_EXTSEL_3 | ADC_CFGR_EXTSEL_2 | ADC_CFGR_EXTSEL_1 | ADC_CFGR_EXTSEL_0))
#define ADC_EXTERNALTRIG_HR1_ADCTRG1 ((uint32_t) ADC_CFGR_EXTSEL_4)
#define ADC_EXTERNALTRIG_HR1_ADCTRG3 ((uint32_t) (ADC_CFGR_EXTSEL_4 | ADC_CFGR_EXTSEL_0))
#define ADC_EXTERNALTRIG_LPTIM1_OUT ((uint32_t) (ADC_CFGR_EXTSEL_4 | ADC_CFGR_EXTSEL_1))
#define ADC_EXTERNALTRIG_LPTIM2_OUT ((uint32_t) (ADC_CFGR_EXTSEL_4 | ADC_CFGR_EXTSEL_1| ADC_CFGR_EXTSEL_0))
#define ADC_EXTERNALTRIG_LPTIM3_OUT ((uint32_t) (ADC_CFGR_EXTSEL_4 | ADC_CFGR_EXTSEL_2))
#define ADC_EXTERNALTRIGINJEC_T1_TRGO ((uint32_t)0x00000000)
#define ADC_EXTERNALTRIGINJEC_T1_CC4 ((uint32_t)ADC_JSQR_JEXTSEL_0)
#define ADC_EXTERNALTRIGINJEC_T2_TRGO ((uint32_t)ADC_JSQR_JEXTSEL_1)
#define ADC_EXTERNALTRIGINJEC_T2_CC1 ((uint32_t)(ADC_JSQR_JEXTSEL_1 | ADC_JSQR_JEXTSEL_0))
#define ADC_EXTERNALTRIGINJEC_T3_CC4 ((uint32_t)ADC_JSQR_JEXTSEL_2)
#define ADC_EXTERNALTRIGINJEC_T4_TRGO ((uint32_t)(ADC_JSQR_JEXTSEL_2 | ADC_JSQR_JEXTSEL_0))
#define ADC_EXTERNALTRIGINJEC_EXT_IT15 ((uint32_t)(ADC_JSQR_JEXTSEL_2 | ADC_JSQR_JEXTSEL_1))
#define ADC_EXTERNALTRIGINJEC_T8_CC4 ((uint32_t)(ADC_JSQR_JEXTSEL_2 | ADC_JSQR_JEXTSEL_1 |
ADC_JSQR_JEXTSEL_0))
#define ADC_EXTERNALTRIGINJEC_T1_TRGO2 ((uint32_t)ADC_JSQR_JEXTSEL_3)
#define ADC_EXTERNALTRIGINJEC_T8_TRGO ((uint32_t)(ADC_JSQR_JEXTSEL_3 | ADC_JSQR_JEXTSEL_0))
#define ADC_EXTERNALTRIGINJEC_T8_TRGO2 ((uint32_t)(ADC_JSQR_JEXTSEL_3 | ADC_JSQR_JEXTSEL_1))
#define ADC_EXTERNALTRIGINJEC_T3_CC3 ((uint32_t)(ADC_JSQR_JEXTSEL_3 | ADC_JSQR_JEXTSEL_1 | ADC_JSQR_JEXTSEL_0))
#define ADC_EXTERNALTRIGINJEC_T3_TRGO ((uint32_t)(ADC_JSQR_JEXTSEL_3 | ADC_JSQR_JEXTSEL_2))
#define ADC_EXTERNALTRIGINJEC_T3_CC1 ((uint32_t)(ADC_JSQR_JEXTSEL_3 | ADC_JSQR_JEXTSEL_2 | ADC_JSQR_JEXTSEL_0))
#define ADC_EXTERNALTRIGINJEC_T6_TRGO ((uint32_t)(ADC_JSQR_JEXTSEL_3 | ADC_JSQR_JEXTSEL_2 | ADC_JSQR_JEXTSEL_1))
#define ADC_EXTERNALTRIGINJEC_T15_TRGO ((uint32_t)(ADC_JSQR_JEXTSEL_3 | ADC_JSQR_JEXTSEL_2 | ADC_JSQR_JEXTSEL_1 | ADC_JSQR_JEXTSEL_0))
#define ADC_EXTERNALTRIGINJEC_HR1_ADCTRG2 ((uint32_t)ADC_JSQR_JEXTSEL_4)
#define ADC_EXTERNALTRIGINJEC_HR1_ADCTRG4 ((uint32_t)(ADC_JSQR_JEXTSEL_4 | ADC_JSQR_JEXTSEL_0))
#define ADC_EXTERNALTRIGINJEC_LPTIM1_OUT ((uint32_t)(ADC_JSQR_JEXTSEL_4 | ADC_JSQR_JEXTSEL_1))
#define ADC_EXTERNALTRIGINJEC_LPTIM2_OUT ((uint32_t)(ADC_JSQR_JEXTSEL_4 | ADC_JSQR_JEXTSEL_1 | ADC_JSQR_JEXTSEL_0))
#define ADC_EXTERNALTRIGINJEC_LPTIM3_OUT ((uint32_t)(ADC_JSQR_JEXTSEL_4 | ADC_JSQR_JEXTSEL_2))
ADC1,ADC2和ADC3均支持 20条通道扫描采样(注意,部分引脚是多个ADC共用的):
反映到硬件上,这些通道的连接方式就是下面这样(以ADC3为例):
ADC的多通道采样过程是单个ADC通过多路选择器不断切换不同的通道进行采样的,也就是说当前通道采集完成后才会进行下一个通道的采样。
通过下面这四幅时序图可以让大家有个感性的认识:
单次转换序列,软件触发:
ADSTART表示软件启动转换。
EOC表示一个通道转换结束。
EOS表示所有通道转换结束。
关于这个时序图的解读:
连续转换序列,软件触发:
ADSTART表示软件启动转换。
ADSTP表示停止转换。
EOC表示一个通道转换结束。
EOS表示所有通道转换结束。
关于这个时序图的解读:
单次转换序列,硬件触发:
ADSTART表示软件启动转换。
EOC表示一个通道转换结束。
EOS表示所有通道转换结束。
TRGX表示硬件上升沿触发。
关于这个时序图的解读:
连续转换序列,硬件触发:
ADSTART表示软件启动转换。
EOC表示一个通道转换结束。
EOS表示所有通道转换结束。
TRGX表示硬件上升沿触发。
关于这个时序图的解读:
初学的话,容易有几个概念搞不清楚,单极性,双极性,真差分和伪差分。在此贴里面有一个专门的截图:http://www.armbbs.cn/forum.php?mod=viewthread&tid=89397 (暂未找到这个图片的原始出处,所以先不放在教程里面)。
单极性,双极性比较好理解,就是单电源供电或者双电源供电,这里的双电源是指的正负电压供电。
STM32H7的差分属于单极性真差分,也就是不可以测量负压。另外要注意下面内容:
(1)当 ADC 配置为差分模式时,两路输入的偏置电压均为 Vref+/2。
(2)输入信号应为差分信号且共模电压应固定。
过采样的意思就是提高单位时间的采样次数,比如原来每秒采集1次,那么16倍过采样就是每秒要采集16次。
STM32H7最高支持1024倍过采样,1024次采样数据累加后存到ADC的数据寄存器里面。如果想求1024次采集的平均数,也不需要用户参与计算,ADC的CFGR2寄存器OVSS[3:0]位支持右移操作(右移1位到11位均可配置),可以方便的求平均。
这个功能在实际项目还是非常实用的。比如下面的测试:
做了一个ADC3+DMA的多通道采样。
通道1:PC0采集2.5V的稳压基准。
通道2:Vbat/4。
通道3:VrefInt。
通道4:温度。
Vbat/4连接至ADC3_INP17,所以可以使用ADC3的通道17进行测量。为什么不是直接测试Vbat,
因为Vbat电压有可能高于Vdda,导致ADC3测量电压超出范围。Vbat的测量框图如下:
注意:必须将 VBATEN 位置1才能使能内部通道 ADC3_INP17采集。
VrefInt连接至ADC3_INP19,所以可以使用ADC3的通道19进行测量。可以通过监测内部电源模块参考电压VrefInt来评估ADC Vref+电压的参考值。VrefInt的测量框图如下:
注意:必须将 ADCx_CCR 寄存器中的 VREFEN 位置1才能使能内部通道 ADC3_INP19采集。
STM32H7带有温度传感器,可以使用ADC3_INP18进行测量,不过读取出来的还是个电压值,需要将其转换为温度值,调用下面的转换公式即可:
TS_CAL1 = *(__IO uint16_t *)(0x1FF1E820);
TS_CAL2 = *(__IO uint16_t *)(0x1FF1E840);
TS_CAL2表示温度110℃时的ADC测量值,读取地址0x1FF1E820可以获得。
TS_CAL1表示温度30℃时的ADC测量值,读取地址0x1FF1E840可以获得。
TS_DATA表示当前的测量值,获得当前的测试值代入上面公式就可以获取温度。
温度测量的框图如下:
注意:必须将VSENSEEN位置1才能使能内部通道 ADC3_VINP18采集。
STM32H7的ADC支持偏移校准和线性度校准,两种校准实现都比较方便,HAL库已经为我们做好了,直接调用API即可,但是使用中务必注意此贴的问题:
http://www.armbbs.cn/forum.php?mod=viewthread&tid=91436 。
如果使用ADC的话,部分电气特性一定要了解:
通过上面的截图,我们要了解到以下几点:
ADC的HAL库用法其实就是几个结构体变量成员的配置和使用,然后配置时钟,并根据需要配置NVIC、中断和DMA。
只是ADC涉及到定义非常多,下面我们逐一展开为大家做个说明。
ADC相关的寄存器是通过HAL库中的结构体ADC_TypeDef和ADC_Common_TypeDef定义的,在stm32h743xx.h中可以找到它们的具体定义如下:
/**
* @brief Analog to Digital Converter
*/
typedef struct
{
__IO uint32_t ISR; /*!< ADC Interrupt and Status Register, Address offset: 0x00 */
__IO uint32_t IER; /*!< ADC Interrupt Enable Register, Address offset: 0x04 */
__IO uint32_t CR; /*!< ADC control register, Address offset: 0x08 */
__IO uint32_t CFGR; /*!< ADC Configuration register, Address offset: 0x0C */
__IO uint32_t CFGR2; /*!< ADC Configuration register 2, Address offset: 0x10 */
__IO uint32_t SMPR1; /*!< ADC sample time register 1, Address offset: 0x14 */
__IO uint32_t SMPR2; /*!< ADC sample time register 2, Address offset: 0x18 */
__IO uint32_t PCSEL; /*!< ADC pre-channel selection, Address offset: 0x1C */
__IO uint32_t LTR1; /*!< ADC watchdog Lower threshold register 1, Address offset: 0x20 */
__IO uint32_t HTR1; /*!< ADC watchdog higher threshold register 1, Address offset: 0x24 */
uint32_t RESERVED1; /*!< Reserved, 0x028 */
uint32_t RESERVED2; /*!< Reserved, 0x02C */
__IO uint32_t SQR1; /*!< ADC regular sequence register 1, Address offset: 0x30 */
__IO uint32_t SQR2; /*!< ADC regular sequence register 2, Address offset: 0x34 */
__IO uint32_t SQR3; /*!< ADC regular sequence register 3, Address offset: 0x38 */
__IO uint32_t SQR4; /*!< ADC regular sequence register 4, Address offset: 0x3C */
__IO uint32_t DR; /*!< ADC regular data register, Address offset: 0x40 */
uint32_t RESERVED3; /*!< Reserved, 0x044 */
uint32_t RESERVED4; /*!< Reserved, 0x048 */
__IO uint32_t JSQR; /*!< ADC injected sequence register, Address offset: 0x4C */
uint32_t RESERVED5[4]; /*!< Reserved, 0x050 - 0x05C */
__IO uint32_t OFR1; /*!< ADC offset register 1, Address offset: 0x60 */
__IO uint32_t OFR2; /*!< ADC offset register 2, Address offset: 0x64 */
__IO uint32_t OFR3; /*!< ADC offset register 3, Address offset: 0x68 */
__IO uint32_t OFR4; /*!< ADC offset register 4, Address offset: 0x6C */
uint32_t RESERVED6[4]; /*!< Reserved, 0x070 - 0x07C */
__IO uint32_t JDR1; /*!< ADC injected data register 1, Address offset: 0x80 */
__IO uint32_t JDR2; /*!< ADC injected data register 2, Address offset: 0x84 */
__IO uint32_t JDR3; /*!< ADC injected data register 3, Address offset: 0x88 */
__IO uint32_t JDR4; /*!< ADC injected data register 4, Address offset: 0x8C */
uint32_t RESERVED7[4]; /*!< Reserved, 0x090 - 0x09C */
__IO uint32_t AWD2CR; /*!< ADC Analog Watchdog 2 Configuration Register, Address offset: 0xA0 */
__IO uint32_t AWD3CR; /*!< ADC Analog Watchdog 3 Configuration Register, Address offset: 0xA4 */
uint32_t RESERVED8; /*!< Reserved, 0x0A8 */
uint32_t RESERVED9; /*!< Reserved, 0x0AC */
__IO uint32_t LTR2; /*!< ADC watchdog Lower threshold register 2, Address offset: 0xB0 */
__IO uint32_t HTR2; /*!< ADC watchdog Higher threshold register 2, Address offset: 0xB4 */
__IO uint32_t LTR3; /*!< ADC watchdog Lower threshold register 3, Address offset: 0xB8 */
__IO uint32_t HTR3; /*!< ADC watchdog Higher threshold register 3, Address offset: 0xBC */
__IO uint32_t DIFSEL; /*!< ADC Differential Mode Selection Register, Address offset: 0xC0 */
__IO uint32_t CALFACT; /*!< ADC Calibration Factors, Address offset: 0xC4 */
__IO uint32_t CALFACT2; /*!< ADC Linearity Calibration Factors, Address offset: 0xC8 */
} ADC_TypeDef;
typedef struct
{
__IO uint32_t CSR; /*!< ADC Common status register, Address offset: ADC1/3 base address + 0x300 */
uint32_t RESERVED; /*!< Reserved, ADC1/3 base address + 0x304 */
__IO uint32_t CCR; /*!< ADC common control register, Address offset: ADC1/3 base address + 0x308 */
__IO uint32_t CDR; /*!< ADC common regular data register for dual Address offset: ADC1/3 base address+0x30C */
__IO uint32_t CDR2; /*!< ADC common regular data register for 32-bit dual mode Address offset: ADC1/3 base address + 0x310 */
} ADC_Common_TypeDef;
__IO表示volatile, 这是标准C语言中的一个修饰字,表示这个变量是非易失性的,编译器不要将其优化掉。core_m7.h 文件定义了这个宏:
#define __O volatile /*!< Defines 'write only' permissions */
#define __IO volatile /*!< Defines 'read / write' permissions */
结构体变量ADC_TypeDef用于ADC1,ADC2和ADC3,每个ADC都有一组。结构体变量ADC_Common_TypeDef是公共寄存器,ADC1和ADC2共用一组,而ADC3单独用一组。
下面我们再看ADC1,ADC2和ADC3以及公共寄存器的定义,在stm32h743xx.h文件。
#define PERIPH_BASE ((uint32_t)0x40000000)
#define D2_AHB1PERIPH_BASE (PERIPH_BASE + 0x00020000)
#define D3_AHB1PERIPH_BASE (PERIPH_BASE + 0x18020000)
#define ADC1_BASE (D2_AHB1PERIPH_BASE + 0x2000)
#define ADC2_BASE (D2_AHB1PERIPH_BASE + 0x2100)
#define ADC12_COMMON_BASE (D2_AHB1PERIPH_BASE + 0x2300)
#define ADC3_BASE (D3_AHB1PERIPH_BASE + 0x6000)
#define ADC3_COMMON_BASE (D3_AHB1PERIPH_BASE + 0x6300)
#define ADC1 ((ADC_TypeDef *) ADC1_BASE) <----- 展开这个宏,(ADC_TypeDef *) 0x40022000
#define ADC2 ((ADC_TypeDef *) ADC2_BASE)
#define ADC3 ((ADC_TypeDef *) ADC3_BASE)
#define ADC12_COMMON ((ADC_Common_TypeDef *) ADC12_COMMON_BASE)
#define ADC3_COMMON ((ADC_Common_TypeDef *) ADC3_COMMON_BASE)
我们访问ADC1的ISR寄存器可以采用这种形式:ADC1->ISR = 0;
HAL库在ADC_TypeDef的基础上封装了一个结构体ADC_HandleTypeDef,定义如下:
typedef struct
{
ADC_TypeDef *Instance;
ADC_InitTypeDef Init;
DMA_HandleTypeDef *DMA_Handle;
HAL_LockTypeDef Lock;
__IO uint32_t State;
__IO uint32_t ErrorCode;
ADC_InjectionConfigTypeDef InjectionConfig ;
}ADC_HandleTypeDef;
下面将这几个参数逐一做个说明。
这个参数是寄存器的例化,方便操作寄存器,比如使能ADC内部稳压器。
SET_BIT(hadc->Instance->CR, ADC_CR_ADVREGEN);
这个参数是用户接触最多的,用于配置ADC的基本参数,像ADC时钟、分辨率、扫描模式、过采样等。ADC_InitTypeDef结构体的定义如下:
typedef struct
{
uint32_t ClockPrescaler;
uint32_t Resolution;
uint32_t ScanConvMode;
uint32_t EOCSelection;
FunctionalState LowPowerAutoWait;
FunctionalState ContinuousConvMode;
uint32_t NbrOfConversion;
FunctionalState DiscontinuousConvMode;
uint32_t NbrOfDiscConversion;
uint32_t ExternalTrigConv;
uint32_t ExternalTrigConvEdge;
uint32_t ConversionDataManagement;
uint32_t Overrun;
uint32_t LeftBitShift;
FunctionalState BoostMode;
FunctionalState OversamplingMode;
ADC_OversamplingTypeDef Oversampling;
}ADC_InitTypeDef;
具体每个成员的含义在本章3.3小节有说明。
如果ADC使用DMA模式的话,此参数用于关联DMA的句柄,方便DMA的配置。
__IO uint32_t State;
__IO uint32_t ErrorCode
这三个变量主要供函数内部使用。Lock用于设置锁状态,State用于设置ADC通信状态,而ErrorCode用于配置代码错误。
用于配置ADC注入模式。
参数初始化结构体ADC _InitTypeDef要注意的事项比较多,所以专门开一个小节单独说明。
跟寄存器结构体ADC_TypeDef一样,参数初始化结构体ADC_InitTypeDef也是封装在了ADC的句柄结构体ADC_HandleTypeDef里面,定义如下:
typedef struct
{
uint32_t ClockPrescaler;
uint32_t Resolution;
uint32_t ScanConvMode;
uint32_t EOCSelection;
FunctionalState LowPowerAutoWait;
FunctionalState ContinuousConvMode;
uint32_t NbrOfConversion;
FunctionalState DiscontinuousConvMode;
uint32_t NbrOfDiscConversion;
uint32_t ExternalTrigConv;
uint32_t ExternalTrigConvEdge;
uint32_t ConversionDataManagement;
uint32_t Overrun;
uint32_t LeftBitShift;
FunctionalState BoostMode;
FunctionalState OversamplingMode;
ADC_OversamplingTypeDef Oversampling;
}ADC_InitTypeDef;
下面将这几个参数逐一做说明:
ClockPrescaler
用于ADC的时钟分频设置,ADC有两种时钟源可供选择,可以使用来自AHB总线的系统时钟(属于同步时钟),也可以使用PLL2,PLL3,HSE,HSI或者CSI时钟(属于异步时钟)。
有以下几种参数可供选择:
/** @defgroup ADC_ClockPrescaler ADC clock source and clock prescaler
* @{
*/
#define ADC_CLOCK_SYNC_PCLK_DIV1 ((uint32_t)ADC_CCR_CKMODE_0)
#define ADC_CLOCK_SYNC_PCLK_DIV2 ((uint32_t)ADC_CCR_CKMODE_1)
#define ADC_CLOCK_SYNC_PCLK_DIV4 ((uint32_t)ADC_CCR_CKMODE)
#define ADC_CLOCKPRESCALER_PCLK_DIV1 ADC_CLOCK_SYNC_PCLK_DIV1 /* 这三个仅仅是为了兼容,已经不推荐使用 */
#define ADC_CLOCKPRESCALER_PCLK_DIV2 ADC_CLOCK_SYNC_PCLK_DIV2
#define ADC_CLOCKPRESCALER_PCLK_DIV4 ADC_CLOCK_SYNC_PCLK_DIV4
#define ADC_CLOCK_ASYNC_DIV1 ((uint32_t)0x00000000)
#define ADC_CLOCK_ASYNC_DIV2 ((uint32_t)ADC_CCR_PRESC_0)
#define ADC_CLOCK_ASYNC_DIV4 ((uint32_t)ADC_CCR_PRESC_1)
#define ADC_CLOCK_ASYNC_DIV6 ((uint32_t)(ADC_CCR_PRESC_1|ADC_CCR_PRESC_0))
#define ADC_CLOCK_ASYNC_DIV8 ((uint32_t)(ADC_CCR_PRESC_2))
#define ADC_CLOCK_ASYNC_DIV10 ((uint32_t)(ADC_CCR_PRESC_2|ADC_CCR_PRESC_0))
#define ADC_CLOCK_ASYNC_DIV12 ((uint32_t)(ADC_CCR_PRESC_2|ADC_CCR_PRESC_1))
#define ADC_CLOCK_ASYNC_DIV16 ((uint32_t)(ADC_CCR_PRESC_2|ADC_CCR_PRESC_1|ADC_CCR_PRESC_0))
#define ADC_CLOCK_ASYNC_DIV32 ((uint32_t)(ADC_CCR_PRESC_3))
#define ADC_CLOCK_ASYNC_DIV64 ((uint32_t)(ADC_CCR_PRESC_3|ADC_CCR_PRESC_0))
#define ADC_CLOCK_ASYNC_DIV128 ((uint32_t)(ADC_CCR_PRESC_3|ADC_CCR_PRESC_1))
#define ADC_CLOCK_ASYNC_DIV256 ((uint32_t)(ADC_CCR_PRESC_3|ADC_CCR_PRESC_1|ADC_CCR_PRESC_0))
Resolution
用于ADC的分辨率配置,支持如下几种:
/** @defgroup ADC_Resolution ADC Resolution
* @{
*/
#define ADC_RESOLUTION_16B ((uint32_t)0x00000000)
#define ADC_RESOLUTION_14B ((uint32_t)ADC_CFGR_RES_0)
#define ADC_RESOLUTION_12B ((uint32_t)ADC_CFGR_RES_1)
#define ADC_RESOLUTION_10B ((uint32_t)(ADC_CFGR_RES_1 | ADC_CFGR_RES_0))
#define ADC_RESOLUTION_8B ((uint32_t)ADC_CFGR_RES_2)
ScanConvMode
用于使能或者禁止ADC的扫描模式,即多通道转换。此参数配合成员DiscontinuousConvMode可以将主转换序列分成多个子系列进行逐步转换。
支持的参数如下:
#define ADC_SCAN_DISABLE ((uint32_t)0x00000000)
#define ADC_SCAN_ENABLE ((uint32_t)0x00000001)
EOCSelection
用于中断或者查询模式时,转换结束标志EOC (End Of Conversion)的选择。参数可以单通道转换结束或者序列转换结束:
#define ADC_EOC_SINGLE_CONV ((uint32_t) ADC_ISR_EOC) /*!< End of unitary conversion flag */
#define ADC_EOC_SEQ_CONV ((uint32_t) ADC_ISR_EOS) /*!< End of sequence conversions flag */
LowPowerAutoWait
用于使能或者禁止低功耗自动延迟等待模式。仅当用户调用函数HAL_ADC_GetValue()获取规则通道数据或者调用函数HAL_ADCEx_InjectedGetValue()获取注入通道数据后才会开启下一次ADC转换。
参数可以是使能ENABLE或者禁能DISABLE。
ContinuousConvMode
用于配置使用单次转换还是连续转换,此参数仅对规则通道有效。触发方式可以选择软件触发或者外部触发。
参数可以是使能ENABLE,表示连续转换或者DISABLE禁能,表示单次转换。
NbrOfConversion
用于配置规则通道要转换的通道数。
DiscontinuousConvMode
用于配置ADC规则组转换序列的不连续方式。这里的不连续含义是指每次触发进行一个子组的转换。注意跟参数成员ContinuousConvMode的含义区分开。
使用此参数要注意以下两点:
参数可以是使能ENABLE或者禁止DISABLE。
NbrOfDiscConversion
使能了参数DiscontinuousConvMode的情况下,用于设置子组的大小。
ExternalTrigConv
用于规则通道外部触发源的选择。如果使能了软件触发,那么外部触发将被关闭,使用软件触发。ADC1,ADC2和ADC3支持的触发源是相同的。具体支持的触发源参数如下:
/** @defgroup ADC_regular_external_trigger_source ADC group regular trigger source
* @{
*/
/* External triggers of regular group for ADC1, ADC2, ADC3 */
#define ADC_EXTERNALTRIG_T1_CC1 ((uint32_t)0x00000000)
#define ADC_EXTERNALTRIG_T1_CC2 ((uint32_t)ADC_CFGR_EXTSEL_0)
#define ADC_EXTERNALTRIG_T1_CC3 ((uint32_t)ADC_CFGR_EXTSEL_1)
#define ADC_EXTERNALTRIG_T2_CC2 ((uint32_t)(ADC_CFGR_EXTSEL_1 | ADC_CFGR_EXTSEL_0))
#define ADC_EXTERNALTRIG_T3_TRGO ((uint32_t)ADC_CFGR_EXTSEL_2)
#define ADC_EXTERNALTRIG_T4_CC4 ((uint32_t)(ADC_CFGR_EXTSEL_2 | ADC_CFGR_EXTSEL_0))
#define ADC_EXTERNALTRIG_EXT_IT11 ((uint32_t)(ADC_CFGR_EXTSEL_2 | ADC_CFGR_EXTSEL_1))
#define ADC_EXTERNALTRIG_T8_TRGO ((uint32_t)(ADC_CFGR_EXTSEL_2 | ADC_CFGR_EXTSEL_1 |
ADC_CFGR_EXTSEL_0))
#define ADC_EXTERNALTRIG_T8_TRGO2 ((uint32_t) ADC_CFGR_EXTSEL_3)
#define ADC_EXTERNALTRIG_T1_TRGO ((uint32_t)(ADC_CFGR_EXTSEL_3 | ADC_CFGR_EXTSEL_0))
#define ADC_EXTERNALTRIG_T1_TRGO2 ((uint32_t)(ADC_CFGR_EXTSEL_3 | ADC_CFGR_EXTSEL_1))
#define ADC_EXTERNALTRIG_T2_TRGO ((uint32_t)(ADC_CFGR_EXTSEL_3 | ADC_CFGR_EXTSEL_1 |
ADC_CFGR_EXTSEL_0))
#define ADC_EXTERNALTRIG_T4_TRGO ((uint32_t)(ADC_CFGR_EXTSEL_3 | ADC_CFGR_EXTSEL_2))
#define ADC_EXTERNALTRIG_T6_TRGO ((uint32_t)(ADC_CFGR_EXTSEL_3 | ADC_CFGR_EXTSEL_2 |
ADC_CFGR_EXTSEL_0))
#define ADC_EXTERNALTRIG_T15_TRGO ((uint32_t)(ADC_CFGR_EXTSEL_3 | ADC_CFGR_EXTSEL_2 |
ADC_CFGR_EXTSEL_1))
#define ADC_EXTERNALTRIG_T3_CC4 ((uint32_t)(ADC_CFGR_EXTSEL_3 | ADC_CFGR_EXTSEL_2 |
ADC_CFGR_EXTSEL_1 | ADC_CFGR_EXTSEL_0))
#define ADC_EXTERNALTRIG_HR1_ADCTRG1 ((uint32_t) ADC_CFGR_EXTSEL_4)
#define ADC_EXTERNALTRIG_HR1_ADCTRG3 ((uint32_t) (ADC_CFGR_EXTSEL_4 | ADC_CFGR_EXTSEL_0))
#define ADC_EXTERNALTRIG_LPTIM1_OUT ((uint32_t) (ADC_CFGR_EXTSEL_4 | ADC_CFGR_EXTSEL_1))
#define ADC_EXTERNALTRIG_LPTIM2_OUT ((uint32_t) (ADC_CFGR_EXTSEL_4 | ADC_CFGR_EXTSEL_1| ADC_CFGR_EXTSEL_0))
#define ADC_EXTERNALTRIG_LPTIM3_OUT ((uint32_t) (ADC_CFGR_EXTSEL_4 | ADC_CFGR_EXTSEL_2))
ExternalTrigConvEdge
如果使用外部触发的话,设置触发沿类型,支持上升沿、下降沿或者双沿触发。
#define ADC_EXTERNALTRIGCONVEDGE_NONE ((uint32_t)0x00000000)
#define ADC_EXTERNALTRIGCONVEDGE_RISING ((uint32_t)ADC_CFGR_EXTEN_0)
#define ADC_EXTERNALTRIGCONVEDGE_FALLING ((uint32_t)ADC_CFGR_EXTEN_1)
#define ADC_EXTERNALTRIGCONVEDGE_RISINGFALLING ((uint32_t)ADC_CFGR_EXTEN)
注意,如果使能了软件触发,那么外部触发将被关闭,使用软件触发,此参数已经不起作用。
ConversionDataManagement
此参数成员用于ADC采集数据的管理,可以存到ADC的DR寄存器,传输给DFSDM,又或者通过DMA的单次或者循环模式传输数据到指定地址。
/** @defgroup ADC_ConversionDataManagement ADC Conversion Data Management
* @{
*/
#define ADC_CONVERSIONDATA_DR ((uint32_t)0x00000000)
#define ADC_CONVERSIONDATA_DFSDM ((uint32_t)ADC_CFGR_DMNGT_1)
#define ADC_CONVERSIONDATA_DMA_ONESHOT ((uint32_t)ADC_CFGR_DMNGT_0)
#define ADC_CONVERSIONDATA_DMA_CIRCULAR ((uint32_t)(ADC_CFGR_DMNGT_0 | ADC_CFGR_DMNGT_1))
使用此参数成员注意以下问题:
Overrun
用于配置ADC转换数据未及时读取,造成溢出时的处理,可以选择继续保留上次转换的数据,也可以选择新转换的数据覆盖,具体支持的参数如下:
#define ADC_OVR_DATA_PRESERVED ((uint32_t)0x00000000)
#define ADC_OVR_DATA_OVERWRITTEN ((uint32_t)ADC_CFGR_OVRMOD)
使用此参数成员注意以下问题:
此参数仅可用于规则通道。
LeftBitShift
用于设置ADC转换结果的左移位数,使用或者没有使用过采样的情况下,都可以使用此参数。
具体支持的参数如下:
#define ADC_LEFTBITSHIFT_NONE ((uint32_t)0x00000000)
#define ADC_LEFTBITSHIFT_1 ((uint32_t)ADC_CFGR2_LSHIFT_0)
#define ADC_LEFTBITSHIFT_2 ((uint32_t)ADC_CFGR2_LSHIFT_1)
#define ADC_LEFTBITSHIFT_3 ((uint32_t)(ADC_CFGR2_LSHIFT_1 | ADC_CFGR2_LSHIFT_0))
#define ADC_LEFTBITSHIFT_4 ((uint32_t)ADC_CFGR2_LSHIFT_2)
#define ADC_LEFTBITSHIFT_5 ((uint32_t)(ADC_CFGR2_LSHIFT_2 | ADC_CFGR2_LSHIFT_0))
#define ADC_LEFTBITSHIFT_6 ((uint32_t)(ADC_CFGR2_LSHIFT_2 | ADC_CFGR2_LSHIFT_1))
#define ADC_LEFTBITSHIFT_7 ((uint32_t)(ADC_CFGR2_LSHIFT_2 | ADC_CFGR2_LSHIFT_1 | ADC_CFGR2_LSHIFT_0))
#define ADC_LEFTBITSHIFT_8 ((uint32_t)ADC_CFGR2_LSHIFT_3)
#define ADC_LEFTBITSHIFT_9 ((uint32_t)(ADC_CFGR2_LSHIFT_3 | ADC_CFGR2_LSHIFT_0))
#define ADC_LEFTBITSHIFT_10 ((uint32_t)(ADC_CFGR2_LSHIFT_3 | ADC_CFGR2_LSHIFT_1))
#define ADC_LEFTBITSHIFT_11 ((uint32_t)(ADC_CFGR2_LSHIFT_3 | ADC_CFGR2_LSHIFT_1 | ADC_CFGR2_LSHIFT_0))
#define ADC_LEFTBITSHIFT_12 ((uint32_t)(ADC_CFGR2_LSHIFT_3 | ADC_CFGR2_LSHIFT_2))
#define ADC_LEFTBITSHIFT_13 ((uint32_t)(ADC_CFGR2_LSHIFT_3 | ADC_CFGR2_LSHIFT_2 | ADC_CFGR2_LSHIFT_0))
#define ADC_LEFTBITSHIFT_14 ((uint32_t)(ADC_CFGR2_LSHIFT_3 | ADC_CFGR2_LSHIFT_2 | ADC_CFGR2_LSHIFT_1))
#define ADC_LEFTBITSHIFT_15 ((uint32_t)(ADC_CFGR2_LSHIFT_3 | ADC_CFGR2_LSHIFT_2 | ADC_CFGR2_LSHIFT_1 |
ADC_CFGR2_LSHIFT_0))
BoostMode
用于设置ADC的BOOST模式,当ADC的时钟高于20MHz时,必须使能此位。
参数可以是使能ENABLE或者禁止DISABLE。
OversamplingMode
此参数成员用于使能或者禁止过采样模式。只有当ADC规则通道或者注入通道没有数据转换时才可以修改此参数。
参数可以是使能ENABLE或者禁止DISABLE。
Oversampling
此参数是ADC_OversamplingTypeDef类型结构体变量,用于设置过采样的相关参数。
结构体变量ADC_ChannelConfTypeDef用于配置ADC规则通道的一些特性,定义如下:
typedef struct
{
uint32_t Channel;
uint32_t Rank;
uint32_t SamplingTime;
uint32_t SingleDiff;
uint32_t OffsetNumber;
uint32_t Offset;
FunctionalState OffsetRightShift;
FunctionalState OffsetSignedSaturation;
}ADC_ChannelConfTypeDef;
下面将这几个参数逐一做说明:
Channel
具体支持的通道参数如下:
/** @defgroup ADC_channels ADC Channels
* @{
*/
#define ADC_CHANNEL_0 ((uint32_t)(0x00000000))
#define ADC_CHANNEL_1 ((uint32_t)(ADC_SQR3_SQ10_0))
#define ADC_CHANNEL_2 ((uint32_t)(ADC_SQR3_SQ10_1))
#define ADC_CHANNEL_3 ((uint32_t)(ADC_SQR3_SQ10_1 | ADC_SQR3_SQ10_0))
#define ADC_CHANNEL_4 ((uint32_t)(ADC_SQR3_SQ10_2))
#define ADC_CHANNEL_5 ((uint32_t)(ADC_SQR3_SQ10_2 | ADC_SQR3_SQ10_0))
#define ADC_CHANNEL_6 ((uint32_t)(ADC_SQR3_SQ10_2 | ADC_SQR3_SQ10_1))
#define ADC_CHANNEL_7 ((uint32_t)(ADC_SQR3_SQ10_2 | ADC_SQR3_SQ10_1 | ADC_SQR3_SQ10_0))
#define ADC_CHANNEL_8 ((uint32_t)(ADC_SQR3_SQ10_3))
#define ADC_CHANNEL_9 ((uint32_t)(ADC_SQR3_SQ10_3 | ADC_SQR3_SQ10_0))
#define ADC_CHANNEL_10 ((uint32_t)(ADC_SQR3_SQ10_3 | ADC_SQR3_SQ10_1))
#define ADC_CHANNEL_11 ((uint32_t)(ADC_SQR3_SQ10_3 | ADC_SQR3_SQ10_1 | ADC_SQR3_SQ10_0))
#define ADC_CHANNEL_12 ((uint32_t)(ADC_SQR3_SQ10_3 | ADC_SQR3_SQ10_2))
#define ADC_CHANNEL_13 ((uint32_t)(ADC_SQR3_SQ10_3 | ADC_SQR3_SQ10_2 | ADC_SQR3_SQ10_0))
#define ADC_CHANNEL_14 ((uint32_t)(ADC_SQR3_SQ10_3 | ADC_SQR3_SQ10_2 | ADC_SQR3_SQ10_1))
#define ADC_CHANNEL_15 ((uint32_t)(ADC_SQR3_SQ10_3 | ADC_SQR3_SQ10_2 | ADC_SQR3_SQ10_1 | ADC_SQR3_SQ10_0))
#define ADC_CHANNEL_16 ((uint32_t)(ADC_SQR3_SQ10_4))
#define ADC_CHANNEL_17 ((uint32_t)(ADC_SQR3_SQ10_4 | ADC_SQR3_SQ10_0))
#define ADC_CHANNEL_18 ((uint32_t)(ADC_SQR3_SQ10_4 | ADC_SQR3_SQ10_1))
#define ADC_CHANNEL_19 ((uint32_t)(ADC_SQR3_SQ10_4 | ADC_SQR3_SQ10_1| ADC_SQR3_SQ10_0))
/* Note: Vbat/4, TempSensor and VREFINT internal channels are available on ADC3 only */
#define ADC_CHANNEL_VBAT_DIV4 ADC_CHANNEL_17
#define ADC_CHANNEL_TEMPSENSOR ADC_CHANNEL_18
#define ADC_CHANNEL_VREFINT ADC_CHANNEL_19
/* Note: DAC1CH1 and DAC1CH2 internal channels is available on ADC2 only */
/*!< ADC internal channel connected to DAC1 channel 1, channel specific to ADC2 */
#define ADC_CHANNEL_DAC1CH1_ADC2 (ADC_CHANNEL_16)
/*!< ADC internal channel connected to DAC1 channel 2, channel specific to ADC2 */
#define ADC_CHANNEL_DAC1CH2_ADC2 (ADC_CHANNEL_17)
这里要特别注意:
Rank
用于配置规则通道的转换顺序,如果想禁止一个通道或者改变一个通道的顺序,可以使用新配置覆盖。
具体支持的参数如下:
/** @defgroup ADC_regular_rank ADC group regular sequencer rank
* @{
*/
#define ADC_REGULAR_RANK_1 ((uint32_t)0x00000001) /*!< ADC regular conversion rank 1 */
#define ADC_REGULAR_RANK_2 ((uint32_t)0x00000002) /*!< ADC regular conversion rank 2 */
#define ADC_REGULAR_RANK_3 ((uint32_t)0x00000003) /*!< ADC regular conversion rank 3 */
#define ADC_REGULAR_RANK_4 ((uint32_t)0x00000004) /*!< ADC regular conversion rank 4 */
#define ADC_REGULAR_RANK_5 ((uint32_t)0x00000005) /*!< ADC regular conversion rank 5 */
#define ADC_REGULAR_RANK_6 ((uint32_t)0x00000006) /*!< ADC regular conversion rank 6 */
#define ADC_REGULAR_RANK_7 ((uint32_t)0x00000007) /*!< ADC regular conversion rank 7 */
#define ADC_REGULAR_RANK_8 ((uint32_t)0x00000008) /*!< ADC regular conversion rank 8 */
#define ADC_REGULAR_RANK_9 ((uint32_t)0x00000009) /*!< ADC regular conversion rank 9 */
#define ADC_REGULAR_RANK_10 ((uint32_t)0x0000000A) /*!< ADC regular conversion rank 10 */
#define ADC_REGULAR_RANK_11 ((uint32_t)0x0000000B) /*!< ADC regular conversion rank 11 */
#define ADC_REGULAR_RANK_12 ((uint32_t)0x0000000C) /*!< ADC regular conversion rank 12 */
#define ADC_REGULAR_RANK_13 ((uint32_t)0x0000000D) /*!< ADC regular conversion rank 13 */
#define ADC_REGULAR_RANK_14 ((uint32_t)0x0000000E) /*!< ADC regular conversion rank 14 */
#define ADC_REGULAR_RANK_15 ((uint32_t)0x0000000F) /*!< ADC regular conversion rank 15 */
#define ADC_REGULAR_RANK_16 ((uint32_t)0x00000010) /*!< ADC regular conversion rank 16 */
SamplingTime
用于所选通道的采样时间配置,ADC的采样速度是由采样时间和转换时间同决定。用于内部通道测量时(VrefInt/Vbat/TempSensor),务必要遵循数据手册要求的参数范围。此参数成员具体支持的定义如下:
/** @defgroup ADC_sampling_times ADC Sampling Times
* @{
*/
#define ADC_SAMPLETIME_1CYCLE_5 ((uint32_t)0x00000000)
#define ADC_SAMPLETIME_2CYCLES_5 ((uint32_t)ADC_SMPR2_SMP10_0)
#define ADC_SAMPLETIME_8CYCLES_5 ((uint32_t)ADC_SMPR2_SMP10_1)
#define ADC_SAMPLETIME_16CYCLES_5 ((uint32_t)(ADC_SMPR2_SMP10_1 | ADC_SMPR2_SMP10_0))
#define ADC_SAMPLETIME_32CYCLES_5 ((uint32_t)ADC_SMPR2_SMP10_2)
#define ADC_SAMPLETIME_64CYCLES_5 ((uint32_t)(ADC_SMPR2_SMP10_2 | ADC_SMPR2_SMP10_0))
#define ADC_SAMPLETIME_387CYCLES_5 ((uint32_t)(ADC_SMPR2_SMP10_2 | ADC_SMPR2_SMP10_1))
#define ADC_SAMPLETIME_810CYCLES_5 ((uint32_t)ADC_SMPR2_SMP10)
SingleDiff
此参数成员用于选择单端输入还是差分输入。差分输入要用到输入通道i(正向输入)和i+1反向输入,用户仅需配置通道i即可,通道i+1会被自动配置。具体支持的定义如下:
/** @defgroup ADCEx_SingleDifferential ADC Extended Single-ended/Differential input mode
* @{
*/
#define ADC_SINGLE_ENDED ((uint32_t)0x00000000)
#define ADC_DIFFERENTIAL_ENDED ((uint32_t)ADC_CR_ADCALDIF)
使用此参数要注意以下问题:
OffsetNumber
此参数成员用于选择偏移序号Offset Number,具体支持的参数定义如下:
/** @defgroup ADCEx_OffsetNumber ADC Extended Offset Number
* @{
*/
#define ADC_OFFSET_NONE ((uint32_t)0x00) /*!< No offset correction */
#define ADC_OFFSET_1 ((uint32_t)0x01) /*!< Offset correction to apply to a first channel */
#define ADC_OFFSET_2 ((uint32_t)0x02) /*!< Offset correction to apply to a second channel */
#define ADC_OFFSET_3 ((uint32_t)0x03) /*!< Offset correction to apply to a third channel */
#define ADC_OFFSET_4 ((uint32_t)0x04) /*!< Offset correction to apply to a fourth channel */
注意,每个通道仅支持一个偏移设置。
Offset
定义要从原始数据中减去的偏移量。
OffsetRightShift
此参数成员用于选择是否使能偏移校准后数据右移,仅适用于16bit或者8bit分辨率。
支持的参数可以是使能ENABLE或者禁止DISABLE。
OffsetSignedSaturation
此参数成员用于选择是否使能有符号饱和特性,仅适用于16bit或者8bit分辨率。
支持的参数可以是使能ENABLE或者禁止DISABLE。
结构体ADC_OversamplingTypeDef主要用于过采样方面参数配置,定义如下:
typedef struct
{
uint32_t Ratio;
uint32_t RightBitShift;
uint32_t TriggeredMode;
uint32_t OversamplingStopReset;
}ADC_OversamplingTypeDef;
下面将这几个参数逐一做说明:
Ratio
此参数成员用于配置过采样率。
RightBitShift
此参数用于设置右移,即分频因数。具体支持的参数如下:
/** @defgroup ADCEx_Right_Bit_Shift ADC Extended Oversampling Right Shift
* @{
*/
#define ADC_RIGHTBITSHIFT_NONE ((uint32_t)0x00000000)
#define ADC_RIGHTBITSHIFT_1 ((uint32_t)ADC_CFGR2_OVSS_0)
#define ADC_RIGHTBITSHIFT_2 ((uint32_t)ADC_CFGR2_OVSS_1)
#define ADC_RIGHTBITSHIFT_3 ((uint32_t)(ADC_CFGR2_OVSS_1 | ADC_CFGR2_OVSS_0))
#define ADC_RIGHTBITSHIFT_4 ((uint32_t)ADC_CFGR2_OVSS_2)
#define ADC_RIGHTBITSHIFT_5 ((uint32_t)(ADC_CFGR2_OVSS_2 | ADC_CFGR2_OVSS_0))
#define ADC_RIGHTBITSHIFT_6 ((uint32_t)(ADC_CFGR2_OVSS_2 | ADC_CFGR2_OVSS_1))
#define ADC_RIGHTBITSHIFT_7 ((uint32_t)(ADC_CFGR2_OVSS_2 | ADC_CFGR2_OVSS_1 | ADC_CFGR2_OVSS_0))
#define ADC_RIGHTBITSHIFT_8 ((uint32_t)ADC_CFGR2_OVSS_3)
#define ADC_RIGHTBITSHIFT_9 ((uint32_t)(ADC_CFGR2_OVSS_3 | ADC_CFGR2_OVSS_0))
#define ADC_RIGHTBITSHIFT_10 ((uint32_t)(ADC_CFGR2_OVSS_3 | ADC_CFGR2_OVSS_1))
#define ADC_RIGHTBITSHIFT_11 ((uint32_t)(ADC_CFGR2_OVSS_3 | ADC_CFGR2_OVSS_1 | ADC_CFGR2_OVSS_0))
TriggeredMode
此参数成员用于过采样的触发模式配置,具体支持的定义如下:
/** @defgroup ADCEx_Triggered_Oversampling_Mode ADC Extended Triggered Regular Oversampling
* @{
*/
#define ADC_TRIGGEREDMODE_SINGLE_TRIGGER ((uint32_t)0x00000000)
#define ADC_TRIGGEREDMODE_MULTI_TRIGGER ((uint32_t)ADC_CFGR2_TROVS)
OversamplingStopReset
此参数成员用于配置使用注入通道时,过采样的处理。可以选择保持原有过采样缓冲数据,或者缓冲数据清零。具体支持的定义如下:
/** @defgroup ADCEx_Regular_Oversampling_Mode ADC Extended Regular Oversampling Continued or Resumed Mode
* @{
*/
/*!< Oversampling buffer maintained during injection sequence */
#define ADC_REGOVERSAMPLING_CONTINUED_MODE ((uint32_t)0x00000000)
/*!< Oversampling buffer zeroed during injection sequence */
#define ADC_REGOVERSAMPLING_RESUMED_MODE ((uint32_t)ADC_CFGR2_ROVSM)
注意,如果规则通道和注入通道同时使用过采样,此参数成员的配置将被忽略,强制设置为ADC_REGOVERSAMPLING_RESUMED_MODE。
结构体ADC_AnalogWDGConfTypeDef主要用于模拟看门狗参数配置,ADC1,ADC2和ADC3都有三个模拟看门狗,结构体定义如下:
typedef struct
{
uint32_t WatchdogNumber;
uint32_t WatchdogMode;
uint32_t Channel;
FunctionalState ITMode;
uint32_t HighThreshold;
uint32_t LowThreshold;
}ADC_AnalogWDGConfTypeDef;
下面将这几个参数逐一做说明:
WatchdogNumber
此参数成员用于配置选择那个看门狗监测通道。
具体支持的定义如下:
/** @defgroup ADCEx_analog_watchdog_number ADC Extended Analog Watchdog Selection
* @{
*/
#define ADC_ANALOGWATCHDOG_1 ((uint32_t)0x00000001)
#define ADC_ANALOGWATCHDOG_2 ((uint32_t)0x00000002)
#define ADC_ANALOGWATCHDOG_3 ((uint32_t)0x00000003)
WatchdogMode
此参数用于设置模拟看门狗模式。
此参数具体支持的定义如下:
/** @defgroup ADCEx_analog_watchdog_mode ADC Extended Analog Watchdog Mode
* @{
*/
#define ADC_ANALOGWATCHDOG_NONE ((uint32_t) 0x00000000)
#define ADC_ANALOGWATCHDOG_SINGLE_REG ((uint32_t)(ADC_CFGR_AWD1SGL | ADC_CFGR_AWD1EN))
#define ADC_ANALOGWATCHDOG_SINGLE_INJEC ((uint32_t)(ADC_CFGR_AWD1SGL | ADC_CFGR_JAWD1EN))
#define ADC_ANALOGWATCHDOG_SINGLE_REGINJEC ((uint32_t)(ADC_CFGR_AWD1SGL | ADC_CFGR_AWD1EN |
ADC_CFGR_JAWD1EN))
#define ADC_ANALOGWATCHDOG_ALL_REG ((uint32_t) ADC_CFGR_AWD1EN)
#define ADC_ANALOGWATCHDOG_ALL_INJEC ((uint32_t) ADC_CFGR_JAWD1EN)
#define ADC_ANALOGWATCHDOG_ALL_REGINJEC ((uint32_t)(ADC_CFGR_AWD1EN | ADC_CFGR_JAWD1EN))
Channel
用于配置要监测的通道。
ITMode
用于配置模拟看门狗为中断方式或者查询方式。
配置为ENABEL表示使用中断方式,配置为DISABLE表示查询方式。
HighThreshold
用于配置模拟看门狗高阀值。根据配置的ADC的分辨率16, 14, 12, 10或者8bit,高阀值最小都是0x0000,最大值分别是0xFFFF, 0x3FFF, 0xFFF, 0x3FF 和 0xFF。
LowThreshold
用于配置模拟看门狗低阀值。根据配置的ADC的分辨率16, 14, 12, 10或者8bit,高阀值最小都是0x0000,最大值分别是0xFFFF, 0x3FFF, 0xFFF, 0x3FF 和 0xFF。
下面我们介绍__HAL_ADC_GET_FLAG函数。这个函数用来检查ADC标志位是否被设置。
/**
* @brief Checks whether the specified ADC flag is set or not.
* @param __HANDLE__: ADC handle
* @param __FLAG__: ADC flag to check
* This parameter can be one of the following values:
* @arg ADC_FLAG_RDY ADC Ready (ADRDY) flag
* @arg ADC_FLAG_EOSMP ADC End of Sampling flag
* @arg ADC_FLAG_EOC ADC End of Regular Conversion flag
* @arg ADC_FLAG_EOS ADC End of Regular sequence of Conversions flag
* @arg ADC_FLAG_OVR ADC overrun flag
* @arg ADC_FLAG_JEOC ADC End of Injected Conversion flag
* @arg ADC_FLAG_JEOS ADC End of Injected sequence of Conversions flag
* @arg ADC_FLAG_AWD1 ADC Analog watchdog 1 flag (main analog watchdog)
* @arg ADC_FLAG_AWD2 ADC Analog watchdog 2 flag (additional analog watchdog)
* @arg ADC_FLAG_AWD3 ADC Analog watchdog 3 flag (additional analog watchdog)
* @arg ADC_FLAG_JQOVF ADC Injected Context Queue Overflow flag
* @retval The new state of __FLAG__ (TRUE or FALSE).
*/
#define __HAL_ADC_GET_FLAG(__HANDLE__, __FLAG__) ((((__HANDLE__)->Instance->ISR) & (__FLAG__)) == (__FLAG__))
与标志获取函数__HAL_ADC_GET_FLAG对应的清除函数是__HAL_ADC_CLEAR_FLAG:
/**
* @brief Clear a specified ADC flag
* @param __HANDLE__: ADC handle
* @param __FLAG__: ADC flag to clear
* This parameter can be one of the following values:
* @arg ADC_FLAG_RDY ADC Ready (ADRDY) flag
* @arg ADC_FLAG_EOSMP ADC End of Sampling flag
* @arg ADC_FLAG_EOC ADC End of Regular Conversion flag
* @arg ADC_FLAG_EOS ADC End of Regular sequence of Conversions flag
* @arg ADC_FLAG_OVR ADC overrun flag
* @arg ADC_FLAG_JEOC ADC End of Injected Conversion flag
* @arg ADC_FLAG_JEOS ADC End of Injected sequence of Conversions flag
* @arg ADC_FLAG_AWD1 ADC Analog watchdog 1 flag (main analog watchdog)
* @arg ADC_FLAG_AWD2 ADC Analog watchdog 2 flag (additional analog watchdog)
* @arg ADC_FLAG_AWD3 ADC Analog watchdog 3 flag (additional analog watchdog)
* @arg ADC_FLAG_JQOVF ADC Injected Context Queue Overflow flag
* @note: bit cleared bit by writing 1 (writing 0 has no effect on any bit of register ISR)
* @retval None
*/
#define __HAL_ADC_CLEAR_FLAG(__HANDLE__, __FLAG__) (((__HANDLE__)->Instance->ISR) = (__FLAG__))
清除标志函数所支持的参数跟获取函数是一 一对应的。除了这两个函数,还有ADC的中断开启和中断关闭函数,有时候也要用到。
/**
* @brief Enable an ADC interrupt.
* @param __HANDLE__: ADC handle
* @param __INTERRUPT__: ADC Interrupt to enable
* This parameter can be one of the following values:
* @arg ADC_IT_RDY ADC Ready (ADRDY) interrupt source
* @arg ADC_IT_EOSMP ADC End of Sampling interrupt source
* @arg ADC_IT_EOC ADC End of Regular Conversion interrupt source
* @arg ADC_IT_EOS ADC End of Regular sequence of Conversions interrupt source
* @arg ADC_IT_OVR ADC overrun interrupt source
* @arg ADC_IT_JEOC ADC End of Injected Conversion interrupt source
* @arg ADC_IT_JEOS ADC End of Injected sequence of Conversions interrupt source
* @arg ADC_IT_AWD1 ADC Analog watchdog 1 interrupt source (main analog watchdog)
* @arg ADC_IT_AWD2 ADC Analog watchdog 2 interrupt source (additional analog watchdog)
* @arg ADC_IT_AWD3 ADC Analog watchdog 3 interrupt source (additional analog watchdog)
* @arg ADC_IT_JQOVF ADC Injected Context Queue Overflow interrupt source
* @retval None
*/
#define __HAL_ADC_ENABLE_IT(__HANDLE__, __INTERRUPT__) (((__HANDLE__)->Instance->IER) |= (__INTERRUPT__))
/**
* @brief Disable an ADC interrupt.
* @param __HANDLE__: ADC handle
* @param __INTERRUPT__: ADC Interrupt to disable
* @arg ADC_IT_RDY ADC Ready (ADRDY) interrupt source
* @arg ADC_IT_EOSMP ADC End of Sampling interrupt source
* @arg ADC_IT_EOC ADC End of Regular Conversion interrupt source
* @arg ADC_IT_EOS ADC End of Regular sequence of Conversions interrupt source
* @arg ADC_IT_OVR ADC overrun interrupt source
* @arg ADC_IT_JEOC ADC End of Injected Conversion interrupt source
* @arg ADC_IT_JEOS ADC End of Injected sequence of Conversions interrupt source
* @arg ADC_IT_AWD1 ADC Analog watchdog 1 interrupt source (main analog watchdog)
* @arg ADC_IT_AWD2 ADC Analog watchdog 2 interrupt source (additional analog watchdog)
* @arg ADC_IT_AWD3 ADC Analog watchdog 3 interrupt source (additional analog watchdog)
* @arg ADC_IT_JQOVF ADC Injected Context Queue Overflow interrupt source
* @retval None
*/
#define __HAL_ADC_DISABLE_IT(__HANDLE__, __INTERRUPT__) (((__HANDLE__)->Instance->IER) &= ~(__INTERRUPT__))
注意:操作ADC的寄存器不限制必须要用HAL库提供的API,比如要操作ADC1的寄存器IER,直接调用DMA1->IER操作即可。
使用方法由HAL库提供:
第1步:ADC时钟源选择。
两种时钟源可供选择,可以选择同步时钟,来自AHB;也可以选择异步时钟,来自系统时钟,PLL2或者PLL3的时钟。
比如使用PLL2:
RCC_PeriphClkInitTypeDef RCC_PeriphClkInit;
PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_ADC;
PeriphClkInit.AdcClockSelection = RCC_ADCCLKSOURCE_PLL2;
HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit);
第2步:ADC输入引脚配置。
第3步:ADC中断配置(如果用到的话)。
第4步:ADC使用DMA方式配置(如果用到的话)
第5步:配置ADC,ADC通道和模拟看门狗
第6步:调用函数HAL_ADCEx_Calibration_Start做自动校准。
第7步:ADC数值获取的三种方式。
HAL_ADC_Start()
HAL_ADC_PollForConversion()
HAL_ADC_GetValue()
HAL_ADC_Stop()
HAL_ADC_Start_IT()
HAL_ADC_ConvCpltCallback()
HAL_ADC_GetValue()
HAL_ADC_Stop_IT()
HAL_ADC_Start_DMA()
HAL_ADC_ConvCpltCallback() 和 HAL_ADC_ConvHalfCpltCallback()
HAL_ADC_Stop_DMA()
此文件涉及到的函数比较多,这里把我们几个常用的函数做个说明:
函数原型:
HAL_StatusTypeDef HAL_ADC_Init(ADC_HandleTypeDef* hadc)
{
HAL_StatusTypeDef tmp_hal_status = HAL_OK;
ADC_Common_TypeDef *tmpADC_Common;
uint32_t tmpCFGR = 0;
__IO uint32_t wait_loop_index = 0;
/* 程序中不重要的部分被清除掉,仅留下关键部分做注释 */
/* 检测ADC句柄 */
if(hadc == NULL)
{
return HAL_ERROR;
}
/* 复位状态初始化 */
if (hadc->State == HAL_ADC_STATE_RESET)
{
HAL_ADC_MspInit(hadc);
ADC_CLEAR_ERRORCODE(hadc);
hadc->Lock = HAL_UNLOCKED;
}
/* ADC退出深度掉电模式 */
if (HAL_IS_BIT_SET(hadc->Instance->CR, ADC_CR_DEEPPWD))
{
/* 退出深度掉电模式Exit deep power down mode */
CLEAR_BIT(hadc->Instance->CR, ADC_CR_DEEPPWD);
/* 退出深度掉电模式,一旦ADC稳压器使能,必须重新校准或者应用之前保存的校准值 */
}
if (HAL_IS_BIT_CLR(hadc->Instance->CR, ADC_CR_ADVREGEN))
{
/* 使能ADC内部稳压器 */
SET_BIT(hadc->Instance->CR, ADC_CR_ADVREGEN);
/* 等待ADC稳定 */
wait_loop_index = (ADC_STAB_DELAY_US * (SystemCoreClock / (1000000 * 2)));
while(wait_loop_index != 0)
{
wait_loop_index--;
}
}
/* 检测ADC稳压器是否使能,潜在的时钟稳定会导致使失败 */
if (HAL_IS_BIT_CLR(hadc->Instance->CR, ADC_CR_ADVREGEN))
{
/* 更新ADC状态 */
SET_BIT(hadc->State, HAL_ADC_STATE_ERROR_INTERNAL);
/* 设置内部错误 */
SET_BIT(hadc->ErrorCode, HAL_ADC_ERROR_INTERNAL);
tmp_hal_status = HAL_ERROR;
}
/* 如果ADC之前的配置成功且没有继续进行规则通道的 */
if (HAL_IS_BIT_CLR(hadc->State, HAL_ADC_STATE_ERROR_INTERNAL) &&
(ADC_IS_CONVERSION_ONGOING_REGULAR(hadc) == RESET) )
{
/* Initialize the ADC state */
SET_BIT(hadc->State, HAL_ADC_STATE_BUSY_INTERNAL);
/* 配置ADC的公共参数 */
if((hadc->Instance == ADC1) || (hadc->Instance == ADC2))
{
tmpADC_Common = ADC12_COMMON_REGISTER(hadc);
}
else
{
tmpADC_Common = ADC3_COMMON_REGISTER(hadc);
}
if ((ADC_IS_ENABLE(hadc) == RESET) &&
(ADC_ANY_OTHER_ENABLED(hadc) == RESET) )
{
/* 配置CCR寄存器 */
MODIFY_REG(tmpADC_Common->CCR, ADC_CCR_PRESC|ADC_CCR_CKMODE, hadc->Init.ClockPrescaler);
}
/* 配置ADC参数 */
tmpCFGR = ( ADC_CFGR_CONTINUOUS(hadc->Init.ContinuousConvMode) |
hadc->Init.Overrun |
hadc->Init.Resolution |
ADC_CFGR_REG_DISCONTINUOUS(hadc->Init.DiscontinuousConvMode) );
if (hadc->Init.DiscontinuousConvMode == ENABLE)
{
tmpCFGR |= ADC_CFGR_DISCONTINUOUS_NUM(hadc->Init.NbrOfDiscConversion);
}
/* 注意,如果参数ExternalTrigConvEdge设置为trigger edge none等效于软件启动 */
if ((hadc->Init.ExternalTrigConv != ADC_SOFTWARE_START)
&& (hadc->Init.ExternalTrigConvEdge != ADC_EXTERNALTRIGCONVEDGE_NONE))
{
tmpCFGR |= ( hadc->Init.ExternalTrigConv | hadc->Init.ExternalTrigConvEdge);
}
MODIFY_REG(hadc->Instance->CFGR, ADC_CFGR_FIELDS_1, tmpCFGR);
/* 更新ADC参数 */
if (ADC_IS_CONVERSION_ONGOING_REGULAR_INJECTED(hadc) == RESET)
{
tmpCFGR = ( ADC_CFGR_AUTOWAIT(hadc->Init.LowPowerAutoWait) |
ADC_CFGR_DMACONTREQ(hadc->Init.ConversionDataManagement) );
MODIFY_REG(hadc->Instance->CFGR, ADC_CFGR_FIELDS_2, tmpCFGR);
if (hadc->Init.OversamplingMode == ENABLE)
{
if ((hadc->Init.ExternalTrigConv == ADC_SOFTWARE_START)
|| (hadc->Init.ExternalTrigConvEdge == ADC_EXTERNALTRIGCONVEDGE_NONE))
{
/* 软件启动不能用于多触发,只能单触发 */
assert_param((hadc->Init.Oversampling.TriggeredMode == ADC_TRIGGEREDMODE_SINGLE_TRIGGER));
}
/* 配置过采样 */
MODIFY_REG(hadc->Instance->CFGR2, ADC_CFGR2_FIELDS,
ADC_CFGR2_ROVSE |
(hadc->Init.Oversampling.Ratio << 16) |
hadc->Init.Oversampling.RightBitShift |
hadc->Init.Oversampling.TriggeredMode |
hadc->Init.Oversampling.OversamplingStopReset);
}
else
{
/* 禁止规则通道过采样 */
CLEAR_BIT( hadc->Instance->CFGR2, ADC_CFGR2_ROVSE);
}
/* 设置左移参数 */
MODIFY_REG(hadc->Instance->CFGR2, ADC_CFGR2_LSHIFT, hadc->Init.LeftBitShift);
/* 是否使能BOOST模式 */
if(hadc->Init.BoostMode == ENABLE)
{
SET_BIT(hadc->Instance->CR, ADC_CR_BOOST);
}
else
{
CLEAR_BIT(hadc->Instance->CR, ADC_CR_BOOST);
}
}
/* 配置规则通道 */
if (hadc->Init.ScanConvMode == ADC_SCAN_ENABLE)
{
/* 配置规格通道转换个数 */
MODIFY_REG(hadc->Instance->SQR1, ADC_SQR1_L, (hadc->Init.NbrOfConversion - (uint8_t)1));
}
else
{
CLEAR_BIT(hadc->Instance->SQR1, ADC_SQR1_L);
}
/* 初始ADC就绪状态 */
ADC_STATE_CLR_SET(hadc->State, HAL_ADC_STATE_BUSY_INTERNAL, HAL_ADC_STATE_READY);
}
else
{
/* 设置ADC状态错误 */
SET_BIT(hadc->State, HAL_ADC_STATE_ERROR_INTERNAL);
tmp_hal_status = HAL_ERROR;
}
/* 返回状态 */
return tmp_hal_status;
}
函数描述:
此函数用于初始化ADC1,ADC2或者ADC3。
函数参数:
注意事项:
对于局部变量来说,这个参数就是一个随机值,如果是全局变量还好,一般MDK和IAR都会将全部变量初始化为0,而恰好这个HAL_ADC_STATE_RESET = 0x00U。
解决办法有四
方法1:用户自己初始定时器和涉及到的GPIO等。
方法2:定义ADC_HandleTypeDef AdcHandle为全局变量。
方法3:定义为局部变量要赋初始值ADC_HandleTypeDef AdcHandle = {0}。
方法4:下面的方法:
if(HAL_ADC_DeInit(&AdcHandle)!= HAL_OK)
{
Error_Handler();
}
if(HAL_ADC_Init(&AdcHandle)!= HAL_OK)
{
Error_Handler();
}
使用举例:
ADC_HandleTypeDef AdcHandle = {0};
__HAL_RCC_ADC12_CLK_ENABLE();
AdcHandle.Instance = ADC1;
/* 采用AHB同步时钟,4分频,即200MHz/4 = 50MHz */
AdcHandle.Init.ClockPrescaler = ADC_CLOCK_SYNC_PCLK_DIV4;
AdcHandle.Init.Resolution = ADC_RESOLUTION_16B; /* 16位分辨率 */
AdcHandle.Init.ScanConvMode = ADC_SCAN_DISABLE; /* 禁止扫描,因为仅开了一个通道 */
AdcHandle.Init.EOCSelection = ADC_EOC_SINGLE_CONV; /* EOC转换结束标志 */
AdcHandle.Init.LowPowerAutoWait = DISABLE; /* 禁止低功耗自动延迟特性 */
AdcHandle.Init.ContinuousConvMode = DISABLE; /* 禁止自动转换,采用的定时器触发转换 */
AdcHandle.Init.NbrOfConversion = 1; /* 使用了1个转换通道 */
AdcHandle.Init.DiscontinuousConvMode = DISABLE; /* 禁止不连续模式 */
/* 禁止不连续模式后,此参数忽略,此位是用来配置不连续子组中通道数 */
AdcHandle.Init.NbrOfDiscConversion = 1;
AdcHandle.Init.ExternalTrigConv = ADC_EXTERNALTRIG_T1_CC1; /* 定时器1的CC1触发 */
AdcHandle.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_RISING; /* 上升沿触发 */
AdcHandle.Init.ConversionDataManagement = ADC_CONVERSIONDATA_DMA_CIRCULAR;/*DMA循环模式接收ADC转换的数据*/
AdcHandle.Init.BoostMode = ENABLE; /* ADC时钟超过20MHz的话,使能boost */
AdcHandle.Init.Overrun = ADC_OVR_DATA_OVERWRITTEN; /* ADC转换溢出的话,覆盖ADC的数据寄存器 */
AdcHandle.Init.OversamplingMode = DISABLE; /* 禁止过采样 */
/* 初始化DMA */
if(HAL_DMA_Init(&DmaHandle) != HAL_OK)
{
Error_Handler(__FILE__, __LINE__);
}
函数原型:
HAL_StatusTypeDef HAL_ADC_ConfigChannel(ADC_HandleTypeDef* hadc, ADC_ChannelConfTypeDef* sConfig)
{
HAL_StatusTypeDef tmp_hal_status = HAL_OK;
ADC_Common_TypeDef *tmpADC_Common;
uint32_t tmpOffsetShifted;
__IO uint32_t wait_loop_index = 0;
/* 程序中不重要的部分被清除掉,仅留下关键部分做注释 */
/* 上锁 */
__HAL_LOCK(hadc);
/* 配置ADC参数 */
if (ADC_IS_CONVERSION_ONGOING_REGULAR(hadc) == RESET)
{
/* ADC通道选择 */
hadc->Instance->PCSEL |= (1U << sConfig->Channel);
/* Rank 1 to 4 */
if (sConfig->Rank < 5)
{
MODIFY_REG(hadc->Instance->SQR1,
ADC_SQR1_RK(ADC_SQR2_SQ5, sConfig->Rank),
ADC_SQR1_RK(sConfig->Channel, sConfig->Rank));
}
/* For Rank 5 to 9 */
else if (sConfig->Rank < 10)
{
MODIFY_REG(hadc->Instance->SQR2,
ADC_SQR2_RK(ADC_SQR2_SQ5, sConfig->Rank),
ADC_SQR2_RK(sConfig->Channel, sConfig->Rank));
}
/* For Rank 10 to 14 */
else if (sConfig->Rank < 15)
{
MODIFY_REG(hadc->Instance->SQR3,
ADC_SQR3_RK(ADC_SQR3_SQ10, sConfig->Rank),
ADC_SQR3_RK(sConfig->Channel, sConfig->Rank));
}
/* For Rank 15 to 16 */
else
{
MODIFY_REG(hadc->Instance->SQR4,
ADC_SQR4_RK(ADC_SQR4_SQ15, sConfig->Rank),
ADC_SQR4_RK(sConfig->Channel, sConfig->Rank));
}
/* 更新ADC参数 */
if (ADC_IS_CONVERSION_ONGOING_REGULAR_INJECTED(hadc) == RESET)
{
/* 通道采样时间配置 */
/* For channels 10 to 19 */
if (sConfig->Channel >= ADC_CHANNEL_10)
{
MODIFY_REG(hadc->Instance->SMPR2,
ADC_SMPR2(ADC_SMPR2_SMP10, sConfig->Channel),
ADC_SMPR2(sConfig->SamplingTime, sConfig->Channel));
}
else /* For channels 0 to 9 */
{
MODIFY_REG(hadc->Instance->SMPR1,
ADC_SMPR1(ADC_SMPR1_SMP0, sConfig->Channel),
ADC_SMPR1(sConfig->SamplingTime, sConfig->Channel));
}
/* 配置偏移 */
tmpOffsetShifted = ADC_OFFSET_SHIFT_RESOLUTION(hadc, sConfig->Offset);
switch (sConfig->OffsetNumber)
{
case ADC_OFFSET_1:
MODIFY_REG(hadc->Instance->OFR1,
ADC_OFR_FIELDS,
ADC_OFR_CHANNEL(sConfig->Channel) | tmpOffsetShifted);
MODIFY_REG(hadc->Instance->CFGR2, ADC_CFGR2_RSHIFT1, sConfig->OffsetRightShift);
if(sConfig->OffsetSignedSaturation != DISABLE)
{
SET_BIT(hadc->Instance->OFR1, ADC_OFR1_SSATE);
}
else
{
CLEAR_BIT(hadc->Instance->OFR1, ADC_OFR1_SSATE);
}
break;
case ADC_OFFSET_2:
break;
case ADC_OFFSET_3:
break;
case ADC_OFFSET_4:
break;
default :
break;
}
}
/* ADC参数更新 */
/* 内部的 Vbat/VrefInt/TempSensor */
if (ADC_IS_ENABLE(hadc) == RESET)
{
/* 配置差分模式 */
if (sConfig->SingleDiff != ADC_DIFFERENTIAL_ENDED)
{
/* 禁止差分 */
CLEAR_BIT(hadc->Instance->DIFSEL, ADC_DIFSEL_CHANNEL(sConfig->Channel));
}
else
{
/* 使能差分 */
SET_BIT(hadc->Instance->DIFSEL, ADC_DIFSEL_CHANNEL(sConfig->Channel));
/* 配置通道ADC_IN+1 (negative input)的采样时间 */
/* 通道 9 to 15 (ADC1, ADC2) or to 11 (ADC3), SMPR2寄存器必须配置 */
if (sConfig->Channel >= ADC_CHANNEL_9)
{
MODIFY_REG(hadc->Instance->SMPR2,
ADC_SMPR2(ADC_SMPR2_SMP10, sConfig->Channel +1),
ADC_SMPR2(sConfig->SamplingTime, sConfig->Channel +1));
}
else /* 对于通道0 to 8, SMPR1必须配置 */
{
MODIFY_REG(hadc->Instance->SMPR1,
ADC_SMPR1(ADC_SMPR1_SMP0, sConfig->Channel +1),
ADC_SMPR1(sConfig->SamplingTime, sConfig->Channel +1));
}
}
/* 内部测量通道配置: Vbat/VrefInt/TempSensor */
/* 公用寄存器配置 */
if((hadc->Instance == ADC1) || (hadc->Instance == ADC2))
{
tmpADC_Common = ADC12_COMMON_REGISTER(hadc);
}
else
{
tmpADC_Common = ADC3_COMMON_REGISTER(hadc);
}
/* 具体内部通道的配置,省略未写 */
}
}
else
{
SET_BIT(hadc->State, HAL_ADC_STATE_ERROR_CONFIG);
tmp_hal_status = HAL_ERROR;
}
/* 解锁 */
__HAL_UNLOCK(hadc);
/* 返回函数状态 */
return tmp_hal_status;
}
函数描述:
调用函数HAL_ADC_Init配置了基础功能后,就可以调用此函数配置ADC的具体通道了。
函数参数:
注意事项:
使用举例:
ADC_ChannelConfTypeDef sConfig = {0};
/* 配置ADC通道 */
sConfig.Channel = ADC_CHANNEL_10; /* 配置使用的ADC通道 */
sConfig.Rank = ADC_REGULAR_RANK_1; /* 采样序列里的第1个 */
sConfig.SamplingTime = ADC_SAMPLETIME_1CYCLE_5; /* 采样周期 */
sConfig.SingleDiff = ADC_SINGLE_ENDED; /* 单端输入 */
sConfig.OffsetNumber = ADC_OFFSET_NONE; /* 无偏移 */
sConfig.Offset = 0; /* 无偏移的情况下,此参数忽略 */
if (HAL_ADC_ConfigChannel(&AdcHandle, &sConfig) != HAL_OK)
{
Error_Handler(__FILE__, __LINE__);
}
函数原型:
HAL_StatusTypeDef HAL_ADC_Start(ADC_HandleTypeDef* hadc)
函数描述:
调用函数HAL_ADC_Init配置了基础功能后,就可以调用此函数启动ADC了。
函数参数:
注意事项:
使用举例:
if (HAL_ADC_ConfigChannel(&AdcHandl) != HAL_OK)
{
Error_Handler(__FILE__, __LINE__);
}
函数原型:
HAL_StatusTypeDef HAL_ADC_Start_DMA(ADC_HandleTypeDef* hadc, uint32_t* pData, uint32_t Length)
函数描述:
调用函数HAL_ADC_Init配置了基础功能后,就可以调用此函数启动ADC的DMA方式了。
函数参数:
注意事项:
使用举例:
uint16_t ADCxValues[4];
ADC_HandleTypeDef AdcHandle = {0};
/* ADC和DMA的配置部分未贴,函数较多 */
if (HAL_ADC_Start_DMA(&AdcHandle, (uint32_t *)ADCxValues, 4) != HAL_OK)
{
Error_Handler(__FILE__, __LINE__);
}
函数原型:
HAL_StatusTypeDef HAL_ADCEx_Calibration_Start(ADC_HandleTypeDef* hadc, uint32_t CalibrationMode, uint32_t SingleDiff)
函数描述:
调用函数HAL_ADC_Init配置了基础功能后,就可以调用此函数启动ADC的自校准功能了,支持偏移校准和线性度校准。
函数参数:
注意事项:
使用举例:
/* 校准ADC,采用偏移校准 */
if (HAL_ADCEx_Calibration_Start(&AdcHandle, ADC_CALIB_OFFSET, ADC_SINGLE_ENDED) != HAL_OK)
{
Error_Handler(__FILE__, __LINE__);
}
本章节就为大家讲解这么多,由于ADC用到的场合比较多,建议将常用的知识点熟练掌握。