STM32学习笔记(7_2)- ADC模数转换器代码

无人问津也好,技不如人也罢,都应静下心来,去做该做的事。

最近在学STM32,所以也开贴记录一下主要内容,省的过目即忘。视频教程为江科大(改名江协科技),网站jiangxiekeji.com

本期开始介绍STM32的ADC——模数转换器,对于GPIO来说,它只能读取引脚的高低电平,要么是高电平,要么是低电平,只有两个值。而使用ADC,我们就可以对这个高电平和低电平之间的任意电压进行量化,最终用一个变量来表示,读取这个变量,就可以知道引脚的具体电压到底是多少了。

所以ADC其实就是一个电压表,把引脚的电压值测出来,放在一个变量里。这就是ADC的作用。

CTRL+ALT+空格或CTRL+空格:提示代码,代码自动补全

ADC常用函数

RCC_ADCCLKConfig:这个函数是用来配置ADCCLK分频器的,'它可以对APB2的72MHz时钟选择2、4、6、8分频,输入到ADCCLK。这个函数在RCC库函数里。

void RCC_ADCCLKConfig(uint32_t RCC_PCLK2);

下面的函数在ADC.h里

ADC_DeInit恢复缺省配置、ADC_Init初始化、ADC_StructInit结构体初始化

void ADC_DeInit(ADC_TypeDef* ADCx);
void ADC_Init(ADC_TypeDef* ADCx, ADC_InitTypeDef* ADC_InitStruct);
void ADC_StructInit(ADC_InitTypeDef* ADC_InitStruct);

 ADC_Cmd:这个是用于给ADC上电的,就是ADC基本结构图里的开关控制。

void ADC_Cmd(ADC_TypeDef* ADCx, FunctionalState NewState);

DMA_Cmd:这个是用于开启DMA输出信号的,如果使用DMA转运数据,那就得调用这个函数。

void ADC_DMACmd(ADC_TypeDef* ADCx, FunctionalState NewState);

ADC_ITConfig:中断输出控制,用于控制某个中断,能不能通往NVIC。

void ADC_ITConfig(ADC_TypeDef* ADCx, uint16_t ADC_IT, FunctionalState NewState);

接下来四个函数分别是复位校准、获取复位校准状态、开始校准、获取开始校准状态,这是用于控制校准的函数。我们在ADC初始化完成之后,依次调用就行了。

void ADC_ResetCalibration(ADC_TypeDef* ADCx);
FlagStatus ADC_GetResetCalibrationStatus(ADC_TypeDef* ADCx);
void ADC_StartCalibration(ADC_TypeDef* ADCx);
FlagStatus ADC_GetCalibrationStatus(ADC_TypeDef* ADCx);

ADC软件开始转换控制,这个就是用于软件触发的函数了。调用一下就能进行软件触发控制,我们这个代码目前使用软件触发。

void ADC_SoftwareStartConvCmd(ADC_TypeDef* ADCx, FunctionalState NewState);

ADC获取软件开始转换状态,这个函数的返回值跟转换是否结束,毫无关系。这个函数其实没啥用,我们一般不用,不要被他误导了。

FlagStatus ADC_GetSoftwareStartConvStatus(ADC_TypeDef* ADCx);

ADC_GetFlagStatus:这个函数才是判断是否转换结束的。获取标志位状态,然后参数给EOC的标志位,判断EOC标志位是不是置1了。如果转换结束,EOC标志位置1,然后调用这个函数,判断标志位。这样才是正确的判断转换是否结束的方法。

FlagStatus ADC_GetFlagStatus(ADC_TypeDef* ADCx, uint8_t ADC_FLAG);

然后下面这两个函数,是用来配置间断模式的。

ADC_DiscModeChannelCountConfig:每隔几个通道间断一次。

ADC_DiscModeCmd:是不是启用间断模式。

void ADC_DiscModeChannelCountConfig(ADC_TypeDef* ADCx, uint8_t Number);
void ADC_DiscModeCmd(ADC_TypeDef* ADCx, FunctionalState NewState);

ADC_RegularChannelConfig(ADCx,你想指定的通道,序列几的位置,指定通道的采样时间):ADC规则组通道配置,这个函数比较重要,它的作用就是给序列的每个位置填写指定的通道,就是填写点菜菜单的过程。

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获取转换值,这个函数也比较重要。获取AD转换的数据寄存器,读取转换结果就要使用这个函数。

