使用STM32编写ADC功能,实现单路电压测量并在OLED上显示

先来看看本次实验的结果吧:stm32点电压测量范围为0-3.3V,数值为:0-4095

来看看这个工程的文件布局吧:

实现ADC功能总共分为六步:

第一步:开始RCC时钟,包括ADC和GPIO的时钟,ADCCLK的分频器也需要配置一下。

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

第三步:配置多路开关,把左边的通道接入规则组列表里

第四步:配置ADC转换器,用结构体配置,一大块的参数。

第五步:打开ADC_CMD()开启ADC。

第六步:校准ADC

接着来学习一下ADC相关的库函数:(看起来好像有点乱,后面有截图)

void RCC_ADCCLKConfig(uint32_t RCC_PCLK2); 用来配置ADCCLK分频器的 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_GetSoftwareStartConvStatus(ADC_TypeDef* ADCx); ADC获取软件开始转换状态 FlagStatus ADC_GetFlagStatus(ADC_TypeDef* ADCx, uint8_t ADC_FLAG); 获取转换完成标志位状态,判断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); 规则组通道配置 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_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);  //ADC温度传感器内部参考电压控制,用来开启内部通道 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);   //清楚中断挂起位

接下来就是每个文件的源码了:

MyADC.c文件:

#include "stm32f10x.h"                  // Device header


void MyADC_Init(void)
	
{
	//第一步:开始RCC时钟,包括ADC和GPIO的时钟,ADCCLK的分频器也需要配置一下。
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);   //开启ADC1的时钟
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);  //开启GPIOA的时钟
	
	RCC_ADCCLKConfig(RCC_PCLK2_Div6);      // ADC的时钟选择6分频,也就是72M/6=12M
	
	//第二步:配置GPIO,把需要用的GPIO配置成模拟输入的模式
	GPIO_InitTypeDef GPIO_InitStruct;    //GPIO初始化的结构体
	GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AIN;  // 模式为模拟输入
	GPIO_InitStruct.GPIO_Pin = GPIO_Pin_0;       // 初始化端口0
	GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;  //端口频率50M
	GPIO_Init(GPIOA, &GPIO_InitStruct);           // GPIOA初始化
	
	//第三步:配置多路开关,把左边的通道接入规则组列表里
	ADC_RegularChannelConfig(ADC1, ADC_Channel_0, 1, ADC_SampleTime_28Cycles5); //ADC1规则配置(ADC1,通道1,列表1,转换时间28.5个时钟(12M))
	
	//第四步:配置ADC转换器,用结构体配置,一大块的参数。
	ADC_InitTypeDef ADC_InitStruct;                    //ADC初始化结构体
	ADC_InitStruct.ADC_ContinuousConvMode = DISABLE;            //连续转换模式:关闭
	ADC_InitStruct.ADC_DataAlign = ADC_DataAlign_Right;            // 数据对齐:右对齐
	ADC_InitStruct.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;   //ADC中断触发:空,也就是软件触发
	ADC_InitStruct.ADC_Mode = ADC_Mode_Independent;               // ADC模式:独立模式
	ADC_InitStruct.ADC_NbrOfChannel = 1;                   //规则组中的通道数:1
	ADC_InitStruct.ADC_ScanConvMode = DISABLE;             //扫描模式:关闭
	ADC_Init(ADC1, &ADC_InitStruct);                    //ADC初始化
	//第五步:打开ADC_CMD()开启ADC。
	ADC_Cmd(ADC1, ENABLE);                        // ADC开启
	//第六步:校准ADC
	ADC_ResetCalibration(ADC1);                        // 复位校准ADC
	while(ADC_GetResetCalibrationStatus(ADC1) == SET);    // 等待校准标志位置0
	ADC_StartCalibration(ADC1);                         // 开始复位校准ADC
	while(ADC_GetCalibrationStatus(ADC1) == SET);          // 等待开始校准结束标志位置0
	
}

uint16_t Get_val(void)
{
	ADC_SoftwareStartConvCmd(ADC1, ENABLE);                  // 软件触发ADC使能
	while(ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC) == RESET);   // 等待获取EOC标志位置1
	return ADC_GetConversionValue(ADC1);                    // 返回ADC转换的结果值

}

MyADC.h文件:

#ifndef __MYADC_H
#define __MYADC_H


void MyADC_Init(void);

uint16_t Get_val(void);


#endif

主函数main.c文件:

#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,手动增加一些转换的间隔时间
	}
}

还有一个OLED的代码就不展示了,没有的可以在之前的博文中找到,都有公布过,自己挨片的看就能找到的,编译后写入到STM32中就能看到实验结果了,调整电位器就能看到电压和数值的变化,电位器中间抽头接A0,另外两个头中的一个接3.3V电源,这就是整个的接线图了。

作者:尚久龙

物联沃分享整理
物联沃-IOTWORD物联网 » 使用STM32编写ADC功能,实现单路电压测量并在OLED上显示

发表评论