1.接线图:
电位器中间的扭头往左拧,电阻器向左;往右拧,电阻器向右。输出电压即为可调电压。接在PA0(引脚定义图可知,PA0~PB1的十个引脚是ADC的十个通道,可任选接哪个)。
实物图如下:
注:蓝色的电位器要把三个引脚的插在面包板上侧。
2.代码部分如下:
主函数部分:(main.c)
#include "stm32f10x.h" // Device header #include "Delay.h" #include "OLED.h" #include "AD.h" uint16_t ADValue; float Voltage; int main(void) { OLED_Init(); AD_Init(); OLED_ShowString(1,1,"ADValue");//显示AD值(0~4095) OLED_ShowString(2,1,"Voltage");//显示电压值(0~3.3V) while(1) { ADValue=AD_GETValue();//启动等待读取 Voltage=(float)ADValue/4095*3.3;//将ADValue的0~4095变为0~3.3V OLED_ShowNum(1,9,ADValue,4); OLED_ShowNum(2,9,Voltage,1);//只会显示整数的部分,因为该OLED没小数点,需要自行计算小数点部分 OLED_ShowNum(2,11,(uint16_t)(Voltage*100)%100,2);//浮点数不能取余,需要强制类型转换 Delay_ms(100);//刷新/持续时间 } }
//现象:OLED上有AD值,并且左拧数据减小,右拧数据增大。
//注:AD的个位可能会持续跳动,属于正常现象,如果在固定场合规定不能跳动,如AD高于某一值就亮灯,低于就灭灯,
//就会导致频繁的亮灭,因此,可以:1.设置阈值,超过某一值灯就亮,低于某一值灯就灭。2.滤波。3.裁剪分辨率
AD.c部分如下:
#include "stm32f10x.h" // Device header //思路如下:(参照ADC基本结构图) //1.开启RCC时钟,包括ADC和GPIO的时钟,配置ADCCLOCK的分频器 //2.配置GPIO为模拟输入模式 //3.配置多路开关通道,把左边的通道(如GPIO)接到右边的规则组里 //4.配置ADC转换器,用结构体(中断和模拟看门狗,此处用不到,就不写,用到的话可以写) //(参数决定ADC是单次转换还是连续转换,扫描还是非扫描,有几个通道,触发源是什么,数据对齐是左对齐还是右对齐) //5.调用ADC_Cmd进行开关控制 //6.校准4函数 void AD_Init(void) { //1.开启RCC时钟 RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1,ENABLE); RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE); RCC_ADCCLKConfig(RCC_PCLK2_Div6);//对APB2进行6分频 //2.配置GPIO为模拟输入模式(可复制LED.c初始化部分代码) GPIO_InitTypeDef GPIO_InitStructure; GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AIN;//AIN是ADC专属模式(模拟输入模式下,GPIO无效,防止对ADC产生干扰) GPIO_InitStructure.GPIO_Pin=GPIO_Pin_0;//PA0口初始化为模拟输入的引脚 GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz; GPIO_Init(GPIOA,&GPIO_InitStructure); //3.选择输入通道 ADC_RegularChannelConfig(ADC1,ADC_Channel_0, 1,ADC_SampleTime_55Cycles5);//在规则组列表的第一个位置写入通道0 //参数二:选择通道0, 参数三:序列1~16之间的一个数 参数四:指定通道的采样时间(转换快选择参数,稳定选大参数) //4.用结构体初始化ADC(单次转换非扫描) ADC_InitTypeDef ADC_InitStructure; ADC_InitStructure.ADC_ContinuousConvMode=DISABLE;//选择连续转换(ENABLE)还是单次转换(DISABLE) ADC_InitStructure.ADC_DataAlign=ADC_DataAlign_Right;//数据对齐(右对齐:ADC_DataAlign_Right) ADC_InitStructure.ADC_ExternalTrigConv=ADC_ExternalTrigConv_None; //外部触发源选择(不使用外部触发,使用软件触发:ADC_ExternalTrigConv_None) ADC_InitStructure.ADC_Mode=ADC_Mode_Independent;//ADC工作模式,选择是单ADC模式(ADC_Mode_Independent)or双ADC模式 ADC_InitStructure.ADC_NbrOfChannel=1;//写几就几个通道起作用 ADC_InitStructure.ADC_ScanConvMode=DISABLE;//选择扫描模式(ENABLE)还是非扫描模式(DISABLE) ADC_Init(ADC1,&ADC_InitStructure); //5.调用ADC_Cmd进行开关控制 ADC_Cmd(ADC1,ENABLE); //6.校准4函数 ADC_ResetCalibration(ADC1); while(ADC_GetResetCalibrationStatus(ADC1)==SET);//是SET就循环,不是就跳出了 ADC_StartCalibration(ADC1); while(ADC_GetCalibrationStatus(ADC1)==SET); } //启动转换获取结果函数 //思路:软件触发转换+ 等待转换完成,即等待EOC等于一 +读取ADC数据寄存器(参照转换模式图) uint16_t AD_GETValue(void) { ADC_SoftwareStartConvCmd(ADC1,ENABLE);//放在这里表示是单次转换,需要反复触发 while(ADC_GetFlagStatus(ADC1,ADC_FLAG_EOC)==RESET);//获取标志位状态函数,此处第二个参数选择规则转换完成标志位 //第二个参数可填:ADC_FLAG_AWD(模拟看门狗),ADC_FLAG_EOC(规则转换完成标志位),ADC_FLAG_JEOC(注入组转换完成标志位) //ADC_FLAG_JSTRT(注入组开始转换标志位),ADC_FLAG_STRT(规则组开始转换标志位) return ADC_GetConversionValue(ADC1);//ADC获取转换值 }
AD.h代码如下:
#ifndef __AD_H #define __AD_H void AD_Init(void); uint16_t AD_GETValue(void); #endif
3.AD用到的库函数总结
//ADCCLK相关配置函数(在rcc.h里):
//void RCC_ADCCLKConfig(uint32_t RCC_PCLK2);//配置ADCCLK分频器,对APB2的72MHz时钟选择2,4,6,8分频,输入到ADCCLK
//ADC相关库函数(在adc.h里):
//void ADC_DeInit(ADC_TypeDef* ADCx);//恢复出厂配置
//void ADC_Init(ADC_TypeDef* ADCx, ADC_InitTypeDef* ADC_InitStruct);//初始化
//void ADC_StructInit(ADC_InitTypeDef* ADC_InitStruct);//配置结构体
//void ADC_Cmd(ADC_TypeDef* ADCx, FunctionalState NewState);//给ADC上电,即最后一步的开关控制
//void ADC_DMACmd(ADC_TypeDef* ADCx, FunctionalState NewState);//开启DMA输出信号
//void ADC_ITConfig(ADC_TypeDef* ADCx, uint16_t ADC_IT, FunctionalState NewState);//中断输出控制
//以下为控制校准相关函数:
//void ADC_ResetCalibration(ADC_TypeDef* ADCx);//复位校准
//FlagStatus ADC_GetResetCalibrationStatus(ADC_TypeDef* ADCx);//获取复位校准状态,等待校准完成
//void ADC_StartCalibration(ADC_TypeDef* ADCx);//开始校准
//FlagStatus ADC_GetCalibrationStatus(ADC_TypeDef* ADCx);//获取开始校准状态,等待校准完成
//void ADC_SoftwareStartConvCmd(ADC_TypeDef* ADCx, FunctionalState NewState);//ADC软件开始转换控制--触发控制的软件触发
//FlagStatus ADC_GetSoftwareStartInjectedConvCmdStatus(ADC_TypeDef* ADCx);//获取标志位状态,转换结束EOC置1
//以下为配置间断模式相关函数:
//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规则组通道配置,给序列的每个位置填写指定通道(重点)
//参数二:ADC_Channel为指定的通道; 参数三:ADC_Channel序列几; 参数四:ADC_SampleTime指定通道的采样时间
//void ADC_ExternalTrigConvCmd(ADC_TypeDef* ADCx, FunctionalState NewState);//判断是否允许ADC外部触发转换
//uint16_t ADC_GetConversionValue(ADC_TypeDef* ADCx);//ADC获取转换值,读取结果时使用该函数。(重点)
//uint32_t ADC_GetDualModeConversionValue(void);//获取双模式转换结果
//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);//清除中断挂起位