uint16_t ADC_GetConversionValue(ADC_TypeDef* ADCx);

 ADC获取双模式转换值,这个是双ADC模式读取转换结果的函数,暂时不用。

uint32_t ADC_GetDualModeConversionValue(void);

到这里,以上这些函数是对ADC的一些基本功能和规则组的配置。

接下来这些函数里面都带了一个Injected,就是注入组的意思,注入组本期也不用。

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);

这三个函数就是对模拟看门狗进行配置的,第一个是是否启动模拟看门狗,第二个是配置高低阈值,第三个是配置看门的通道。

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);

ADC温度传感器、内部参考电压控制,这个是用来开启内部的两个通道的,如果你要用这两个通道,那得调用这个函数,开启一下。要不然是读不到正确的结果的,这个注意一下。

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);

       

 ADC基本结构

左边是输入通道,16个GPIO口,外加两个内部的通道。然后进入AD转换器,AD转换器里有两个组,一个是规则组,一个是注入组,规则组最多可以选中16个通道,注入组最大可以选择4个通道。然后转换的结果可以存放在AD数据寄存器里,其中规则组只有1个数据寄存器,注入组有4个。然后下面这里有触发控制, 提供了开始转换这个START信号,触发控制可以选择软件触发和硬件触发。硬件触发主要是来自于定时器,当然也可以选择外部中断的引脚。右边这里是来自于RCC的ADC时钟CLOCK,ADC逐次比较的过程就是由这个时钟推动的。然后上面,可以布置一个模拟看门狗用于监测转换结果的范围,如果超出设定的阈值,就通过中断输出控制,向NVIC申请中断。另外,规则组和注入组转换完成后会有个EOC信号,它会置一个标志位,当然也可以通向NVIC。最后右下角这里还有个开关控制,在库函数中,就是ADC_Cmd函数,用于给ADC上电的。

 程序现象

共有两个程序

第一个程序是AD单通道

在面包板上接一个电位器,用这个电位器产生一个0-3.3V连续变化的模拟电压信号,接到STM32的PA0,之后用STM32内部的ADC读取电压数据,显示在屏幕上。这里屏幕第一行显示的是AD转换后的原始数据,第二行是经过处理后实际的电压值。往左拧,AD值减小,电压值也减,;AD值最小是0,对应的电压就是0V;往右拧,AD值变大,对应电压值也变大。STM32的ADC是12位的,所以AD结果最大值是4095,也就是2^12-1,对应电压是3.3V。

那这里AD值的未尾会有些抖动,这是正常的波动。如果你想对这个值进行判断,再执行一些操作,比如光线的AD值小于某一阈值,就开灯;大于某一阈值,就关灯。可能会存在这种情况,比如光线逐渐变暗,AD值逐渐变小,但是由于波动,AD值会在判断阈值附近来回跳变。这会导致输出产生抖动,来回开灯关灯开灯关灯,是吧。

那如何避免?这个可以使用迟滞比较的方法来完成,设置两个阈值,低于下阈值时,开灯;高于上阈值时,才关灯,这就可以避免输出抖动的问题了。还可以采取滤波的方法,让AD值平滑一些,比如均值滤波,就是读10个或20个值,取平均值,作为滤波的AD值。或者还可以裁剪分辨率,把数据的尾数去掉,也能减少波动。

接线图

根据引脚定义表,PA0到PB1这10个脚是ADC的10个通道,可以10个任意选一个接。

初始化步骤

根据ADC基本结构图来一步步配置即可。

第一步,开启RCC时钟,包括ADC和GPIO的时钟。另外这里ADCCLK的分频器,也需要配置一下。

	/*开启时钟*/RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);	//开启ADC1的时钟RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);	//开启GPIOA的时钟/*设置ADC时钟*/RCC_ADCCLKConfig(RCC_PCLK2_Div6);						//选择时钟6分频,ADCCLK = 72MHz / 6 = 12MHz

第二步,配置GPIO,把需要用的GPIO配置成模拟输入的模式。

	/*GPIO初始化*/GPIO_InitTypeDef GPIO_InitStructure;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOA, &GPIO_InitStructure);					//将PA0引脚初始化为模拟输入

第三步,配置这里的多路开关,把左边的通道接入到右边的规则组列表里。这个过程就是我们之前说的点菜,把各个通道的菜,列在菜单里。使用单次转换、非扫描模式。

	/*规则组通道配置*/ADC_RegularChannelConfig(ADC1, ADC_Channel_0, 1, ADC_SampleTime_55Cycles5);		//规则组序列1的位置,配置为通道0

