快速简单带你入门 学习adc (模拟转数字电路)要了解adc

快速简单带你入门 学习adc (模拟转数字电路)要了解adc

ADC(analog to digital converter)即模数转换器,它可以将模拟信号转换为数字信号。按照其转换原理主要分为逐次逼近型、双积分型 、电压频率转换型三种。STM32F1的ADC就是逐次逼近型的模拟数字转换器。

总结:ADC就是数模转换,将模拟量转换为数字量

本次学习使用F103x 系列主板

STM32F103 系列一般都有 3 个 ADC,精度为12位这些 ADC 可以独立使用,也可以使用双重(提高采样率),每个ADC最多有16个外部通道。其中ADC1和ADC2都有16个外部通道,ADC3一般有8个外部通道,各通道的A/D转换可以单次、连续、扫描或间断执行,ADC转换的结果可以左对齐或右对齐储存在16位数据寄存器中。ADC的输入时钟不得超过14MHz,其时钟频率由PCLK2分频产生,ADC具有模拟看门狗特性,允许应用程序检测输入电压是否超出用户定义的阀值上限或者下限。

、、、、、、、、、、学习重点学会使用、、、、、、、、、、、、、、、、、、、、

我们知道STM32F1 ADC转换模式有单次转换与连续转换区分。在单次转换模式下,ADC 执行一次转换。可以通过 ADC_CR2 寄存器的SWSTART 位(只适用于规则通道)启动,也可以通过外部触发启动(适用于规则通道和注入通道),这时 CONT 位为 0。以规则通道为例,一旦所选择的通道转换完成,转换结果将被存在 ADC_DR 寄存器中,EOC(转换结束)标志将被置位,如果设置了 EOCIE,则会产生中断。然后 ADC 将停止,直到下次启动。

在连续转换模式下,ADC 结束一个转换后立即启动一个新的转换。CONT 位为 1 时,可通过外部触发或将 ADC_CR2 寄存器中的 SWSTRT 位置 1 来启动此模式(仅适用于规则通道)。需要注意的是:此模式无法连续转换注入通道。连续模式下唯一的例外情况是,注入通道配置为在规则通道之后自动转换(使用 JAUTO 位)。

STM32F1 ADC配置步骤
接下来我们介绍下如何使用库函数对ADC进行配置。这个也是在编写程序中必须要了解的。具体步骤如下:(ADC相关库函数在stm32f10x_adc.c和stm32f10x_adc.h文件中)

  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初始化
  1. 使能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)); //等待校准结束

  2. 读取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 ));//等待转换结束
    

废话不多说,直接上代码,本次测试使用f103 zet6板子,测试ADC

4.编写ADC控制程序
本章所要实现的功能是:通过ADC1通道1采样外部电压值,将采样的
AD值和转换后的电压值通过串口打印出来,同时D1指示灯闪烁,提示系
统正常运行。程序框架如下:
(1)初始化ADC1_IN1相关参数,开启ADC1
(2)编写获取ADC1_IN1的AD转换值函数
(3)编写主函数

Adc.c
#include "adc.h"
#include "SysTick.h"

/*******************************************************************************
* 函 数 名         : ADCx_Init
* 函数功能		   : ADC初始化	
* 输    入         : 无
* 输    出         : 无
*******************************************************************************/
void ADCx_Init(void)
{
	GPIO_InitTypeDef GPIO_InitStructure; //定义结构体变量	
	ADC_InitTypeDef       ADC_InitStructure;
	
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_ADC1,ENABLE);
	
	RCC_ADCCLKConfig(RCC_PCLK2_Div6);//设置ADC分频因子6 72M/6=12,ADC最大时间不能超过14M
	
	GPIO_InitStructure.GPIO_Pin=GPIO_Pin_1;//ADC
	GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AIN;	//模拟输入
	GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
	GPIO_Init(GPIOA,&GPIO_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初始化
	
	ADC_Cmd(ADC1, ENABLE);//开启AD转换器
	
	ADC_ResetCalibration(ADC1);//重置指定的ADC的校准寄存器
	while(ADC_GetResetCalibrationStatus(ADC1));//获取ADC重置校准寄存器的状态
	
	ADC_StartCalibration(ADC1);//开始指定ADC的校准状态
	while(ADC_GetCalibrationStatus(ADC1));//获取指定ADC的校准程序

	ADC_SoftwareStartConvCmd(ADC1, ENABLE);//使能或者失能指定的ADC的软件转换启动功能
}

