STM32 实现ADC 库函数版

ADC 顾名思义 将模拟信号转换为数字信号

ADC转换分为2个通道组:规则通道组和注入通道组。
规则通道相当于正常运行的程序,而注入通道,就是中断。
程序正常运行(执行规则通道),外部中断产生,执行中断代码(执行注入通道)

STM32的ADC的规则通道组包含16个转换,而注入通道包含4个通道内

数据存储方式:左对齐 右对齐(存储在16位数据寄存器中 左高 右低)

不要将高于3.3V的接到ADC上面

通道16 只在ADC1 (内部温度传感器)
通道17 只在ADC1 (内部参考电压VREF)

外设挂接在APB2
ADC时钟 最大14M 通过分频因子改变时钟 一般分频设置为6 (72 / 6 = 12)

stm32f103 CUBEMX adc注入配置_#include

ADC总转换时间公式
Tconv = 采样时间 + 12.5个周期

ADC 转换模式 : 单次转换 和 连续转换

单次转换 ADC执行一次 转换,可以通过外部触发执行转换
连续转换 ADC执行的一次 后准备下一次转换

配置步骤

(1)使能端口时钟和ADC时钟,设置引脚模式为模拟输入

RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
 RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1,ENABLE);
 GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AN; //模拟输入模式

(2)设置ADC的分频因子

RCC_ADCCLKConfig(RCC_PCLK2_Div6);

(3)初始化ADC参数,包括ADC工作模式、规则序列等

void ADC_Init(ADC_TypeDef* ADCx, ADC_InitTypeDef* ADC_InitStruct);
 //
 typedef struct
 {
 uint32_t ADC_Mode; // ADC 工作模式选择
 FunctionalState ADC_ScanConvMode; / ADC 扫描(多通道)或者单次(单通道)模式选择 */
 FunctionalState ADC_ContinuousConvMode; // ADC 单次转换或者连续转换选择
 uint32_t ADC_ExternalTrigConv; // ADC 转换触发信号选择
 uint32_t ADC_DataAlign; // ADC 数据寄存器对齐格式
 uint8_t ADC_NbrOfChannel; // ADC 采集通道数
 } ADC_InitTypeDef;
 /***/ADC_InitTypeDef ADC_InitStructure;
 ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;
 ADC_InitStructure.ADC_ScanConvMode = DISABLE;//非扫描模式 
 ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;//关闭连续转换
 ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;//禁止触发检测,使用软件触发
 ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;//右对齐 
 ADC_InitStructure.ADC_NbrOfChannel = 1;//1个转换在规则序列中 也就是只转换规则序列1
 ADC_Init(ADC1, &ADC_InitStructure);//ADC初始化

/********************************************************************************/
(4)使能ADC并校准

void ADC_Cmd(ADC_TypeDef* ADCx, FunctionalState NewState);
 ADC_Cmd(ADC1, ENABLE);//开启AD转换器

执行复位校准的方法是:

ADC_ResetCalibration(ADC1);

执行 ADC 校准的方法是:

ADC_StartCalibration(ADC1); //开始指定 ADC1 的校准状态
 while(ADC_GetResetCalibrationStatus(ADC1)); //等待复位校准结束
 while(ADC_GetCalibrationStatus(ADC1)); //等待校准结束

(5)读取ADC转换值
设置规则序列通道以及采样周期的库函数是:

void ADC_RegularChannelConfig(ADC_TypeDef* ADCx, uint8_t
 ADC_Channel,uint8_t Rank, uint8_t ADC_SampleTime);ADC_RegularChannelConfig(ADC1, ADC_Channel_1, 1, ADC_SampleTime_239Cycles5 );

设置好规则序列通道及采样周期,接下来就要开启转换,由于我们采
用的是软件触发,库函数

void ADC_SoftwareStartConvCmd(ADC_TypeDef* ADCx, FunctionalState NewState);

开启转换之后,就可以获取ADC 转换结果数据,调用的库函数是:

uint16_t ADC_GetConversionValue(ADC_TypeDef* ADCx);

获取 AD 转换的状态信息的库函数是:

FlagStatus ADC_GetFlagStatus(ADC_TypeDef* ADCx, uint8_t
 ADC_FLAG);

例如我们要判断 ADC1 的转换是否结束,方法是:

while(!ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC ));//等待转换结束

实现代码如下

#include "Adc.h"

void ADCx_Init(void)
{
	GPIO_InitTypeDef gpioA;
	ADC_InitTypeDef adc;
	
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_ADC1,ENABLE);
	
	//设置ADC分频因子6 72M/6=12,ADC最大时间不能超过14M
	RCC_ADCCLKConfig(RCC_PCLK2_Div6);
	
	gpioA.GPIO_Mode = GPIO_Mode_AIN;   //模拟输入
	gpioA.GPIO_Pin = GPIO_Pin_1;
	gpioA.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOA,&gpioA);
	
	
	adc.ADC_Mode = ADC_Mode_Independent;  //独立
	adc.ADC_ScanConvMode = DISABLE;  //非扫描式
	adc.ADC_ContinuousConvMode = DISABLE;  //关闭连续转换
	adc.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;  //禁止触发检测,使用软件触发
	adc.ADC_DataAlign = ADC_DataAlign_Right; //右对齐
	adc.ADC_NbrOfChannel = 1;  //1个转换在规则序列中 也就是只转换规则序列1 
	ADC_Init(ADC1,&adc);
	
	ADC_Cmd(ADC1,ENABLE);  //开启AD转换
	
	ADC_ResetCalibration(ADC1);  //重置指定的ADC的校准寄存器
	
	//获取ADC重置校准寄存器的状态
	while(ADC_GetResetCalibrationStatus(ADC1));
	
	ADC_StartCalibration(ADC1);  //开始指定ADC的校准状态
	while(ADC_GetCalibrationStatus(ADC1));	//获取指定ADC的校准程序
	
	ADC_SoftwareStartConvCmd(ADC1,ENABLE);  //使能
	
}

u16 Get_ADC_Value(u8 ch,u8 times)
{
	u32 temp_val = 0;
	u8 i;
	
	//设置指定ADC的规则组通道,一个序列,采样时间
	ADC_RegularChannelConfig(ADC1,ch,1,ADC_SampleTime_239Cycles5);
	
	for(i = 0; i < times; i++)
	{
		ADC_SoftwareStartConvCmd(ADC1,ENABLE);  //使能指定的ADC1的软件转换启动功能
		while(!ADC_GetFlagStatus(ADC1,ADC_FLAG_EOC));  //等待转换结束
		
		temp_val += ADC_GetConversionValue(ADC1);
		
		delay_ms(5);
	}
	
	return temp_val / times;
}

主函数实现如下

#include "stm32f10x.h"
#include "Uart.h"
#include "Adc.h"
#include "led.h"

int main()
{
	u16 indata = 0;
	u8 i;
	float vol;
	
	SysTick_Init(72);
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
	
	UART1_Init(9600);
	printf ("捕获开始\r\n");
	ADCx_Init();
	LED_Init();
	
	led1 = 0;
	while(1)
	{
		i++;
		if(i % 20 == 0)
		{
			led1 = !led1;
		}
		
		if(i % 50 == 0)
		{
			indata = Get_ADC_Value(ADC_Channel_1,20);
			
			printf("检测AD值为:     %d\r\n",indata);
			
			vol = (float) indata * (3.3 / 4096);
			
			printf("检测电压值为:   %.2fV\r\n",vol);
		}
		
		delay_ms(500);
	}
}