STM32F103入门 | 16.ADC实验

 

16.1 ADC简介

Analog-to-Digital Converter 的缩写。指模/数转换器或者模拟/数字转换器。是指将连续变量的模拟信号转换为离散的数字信号的器件。典型的模拟数字转换器将模拟信号转换为表示一定比例电压值的数字信号。在存储或传输时,模数转换器几乎必不可少。

STM32 在片上集成的 ADC 外设非常强大,STM32F103 属于增强型 CPU,它有 18 个通道,可测量 16 个外部和 2 个内部信号源。各通道的 A/D 转换可以单次、连续、扫描或间断模式执行,ADC 的结果可以左对齐或右对齐方式存储在 16 位数据寄存器中。

 

16.2 ADC工作原理

 

STM32F10x系列芯片

ADC通道和引脚对应关系

ADC工作框图

ADC引脚

在框图中最左边的一列是ADC的各个引脚,它们的名称、信号类型和作用见下图:

一般情况下,VDD 是 3.3V,VSS 接地,相对应的,VDDA 是 3.3V,VSSA 也接地,模拟输入信号不要超过 VDD(3.3V)!

 

ADC时钟配置

框图中标注的来自ADC预分频器的ADCCLK是ADC模块的时钟来源。通常,由时钟控制器提供的ADCCLK时钟和PCLK2(APB2时钟)同步。RCC控制器为ADC时钟提供一个专用的可编程预分频器。

 

这里需要注意,一般情况下:不要让 ADC 时钟频率超过 14MHz,否则可能不准。也就是说,如果按照默认设置 PCLK2 为 72MHz,此时应为 6 分频或者 8 分频。

 

ADC中断

在框图中的最顶部,显示ADC的各种中断。很显然可以看出:规则和注入组转换结束时能产生中断,当模拟看门狗状态位被设置时也能产生中断。它们都有独立的中断使能位。 

注: ADC1和ADC2的中断映射在同一个中断向量上,而ADC3的中断有自己的中断向量。

ADC中断事件的具体类型有三种,具体见下图:

 

ADC通道选择

前面说到ADC规则组转换转换结束、注入组转换结束可以产生中断,那么什么是规则组、注入组呢?这就是框图中的中间部位。

STM32的ADC控制器有很多通道,所以模块通过内部的模拟多路开关,可以切换到不同的输入通道并进行转换。

STM32特别地加入了多种成组转换的模式,可以由程序设置好之后,对多个模拟通道自动地进行逐个地采样转换。它们可以组织成两组:规则通道组和注入通道组。

例如,可以如下顺序完成转换:通道3、通道8、通道2、通道2、通道0、通道2、通道2、通道15。

 

规则通道组:最多可以安排16个通道。规则通道和它的转换顺序在ADC_SQRx寄存器中选择,规则组转换的总数应写入ADC_SQR1寄存器的L[3:0]中;

注入通道组:最多可以安排4个通道。注入组和它的转换顺序在ADC_JSQR寄存器中选择。注入组里转化的总数应写入ADC_JSQR寄存器的L[1:0]中。

 

在执行规则通道组扫描转换时,如有例外处理则可启用注入通道组的转换。也就是说,注入通道的转换可以打断规则通道的转换,在注入通道被转换完成之后,规则通道才可以继续转换。

当然,需要注意的是:如果ADC_SQRx或ADC_JSQR寄存器在转换期间被更改,当前的转换被清除,一个新的启动脉冲将发送到ADC以转换新选择的组。

 

ADC转换方式

STM32的ADC的各通道可以组成规则通道组或注入通道组,但是在转换方式还可以有单次转换、连续转换、扫描转换模式。

 

单次转换模式:

单次转换模式下,ADC只执行一次转换。该模式既可通过设置ADC_CR2寄存器的ADON位(只适用于规则通道)启动也可通过外部触发启动(适用于规则通道或注入通道),这时CONT位为0。

 

