单片机
返回首页

STM32模数转换器 (ADC)介绍

2024-08-30 来源:elecfans

STM32F4xx系列提供的12位ADC是逐次逼近型模数转换器。它具有多达 19 个复用通道,可测量来自 16 个外部源、两个内部源和 V BAT 通道的信号。这些通道的 A/D 转换可在单次、连续、扫描或不连续采样模式下进行。ADC 的结果存储在一个左对齐或右对齐的 16 位数据寄存器中。


ADC 具有模拟看门狗特性,允许应用检测输入电压是否超过了用户自定义的阈值上限或下限。


单个ADC框图

图片

ADC 引脚

图片

ADC开关控制

可通过将ADC_CR2寄存器中的 ADON 位置1来为 ADC 供电。首次将 ADON 位置1时,会将ADC从掉电模式中唤醒。

SWSTART 或 JSWSTART 位置 1 时,启动 AD 转换。

可通过将 ADON 位清零来停止转换并使 ADC 进入掉电模式。在此模式式下,ADC 几乎不耗电(只有几 μA)。

ADC时钟

ADC 具有两个时钟方案:

● 用于模拟电路的时钟:ADCCLK,所有 ADC 共用

此时钟来自于经可编程预分频器分频的 APB2 时钟,该预分频器允许 ADC 在 f PCLK2 /2、/4、/6 或 /8 下工作。有关 ADCCLK 的最大值,请参见数据手册。

● 用于数字接口的时钟(用于寄存器读/写访问)

此时钟等效于 APB2 时钟。可以通过 RCC APB2 外设时钟使能寄存器 (RCC_APB2ENR)分别为每个 ADC 使能/禁止数字接口时钟。

通道选择

有 16 条复用通道。可以将转换分为两组:规则转换和注入转换。每个组包含一个转换序列,该序列可按任意顺序在任意通道上完成。例如,可按以下顺序对序列进行转换:ADC_IN3、ADC_IN8、ADC_IN2、ADC_IN2、ADC_IN0、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 发送一个新的启动脉冲,以转换新选择的组。

温度传感器、V REFINT 和 V BAT 内部通道

● 对于 STM32F40x 和 STM32F41x 器件,温度传感器内部连接到通道 ADC1_IN16。

内部参考电压 VREFINT 连接到 ADC1_IN17。

● 对于 STM23F42x 和 STM32F43x 器件,温度传感器内部连接到与 VBAT 共用的通道

ADC1_IN18。一次只能选择一个转换(温度传感器或 VBAT)。同时设置了温度传感器和 VBAT 转换时,将只进行 VBAT 转换。

内部参考电压 VREFINT 连接到 ADC1_IN17。

VBAT通道连接到通道ADC1_IN18。该通道也可转换为注入通道或规则通道。

单次转换模式

在单次转换模式下, 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 时将产生中断

时序图

ADC 在开始精确转换之前需要一段稳定时间 t STAB 。ADC 开始转换并经过 15 个时钟周期后,EOC 标志置 1,转换结果存放在 16 位 ADC 数据寄存器中。

图片

扫描模式

此模式用于扫描一组模拟通道。

通过将 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_JDRx 寄存器中。

数据对齐

由于STM32的ADC是12位的,结果存储在16位的数据寄存器中,有4位用不到,所以ADC存在左对齐或右对齐的方式。为方便读数,一般都选择右对齐。

可独立设置各通道采样时间

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

总转换时间的计算公式如下:

T conv = 采样时间 + 12 个周期

快速转换模式

可通过降低 ADC 分辨率来执行快速转换。RES 位用于选择数据寄存器中可用的位数。每种分辨率的最小转换时间如下:

● 12 位:3 + 12 = 15 ADCCLK 周期

● 10 位:3 + 10 = 13 ADCCLK 周期

● 8 位:3 + 8 = 11 ADCCLK 周期

● 6 位:3 + 6 = 9 ADCCLK 周期

温度传感器和VRENFINT通道框图

图片

要使用传感器,请执行以下操作:

  1. 选择 ADC1_IN16 或 ADC1_IN18 输入通道。

  2. 选择一个采样时间,该采样时间要大于数据手册中所指定的最低采样时间。

  3. 在 ADC_CCR 寄存器中将 TSVREFE 位置 1,以便将温度传感器从掉电模式中唤醒。

  4. 通过将 SWSTART 位置 1(或通过外部触发)开始 ADC 转换

  5. 读取 ADC 数据寄存器中生成的 V SENSE 数据

  6. 使用以下公式计算温度:

