超详细!!STM32-ADC模数转换器-驱动内部温度传感器


  

一、模数转换器概述

  在STM32微控制器系列中,ADC(Analog-to-Digital Converter)是一个重要的外设模块,它允许微控制器将模拟信号转换成数字信号以进行处理。模拟信号–>数字信号。
   MCU只能处理数字量(10011001),如果需要MCU区分模拟输入信号时,MCU直接做不了,需要将模拟信号通过模数转换器,转成数字量供MCU处理。模数转换器一般用在各类传感器〈光敏电阻)上,还有部分用在音视频处理上。
   工作流程:初始化GPIO–配置ADC–读取ADC值–将ADC值按具体公式(公式查看模块手册)转换。

二、模数转换器分类

1. 并联比较型

在这里插入图片描述

2. 逐次逼近型(天平称重原理类型)

  转换开始前先将所有寄存器清零。开始转换以后,时钟脉冲首先将寄存器最高位置成1,使输出数字为100···0。这个数码被D/A转换器转换成相应的模拟电压Uo,送到比较器中与Ui进行比较。
  若Ui<Uo,说明数字过大了,故将最高位的1清除为0。将其下一个高位置1,继续进行比较。(减/换砝码)
  若Ui>Uo,说明数字还不够大,应将这一位保留。然后,再按同样的方式将下一个高位置成1 ,再继续进行比较。(加砝码)
  并且经过比较以后确定这个1是否应该保留。这样逐位比较下去,一直到最低位为止。比较完毕后,寄存器中的状态就是所要求的数字量输出。

三、模数转换器主要参数

   分辨率:它表明A/D对模拟信号的分辨能力,由它确定能被A/D辨别的最小模拟量变化。通常为8,10,12,16位等。如电压为0~3.3v,分辨率为4096,则可识别最小A/D模拟量变化为 3.3/ 4096 v。
   转换时间:转换时间是A/D完成一次转换所需要的时间。一般转换速度。越快越好。

四、STM32中的模数转换器

  分辨率12位(最高)ADC是逐次趋近型模数转换器。它具有多达19个复用通道,可测量来自16众外部源、两个内部源和VBAT通道的信号。这些通道的A/D转换可在单次、连续、扫描或不连续采样模式下进行。ADC的结果存储在一个左对齐或右对齐的16位数据寄存器中。
  ADC具有模拟看门狗特性,允许应用检测输入电压是否超过了用户自定义的阈值上限或下限。

1. 主要特性

   ●12位分辨率
   ● 转换结束、注入转换结束和发生模拟看门狗事件时产生中断
   ● 单次和连续转换模式
   ● 从通道0到通道n的自动扫描模式
   ● 自校准
   ● 带内嵌数据一致性的数据对齐
   ● 采样间隔可以按通道分别编程
   ● 规则转换和注入转换均有外部触发选项
   ● 间断模式
   ● 双重模式(带2个或以上ADC的器件)

2. 框图

在这里插入图片描述
在这里插入图片描述

3. 功能分析

(1) ADC开关控制

  可通过将 ADC_CR2寄存器中的 ADON位置1来为ADC供电。首次将ADON位置1时,会将ADC 从掉电(低功耗)模式中唤醒。SWSTART或JSWSTART位置1时,启动AD 转换。
  可通过将 ADON位清零来停止转换,并使ADC进入掉电(低功耗)模式。在此模式下ADC 几乎不耗电(只有几A)。
在这里插入图片描述

(2) ADC时钟

ADC具有两个时钟方案:
  用于数字接口的时钟:(用于寄存器读/写访问)此时钟等效于APB2时钟。可以通过 RCC APB2外设时钟使能寄存器(RCC_APB2ENR)分别为每个ADC使能/禁止数字接口时钟。
  用于模拟电路的时钟:ADCCLK,所有ADC共用此时钟来自于经可编程预分频器分频的APB2时钟,该预分频器允许ADC在fpclk2/2、/4、/6或/8下工作。有关ADCCLK的最大值,请参见数据手册。

(3)通道选择

  有16条复用通道。可以将转换分为两组:规则转换(规则组)和注入转换(注入组)。每个组包含一个转换序列,该序列可按任意顺序在任意通道上完成。例如,可按以下顺序对序列进行转换: ADC_IN3、ADC_IN8、ADC_IN2、ADC_IN2、ADC_INO、ADC_IN2、ADC_IN2、ADC_IN15。
  一个规则转换组最多由16个转换构成。必须在ADC_SQRx寄存器中选择转换序列的规则通道及其顺序。规则转换组中的转换总数必须写入ADC_SQR1寄存器中的 L[3:0]位。