/*******************************************************************************
* 函 数 名         : Get_ADC_Value
* 函数功能		   : 获取通道ch的转换值,取times次,然后平均 	
* 输    入         : ch:通道编号
					 times:获取次数
* 输    出         : 通道ch的times次转换结果平均值
*******************************************************************************/
u16 Get_ADC_Value(u8 ch,u8 times)
{
	u32 temp_val=0;
	u8 t;
	//设置指定ADC的规则组通道,一个序列,采样时间
	ADC_RegularChannelConfig(ADC1, ch, 1, ADC_SampleTime_239Cycles5);	//ADC1,ADC通道,239.5个周期,提高采样时间可以提高精确度			    
	
	for(t=0;t<times;t++)
	{
		ADC_SoftwareStartConvCmd(ADC1, ENABLE);//使能指定的ADC1的软件转换启动功能	
		while(!ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC ));//等待转换结束
		temp_val+=ADC_GetConversionValue(ADC1);
		delay_ms(5);
	}
	return temp_val/times;
} 
Adc.h

#ifndef _adc_H
#define _adc_H

#include "system.h"

void ADCx_Init(void);
u16 Get_ADC_Value(u8 ch,u8 times);


#endif
Main.c


/*******************************************************************************
* 函 数 名         : main
* 函数功能		   : 主函数
* 输    入         : 无
* 输    出         : 无
*******************************************************************************/
int main()
{
	u8 i=0;
	u16 value=0;
	float vol;
	
	SysTick_Init(72);
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);  //中断优先级分组 分2组
	LED_Init();
	USART1_Init(115200);
	ADCx_Init();
	
	while(1)
	{
		i++;
		if(i%20==0)
		{
			LED1=!LED1;
		}
		
		if(i%50==0)
		{
			value=Get_ADC_Value(ADC_Channel_1,20);
			printf("检测AD值为:%d\r\n",value);
			vol=(float)value*(3.3/4096);
			printf("检测电压值为:%.2fV\r\n",vol);
		}
		delay_ms(10);	
	}
}

测试效果图如下,adc 测电压

在这里插入图片描述

菜鸟止步------------------文字终结者----我看了也烦-------------------------------------》