第四步,就是配置ADC转换器了。在库函数里,是用结构体来配置的,可以配置AD转换器和AD数据寄存器电路的参数。包括ADC是单次转换还是连续转换、扫描还是非扫描、有几个通道。触发源是什么,数据对齐是左对齐还是右对齐。这一大批参数,用一个结构体配置就可以了。

	/*ADC初始化*/ADC_InitTypeDef ADC_InitStructure;						//定义结构体变量ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;		//模式,选择独立模式,即单独使用ADC1ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;	//数据对齐,选择右对齐ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;	//外部触发,使用软件触发,不需要外部触发ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;		//连续转换,失能,每转换一次规则组序列后停止ADC_InitStructure.ADC_ScanConvMode = DISABLE;			//扫描模式,失能,只转换规则组的序列1这一个位置ADC_InitStructure.ADC_NbrOfChannel = 1;					//通道数,为1,仅在扫描模式下,才需要指定大于1的数,在非扫描模式下,只能是1ADC_Init(ADC1, &ADC_InitStructure);						//将结构体变量交给ADC_Init,配置ADC1

如果你需要模拟看门狗,那会有几个函数用来配置阈值和监测通道的。

如果你想开启中断,那就在中断输出控制里用ITConfig函数开启对应的中断输出,然后再在NVIC里,配置一下优先级,这样就能触发中断了。不过这一块,模拟看门狗和中断,我们本期暂时不用。

第五步,就是开关控制,调用一下ADC_Cmd函数,开启ADC。这样ADC就酒配置完成了,就能正常工作了。当然,在开启ADC之后,根据手册里的建议。我们还可以对ADC开启校准,减小误差。

	/*ADC使能*/ADC_Cmd(ADC1, ENABLE);									//使能ADC1,ADC开始运行/*ADC校准*/ADC_ResetCalibration(ADC1);								//固定流程,内部有电路会自动执行校准while (ADC_GetResetCalibrationStatus(ADC1) == SET);ADC_StartCalibration(ADC1);while (ADC_GetCalibrationStatus(ADC1) == SET);

在ADC工作时,如果想要软件触发转换,那会有函数可以触发。如果想读取转换结果,那也会有函数可以读取结果。

/*** 函    数:获取AD转换的值* 参    数:无* 返 回 值:AD转换的值,范围:0~4095*/
uint16_t AD_GetValue(void)
{ADC_SoftwareStartConvCmd(ADC1, ENABLE);					//软件触发AD转换一次while (ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC) == RESET);	//等待EOC标志位,即等待AD转换结束,此程序这里大概会等待5.6usreturn ADC_GetConversionValue(ADC1);					//读数据寄存器,得到AD转换的结果
}

此程序的转换时间:72MHz/6 × (55.5+12.5)= 5.6us

代码展示

在Hardware文件夹下新建AD_Init.h、.c文件,把ADC驱动函数封装起来。

main函数

#include "stm32f10x.h"                  // Device header
#include "Delay.h"
#include "OLED.h"
#include "AD.h"uint16_t ADValue;			//定义AD值变量
float Voltage;				//定义电压变量int main(void)
{/*模块初始化*/OLED_Init();			//OLED初始化AD_Init();				//AD初始化/*显示静态字符串*/OLED_ShowString(1, 1, "ADValue:");OLED_ShowString(2, 1, "Voltage:0.00V");while (1){ADValue = AD_GetValue();					//获取AD转换的值Voltage = (float)ADValue / 4095 * 3.3;		//将AD值线性变换到0~3.3的范围,表示电压OLED_ShowNum(1, 9, ADValue, 4);				//显示AD值OLED_ShowNum(2, 9, Voltage, 1);				//显示电压值的整数部分OLED_ShowNum(2, 11, (uint16_t)(Voltage * 100) % 100, 2);	//显示电压值的小数部分Delay_ms(100);			//延时100ms,手动增加一些转换的间隔时间}
}

AD.h文件

#ifndef __AD_H
#define __AD_Hvoid AD_Init(void);
uint16_t AD_GetValue(void);#endif

AD.c文件