在这里插入图片描述

  一个注入转换组最多由4个转换构成。必须在 ADC_JSQR寄存器中选择转换序列的注入通道及其顺序。注入转换组中的转换总数必须写入ADC_JSQR寄存器中的L[1:0]位。
在这里插入图片描述

  如果在转换期间修改 ADC_SQRx或 ADC_JSQR寄存器,将复位当前转换并向ADC发送一个新的启动脉冲,以转换新选择的组。

(4)转换模式

●单次转换模式:

在单次转换模式下,ADC执行一次转换。CONT位为0时,可通过以下方式启动此模式:
在这里插入图片描述

适用规则通道:将 ADC_CR2寄存器中的 SWSTART位置1。
适用注入通道:将JSWSTART位置1。
适用规则通道或注入通道:外部触发,完成所选通道的转换之后。

如果转换了规则通道:
   转换数据存储在16位 ADC_DR寄存器中—EOC(转换结束)标志置1。
   EOCIE位置1时将产生中断。
如果转换了注入通道:
  转换数据存储在16位 ADC_JDR1寄存器中一JEOC(注入转换结束)标志置1。
  JEOCIE位置1时将产生中断。
然后,ADC停止。

●连续转换模式:(仅适用于规则通道)

  在连续转换模式下, ADC 结束一个转换后立即启动一个新的转换。 CONT 位为 1 时,可通过外部触发或将 ADC_CR2 寄存器中的 SWSTRT 位置 1 来启动此模式。
在这里插入图片描述
每次转换之后:
  上次转换的数据存储在16 位 ADC_DR 寄存器中。
  EOC(转换结束)标志置 1。
  EOCIE 位置1时将产生中断。
  注意: 无法连续转换注入通道。连续模式下唯一的例外情况是,注入通道配置为在规则通道之后自动转换(使用 JAUTO 位),请参见自动注入一节。

●扫描模式:(此模式用于扫描一组模拟通道)

  通过将 ADC_CR1寄存器中的 SCAN位置1来选择扫描模式。将此位置1后,ADC会扫描在ADC_SQRx寄存器(对于规则通道)或ADC_JSQR寄存器(对于注入通道)中选择的所有通道。为组中的每个通道都执行一次转换。每次转换结束后,会自动转换该组中的下一个通道。如果将CONT位置1,规则通道转换不会在组中最后一个所选通道处停止,而是再次从第一个所选通道继续转换。
在这里插入图片描述

  如果将 DMA位置1,则在每次规则通道转换之后,均使用直接存储器访问(DMA)控制器将转换自规则通道组的数据(存储在ADC_DR寄存器中)传输到SRAM。

在以下情况下,ADC_SR寄存器中的EOC位置1:
  如果EOCS位清零,在每个规则组序列转换结束时
  如果 EOCS位置1,在每个规则通道转换结束时
  从注入通道转换的数据始终存储在 ADC_IDRx寄存器中。

(5)注入通道管理

●触发注入(类似于中断,优先级:注入组 >规则组)
  要使用触发注入,必须将 ADC_CR1寄存器中的 JAUTO位清零。
  1.通过外部触发或将ADC_CR2寄存器中的 SWSTART位置1来启动规则通道组转换。
  2.如果在规则通道组转换期间出现外部注入触发或者JSWSTART位置1,则当前的转换会复位,并且注入通道序列会切换为单次扫描模式。
  3.然后,规则通道组的规则转换会从上次中断的规则转换处恢复。
  如果在注入转换期间出现规则事件,注入转换不会中断,但在注入序列结束时会执行规则序列。图37 显示了相应的时序图。
  注意:使用触发注入时,必须确保触发事件之间的间隔长于注入序列。例如,如果序列长度为30个ADC时钟周期(即,采样时间为3个时钟周期的两次转换),则触发事件的最小间隔不能小于31个ADC时钟周期。

●自动注入(相当于注入组的连续转换,但必须跟在规则组的连续转换之后转换)
  如果将JAUTO位置1,则注入组中的通道会在规则组通道之后自动转换。
  这可用于转换最多由20个转换构成的序列,这些转换在ADC_SQRx和 ADC_JSQR寄存器中编程。
  在此模式下,必须禁止注入通道上的外部触发。如果CONT位和 JAUTO位均已置1,则在转换规则通道之后会继续转换注入通道。

;注意:不能同时使用自动注入和不连续采样模式。

(6)数据对齐

  ADC_CR2寄存器中的ALIGN位用于选择转换后存储的数据的对齐方式。可选择左对齐或右对齐两种方式,如图38和图39所示。
  注入通道组的转换数据将减去 ADC_JOFRx寄存器中写入的用户自定义偏移量,因此结果可以是一个负值。SEXT位表示扩展的符号值。
  对于规则组中的通道,不会减去任何偏移量,因此只有十二个位有效。

