STM32F103VET6——模数转换器(ADC)

本文详细介绍了STM32F103系列ADC的工作原理、特点、转换顺序、中断机制、DMA请求以及电压转换过程。重点讲解了ADC的12位精度、多种工作模式、中断配置和实际应用示例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、ADC的介绍

        ADC是英文Analog-to-digital converter 的缩写,意思是模拟数字转换器,简称模数转换器。在STM32F103 系列有 3 ADC,精度为 12 位,每个 ADC 最多有 16 个外部通道。其中 ADC1 和ADC2 都有 16 个外部通道,ADC3 根据 CPU 引脚的不同通道数也不同,一般都有 8 个外部通道。ADC 的模式非常多,功能非常强大。ADC是由PCLK2经分频产生,它的输入时钟不得超过14MHz。

二、ADC的特点

● 它的精度是12位
● 转换结束、注入转换结束和发生模拟看门狗事件时产生中断
● 他有两种模式:单次和连续转换模式
● 从通道 0 到通道 n 的自动扫描模式
● 它能够自校准
● 带内嵌数据一致性的数据对齐
● 采样间隔可以按通道分别编程
● 规则转换和注入转换均有外部触发选项
● 间断模式
● 双重模式 (一起使用两个或者两个以上 ADC 的器件 )
ADC 转换时间: STM32F103xx增强型产品:时钟为 56MHz 时为 1 μ s( 时钟为 72MHz 1.17 μ s)
ADC 供电要求: 2.4V 3.6V
ADC 输入范围: V REF- V IN V REF+。
● 规则通道转换期间有 DMA 请求产生。
三、ADC的功能框图
1)左上:电压输入范围
        ADC输入范围为: V REF- ≤V IN ≤V REF+ 。由 V REF- V REF+ V DDA V SSA 、这四个外部引脚决定。我们在设计原理图的时候一般把V SSA V REF- 接地,把 V REF+ V DDA 3V3 ,得到 ADC 的输入电压范围为:0~3.3V
2)左中:输入通道       
        STM32的ADC多达18 个通道,其中外部的 16 个通道就是框图中的 ADCx_IN0 ADCx_IN1 ADCx_IN5 。这16 个通道对应着不同的 IO 口,具体是哪一个 IO 口可以从手册查询到。其 ADC1/2/3 还有内部通道:ADC1 的通道 16 连接到了芯片内部的温度传感器, Vrefint 连接到了通 17 ADC2 的模拟通道16 17 连接到了内部的 VSS ADC3 的模拟通道 9 14 15 16 17 连接到了内部VSS 。具体看图:
3)左下:外部触发转换
        
        转换可以由外部事件触发( 例如定时器捕获, EXTI 线 ) 。如果设置了 EXTTRIG 控制位,则外部事 件就能够触发转换。EXTSEL[2:0] JEXTSEL2:0] 控制位允许应用程序选择 8 个可能的事件中的
某一个,可以触发规则和注入组的采样。
        ADC1 ADC2 用于规则通道的外部触发
         ADC1 ADC2 用于注入通道的外部触发
         ADC3 用于规则通道的外部触发
         ADC3 用于注入通道的外部触发
4)中中:通道类型
        规则通道:由16个转换组规则通道和它们的转换顺序在ADC_SQRx寄存器中选择。规则组中转换的总数应写入ADC_SQR1寄存器的L[3:0]位中。使用的比较多就是这个通道。
        注入通道:由多达4个转换组成。注入通道和它们的转换顺序在ADC_JSQR寄存器中选择。注入组里的转换总数目应写入ADC_JSQR寄存器的L[1:0]位中。