连续转换模式:

在连续转换模式中,当前面ADC转换一结束马上就启动另一次转换。此模式可通过外部触发启动或通过设置ADC_CR2寄存器上的ADON位启动,此时CONT位是1。

 

ADC扫描模式

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

扫描模式可通过设置ADC_CR1寄存器的SCAN位来选择。一旦这个位被设置,ADC扫描所有被ADC_SQRX寄存器(对规则通道)或ADC_JSQR(对注入通道)选中的所有通道。在每个组的每个通道上执行单次转换。在每个转换结束时,同一组的下一个通道被自动转换。如果设置了CONT位,转换不会在选择组的最后一个通道上停止,而是再次从选择组的第一个通道继续转换。

这里需要注意的是:如果在使用扫描模式的情况下使用中断,会在最后一个通道转换完毕后才会产生中断。而连续转换,是在每次转换后,都会产生中断。

如果设置了DMA位,在每次EOC后,DMA控制器把规则组通道的转换数据传输到SRAM中。而注入通道转换的数据总是存储在ADC_JDRx寄存器中。

 

模拟看门狗

ADC中断的产生方式除了规则组转换完成、注入组转换完成之外,还有模拟看门狗事件。

如果被ADC转换的模拟电压低于低阀值或高于高阀值,AWD模拟看门狗状态位被设置。阀值位于ADC_HTR和ADC_LTR寄存器的最低12个有效位中。通过设置ADC_CR1寄存器的AWDIE位以允许产生相应中断。

需要注意的是:阀值独立于由ADC_CR2寄存器上的ALIGN位选择的数据对齐模式。比较是在对齐之前完成的。也就是说,在数据保存到数据寄存器之前,就已经完成了比较(数据对齐在下文中有讲解)!

通过配置ADC_CR1寄存器,模拟看门狗可以作用于1个或多个通道。

 

ADC外部触发转换

在框图的下方,显示了规则转换、注入转换可以由外部事件触发(比如定时器捕捉、EXTI线)。如果设置了EXTTRIG控制位,则外部事件就能够触发转换。EXTSEL[2:0]和JEXTSEL2:0]控制位允许应用程序选择8个可能的事件中的某一个,可以触发规则和注入组的采样。

注意: 当外部触发信号被选为ADC规则或注入转换时,只有它的上升沿可以启动转换。

 

ADC自动校准

校准ADC有一个内置自校准模式。校准可大幅减小因内部电容器组的变化而造成的准精度误差。在校准期间,在每个电容器上都会计算出一个误差修正码(数字值),这个码用于消除在随后的转换中每个电容器上产生的误差。

通过设置ADC_CR2寄存器的CAL位启动校准。一旦校准结束,CAL位被硬件复位,可以开始正常转换。建议在上电时执行一次ADC校准。校准阶段结束后,校准码储存在ADC_DR中。

注意:建议在每次上电后执行一次校准。同时启动校准前,ADC必须处于关电状态(ADON=0)超过至少两个ADC时钟周期。

 

ADC数据对齐

由于 STM32 的 ADC 是 12 位逐次逼近型的模拟数字转换器,而数据保存在 16 位寄存器中。所以,ADC_CR2 寄存器中的 ALIGN 位选择转换后数据储存的对齐方式。数据可以左对齐或右对齐,如下图所示:

  • 注入组通道转换的数据值已经减去了在ADC_JOFRx寄存器中定义的偏移量,因此结果可以是一个负值。SEXT位是扩展的符号值。 

  • 对于规则组通道,不需减去偏移值,因此只有12个位有效。

 

ADC通道采样时间

ADC使用若干个ADC_CLK周期对输入电压采样,采样周期数目可以通过ADC_SMPR1和ADC_SMPR2寄存器中的SMP[2:0]位更改。每个通道可以分别用不同的时间采样。
总转换时间如下计算:
TCONV = 采样时间+ 12.5个周期