#include "stm32f10x.h"                  // Device header/*** 函    数:AD初始化* 参    数:无* 返 回 值:无*/
void AD_Init(void)
{/*开启时钟*/RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);	//开启ADC1的时钟RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);	//开启GPIOA的时钟/*设置ADC时钟*/RCC_ADCCLKConfig(RCC_PCLK2_Div6);						//选择时钟6分频,ADCCLK = 72MHz / 6 = 12MHz/*GPIO初始化*/GPIO_InitTypeDef GPIO_InitStructure;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOA, &GPIO_InitStructure);					//将PA0引脚初始化为模拟输入/*规则组通道配置*/ADC_RegularChannelConfig(ADC1, ADC_Channel_0, 1, ADC_SampleTime_55Cycles5);		//规则组序列1的位置,配置为通道0/*ADC初始化*/ADC_InitTypeDef ADC_InitStructure;						//定义结构体变量ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;		//模式,选择独立模式,即单独使用ADC1ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;	//数据对齐,选择右对齐ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;	//外部触发,使用软件触发,不需要外部触发ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;		//连续转换,失能,每转换一次规则组序列后停止ADC_InitStructure.ADC_ScanConvMode = DISABLE;			//扫描模式,失能,只转换规则组的序列1这一个位置ADC_InitStructure.ADC_NbrOfChannel = 1;					//通道数,为1,仅在扫描模式下,才需要指定大于1的数,在非扫描模式下,只能是1ADC_Init(ADC1, &ADC_InitStructure);						//将结构体变量交给ADC_Init,配置ADC1/*ADC使能*/ADC_Cmd(ADC1, ENABLE);									//使能ADC1,ADC开始运行/*ADC校准*/ADC_ResetCalibration(ADC1);								//固定流程,内部有电路会自动执行校准while (ADC_GetResetCalibrationStatus(ADC1) == SET);ADC_StartCalibration(ADC1);while (ADC_GetCalibrationStatus(ADC1) == SET);
}/*** 函    数:获取AD转换的值* 参    数:无* 返 回 值:AD转换的值,范围:0~4095*/
uint16_t AD_GetValue(void)
{ADC_SoftwareStartConvCmd(ADC1, ENABLE);					//软件触发AD转换一次while (ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC) == RESET);	//等待EOC标志位,即等待AD转换结束return ADC_GetConversionValue(ADC1);					//读数据寄存器,得到AD转换的结果
}

第二个是AD多通道

在第一个实验的基础上接多三个模块,把它们的AO(模拟电压输出端),分别接在了A1、A2、A3脚,加上刚才的电位器,总共4个输出通道。然后测出来的4个AD数据分别显示在屏幕上。

第一个电位器,看第一行的AD0。往右拧增大,和第一个程序一样;光敏电阻,看第二行的AD1,遮挡一下光敏电阻,光线减小,AD值增大;热敏电阻,看第三行的AD2,用手热一下这个热敏电阻,温度升高,AD值减小;最后是反射式红外传感器,手靠近,有反光,AD值减小。

接线图

同样,这些GPIO口也是可以在PA0~PB1之间任意选择的。这里选择前四个GPIO口。

初始化步骤

如果想要用扫描模式实现多通道,最好要配合DMA来实现。

这里使用单次转换、非扫描模式,只需要在每次触发转换之前,手动更改一下列表第一个位置的通道就行了。比如第一次转换,先写入通道0,之后触发、等待、读值;第二次转换,再把通道0改成通道1,之后触发、等待、读值;第三次转换,再先改成通道2,等等等等。

在AD单通道的代码上稍加修改即可,把规则组通道配置代码移动到

	/*规则组通道配置*/ADC_RegularChannelConfig(ADC1, ADC_Channel_0, 1, ADC_SampleTime_55Cycles5);		//规则组序列1的位置,配置为通道0

 以下函数里,并添加多一个参数uint8_t  ADC_Channel

/*** 函    数:获取AD转换的值* 参    数:ADC_Channel 指定AD转换的通道,范围:ADC_Channel_x,其中x可以是0/1/2/3* 返 回 值:AD转换的值,范围:0~4095*/
uint16_t AD_GetValue(uint8_t ADC_Channel)
{ADC_RegularChannelConfig(ADC1, ADC_Channel, 1, ADC_SampleTime_55Cycles5);	//在每次转换前,根据函数形参灵活更改规则组的通道1ADC_SoftwareStartConvCmd(ADC1, ENABLE);					//软件触发AD转换一次while (ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC) == RESET);	//等待EOC标志位,即等待AD转换结束return ADC_GetConversionValue(ADC1);					//读数据寄存器,得到AD转换的结果
}

代码展示

现在就是依次启动4次转换,并且在转换之前,指定了转换的通道。每次转换完成之后,把结果分别存在4个数据里,最后显示一下。这就是使用单次转换非扫描的模式,实现AD多通道的方法。

main函数