在这里插入图片描述

(7)独立通道的采样时间设置

  ADC会在数个ADC_CLK周期内对输入电压进行采样,可使用ADC_SMPR1 和 ADC_SMPR2寄存器中的SMP[2:0]位修改周期数。每个通道均可以使用不同的采样时间进行采样。
在这里插入图片描述

总转换时间的计算公式如下:
Tconv =采样时间+12个周期
示例:若ADC_CLK = 30 MHz 且采样时间=3个周期时:
Tconv= 3 + 12= 15 个周期 =15/30 us =0.5 us

(8)快速转换模式

  可通过降低ADC分辨率来执行快速转换。RES位用于选择数据寄存器中可用的位数。每种分辨率的最小转换时间如下:
12位:3+12= 15 ADCCLK周期
10位:3+ 10= 13 ADCCLK周期
8位:3+8= 11 ADCCLK周期
6位:3+6= 9 ADCCLK周期

五、实验

1. 实验内容

通过ADC采集STM32内部温度传感器。

2. 实验分析

  温度传感器可用于测量器件的环境温度。对于STM32F40x和 STM32F41x器件,温度传感器内部连接到ADC1_IN16 通道,使用ADC1 将传感器输出电压转换为数字值。
  不使用时可将传感器置于掉电模式。
  注意:必须将TSVREFE位置1才能同时对两个通道进行转换。ADC1_IN16或ADC1_IN18(温度传感器)和ADC1_IN17 (VREFINT)。
在这里插入图片描述

在这里插入图片描述

3. 温度转换公式

在这里插入图片描述

在这里插入图片描述

假设现有采集到的AD值为adVal。按照公式:
0- 3.3V按照12bitADC进行采样==区间为0-4095 ,相当于将3.3V分为4096份,每一个份的电压值为3.3V /4096 =0.0008056640625 V。
VSENSE= adVal*3.3V/4096。
Tempture=( adVal * 3.3V / 4096 - 0.76 ) /2.5 +25。

4. 软件配置流程

  1. 打开ADC1时钟。
  2. 使能温度传感器通道。
  3. 配置ADC分频。
  4. 配置好CR1、CR2。
  5. 构造规则组–转换序列长度1,序列顺序16。
  6. 设置ADC_IN16通道采样时间。
  7. 使能ADC。
  8. 将CR2中的SWSTART位置1–开始转换
  9. 等待EOC完成标志。
  10. 读取转换结果。
  11. 失能ADC。

5. 寄存器代码实现

void ADC1_IN16_Init (void)
{
	RCC->APB2ENR |=(0x1 <<8);//1.打开ADC1时钟
	ADC->CCR |=(0x1 <<23);  //2.使能温度传感器通道
	ADC->CCR &=~(0x3 <<16);  //3.配置ADC分频 
	ADC->CCR |= (0x1 <<16); //4分频84Mhz /4=21Mhz 
	
 //4.配置好CR1、CR2
	ADC1->CR1 =0;//整体清零
	/*
	*12bit分辨率
	*禁止规则通道不连续采样*禁止扫描模式
	*/
	ADC1->CR2 =0;//整体清零
	ADC1->CR2l=(0xl<<10);//每个规则通道转换,将Eoc置一
	/*
	*禁止规则通道外部触发
	*数据右对齐
	*单次转换*/
	
//5.构造规则组-转换序列长度1,序列顺序16
	ADC1->SQR1 &=~ (0xF <<20);//规则序列长度=1
	ADC1->SQR3 &=~ (0x1F <<0);
	ADC1->SQR3 |=(16<<0);//第一次转换通道16
	ADC1->SMPR1 |=(0x7<<18);//6.设置ADc IN16通道采样时间 480 + 12=23.4us
	
}

ul6 ADC1_ReadDate (void)
{
	ul6 adval;
	ADC1->CR2 |=(0x1 <<0);//7.使能ADC
	ADC1->CR2 |=(0x1<< 30); //8.将CR2中的SWSTAET位置1--开始转换
	
	while( !(ADC1->SR &(0x1<<1)) );//9.等待EOC置1
	ADC1->SR &=~(0x1 <<1);//清除EOC标志
	ad = ADC1->DR; //10.读取转换结果
	ADC1->CR2 &= ~(0x1 <<0);//11.失能ADC
	
	return adval;
}


//-------------------------主函数main.c内容
void main(void)
{
	u16 r_adval;
	float tempture;
	ADC1_IN16_Init();
	
	while(1)
	{
	  r_adval =ADC1_ReadDate();
	  tempture=(r_adval * 3.3 / 4096-0.76) /2.5 +25;
	  printf("tempture=%f\n",tempture);
	  delay_ms(500);
	}

}