例如:当ADCCLK=14MHz,采样时间为1.5周期时,TCONV =1.5+12.5=14周期=1μs。

因此,ADC的最小采样时间1us(ADC时钟=14MHz,采样周期为1.5周期下得到)。


16.3 ADC配置步骤

 

1. 新建两个文件,adc.c 和 adc.h

 

2. 在头文件 adc.h 添加下面代码:

 

3. 把 adc.c 添加到工程中

 

4. 在 adc.c 中添加以下代码:

#include "adc.h"

void adc_init(void)
{
    GPIO_InitTypeDef GPIO_InitStructure;        //定义GPIO结构体
    ADC_InitTypeDef ADC_InitStructure;          //定义ADC结构体
    
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);                //使能GPIOA时钟
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1,ENABLE);                 //使能ADC1时钟
    RCC_ADCCLKConfig(RCC_PCLK2_Div6);            //设置ADC分频因子6,72M/6=12,ADC最大时间不能超过14M
    
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1;                           //配置PA01
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;                       //模拟输入
    GPIO_Init(GPIOA,&GPIO_InitStructure);                               //初始化GPIOA
    
    ADC_DeInit(ADC1);                            //复位ADC1,重设为默认缺省值
    
    ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;                  //ADC工作模式:ADC1和ADC2工作在独立模式
    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数据右对齐
    ADC_InitStructure.ADC_NbrOfChannel = 1;                             //顺序进行规则转换的ADC通道的数目
    ADC_Init(ADC1,&ADC_InitStructure);                                  //初始化ADC1
    
    ADC_Cmd(ADC1,ENABLE);                        //使能ADC1
    
    ADC_ResetCalibration(ADC1);                  //使能复位校准
    while(ADC_GetResetCalibrationStatus(ADC1));  //等待复位校准结束
    ADC_StartCalibration(ADC1);                  //开启AD校准
    while(ADC_GetCalibrationStatus(ADC1));       //等待校准结束
    ADC_SoftwareStartConvCmd(ADC1,ENABLE);       //使能ADC1的软件转换启动功能
}

u16 get_adc(void)
{
    //配置ADCx,ADC通道,规则采样顺序,采样时间
    ADC_RegularChannelConfig(ADC1,1,1,ADC_SampleTime_239Cycles5);
    ADC_SoftwareStartConvCmd(ADC1,ENABLE);          //使能ADC1的软件转换启动功能
    while(!ADC_GetFlagStatus(ADC1,ADC_FLAG_EOC));   //等待转换结束
    return ADC_GetConversionValue(ADC1);            //返回最近一次ADC1规则组的转换结果
}

 

5. 实现ADC电压采样功能

#include "stm32f10x.h"
#include "delay.h"
#include "led.h"
#include "tim.h"
#include "key.h"
#include "pwm.h"
#include "usart.h"
#include "cap.h"
#include "adc.h"

int main(void)
{
    float vol=0.0;
    u16 temp=0;
    
    delay_init();
    usart_init(115200);
    adc_init();
    
    printf("SYSTEM Init Complete.\r\n");
    while(1)
    {
        temp = get_adc();
        vol = (float)temp*3300/4096;                        //电压值(mV)
        printf("Voltage measurement is : %f mV\r\n",vol);    //串口打印电压值
        delay_ms(1000);
    }
}

 

 

测试截图:

开始的时候小R故意把 PA01 悬空(其实是当时在黑暗中没找到 PA01在哪...),测量值一直在大幅跳变;然后小R把 PA01 接地,可以看到确确实实显示了 0.000000mV;然后小R把 PA01 接到了 3.3V 电源,于是测到了 3.3V 左右的电压值;然后小R把 PA01 接到了 5V 电源,然后,就没有然后了。最后,亲切提醒小伙伴们注意不要接超过 3.3V 的电压!切记!

 

欢迎关注微信公众号『OpenSSR』

评论 13
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值