STM32 ADC采集原理

STM32     ADC 概念
ADC 就是模拟量输入转换成数字量。
我们先简单介绍一下逐次比较型 A/D,逐次比较型 A/D 包括 n 位逐次比
较型 A/D 转换器如图 1 所示。 它由控制逻辑电路、 时序产生器、 移位寄存器、
D/A 转换器及电压比较器组成。

图 1 的电路,它由启动脉冲启动后,在第一个时钟脉冲作用下,控制电
路使时序产生器的最高位置 1, 其他位置 0, 其输出经数据寄存器将 1000……
0,送入 D/A 转换器。输入电压首先与 D/A 器输出电压(VREF/2)相比较,如
v1≥VREF/2,比较器输出为 1,若 vI< VREF/2,则为 0。比较结果存于数据
寄存器的 Dn-1 位。然后在第二个 CP 作用下,移位寄存器的次高位置 1,其
他低位置 0。 如最高位已存 1, 则此时 vO=(3/4)VREF。 于是 v1 再与(3/4)VREF
相比较,如 v1≥(3/4)VREF,则次高位 Dn-2 存 1,否则 Dn-2=0;如最高位为
0, 则 vO=VREF/4, 与 vO 比较, 如 v1≥VREF/4, 则 Dn-2 位存 1, 否则存 0……。
以此类推,逐次比较得到输出数字量。
为了进一步理解逐次比较 A/D 转换器的工作原理及转换过程。下面用实
例加以说明。
设图 1 电路为 8 位 A/D 转换器,输入模拟量 vA=6.84V,D/A 转换器基准
电压 VREF=10V。 根据逐次比较 D/A 转换器的工作原理,可画出在转换过程
中 CP、启动脉冲、D7~D0 及 D/A 转换器输出电压 vO 的波形,如图 11.10.2
所示。
由图.2 可见,当启动脉冲低电平到来后转换开始,在第一个 CP 作用下,
数据寄存器将 D7~D0=10000000 送入 D/A 转换器,其输出电压 v0=5V,vA
与 v0 比较,vA>v0 存 1;第二个 CP 到来时,寄存器输出 D7~D0=11000000,
v0 为 7.5V,vA 再与 7.5V 比较,因 vA<7.5V,所以 D6 存 0;输入第三个 CP
时,D7~D0=10100000,v0=6.25V;vA 再与 v0 比较,……如此重复比较下去,

经 8 个时钟周期,转换结束。由图中 v0 的波形可见,在逐次比较过程中,
与输出数字量对应的模拟电压 v0 逐渐逼近 vA 值,最后得到 A/D 转换器转换
结果 D7~D0 为 10101111。该数字量所对应的模拟电压为 6.8359375V,与实
际输入的模拟电压 6.84V 的相对误差仅为 0.06%。

4.11.1.3 STM32 ADC 模拟量输入功能
1、STM32 单片机自带 ADC 转换,STM32 ADC 是 12 位逐次逼近型模拟数字转
换器。它有多达 18 个通道,可测量 16 个外部和 2 个内部信号源。各通道的
A/D 转换可以单次、连续、扫描或者间断模式执行。ADC 的结果可以左对齐
或者右对齐方式存储在 16 位数据寄存器中。模拟看门狗特性允许应用程序
检测输入电压是否超出用户定义的高/低阀值。ADC 的输入时钟不得超过
14MHz,它是由 PCLK2 经分频产生。
2、STM32 ADC 主要特性
 12 位分辨率
 转换结束、注入转换结束和发生模拟看门狗事件时产生中断
 单次和连续转换模式
 从通道 0 到通道 n 的自动扫描模式
 间断模式执行
 自校准
 带内嵌数据一致性的数据对齐
 采样间隔可以按通道分别编成
 规律转换和注入转换均有外部触发选项
 双重模式(带 2 个或者以上 ADC 的器件)
3、ADC 转换时间
 STM32F103xx 增强型:时钟为 56MHz 时,转换时间为 1μs(时钟 72MHz
时为 1.17μs);
 STM32F101xx 基本型:时钟为 28MHz 时,转换时间为 1μs(时钟 36MHz
时为 1.55μs);
 STM32F102xxUSB 型:时钟为 48MHz 时,转换时间为 1.2μs;
 STM32F105xx 和 STM32F107xx 型:时钟为 56MHz 时,转换时间为 1μs(时
钟 72MHz 时为 1.17μs);
 ADC 供电要求:2.4V~3.6V