6. 库函数代码实现

补充:ADC初始化结构体

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.c

//#(1)初始化GPIO
void AD_GPIO_Config(void)
{
    GPIO_InitTypeDef GPIO_InitStructure;

    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE);

    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN; // 设置为模拟输入
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1;
    GPIO_Init(GPIOC, &GPIO_InitStructure);
}

//#(2)配置ADC

void AD_Config(void)
{
    ADC_InitTypeDef ADC_InitStructure;

    RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE); // 使能ADC1时钟
    RCC_ADCCLKConfig(RCC_PCLK2_Div6);                    // 配置ADC时钟为PCLK2的6分频(72M/6 = 12MHz)

    ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;                  // 设置ADC工作在独立模式
    ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;              // 数据右对齐
    ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None; // 禁用外部触发转换
    ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;                 // 使用单次转换模式
    ADC_InitStructure.ADC_ScanConvMode = DISABLE;                       // 禁用扫描转换模式
    ADC_InitStructure.ADC_NbrOfChannel = 1;                             // 设置转换通道数量为1
    ADC_Init(ADC1, &ADC_InitStructure);

    ADC_Cmd(ADC1, ENABLE); // 使能ADC1

    ADC_ResetCalibration(ADC1);                                     // 复位ADC1的校准寄存器
    while (ADC_GetResetCalibrationStatus(ADC1) == SET);             // 等待复位校准结束
    ADC_StartCalibration(ADC1);                                     // 启动ADC1的校准
    while (ADC_GetCalibrationStatus(ADC1) == SET);                  // 等待校准完成
}

//#(3)读取adc值

uint16_t AD_GetValue(uint8_t ADC_Channel)
{
	//选择规则组通道
	ADC_RegularChannelConfig(ADC1, ADC_Channel, 1, ADC_SampleTime_55Cycles5); 
	
	ADC_SoftwareStartConvCmd(ADC1, ENABLE);
	while (ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC) == RESET);	//大概会等(55.5+12.5)/(72M/6)= 5.6us
	return ADC_GetConversionValue(ADC1);
}
//#(4)将adc值通过公式转换

main.c

#include "stm32f10x.h"                  // Device header
#include "Delay.h"
#include "adc.h"
 
uint16_t AD0, AD1, AD2, AD3;
 
int main(void)
{
	AD_GPIO_Config();
	AD_Config();
	while(1)
	{
		AD0 = AD_GetValue(ADC_Channel_0);
		AD1 = AD_GetValue(ADC_Channel_1);
		AD2 = AD_GetValue(ADC_Channel_2);
		AD3 = AD_GetValue(ADC_Channel_3);
		Delay_ms(100);
		
	}
}
 

  • 25
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
STM32 ADC模数转换实验中,可能会遇到以下问题: 1. ADC采样值不正确 如果ADC采样值不正确,可能是因为ADC参数配置不正确或者采样时序不正确导致的。需要确认以下几点: - 确认ADC参数配置正确,包括采样时间、采样通道、采样分辨率等参数 - 确认ADC时钟已经使能 - 确认ADC采样时序正确,包括采样开始时间、采样保持时间和转换时间等参数 2. ADC采样速率不稳定或者出现噪声 如果ADC采样速率不稳定或者出现噪声,可能是因为ADC参考电压不稳定或者ADC输入信号不稳定导致的。需要确认以下几点: - 确认ADC参考电压稳定,可以使用稳压器等设备来提供稳定的参考电压 - 确认ADC输入信号稳定,可以使用滤波电路等方法来滤除噪声和干扰信号 解决方法: 在使用STM32 ADC模数转换时,可以采用以下步骤进行配置和编程: 1. 配置ADC参数 使用ADC_Init函数对ADC进行配置,设置相应的采样时间、采样通道、采样分辨率等参数。 2. 开启ADC采样 在程序中开启ADC采样,使得程序能够读取ADC转换结果。 3. 编写中断服务函数 根据需要编写中断服务函数,并在函数中进行相应的处理。需要注意的是,中断服务函数应该尽可能的简单,避免长时间占用CPU资源,否则可能会影响其他重要任务的执行。 4. 烧录程序 将程序烧录到STM32芯片中,通过读取ADC转换结果,观察ADC采样值的情况和中断服务函数的执行情况。 需要注意的是,在编写程序时需要遵循一些规范和最佳实践,如使用宏定义等方法来定义常量和变量,避免使用硬编码方式;使用滤波器等技术来提高ADC采样值的精度和稳定性等。同时,建议使用示波器等工具来观察ADC采样值的情况和中断服务函数的执行情况,以便进行调试和优化。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值