stm32 ADC笔记
框3:ADC的输入通道:共18个,包括16个GPIO口(ADCx_IN0…ADCx_IN15)和2个内部通道温度传感器和Vrefint(内部参考电压)
框5:模拟多路开关,可以指定要选择哪些ADC输入通道(框3),右边是输出,进入到模数转换器(框6)
框6:模数转换器,逐次比较型,输入通道包括ADCCLK(最大14M),注入通道和规则通道,注入通道最多同时连接4个通道,规则通道最多同时连接16个通道(为什么是16个通道?相当于16个通道的模拟信号可以同时进来进行AD转换,提高效率,这就是为什么STM32软件配置有连续、单次、扫描、非扫描配置的原因,设置这些原理可以想一下,比如别人同时告诉你16件事,单次就好比你只记其中1件,连续就是你把16件时都挨到记下来),通道转换结果存放到对应的数据寄存器(虚线框8)。输出分别为DMA请求、规则和注入的数据寄存器(保存AD转换的结果)。
虚线框8:
a.规则通道数据寄存器用于保存ADC转换结果,只有1个,但是对应了最多16个通道的ADC转换结果,如果数据读取不及时,容易出现数据覆盖问题,所以这个寄存器常配合DMA使用,快速搬移数据,防止覆盖,该寄存器输入为模数转换器的规则通道,输入为ADC转换结果。转换并保存完成会输出转换结束信号,状态寄存器置EOC标志位。
b.注入通道数据寄存器用于保存来自注入通道的ADC转换结果,有4个寄存器,对应最多4个通道的ADC转换结果,不担心数据覆盖,所以不用搭配DMA使用也行。转换并保存完会在状态寄存器置JEOC标志位。
c.DMA请求,用于触发DMA进行数据转运。
框1和框2:触发源,前者是规则组的触发源,后者是注入的触发源,都是硬件触发, 触发的作用是让ADC开始转换,可在ADC初始化结构体进行选择(见下图)。以框1讲解,触发主要有定时器各个通道和TRGO,以及外部中断EXTI(见下图2)。有了硬件触发,那软件触发什么呢?软件触发在程序中调用代码就可以启动转换(ADC_SoftwareStartConvCmd),ADC初始话结构体中需要将硬件触发源选择为ADC_ExternalTrigConv_None
框4: Vref为ADC参考电压,决定了ADC输入电压的范围,Vdda和Vssa是ADC的供电引脚,一般情况是Vref+接Vdda,Vref-接Vssa
框7:ADC时钟,由APB2时钟72M通过ADC预分频器分频后的时钟,ADCCLK最大14M,所以分频系数选择就是6或8分频。
什么是单次转换和连续转换:ADC转换完成会置EOC标志位,单次转换就是置EOC标志位就停止转换,需要再次触发才会转换。而连续转换是置EOC标志位后,继续进行下一轮转换,周而复始,所以触发只需要给1次就行了(总结:就是转换1次还是不停转换)。ADC结构体配置ADC_ContinuousConvMode
什么是扫描和非扫描模式:非扫描模式就是假如你指定了一个通道,比如序列1为通道2,序列2为通道5,那么转换去转换序列1,然后置EOC就停止了。而扫描模式就是会全部扫描(总结:就是转换指定通道,还是转换所有通道)。ADC结构体配置ADC_ScanConvMode
下面来看看规则组的4种转换模式
1.单次转换,非扫描模式:只转换1次序列1通道就置EOC标志
2.连续转换,非扫描模式:转换完序列1通道置EOC标志,立刻开始下一次转换序列1
3.单次转换,扫描模式:指定通道数目为7,那么会将序列1-7转换完置EOC标志位,然后停止(数据存在数据寄存器里,因为数据寄存器只有1个,会出现覆盖问题,需要DMA搬运)
4.连续转换,扫描模式:指定通道数目为7,将序列1-7转换完置EOC标志,自动开始下一次转换。
所以,4总模式其实就是转换次数+转换哪些通道的组合。
通道数目ADC结构体配置ADC_NbrOfChannel,扫描模式用几个通道就写几。
填充通道方法:如想把序列1配置为通道2就用函数ADC_ReglarChannelConfig(ADC1,ADC_Channel_2,1,ADC_SampleTime_55Cycles5)将序列1设置为ADC1的通道2,ADC_SampleTime_55Cycles5为采样时间,需要快速就选择55位置值小的,稳定就选择55位置值大的。将序列2设置为通道5:ADC_ReglarChannelConfig(ADC1,ADC_Channel_5,2,ADC_SampleTime_55Cycles5)其它依次这样设置。
ADC12_IN0:并不是ADC12,是指ADC1和ADC2的IN0都在PA0上
数据对齐:因为ADC转换结果是12位的,而规则通道数据寄存器是16位的,有4位必须补0,数据存放就有2种方式,一般常用右对齐,便于取数据,左对齐一般用于低分辨率。
综上就可以看出来,ADC使用其实并不难,无非就是GPIO和ADC时钟配置,GPIO初始化、ADC初始化,校准那一块代码是固定的,不用了解,只需要写进去就行,见下面校准代码。
ADC_ResetCalibration(ADC1); //使能复位校准
while(ADC_GetResetCalibrationStatus(ADC1)); //等待复位校准结束
ADC_StartCalibration(ADC1); //开启AD校准
while(ADC_GetCalibrationStatus(ADC1)); //等待校准结束
ADC配置步骤
通过以上框图可以大概知道ADC运转的配置步骤了,第一步:开启GPIO和ADC的RCC时钟,第二步:配置GPIO模式为模拟输入模式;第三步:配置多路开关,把ADC通道接入到规则组列表;第四步:配置ADC转换器;第五步:配置模拟看门狗或者中断(如需要);第六步:校准ADC,第七步:打开开关,开启ADC。
相关库函数说明:
void ADC_DeInit(ADC_TypeDef* ADCx);恢复缺省配置
void ADC_Init(ADC_TypeDef* ADCx, ADC_InitTypeDef* ADC_InitStruct);初始化函数
void ADC_StructInit(ADC_InitTypeDef* ADC_InitStruct);StructInit结构体初始化
void ADC_Cmd(ADC_TypeDef* ADCx, FunctionalState NewState);ADC使能上电(开关控制)
void ADC_DMACmd(ADC_TypeDef* ADCx, FunctionalState NewState);
开启DMA输出,使用DMA转运数据需要使用此函数。
void ADC_ITConfig(ADC_TypeDef* ADCx, uint16_t ADC_IT, FunctionalState NewState);
中断输出控制,用于控制某个中断,能不能通往NVIC。
—————————————————————————————————————-
void ADC_ResetCalibration(ADC_TypeDef* ADCx);复位校准
FlagStatus ADC_GetResetCalibrationStatus(ADC_TypeDef* ADCx);获取复位校准状态
void ADC_StartCalibration(ADC_TypeDef* ADCx);开始校准
FlagStatus ADC_GetCalibrationStatus(ADC_TypeDef* ADCx);获取开始校准状态
——————–以上4个位控制校准的函数,ADC初始化完依次调用————————
void ADC_SoftwareStartConvCmd(ADC_TypeDef* ADCx, FunctionalState NewState);
ADC软件开始转换控制,用于软件触发的函数
FlagStatus ADC_GetSoftwareStartConvStatus(ADC_TypeDef* ADCx);这个函数没啥用
—————————————————————————————————————-
void ADC_DiscModeChannelCountConfig(ADC_TypeDef* ADCx, uint8_t Number);
每隔几个通道间断一次
void ADC_DiscModeCmd(ADC_TypeDef* ADCx, FunctionalState NewState);是否启用间断模式
—————————————-上面2个函数用于配置间断模式——————————–
void ADC_RegularChannelConfig(ADC_TypeDef* ADCx, uint8_t ADC_Channel, uint8_t Rank, uint8_t ADC_SampleTime);ADC规则组通道配置,用于给序列的每个位置填写指定的通道
void ADC_ExternalTrigConvCmd(ADC_TypeDef* ADCx, FunctionalState NewState);
ADC外部触发转换控制,是否允许外部触发转换
uint16_t ADC_GetConversionValue(ADC_TypeDef* ADCx);获取ADC转换值,读取转换结果。
uint32_t ADC_GetDualModeConversionValue(void);
ADC获取双模式转换值,双ADC模式读取转换结果的函数
—————————————————————————————————————
void ADC_AutoInjectedConvCmd(ADC_TypeDef* ADCx, FunctionalState NewState);
void ADC_InjectedDiscModeCmd(ADC_TypeDef* ADCx, FunctionalState NewState);
void ADC_ExternalTrigInjectedConvConfig(ADC_TypeDef* ADCx, uint32_t ADC_ExternalTrigInjecConv);
void ADC_ExternalTrigInjectedConvCmd(ADC_TypeDef* ADCx, FunctionalState NewState);
void ADC_SoftwareStartInjectedConvCmd(ADC_TypeDef* ADCx, FunctionalState NewState);
FlagStatus ADC_GetSoftwareStartInjectedConvCmdStatus(ADC_TypeDef* ADCx);
void ADC_InjectedChannelConfig(ADC_TypeDef* ADCx, uint8_t ADC_Channel, uint8_t Rank, uint8_t ADC_SampleTime);
void ADC_InjectedSequencerLengthConfig(ADC_TypeDef* ADCx, uint8_t Length);
void ADC_SetInjectedOffset(ADC_TypeDef* ADCx, uint8_t ADC_InjectedChannel, uint16_t Offset);
uint16_t ADC_GetInjectedConversionValue(ADC_TypeDef* ADCx, uint8_t ADC_InjectedChannel);
———————————–Injected注入组,上面函数对注入组进行配置——————
void ADC_AnalogWatchdogCmd(ADC_TypeDef* ADCx, uint32_t ADC_AnalogWatchdog);
是否启动模拟看门狗
void ADC_AnalogWatchdogThresholdsConfig(ADC_TypeDef* ADCx, uint16_t HighThreshold, uint16_t LowThreshold);配置高低阈值
void ADC_AnalogWatchdogSingleChannelConfig(ADC_TypeDef* ADCx, uint8_t ADC_Channel);
配置看门通道
void ADC_TempSensorVrefintCmd(FunctionalState NewState);
温度传感器的内部参考电压控制,用于开启内部的温度和参考电压通道
FlagStatus ADC_GetFlagStatus(ADC_TypeDef* ADCx, uint8_t ADC_FLAG);
获取标志位状态,用于判断转换是否结束
void ADC_ClearFlag(ADC_TypeDef* ADCx, uint8_t ADC_FLAG);
清除标志位
ITStatus ADC_GetITStatus(ADC_TypeDef* ADCx, uint16_t ADC_IT);
获取中断状态
void ADC_ClearITPendingBit(ADC_TypeDef* ADCx, uint16_t ADC_IT);
清除中断挂起位
作者:m0_60900496