温度(单位为 °C)= {(V SENSE — V 25 ) / Avg_Slope} + 25

其中:

— V 25 = 25 °C 时的 V SENSE 值

— Avg_Slope = 温度与 V SENSE 曲线的平均斜率(以 mV/°C 或 μV/°C 表示)

由于ADC寄存器的相关配置相对比较简单,这里直接附上测量温度相关的ADC初始化和中断程序:

void ADC_Init()

{

  u32 prigroup = 0;                          

  u32 priority = 0;        


  RCC- >APB2ENR  |=  1< < 8;    //开ADC1时钟        


  ADC- >CCR  =  0;

  ADC- >CCR  |=  1< < 23;    //使能温度传感器和 V REFINT 通道

  ADC- >CCR  |=  1< < 16;    //ADCCLK=21mHZ


  ADC1- >CR1  =  0;//分辨率12位


  ADC1- >CR2  =  0;          //数据右对齐

  ADC1- >CR2  |=  1< < 10;    //通道只要转换结束,则将EOC置1,使能溢出检测


  ADC1- >SMPR1  =0;          //通道16采样时间3T


  ADC1- >SQR3  |=  16< < 0;


  ADC1- >CR1  |=  1< < 5;          //使能EOC中断

  ADC1- >SR  &=~  (1< < 1);        //清中断标记33

  prigroup = NVIC_GetPriorityGrouping();        //得到优先级分组

  priority = NVIC_EncodePriority(prigroup,1,2);  //优先级编码

  NVIC_SetPriority(ADC_IRQn,priority);        //设置中断优先级

  NVIC_EnableIRQ(ADC_IRQn);                  //使能ADC中断


  ADC1- >CR2  |=  1< < 0;      //使能ADC

  Delay_us(3);

  ADC1- >CR2  |=  1< < 30;  //启动AD转换

}



u16 ADC1_Value={0};      //定义二维数组,按行存入三个通道的转换结束

u8 ADC1_OK = 0;



//中断处理函数

void ADC_IRQHandler()

{

  if(ADC1- >SR  &  (1< < 1))

  {      

    ADC1- >SR  &=~  (1< < 1);        //写0,请标记

    ADC1_Value = ADC1- >DR;    //按行依次存入各通道的转换结果

    ADC1_OK  =  1;                //采集完成结束标记置1

  }

}

接着编写主函数测试


#include 'stm32f4xx.h'

#include 'usart.h'

#include 'delay.h'

#include 'stdio.h'

#include 'ADC.h'



extern u8 ADC1_OK;

extern u16 ADC1_Value;



int main()

{

  float wendu = 0; 


  NVIC_SetPriorityGrouping(7-2);

  Usart1_Init(115200);

  ADC_Init();



  while(1)

  {

    if(ADC1_OK == 1)

    {

      ADC1- >SR  &=~ (1< < 1);      //清中断标记

      ADC1_OK = 0;

      wendu = 3.3*ADC1_Value/4095;        //求温度数字值对应的模拟电压值

      wendu = (wendu -0.76)*1000/2.5+25;    //计算温度值


      printf('温度AD值:%drnwendu = %.lf°Crn',ADC1_Value,wendu);

      ADC1- >CR2  |=  1< < 0;        //再次开启ADC1

      Delay_us(3);

      ADC1- >CR2  |=  1< < 30;      //触发一次转换

    }

    Delay_ms(1000);

  }

}


从串口可以看到ADC读取的温度值,ADC温度测量成功。

图片

对于电池电压或者其他外部模拟量的测量,配置方法与温度测量类似,这里不再赘述。如果想要让CPU更多地用于算法或者其他功能的处理,同样可以配置DMA进行数据传输。


进入单片机查看更多内容>>
相关视频
  • RISC-V嵌入式系统开发

  • SOC系统级芯片设计实验

  • 云龙51单片机实训视频教程(王云,字幕版)

  • 2022 Digi-Key KOL 系列: 你见过1GHz主频的单片机吗?Teensy 4.1开发板介绍

  • TI 新一代 C2000™ 微控制器:全方位助力伺服及马达驱动应用

  • MSP430电容触摸技术 - 防水Demo演示

精选电路图
  • 红外线探测报警器

  • 短波AM发射器电路设计图

  • 使用ESP8266从NTP服务器获取时间并在OLED显示器上显示

  • 用NE555制作定时器

  • 带有短路保护系统的5V直流稳压电源电路图

  • 基于TDA2003的简单低功耗汽车立体声放大器电路

    相关电子头条文章