#include "stm32f10x.h"                  // Device header
#include "Delay.h"
#include "OLED.h"
#include "AD.h"uint16_t AD0, AD1, AD2, AD3;	//定义AD值变量int main(void)
{/*模块初始化*/OLED_Init();				//OLED初始化AD_Init();					//AD初始化/*显示静态字符串*/OLED_ShowString(1, 1, "AD0:");OLED_ShowString(2, 1, "AD1:");OLED_ShowString(3, 1, "AD2:");OLED_ShowString(4, 1, "AD3:");while (1){AD0 = AD_GetValue(ADC_Channel_0);		//单次启动ADC,转换通道0AD1 = AD_GetValue(ADC_Channel_1);		//单次启动ADC,转换通道1AD2 = AD_GetValue(ADC_Channel_2);		//单次启动ADC,转换通道2AD3 = AD_GetValue(ADC_Channel_3);		//单次启动ADC,转换通道3OLED_ShowNum(1, 5, AD0, 4);				//显示通道0的转换结果AD0OLED_ShowNum(2, 5, AD1, 4);				//显示通道1的转换结果AD1OLED_ShowNum(3, 5, AD2, 4);				//显示通道2的转换结果AD2OLED_ShowNum(4, 5, AD3, 4);				//显示通道3的转换结果AD3Delay_ms(100);			//延时100ms,手动增加一些转换的间隔时间}
}

AD.h文件

#ifndef __AD_H
#define __AD_Hvoid AD_Init(void);
uint16_t AD_GetValue(uint8_t ADC_Channel);#endif

AD.c文件