ADC 输入范围:VREF-<=VIN<=VREF+;
 规则通道转换期间有 DMA 请求产生;
4、ADC 引脚说明
ADC 模拟量输入说明
名称 信号类型 注释
Vref+ 输入,模拟参考正极 ADC 使用的高端/正极参考电压,2.4V<VREF<VDOA
Vdao 输入,模拟电源
Vref- 输入,模拟参考负极
Vssa 输入,模拟电源地 等效于 VSS 的模拟电源地
ADCx_IN[15:0] 模拟输入信号 16 个模拟输入通道
ADC 模拟量输入通道列表
ADC1 ADC2 ADC3
通道 0 PA0 PA0 PA0
通道 1 PA1 PA1 PA1
通道 2 PA2 PA2 PA2
通道 3 PA3 PA3 PA3
通道 4 PA4 PA4
通道 5 PA5 PA5
通道 6 PA6 PA6
通道 7 PA7 PA7
通道 8 PB0 PB0
通道 9 PB1 PB1
通道 10 PC0 PC0 PC0
通道 11 PC1 PC1 PC1
通道 12 PC2 PC2 PC2
通道 13 PC3 PC3 PC3
通道 14 PC4 PC4
通道 15 PC5 PC5
通道 16 温度传感器
通道 17 内部参考电压
4.11.1.4 STM 32 ADC 通道选择说明
有 16 个多路通道,可以把转换组织成两组:规则组和注入组。在任意
多个通道上以任意顺序进行的一系列转换构成成组转换。
 规则组由多达 16 个转换组成。规则通道和它们的转换顺序在 ADC_SQRx
寄存器中选择。规则组中转换的总数应写入 ADC_SQR1 寄存器的 L[3:0]位中。
 注入组由 4 个转换组成。注入通道和它们的转换顺序在 ADC_JSQR 寄存器
中选择,注入组里的转换总数应写入 ADC_JSQR 寄存器的 L[1:0]位中。
如果 ADC_SQRx 或 ADC_JSQR 寄存器在转换期间被更改,当前的转换被清
0,一个新的启动脉冲将发送到 ADC 以转换新选择的组。
温度传感器和通道 ADC1_IN16 相连接,内部参照电压 VREFINT 和 ADC1_IN17
相连接。可以按照注入或者规则通道对这两个内部通道进行转换。
注意:温度传感器和 VREFINT 只能出现在主 ADC1 中。
4.11.1.5 STM 32 ADC 转换模式
1、单次转换模式
单次转换模式下,ADC 只执行一次转换。该模式即可通过设置 ADC_CR2 寄存
器的 ADON 位(仅仅适用于规则通道)启动,也可以通过外部触发启动(适
用于规则通道或注入通道),这时 CONT 位为 0。
一旦选择通道的转换完成:
 如果一个规则通道被转换:
——转换数据被储存在 16 位 ADC_DR 寄存器中
——EOC(转换结束)标志被设置
——如果设置了 EOCIE,则产生中断。
 如果一个注入通道被转换:
——转换数据被储存在 16 位 ADC_DRJ1 寄存器中
——JEOC(转换结束)标志被设置
——如果设置了 EOCIE,则产生中断,然后 ADC 停止。
2、连续转换模式
连续转换模式下,当前面的 ADC 转换一结束就马上启动另一次转换。此
模式可以通过外部触发启动或者设置 ADC_CR2 寄存器上的 ADON 位启动,这
时 CONT 位为 1。
每次转换完成后:
 如果一个规则通道被转换:
——转换数据被储存在 16 位 ADC_DR 寄存器中
——EOC(转换结束)标志被设置
——如果设置了 EOCIE,则产生中断。
 如果一个注入通道被转换:
——转换数据被储存在 16 位 ADC_DRJ1 寄存器中
——JEOC(转换结束)标志被设置
——如果设置了 JEOCIE 位,则产生中断。
3、扫描模式
扫描模式可通过设置 ADC_CR1 寄存器的 SCAN 位来选择。一旦这个位被
设置,ADC 扫描所有被 ADC_SQRX 寄存器()或者 ADC_JSQR()选中的所有通
道。在每个组的每个通道上执行单次转换。在每个转换结束时,同一组的下
一个通道被自动转换。如果设置了 CONT 位,转换不会再选择组的最后一个
通道上停止,而是再次从选择组的第一个通道继续转换。
如果设置了 DMA 位,在没次 ECO 后,DMA 控制器把规则组通道的转换数
据传输到 SRAM 中。而注入通道转换的数据总是存储在 ADC_JDRx 寄存器中。
4.11.1.6 STM 32 ADC 时钟配置
Void RCC_ADCCLKConfing(uint32_t RCC_PCLK2) 分频函数。
输入参数范围:
#define RCC_PCLK2_Div2 ((uint32_t)0x00000000)
#define RCC_PCLK2_Div4 ((uint32_t)0x00004000)
#define RCC_PCLK2_Div6 ((uint32_t)0x00008000)
#define RCC_PCLK2_Div8 ((uint32_t)0x0000C000)
STM32 的 ADC 最大的转换速率时 1MHz,也就是转换时间为 1us(在
ADCCLK=14M,采样周期为 1.5 个 ADC 时钟下得到),不要让 ADC 的时钟超过
14M,否则将导致结果准确率下降。
4.11.1.7 ADC 的采样时间
可编程的通道采样时间
ADC 使用若干个 ADC_CLK 周期对输入电压采样, 采样周期数目可以通过
ADC_SMPR1 和 ADC_SMPR2 寄存器中的 SMP[2:0]位更改。 每个通道可以分别用
不同的时间采样。
总转换时间如下计算:TCONV=采样时间+12.5 个周期
例如:当 ADCCLK=14MHz,采样时间为 1.5 周期
TCON=1.5+12.5=14 周期=1us
常常使用的周期:
1.5 周期、7.5 周期、13.5 周期、28.5 周期、41.5 周期、55.5 周期、
71.5 周期、239.5 周期。
4.11.1.8 ADC 的数据对齐
ADC_CR2 寄存器中的 ALIGN 位选择转换后数据存储的对齐方式。数据可
以左对齐或右对齐,如图 29 和图 30 所示。
注入组通道转换的数据值已经减去了在 ADC_JOFRx 寄存器中定义的偏移量,
因此结果可以是一个负值。SEXT 位是扩展的符号值。
对于规则组通道,不需要减去偏移值,因此只有 12 个位有效

4.11.2 ADC 的数据校准
ADC 有一个内置自校准模式,校准可以大幅减少因内部电容器组的变化
而早晨的准精度误差。在校准期间,在每个电容器上都会计算出一个误差修
正码(数字值),这个码用于消除在随后的转换中每个电容器上产生的误差。
通过设置 ADC_CR2 寄存器的 CAL 位启动校准。一旦校准结束,CAL 位被硬件
复位,可以开始正常转换。建议在上电时执行一次 ADC 校准。校准阶段结束
后,校准码存储在 ADC_DR 中。
注意:
1、建议在每次上电后执行一次校准。
2、启动校准前,ADC 必须处于关电状态(ADON=‘0’)超过至少两个
ADC 时钟周期。

4.11.4 硬件设计


STM32 库函数文件
stm32f10x_gpio.cstm32f10x_rcc.cMisc.c // 中断控制字(优先级设置)库函数stm32f10x_exti.c // 外部中断库处理函数stm32f10x_tim.c // 定时器库处理函数stm32f10x_usart.c // 串口通讯函数stm32f10x_adc.c // ADC 模拟量转换函数
GPIO 引脚时钟使能
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE);//设置串口 1 时钟使能RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);//功能复用 IO 时钟使能RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC,ENABLE);//PC 端口时钟使能RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1,ENABLE);//ADC1模拟量转换时钟使能RCC_ADCCLKConfig(RCC_PCLK2_Div6);//设置分频,6 分频,主频是 72M,分频后是 12M,符合要求,不大于 14M。
本节实验用到了 PA 和 PC 端口,所以要把 PA 和 PC 端口的时钟打开;串
口 1 时钟打开;因为要与外部芯片通讯,所以要打开功能复用时钟;ADC 模
拟量时钟打开;设置分频,6 分频,主频是 72M,分频后是 12M,符合要求,
要求是不大于 14M。
GPIO 管脚电平控制函数
在主程序中采用 while(1)循环语句,采用查询的方式等待 ADC 模拟量
转换完毕,初始化完成以后要在主程序中采集模拟量,加入滤波、取平均值
等措施然后转换送出打印。下面是 while(1)语句中详细的内容。