5)数据寄存器
  四、转换顺序
        规则顺序:规则序列寄存器有3个,分别为SQR3、SQR2、SQR1。SQR3控制着规则序列中的第一个到第六个转换,对应的位为:SQ1[4:0]~SQ6[4:0],第一次转换的是位4:0SQ1[4:0],如果通道16想第一次转换,那么在SQ1[4:0]写16即可。SQR2控制着规则序列中的第7到第12个转换,对应的位为:SQ7[4:0]~SQ12[4:0],如果通道1想第8个转换,则SQ8[4:0]写1即可。SQR1控制着规则序列中的第13到第16个转换,对应位为:SQ13[4:0]~SQ16[4:0],如果通道6想第10个转换,则SQ10[4:0]写6即可。具体使用多少个通道,由SQR1的位L[3:0]决定,最多16个通道。
        注入顺序:注入序列寄存器JSQR只有一个,最多支持4个通道,由JSQR的JL[1:0]决定。如果JL的值小于4的话,则JSQR跟SQR决定转换顺序的设置不一样,第一次转换的不是JSQR1[4:0],而是JCQRx[4:0],x=4-JL),跟SQR刚好相反。如果JL=00(1个转换),那么转换的顺序是从JSQR4[4:0]开始,而不是从JSQR1[4:0]开始,这个要注意,编程的时候不要搞错。当JL等于4时,跟SQR一样。
五、采样时间
        根据介绍可知,ADC的时钟最大值位14MHz,它是由 输入时钟 ADC_CLK PCLK2经过分频产生的。分频因子由RCC时钟配置寄存器RCC_CFGR的位15:14ADCPRE[1:0]设置,可以是2/4/6/8分频。
        
        采样的周期数可通过ADC 采样时间寄存器ADC_SMPR1 ADC_SMPR2 中的 SMP[2:0] 位设置, ADC_SMPR2 控制的是通道 0~9 ,ADC_SMPR1控制的是通道 10~17。每个通道可以分别用不同的时间采样。
        ADC的转换时间跟 ADC 的输入时钟和采样时间有关,公式为: Tconv= 采样时间 +12.5 个周期。
ADCLK=14MHZ (最高),采样时间设置为 1.5 周期(最快),那么总的转换时间(最短) Tconv =1.5周期 +12.5 周期 =14 周期 =1us
六、中断
        数据转换结束后,可以产生中断,中断分为三种:规则通道转换结束中断,注入转换通道转换结束中断,模拟看门狗中断。其中转换结束中断很好理解,跟我们平时接触的中断一样,有相应的中断标志位和中断使能位,我们还可以根据中断类型写相应配套的中断服务程序。
        模拟看门狗中断
当被 ADC 转换的模拟电压低于低阈值或者高于高阈值时,就会产生中断,前提是我们开启了模
拟看门狗中断,其中低阈值和高阈值由 ADC_LTR ADC_HTR 设置。例如我们设置高阈值2.5V,那么模拟电压超过 2.5V 的时候,就会产生模拟看门狗中断,反之低阈值也一样。
七、DMA请求
        规则和注入通道转换结束后,除了产生中断外,还可以产生 DMA请求,把转换好的数据直接存储在内存里面。要注意的是只有ADC1和ADC3可以产生DMA请求。有关DMA请求需要配合
STM32F10X- 中文参考手册》 DMA 控制器这一章节来学习。一般我们在使用 ADC 的时候都会
开启 DMA 传输。
八、电压转换
        
        ADC的输入电压范围设定在: 0~3.3v ,因为 ADC 12 位的,那么12 位满量程对应的就 3.3V 12 位满量程对应的数字值是: 2^12 。数值 0 对应的就是 0V 。如果转换后的数值为X X 对应的模拟电压为 Y ,那么会有这么一个等式成立: 2^12/3.3=X/Y, =>Y=(3.3*X)/2^12
九、串口电压检测实验
        ADC 宏定义
#ifndef __ADC_H
#define	__ADC_H


#include "stm32f10x.h"

// ADC 编号选择
// 可以是 ADC1/2,如果使用ADC3,中断相关的要改成ADC3的
#define    ADC_APBxClock_FUN             RCC_APB2PeriphClockCmd
#define    ADCx                          ADC2
#define    ADC_CLK                       RCC_APB2Periph_ADC2

// ADC GPIO宏定义
// 注意:用作ADC采集的IO必须没有复用,否则采集电压会有影响
#define    ADC_GPIO_APBxClock_FUN        RCC_APB2PeriphClockCmd
#define    ADC_GPIO_CLK                  RCC_APB2Periph_GPIOC  
#define    ADC_PORT                      GPIOC
#define    ADC_PIN                       GPIO_Pin_1
// ADC 通道宏定义
#define    ADC_CHANNEL                   ADC_Channel_11

// ADC 中断相关宏定义
#define    ADC_IRQ                       ADC1_2_IRQn
#define    ADC_IRQHandler                ADC1_2_IRQHandler