#include "stm32f10x.h"                  // Device header/*** 函    数:AD初始化* 参    数:无* 返 回 值:无*/
void AD_Init(void)
{/*开启时钟*/RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);	//开启ADC1的时钟RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);	//开启GPIOA的时钟/*设置ADC时钟*/RCC_ADCCLKConfig(RCC_PCLK2_Div6);						//选择时钟6分频,ADCCLK = 72MHz / 6 = 12MHz/*GPIO初始化*/GPIO_InitTypeDef GPIO_InitStructure;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_2 | GPIO_Pin_3;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOA, &GPIO_InitStructure);					//将PA0、PA1、PA2和PA3引脚初始化为模拟输入/*不在此处配置规则组序列,而是在每次AD转换前配置,这样可以灵活更改AD转换的通道*//*ADC初始化*/ADC_InitTypeDef ADC_InitStructure;						//定义结构体变量ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;		//模式,选择独立模式,即单独使用ADC1ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;	//数据对齐,选择右对齐ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;	//外部触发,使用软件触发,不需要外部触发ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;		//连续转换,失能,每转换一次规则组序列后停止ADC_InitStructure.ADC_ScanConvMode = DISABLE;			//扫描模式,失能,只转换规则组的序列1这一个位置ADC_InitStructure.ADC_NbrOfChannel = 1;					//通道数,为1,仅在扫描模式下,才需要指定大于1的数,在非扫描模式下,只能是1ADC_Init(ADC1, &ADC_InitStructure);						//将结构体变量交给ADC_Init,配置ADC1/*ADC使能*/ADC_Cmd(ADC1, ENABLE);									//使能ADC1,ADC开始运行/*ADC校准*/ADC_ResetCalibration(ADC1);								//固定流程,内部有电路会自动执行校准while (ADC_GetResetCalibrationStatus(ADC1) == SET);ADC_StartCalibration(ADC1);while (ADC_GetCalibrationStatus(ADC1) == SET);
}/*** 函    数:获取AD转换的值* 参    数:ADC_Channel 指定AD转换的通道,范围:ADC_Channel_x,其中x可以是0/1/2/3* 返 回 值:AD转换的值,范围:0~4095*/
uint16_t AD_GetValue(uint8_t ADC_Channel)
{ADC_RegularChannelConfig(ADC1, ADC_Channel, 1, ADC_SampleTime_55Cycles5);	//在每次转换前,根据函数形参灵活更改规则组的通道1ADC_SoftwareStartConvCmd(ADC1, ENABLE);					//软件触发AD转换一次while (ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC) == RESET);	//等待EOC标志位,即等待AD转换结束return ADC_GetConversionValue(ADC1);					//读数据寄存器,得到AD转换的结果
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/571970.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

HTML静态网页成品作业(HTML+CSS+JS)——中华美食八大菜系介绍(1个页面)

🎉不定期分享源码,关注不丢失哦 文章目录 一、作品介绍二、作品演示三、代码目录四、网站代码HTML部分代码 五、源码获取 一、作品介绍 🏷️本套采用HTMLCSS,使用Javacsript代码实现图片轮播切换,共有1个页面。 二、…

实名羡慕!这些人已经用上了Sora

ChatGPT狂飙160天,世界已经不是之前的样子。 新建了人工智能中文站https://ai.weoknow.com 每天给大家更新可用的国内可用chatGPT资源 发布在https://it.weoknow.com 更多资源欢迎关注 Sora 第三方口碑出炉,或许带给艺术家们最大的好处是:…

KingSCADA|如何实现文本显示设备的实时通讯状态?

哈喽,你好啊,我是雷工! 在SCADA项目中,有些要求在界面上实时显示SCADA系统与设备的实时通讯状态,来及时了解PLC或其他设备与SCADA系统的通讯状态是否正常,以及简单的通讯异常分析,在KingSCADA中该如何实现通讯状态的文本显示呢? 接下来用简单的样例介绍KingSCADA如何实…

学成在线项目学习

技术栈 学成在线服务端基于Spring Boot构建,采用Spring Cloud微服务框架。 持久层:MySQL、MongoDB、Redis、ElasticSearch 数据访问层:使用Spring Data JPA 、Mybatis、Spring Data Mongodb等 业务层:Spring IOC、Aop事务控制、S…

3D软件坐标系速查

本文介绍不同3D软件的世界坐标系之间的差异及其工作原理。 基本上,游戏引擎和3D软件包最重要的问题是根据软件的坐标轴系统创建资产,正确缩放它们并根据要完成的工作设置枢轴系统。 坐标系正确性的定义可能会根据模型导入的游戏引擎或 3D 软件而变化。…

【C语言】linux内核pci_set_drvdata函数

一、讲解 该函数pci_set_drvdata是Linux内核中用于PCI设备的一个辅助函数,其主要作用是设置给定PCI设备的驱动程序私有数据。这个函数的参数包括一个指向pci_dev结构体的指针pdev,该结构体描述了一个PCI设备,以及一个void *类型的指针data&a…

鸿蒙OS实例:同步获取应用配置的【versionCode和versionName】

1.同步方式获取 首先需要导包&#xff1a; import bundleManager from ohos.bundle.bundleManager 工具类&#xff1a; public static async getVersionName(): Promise<string> {try {let bundleInfo await bundleManager.getBundleInfoForSelf(bundleManager.Bundle…

面试经典150题【111-120】

文章目录 面试经典150题【111-120】67.二进制求和190.颠倒二进制位191.位1的个数136.只出现一次的数字137.只出现一次的数字II201.数字范围按位与5.最长回文子串97.交错字符串72.编辑距离221.最大正方形 面试经典150题【111-120】 六道位运算&#xff0c;四道二维dp 67.二进制…

Profinet转ModbusTCP:从站设备转换与集成案例

本案例旨在探讨如何将Modbus TCP设备数据成功地接入到西门子PROFINET网络中。为了实 现这一目标&#xff0c;我们将使用西门子S7-1200型PLC以及耐特森Profinet转ModbusTCP网关作为 关键设备。为了模拟Modbus从站&#xff0c;我们将使用电脑安装modbus poll软件。首先需要了解Pr…

VLAN的原理及配置

文章目录 一、VLAN的概述1、VLAN的概念2、VLAN的优势 二、静态VLAN三、静态VLAN的配置1.VLAN的范围2.VLAN基本配置 四、Trunk和access的作用参考 一、VLAN的概述 1、VLAN的概念 VLAN就是将网络从逻辑上划分为若按个小的网络&#xff0c;也就是虚拟局域网。 2、VLAN的优势 使…

逐步学习Go-并发通道chan(channel)

概述 Go的Routines并发模型是基于CSP&#xff0c;如果你看过七周七并发&#xff0c;那么你应该了解。 什么是CSP&#xff1f; "Communicating Sequential Processes"&#xff08;CSP&#xff09;这个词组的含义来自其英文直译以及在计算机科学中的使用环境。 CSP…

今日AI热点:科技前沿新动态

引言&#xff1a; 人工智能领域日新月异&#xff0c;每天都有令人振奋的新进展。从苹果到谷歌&#xff0c;从OpenAI到Meta&#xff0c;各大科技巨头纷纷推出创新产品和技术&#xff0c;不断推动着人工智能的发展。让我们一起来看看今日AI热点&#xff0c;探索这个充满活力和激情…