while(1){ad=0;for(i=0;i<50;i++){

ADC_SoftwareStartConvCmd(ADC1,ENABLE);

while(!ADC_GetFlagStatus(ADC1,ADC_FLAG_EOC));

ad=ad+ADC_GetConversionValue(ADC1);

}

ad=ad/50;

printf("ad =%f\r\n",3.3/4095*ad);//实际电压值
stm32f10x_it.c 文件里的内容是
在中断处理 stm32f10x_it.c 文件里中串口 1 子函数非空,进入中断处理函
数后,先打开串口 1,和外部设备联络好,让后通过 CAN 通讯子函数把数据
发送到总线上。
#include "stm32f10x_it.h"

#include "stm32f10x_exti.h"

#include "stm32f10x_rcc.h"

#include "misc.h"

#include "pbdata.h"

void NMI_Handler(void){

 }

void USART1_IRQHandler(void)

{

if(USART_GetITStatus(USART1,USART_IT_RXNE)!=RESET){

USART_SendData(USART1,USART_ReceiveData(USART1));

while(USART_GetFlagStatus(USART1,USART_FLAG_TXE)==RESET);

}

}

main.c 文件里的内容是
大家都知道 prinif 重定向是把需要显示的数据打印到显示器上。在这
个试验中 ADC 模拟量输入程序,是把从外部得到的模拟量转换成数字信号,
通过 prinif 重定向打印到串口精灵上
void RCC_Configuration(void){

SystemInit();//72m

RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);

RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE);

RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);

RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC,ENABLE);

RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1,ENABLE);

RCC_ADCCLKConfig(RCC_PCLK2_Div6);//12M 最大 14M

}
void GPIO_Configuration(void)

{

GPIO_InitTypeDef GPIO_InitStructure;//

LEDGPIO_InitStructure.GPIO_Pin=GPIO_Pin_9;//

TXGPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;

GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF_PP;

GPIO_Init(GPIOA,&GPIO_InitStructure);

GPIO_InitStructure.GPIO_Pin=GPIO_Pin_10;//

RXGPIO_InitStructure.GPIO_Mode=GPIO_Mode_IN_FLOATING;

GPIO_Init(GPIOA,&GPIO_InitStructure);

GPIO_InitStructure.GPIO_Pin=GPIO_Pin_0;//

RXGPIO_InitStructure.GPIO_Mode=GPIO_Mode_AIN;//模拟量输入

GPIO_Init(GPIOC,&GPIO_InitStructure);

}

void NVIC_Configuration(void)

{

NVIC_InitTypeDef NVIC_InitStructure;

NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);

NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;

NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;

NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;

NVIC_Init(&NVIC_InitStructure);
}

void USART_Configuration(void){

USART_InitTypeDef USART_InitStructure;

USART_InitStructure.USART_BaudRate=9600;USART_InitStructure.USART_WordLength=USART_WordLength_8b;

USART_InitStructure.USART_StopBits=USART_StopBits_1;

USART_InitStructure.USART_Parity=USART_Parity_No;

USART_InitStructure.USART_HardwareFlowControl=USART_HardwareFlowControl_None;

USART_InitStructure.USART_Mode=USART_Mode_Rx|USART_Mode_Tx;USART_Init(USART1,&USART_InitStructure);

USART_ITConfig(USART1,USART_IT_RXNE,ENABLE);

USART_Cmd(USART1,ENABLE);USART_ClearFlag(USART1,USART_FLAG_TC);

}

void ADC_Configuration(void){

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 个通道

ADC_Init(ADC1,&ADC_InitStructure);//把结构体变量参数传递

ADC_RegularChannelConfig(ADC1,ADC_Channel_10,1,ADC_SampleTime_239Cycles5);//规则组

ADC_Cmd(ADC1,ENABLE);//ADC 校准

ADC_ResetCalibration(ADC1);

while(ADC_GetResetCalibrationStatus(ADC1));//等待 ADC 是否复位完成

ADC_StartCalibration(ADC1);//ADC 开始校准

while(ADC_GetCalibrationStatus(ADC1));//ADC 开始校准

ADC_SoftwareStartConvCmd(ADC1,ENABLE);//等待 ADC 校准是否完成后,启动ADC

}

串口通信工程需要如下配置


--------------------- 
作者:yuanmeixiang 
来源:CSDN 
原文:https://blog.csdn.net/yuanmeixiang/article/details/53300109 
版权声明:本文为博主原创文章,转载请附上博文链接!

猜你喜欢

转载自blog.csdn.net/guiwukejiBGG/article/details/83243671