//#define    ADC_IRQ                       ADC3_IRQn
//#define    ADC_IRQHandler                ADC3_IRQHandler


void ADCx_Init(void);


#endif /* __ADC_H */

        ADC_GPIO初始化函数

static void ADCx_GPIO_Config(void)
{
	GPIO_InitTypeDef GPIO_InitStructure;
	
	// 打开 ADC IO端口时钟
	ADC_GPIO_APBxClock_FUN ( ADC_GPIO_CLK, ENABLE );
	
	// 配置 ADC IO 引脚模式
	// 必须为模拟输入
	GPIO_InitStructure.GPIO_Pin = ADC_PIN;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
	
	// 初始化 ADC IO
	GPIO_Init(ADC_PORT, &GPIO_InitStructure);				
}

ADC工作模式配置

static void ADCx_Mode_Config(void)
{
	ADC_InitTypeDef ADC_InitStructure;	

	// 打开ADC时钟
	ADC_APBxClock_FUN ( ADC_CLK, ENABLE );
	
	// ADC 模式配置
	// 只使用一个ADC,属于独立模式
	ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;
	
	// 禁止扫描模式,多通道才要,单通道不需要
	ADC_InitStructure.ADC_ScanConvMode = DISABLE ; 

	// 连续转换模式
	ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;

	// 不用外部触发转换,软件开启即可
	ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;

	// 转换结果右对齐
	ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
	
	// 转换通道1个
	ADC_InitStructure.ADC_NbrOfChannel = 1;	
		
	// 初始化ADC
	ADC_Init(ADCx, &ADC_InitStructure);
	
	// 配置ADC时钟为PCLK2的8分频,即9MHz
	RCC_ADCCLKConfig(RCC_PCLK2_Div8); 
	
	// 配置 ADC 通道转换顺序和采样时间
	ADC_RegularChannelConfig(ADCx, ADC_CHANNEL, 1, 
	                         ADC_SampleTime_55Cycles5);
	
	// ADC 转换结束产生中断,在中断服务程序中读取转换值
	ADC_ITConfig(ADCx, ADC_IT_EOC, ENABLE);
	
	// 开启ADC ,并开始转换
	ADC_Cmd(ADCx, ENABLE);
	
	// 初始化ADC 校准寄存器  
	ADC_ResetCalibration(ADCx);
	// 等待校准寄存器初始化完成
	while(ADC_GetResetCalibrationStatus(ADCx));
	
	// ADC开始校准
	ADC_StartCalibration(ADCx);
	// 等待校准完成
	while(ADC_GetCalibrationStatus(ADCx));
	
	// 由于没有采用外部触发,所以使用软件触发ADC转换 
	ADC_SoftwareStartConvCmd(ADCx, ENABLE);
}

static void ADC_NVIC_Config(void)
{
  NVIC_InitTypeDef NVIC_InitStructure;
	// 优先级分组
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);

  // 配置中断优先级
  NVIC_InitStructure.NVIC_IRQChannel = ADC_IRQ;
  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
  NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
  NVIC_Init(&NVIC_InitStructure);
}

main()函数

#include "stm32f10x.h"
#include "bsp_usart.h"
#include "bsp_adc.h"

extern __IO uint16_t ADC_ConvertedValue;

// 局部变量,用于保存转换计算后的电压值 	 
float ADC_ConvertedValueLocal;        

// 软件延时
void Delay(__IO uint32_t nCount)
{
  for(; nCount != 0; nCount--);
} 

/**
  * @brief  主函数
  * @param  无
  * @retval 无
  */
int main(void)
{	
	// 配置串口
	USART_Config();
	
	// ADC 初始化
	ADCx_Init();
	
	printf("\r\n ----这是一个ADC单通道中断读取实验----\r\n");
	
	while (1)
	{
		ADC_ConvertedValueLocal =(float) ADC_ConvertedValue/4096*3.3; 
	
		//printf("\r\n  AD value = 0x%04X \r\n", 
		       //ADC_ConvertedValue); 
		printf("\r\n  AD value = %f V \r\n",
		       ADC_ConvertedValueLocal); 
		printf("\r\n\r\n");

		Delay(0xffffee);  
	}
}
十、总结
        通过以上的学习,应该对ADC有一定的了解,在STM32的官方手册有更多的详细模式哦,代码仅是主要代码。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值