想仔细学习的可以参考下图说明带有注释。视频讲解B战搜-“闰土小蒋” 一起学习ADC内部的结构。如下图所示:(大家也可以查看《STM32F10x中文参考手册》-11模数转换器(ADC)章节。
在这里插入图片描述

  1. 电压输入引脚
    ADC输入电压范围为: VREF- ≤ VIN ≤ VREF+。由 VREF-、 VREF+
    、 VDDA 、 VSSA这四个外部引脚决定。通常我们把 VSSA和 VREF-接地
    ,把 VREF+和 VDDA 接 3.3V,因此ADC的输入电压范围为:0~3.3V。我
    们使用的开发板ADC输入电压范围为0~3.3V。

  2. 标号2:输入通道STM32 的 ADC的输入通道多达 18 个,其中外部的 16 个通道就是框图中的ADCx_IN0、ADCx_IN1…ADCx_IN5(x=1/2/3,表示ADC数),通过这16个外部通道可以采集模拟信号。这 16 个通道对应着不同的 IO 口, 具体是哪一个 IO 口可以从数据手册查询到,也可以从下图查
    看,同样我们在开发板芯片原理图内也给大家标注了。其中 ADC1 还有2个内部通道:ADC1 的通道16连接到了芯片内部的温度传感器,通道17连接到了内部参考电压 VREFINT。ADC2 和ADC3的通道 16、 17全部连接到了内部的 VSS。

  3. 标号3:通道转换顺序外部的 16 个通道在转换的时候可分为2组通道:规则通道组和注入通道组,其中规则通道组最多有16路,注入通道组最多有 4 路。
    规则通道组:从名字来理解,规则通道就是一种规规矩矩的通道,类似于正常执行的程序,通常我们使用的都是这个通道。

    注入通道组:从名字来理解,注入即为插入,是一种不安分的通道,类似于中断。当程序正常往下执行时,中断可以打断程序的执行。同样如果在规则通道转换过程中,有注入通道插入,那么就要先转换完注入通道,等注入通道转换完成后再回到规则通道的转换流程。

    每个组包含一个转换序列,该序列可按任意顺序在任意通道上完成。
    例如,可按以下顺序对序列进行转换: ADC_IN3、ADC_IN8、 ADC_IN2、 ADC_IN2、 ADC_IN0、 ADC_IN2、 ADC_IN2、 ADC_IN15。

  4. 标号4:触发源
    选择好输入通道,设置好转换顺序,接下来就可以开始转换。要开启ADC转换,可以直接设置ADC 控制寄存器ADC_CR2 的 ADON位为1,即使能ADC。当然ADC还支持外部事件触发转换,触发源有很多,具体选择哪一种触发源,由 ADC 控制寄存器2:ADC_CR2 的 EXTSEL[2:0]和 JEXTSEL[2:0]位来控制。EXTSEL[2:0]用于选择规则通道的触发源,JEXTSEL[2:0]用于选择注入通道的触发源。选定好触发源之后,触发源是否要激活,则由 ADC 控制寄存器ADC_CR2 的 EXTTRIG 和 JEXTTRIG
    这两位来激活。

    如果使能了外部触发事件,我们还可以通过设置 ADC 控制寄存器
    2:ADC_CR2 的EXTEN[1:0]和 JEXTEN[1:0]来控制触发极性,可以有 4 种
    状态,分别是:禁止触发检测、上升沿检测、下降沿检测以及上升沿和
    下降沿均检测。

  5. 标号5:ADC时钟
    ADC 输入时钟 ADC_CLK 由 APB2经过分频产生,最大值是14MHz,分频因子由 RCC 时钟配置寄存器 RCC_CFGR 的位 15:14 ADCPRE[1:0]设置,可以是 2/4/6/8 分频,注意这里没有 1 分频。我们知道APB2总线时钟为72M,而ADC最大工作频率为14M,所以一般设置分频因子为6,这样
    ADC的输入时钟为12M。
    ADC要完成对输入电压的采样需要若干个ADC_CLK周期,采样的周期数可通过ADC 采样时间寄存器 ADC_SMPR1 和 ADC_SMPR2 中的 SMP[2:0]位设置, ADC_SMPR2控制的是通道 0~9, ADC_SMPR1 控制的是通道 10~17。每个通道可以分别用不同的时间采样。其中采样周期最小是1.5个,即如果我们要达到最快的采样,那么应该设置采样周期为1.5个周期,这里说的周期就是 1/ADC_CLK。
    ADC 的总转换时间跟ADC 的输入时钟和采样时间有关,其公式如下:Tconv = 采样时间 + 12.5个周期其中Tconv为ADC总转换时间,当ADC_CLK=14Mhz的时候,并设置1.5个周期的采样时间,则Tcovn=1.5+12.5=14个周期=1us。

  6. 标号6:数据寄存器ADC 转换后的数据根据转换组的不同,规则组的数据放在ADC_DR 寄
    存器内,注入组的数据放在 JDRx内。
    因为STM32F1的ADC是12位转换精度,而数据寄存器是16位,所以ADC在存放数据的时候就有左对齐和右对齐区分。如果是左对齐,AD转换完成数据存放在 ADC_DR 寄存器的[4:15]位内;如果是右对齐,则存放在 ADC_DR 寄存器的[0:11]位内。具体选择何种存放方式,需通过ADC_CR2 的 11 位 ALIGN 设置。

  7. 标号7:中断
    当发生如下事件且使能相应中断标志位时,ADC能产生中断。
    1.转换结束(规则转换)与注入转换结束
    2.模拟看门狗事件
    3.DMA请求

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

闰土小蒋

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值