前言
本笔记总结stm32f1xx的adc使用,包括功能介绍、解释、示例,库函数基于标准库函数,主要总结单adc外设模式;
一、概念
模拟数字转换器(英语:Analog-to-digital converter, ADC, A/D or A to D)是用于将模拟形式的连续信号转换为数字形式的离散信号的一类设备。一个模拟数字转换器可以提供信号用于测量。与之相对的设备称为数字模拟转换器。
在过去简单的单片机时代mcu/单片机内部没有adc外设需要选用外部芯片。
二、stm32f1xx的ADC介绍
内部框图
以上为adc内部框图,adc的功能使用可能涉及到五部分的配置:通过引脚从外部采集时GPIO的寄存器配置、不用应用场景时adc外设的寄存器不同配置、使用外部触发触发方式/触发源的配置、使用中断时的NVIC的配置、时钟的配置,通过颜色进行了划分;为了加速采集处理过程可以和DMA结合,图中没有画出;
寄存器
typedef struct
{
__IO uint32_t SR; //状态寄存器
__IO uint32_t CR1; //控制寄存器1
__IO uint32_t CR2; //控制寄存器2
__IO uint32_t SMPR1; //采样时间寄存器1
__IO uint32_t SMPR2; //采样时间寄存器2
__IO uint32_t JOFR1; //注入通道数据偏移寄存器1
__IO uint32_t JOFR2; //注入通道数据偏移寄存器2
__IO uint32_t JOFR3; //注入通道数据偏移寄存器3
__IO uint32_t JOFR4; //注入通道数据偏移寄存器4
__IO uint32_t HTR; //看门狗高阀值寄存器
__IO uint32_t LTR; //看门狗低阀值寄存器
__IO uint32_t SQR1; //规则序列寄存器1
__IO uint32_t SQR2; //规则序列寄存器2
__IO uint32_t SQR3; //规则序列寄存器3
__IO uint32_t JSQR; //注入序列寄存器
__IO uint32_t JDR1; //注入数据寄存器1
__IO uint32_t JDR2; //注入数据寄存器2
__IO uint32_t JDR3; //注入数据寄存器3
__IO uint32_t JDR4; //注入数据寄存器4
__IO uint32_t DR; //规则数据寄存器
} ADC_TypeDef;
通道/组
最多一共支持18个通道
#define ADC_Channel_0 ((uint8_t)0x00)
#define ADC_Channel_1 ((uint8_t)0x01)
#define ADC_Channel_2 ((uint8_t)0x02)
#define ADC_Channel_3 ((uint8_t)0x03)
#define ADC_Channel_4 ((uint8_t)0x04)
#define ADC_Channel_5 ((uint8_t)0x05)
#define ADC_Channel_6 ((uint8_t)0x06)
#define ADC_Channel_7 ((uint8_t)0x07)
#define ADC_Channel_8 ((uint8_t)0x08)
#define ADC_Channel_9 ((uint8_t)0x09)
#define ADC_Channel_10 ((uint8_t)0x0A)
#define ADC_Channel_11 ((uint8_t)0x0B)
#define ADC_Channel_12 ((uint8_t)0x0C)
#define ADC_Channel_13 ((uint8_t)0x0D)
#define ADC_Channel_14 ((uint8_t)0x0E)
#define ADC_Channel_15 ((uint8_t)0x0F)
#define ADC_Channel_16 ((uint8_t)0x10)
#define ADC_Channel_17 ((uint8_t)0x11)
#define ADC_Channel_TempSensor ((uint8_t)ADC_Channel_16)
#define ADC_Channel_Vrefint ((uint8_t)ADC_Channel_17)
其中ADC_Channel_0到ADC_Channel_15通过配置引脚采集芯片外的ad信号;
ADC_Channel_16 和 ADC_Channel_17通道连到芯片内部采集温度传感器和参考电压的ad;
根据配置可以分成注入组和规则组,规则组最多使用16个通道,注入组使用4个通道,进行编组,通道被配置使用时不是规则通道就是注入通道;
扫描模式
此模式用来扫描一组模拟通道。
扫描模式可通过设置ADC_CR1寄存器的SCAN位来选择。一旦这个位被设置, ADC扫描所有被ADC_SQRX寄存器(对规则通道)或ADC_JSQR(对注入通道)选中的所有通道。在每个组的每个通道上执行单次转换;
转换模式
单次转换模式下, ADC只执行一次转换。该模式既可通过设置ADC_CR2寄存器的ADON位(只适用于规则通道)启动也可通过外部触发启动(适用于规则通道或注入通道),这时CONT位为0;在连续转换模式中,当前面ADC转换一结束马上就启动另一次转换。此模式可通过外部触发启动或通过设置ADC_CR2寄存器上的ADON位启动,此时CONT位是1;
注意:扫描模式和转换模式的关系
单次转换 | 连续转换 | 适用组别 | |
---|---|---|---|
扫描模式 | 扫描所有通道(>=1) 每个通道是单次转换,各执行一遍结束 ,一般使用扫描模式会设置不只一个通道 | 扫描所有通道(>=1) 每个通道是单次转换,所有通道执行完后从头再开始,一般使用扫描模式会设置不只一个通道 | 规则组、注入组 |
非扫描模式 | 非扫描模式通道只能是一个,这个通道执行一遍结束 | 非扫描模式通道只能是一个,这个通道执行一遍结束后再继续执行 | 规则组、注入组 |
间断模式
间断模式使用需要先对规则组或者注入组使能间断模式,再设置间断模式的通道个数,通道个数的含义为通过外部触发时每次按序列转换多少个通道;
可以用于规则和注入通道,避免同时为规则和注入组设置间断模式,不能同时使用自动注入和间断模式
双ADC模式
在有2个或以上ADC模块的产品中,可以使用双ADC模式,在双ADC模式里,根据ADC1_CR1寄存器中DUALMOD[2:0]位所选的模式,转换的启动可以是ADC1主和ADC2从的交替触发或同步触发
触发方式
adc采集触发方式可以分为软件触发(非外部事件触发) 和外部事件触发,在寄存器ADC_CR2的bit20配置或者bit15分别配置规则和注入通道是否使用外部事件触发转换;
在寄存器当配置为外部事件触发时,需要配置具体的外部触发事件,在寄存器ADC_CR2的bit19~bit17配置或者bit14 ~ bit12;
三、adc库函数文件
1、stm32f10x_adc.h
定义外设初始化、通道配置等其它配置,adc数据读取等数据结构和函数;
2、stm32f10x_adc.c
封装外设操作的函数;
四、数据结构和函数
初始化结构体
typedef struct
{
uint32_t ADC_Mode; //单ADC模式或是双ADC模式的几种配置,ADC_CR1的bit19~bit16配置
FunctionalState ADC_ScanConvMode; //是否使用扫描模式,ADC_CR1的bit8配置
FunctionalState ADC_ContinuousConvMode; //单次转换还是连续转换配置,ADC_CR2的bit1配置
uint32_t ADC_ExternalTrigConv; //配置内部软件触发或者外部事件的类型ADC_CR2的bit19~bit17配置规则通道,bit14~bit12配置注入通道
uint32_t ADC_DataAlign; //数据对齐配置,ADC_CR2寄存器的bit11配置
uint8_t ADC_NbrOfChannel; //规则通道序列,通道个数的配置,ADC_SQR1寄存器的bit23~bit20,最多到16
}ADC_InitTypeDef;
库函数
void ADC_DeInit(ADC_TypeDef* ADCx);
操作RCC复位ADCx的外设
void ADC_Init(ADC_TypeDef* ADCx, ADC_InitTypeDef* ADC_InitStruct);
通过初始化配置结构体配置ADC_CR1和ADC_CR2的寄存器
void ADC_StructInit(ADC_InitTypeDef* ADC_InitStruct);
配置初始化结构体到默认值
void ADC_Cmd(ADC_TypeDef* ADCx, FunctionalState NewState);
开启ADC并启动转换操作ADC_CR2寄存器bit0位
void ADC_DMACmd(ADC_TypeDef* ADCx, FunctionalState NewState);
使用DMA模式,配置ADC_CR2的bit8
void ADC_ITConfig(ADC_TypeDef* ADCx, uint16_t ADC_IT, FunctionalState NewState);
配置中断,ADC_CR2寄存器的bit7~bit5配置注入通道转换结束、模拟看门狗、规则通道转换结束中断
void ADC_ResetCalibration(ADC_TypeDef* ADCx);
复位校准操作ADC_CR2的bit3,由软件设置硬件自动清除
FlagStatus ADC_GetResetCalibrationStatus(ADC_TypeDef* ADCx);
获取复位校准情况,由硬件自动清除
void ADC_StartCalibration(ADC_TypeDef* ADCx);
启动校准操作ADC_CR2的bit2,由软件设置硬件自动清除
FlagStatus ADC_GetCalibrationStatus(ADC_TypeDef* ADCx);
判断校准情况,由硬件自动清除
void ADC_SoftwareStartConvCmd(ADC_TypeDef* ADCx, FunctionalState NewState);
开始转换规则通道并配置使用外部事件启动转换,设置ADC_CR2的bit22和bit20为1
FlagStatus ADC_GetSoftwareStartConvStatus(ADC_TypeDef* ADCx);
判断开始转换规则通道配置位情况,转换开始后由硬件清除此位
void ADC_DiscModeChannelCountConfig(ADC_TypeDef* ADCx, uint8_t Number);
void ADC_DiscModeCmd(ADC_TypeDef* ADCx, FunctionalState NewState);
void ADC_RegularChannelConfig(ADC_TypeDef* ADCx, uint8_t ADC_Channel, uint8_t Rank, uint8_t ADC_SampleTime);
配置规则通道的序列,操作寄存器ADC_SMPR1、ADC_SMPR2、ADC_SQR1、ADC_SQR2、ADC_SQR3,Rank定义ADC_Channel的编号放入指定序列寄存器的指定位置
void ADC_ExternalTrigConvCmd(ADC_TypeDef* ADCx, FunctionalState NewState);
使用外部事件启动转换,操作ADC_CR2的bit20
uint16_t ADC_GetConversionValue(ADC_TypeDef* ADCx);
获取adc采集的值
uint32_t ADC_GetDualModeConversionValue(void);
获取双adc转换的值
void ADC_AutoInjectedConvCmd(ADC_TypeDef* ADCx, FunctionalState NewState);
开启自动的注入通道组转换,操作ADC_CR1的bit10位
void ADC_InjectedDiscModeCmd(ADC_TypeDef* ADCx, FunctionalState NewState);
注入通道上使用间断模式,操作ADC_CR1的bit12
void ADC_ExternalTrigInjectedConvConfig(ADC_TypeDef* ADCx, uint32_t ADC_ExternalTrigInjecConv);
注入通道外部事件触发的事件类型配置,操作ADC_CR2的bit14~bit12
void ADC_ExternalTrigInjectedConvCmd(ADC_TypeDef* ADCx, FunctionalState NewState);
开启注入通道外部事件触发使能,操作ADC_CR1的bit15位
void ADC_SoftwareStartInjectedConvCmd(ADC_TypeDef* ADCx, FunctionalState NewState);
使能注入通道外部事件触发,开始转换注入通道,操作ADC_CR2的bit15和bit21
FlagStatus ADC_GetSoftwareStartInjectedConvCmdStatus(ADC_TypeDef* ADCx);
判断开始转换bit位设置情况,读取ADC_CR2的bit21位
void ADC_InjectedChannelConfig(ADC_TypeDef* ADCx, uint8_t ADC_Channel, uint8_t Rank, uint8_t ADC_SampleTime);
配置注入通道序列和采样时间,操作ADC_JSQR和ADC_SMPR1、ADC_SMPR2寄存器
void ADC_InjectedSequencerLengthConfig(ADC_TypeDef* ADCx, uint8_t Length);
注入通道的个数配置,操作ADC_JSQR寄存器
void ADC_SetInjectedOffset(ADC_TypeDef* ADCx, uint8_t ADC_InjectedChannel, uint16_t Offset);
设置注入通道的数据偏移
uint16_t ADC_GetInjectedConversionValue(ADC_TypeDef* ADCx, uint8_t ADC_InjectedChannel);
获取注入通道的转换值,操作ADC_JDRx寄存器
void ADC_AnalogWatchdogCmd(ADC_TypeDef* ADCx, uint32_t ADC_AnalogWatchdog);
void ADC_AnalogWatchdogThresholdsConfig(ADC_TypeDef* ADCx, uint16_t HighThreshold, uint16_t LowThreshold);
模拟看门狗阈值设置,操作ADC_HTR和ADC_LRT
void ADC_AnalogWatchdogSingleChannelConfig(ADC_TypeDef* ADCx, uint8_t ADC_Channel);
给指定通道配置模拟看门狗功能,操作ADC_CR1的bit4~bit0
void ADC_TempSensorVrefintCmd(FunctionalState NewState);
温度传感器和VREFINT使能,操作ADC_CR2的bit23
FlagStatus ADC_GetFlagStatus(ADC_TypeDef* ADCx, uint8_t ADC_FLAG);
获取置位标志,读取ADC_SR寄存器
void ADC_ClearFlag(ADC_TypeDef* ADCx, uint8_t ADC_FLAG);
清除置位标志,操作ADC_SR寄存器或读取ADC_DR寄存器
ITStatus ADC_GetITStatus(ADC_TypeDef* ADCx, uint16_t ADC_IT);
获取中断标志,读取ADC_SR寄存器
void ADC_ClearITPendingBit(ADC_TypeDef* ADCx, uint16_t ADC_IT);
清除中断标志,操作ADC_SR寄存器或读取ADC_DR寄存器
五、应用案例
编程序列
1、使能相关时钟如gpio、adc、dma等;
2、配置adc通道对应的gpio复用(如果是内部采集温度传感器不用配置此项)
3、以adc的初始化结构体初始化adc,配置单双adc模式、通道个数、外部事件触发类型或者内部软件触发、数据对齐、是否开启扫描、单次还是连续转换
4、配置规则或者注入通道
5、是否使用dma,使用的话调用dma相关接口
6、是否选择中断,使用的话操作NVIC设置相应中断号并编辑中断服务函数
7、校准步骤、一些使能操作