一、STM32F1 ADC介绍

  TM32F103 系列一般都有 3 个 ADC,这些 ADC 可以独立使用,也可 以使用双重(提高采样率)。STM32F1 的 ADC 是 12 位逐次 逼近型的模拟数字转换器。它具有多达 18个复用通道,可测量来自16 个外部源、2 个内部源信号。 这些通道的 A/D 转换可 以单次、连续、扫描或间断模式执行。ADC 的结果可以左对齐或右对齐 方式存储在 16 位数据寄存器中。ADC具有模拟看门狗特性,允许应用程 序检测输入电压是否超出用户定义的阀值上限或者下限。

1.2 STM32F1 ADC结构框图

STM32F1 ADC拥有这么多功能,是由ADC内部结构所决定。要更好的理 解STM32F1的ADC,就需要了解它内部的结构。如下图所示:(大家 也可以查看《STM32F10x中文参考手册》-11模数转换器(ADC)章-ADC功 能说明)。

(1)标号1:电压输入引脚

  ADC输入电压范围为: VREF- ≤ VIN ≤ VREF+。由 VREF-、 VREF+ 、 VDDA 、 VSSA这四个外部引脚决定。通常我们把 VSSA和 VREF-接地 ,把 VREF+和 VDDA 接 3.3V,因此ADC的输入电压范围为:0~3.3V。我 们使用的开发板ADC输入电压范围为0~3.3V。

(2)标号2:输入通道

  STM32 的 ADC的输入通道多达 18 个,其中外部的 16 个通道就是框 图中的 ADCx_IN0、ADCx_IN1...ADCx_IN5(x=1/2/3,表示ADC数),通 过这16个外部通道可以采集模拟信号这 16 个通道对应着不同的 IO 口, 具体是哪一个 IO 口可以从数据手册查询到,也可以从下图查 看,同样我们在开发板芯片原理图内也给大家标注了。其中 ADC1 还有2 个内部通道:ADC1 的通道16连接到了芯片内部的温度传感器通道17连 接到了内部参考电压 VREFINT。ADC2 和ADC3的通道 16、 17全部连接到 了内部的 VSS。

(3)标号3:通道转换顺序

  外部的 16 个通道在转换的时候可分为2组通道:规则通道组注入 通道组,其中规则通道组最多有16路,注入通道组最多有 4 路。 规则通道组:从名字来理解,规则通道就是一种规规矩矩的通道,类 似于正常执行的程序,通常我们使用的都是这个通道。 注入通道组:从名字来理解,注入即为插入,是一种不安分的通道, 类似于中断。当程序正常往下执行时,中断可以打断程序的执行。同样 如果在规则通道转换过程中,有注入通道插入,那么就要先转换完注入 通道,等注入通道转换完成后再回到规则通道的转换流程。 每个组包含一个转换序列,该序列可按任意顺序在任意通道上完成。 例如,可按以下顺序对序列进行转换: ADC_IN3、ADC_IN8、 ADC_IN2、 ADC_IN2、 ADC_IN0、 ADC_IN2、 ADC_IN2、 ADC_IN15。

(4)标号4:触发源(外部触发和软件触发)

  选择好输入通道,设置好转换顺序,接下来就可以开始转换。要开启 ADC转换,可以直接设置ADC 控制寄存器ADC_CR2 的 ADON位为1,即使能 ADC。当然ADC还支持外部事件触发转换,触发源有很多,具体选择哪一 种触发源,由 ADC 控制寄存器2:ADC_CR2 的 EXTSEL[2:0]和 JEXTSEL[2:0]位来控制。EXTSEL[2:0]用于选择规则通道的触发源, JEXTSEL[2:0]用于选择注入通道的触发源。选定好触发源之后,触发源 是否要激活,则由 ADC 控制寄存器ADC_CR2 的 EXTTRIG 和 JEXTTRIG 这两位来激活。 如果使能了外部触发事件,我们还可以通过设置 ADC 控制寄存器 2:ADC_CR2 的EXTEN[1:0]和 JEXTEN[1:0]来控制触发极性,可以有 4 种 状态,分别是:禁止触发检测、上升沿检测、下降沿检测以及上升沿和 下降沿均检测。

(5)标号5:ADC时钟

  ADC 输入时钟 ADC_CLK 由 APB2经过分频产生,最大值是14MHz,分 频因子由 RCC 时钟配置寄存器 RCC_CFGR 的位 15:14 ADCPRE[1:0]设置 ,可以是 2/4/6/8 分频,注意这里没有 1 分频。我们知道APB2总线时 钟为72M而ADC最大工作频率为14M所以一般设置分频因子为6,这样 ADC的输入时钟为12MHz。

  ADC要完成对输入电压的采样需要若干个ADC_CLK周期,采样的周期数 可通过ADC 采样时间寄存器 ADC_SMPR1 和 ADC_SMPR2 中的 SMP[2:0]位 设置, ADC_SMPR2控制的是通道 0~9, ADC_SMPR1 控制的是通道 10~17 。每个通道可以分别用不同的时间采样。其中采样周期最小是1.5个,即 如果我们要达到最快的采样,那么应该设置采样周期为1.5个周期,这里 说的周期就是 1/ADC_CLK。

  ADC 的总转换时间跟ADC 的输入时钟和采样时间有关,其公式如下:

  (转换时间) Tconv = 采样时间 + 12.5个周期

其中Tconv为ADC总转换时间,当ADC_CLK=14Mhz的时候,并设置1.5个周 期的采样时间,则Tcovn=1.5+12.5=14个周期=1us

(6)标号6:数据寄存器

  ADC 转换后的数据根据转换组的不同,规则组的数据放在ADC_DR 寄 存器内,注入组的数据放在 JDRx内。 因为STM32F1的ADC是12位转换精度,而数据寄存器是16位,所以ADC 在存放数据的时候就有左对齐和右对齐区分。如果是左对齐,AD转换完 成数据存放在 ADC_DR 寄存器的[4:15]位内;如果是右对齐,则存放在 ADC_DR 寄存器的[0:11]位内。具体选择何种存放方式,需通过ADC_CR2 的 11 位 ALIGN 设置。

(7)标号7:中断

  当发生如下事件且使能相应中断标志位时,ADC能产生中断。

1.转换结束(规则转换)与注入转换结束

2.模拟看门狗事件

3.DMA请求

二、STM32F1 ADC配置步骤

(1)使能端口时钟和ADC时钟,设置引脚模式为模拟输入

  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);

  RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1,ENABLE);

  GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AN; //模拟输入模式

(2)设置ADC的分频因子

  RCC_ADCCLKConfig(RCC_PCLK2_Div6);

(3)初始化ADC参数,包括ADC工作模式、规则序列等

  ADC_Init(ADC_TypeDef* ADCx, ADC_InitTypeDef* ADC_InitStruct);

(4)使能ADC并校准

  ADC_Cmd(ADC_TypeDef* ADCx, FunctionalState NewState);

  ADC_Cmd(ADC1, ENABLE);//开启AD转换器

  执行复位校准的方法是: ADC_ResetCalibration(ADC1);

  执行 ADC 校准的方法是: ADC_StartCalibration(ADC1); //开始指定 ADC1 的校准状态

  while(ADC_GetResetCalibrationStatus(ADC1)); //等待复位校准结束

  while(ADC_GetCalibrationStatus(ADC1)); //等待校准结束

(5)读取ADC转换值 设置规则序列通道以及采样周期的库函数是:

  ADC_RegularChannelConfig(ADC_TypeDef* ADCx, uint8_t ADC_Channel,uint8_t Rank, uint8_t ADC_SampleTime);

  ADC_RegularChannelConfig(ADC1, ADC_Channel_1, 1, ADC_SampleTime_239Cycles5 )

设置好规则序列通道及采样周期,接下来就要开启转换,由于我们采 用的是软件触发,库函数

    ADC_SoftwareStartConvCmd(ADC_TypeDef* ADCx, FunctionalState NewState);

要开启 ADC转换.

三、编写ADC控制程序

本章所要实现的功能是:通过ADC1通道1采样外部电压值,将采样的 AD值和转换后的电压值通过串口打印出来,同时D1指示灯闪烁,提示系 统正常运行。

程序框架如下: (1)初始化ADC1_IN1相关参数,开启ADC1 (2)编写获取ADC1_IN1的AD转换值函数 (3)编写主函数

 1 #ifndef _adc_H
2 #define _adc_H
3
4 #include "system.h"
5
6 void ADCx_Init(void);
7 u16 Get_ADC_Value(u8 ch,u8 times);
8
9
10 #endif
 1 #include "adc.h"
2 #include "SysTick.h"
3
4 /*******************************************************************************
5 * 函 数 名 : ADCx_Init
6 * 函数功能 : ADC初始化
7 * 输 入 : 无
8 * 输 出 : 无
9 *******************************************************************************/
10 void ADCx_Init(void)
11 {
12 GPIO_InitTypeDef GPIO_InitStructure; //定义结构体变量
13 ADC_InitTypeDef ADC_InitStructure;
14
15 RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_ADC1,ENABLE);
16
17 RCC_ADCCLKConfig(RCC_PCLK2_Div6);//设置ADC分频因子6 72M/6=12,ADC最大时间不能超过14M
18
19 GPIO_InitStructure.GPIO_Pin=GPIO_Pin_1;//ADC
20 GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AIN; //模拟输入
21 GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
22 GPIO_Init(GPIOA,&GPIO_InitStructure);
23
24 ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;
25 ADC_InitStructure.ADC_ScanConvMode = DISABLE;//非扫描模式
26 ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;//关闭连续转换
27 ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;//禁止触发检测,使用软件触发
28 ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;//右对齐
29 ADC_InitStructure.ADC_NbrOfChannel = 1;//1个转换在规则序列中 也就是只转换规则序列1
30 ADC_Init(ADC1, &ADC_InitStructure);//ADC初始化
31
32 ADC_Cmd(ADC1, ENABLE);//开启AD转换器
33
34 ADC_ResetCalibration(ADC1);//重置指定的ADC的校准寄存器
35 while(ADC_GetResetCalibrationStatus(ADC1));//获取ADC重置校准寄存器的状态
36
37 ADC_StartCalibration(ADC1);//开始指定ADC的校准状态
38 while(ADC_GetCalibrationStatus(ADC1));//获取指定ADC的校准程序
39
40 ADC_SoftwareStartConvCmd(ADC1, ENABLE);//使能或者失能指定的ADC的软件转换启动功能
41 }
42
43 /*******************************************************************************
44 * 函 数 名 : Get_ADC_Value
45 * 函数功能 : 获取通道ch的转换值,取times次,然后平均
46 * 输 入 : ch:通道编号
47 times:获取次数
48 * 输 出 : 通道ch的times次转换结果平均值
49 *******************************************************************************/
50 u16 Get_ADC_Value(u8 ch,u8 times)
51 {
52 u32 temp_val=0;
53 u8 t;
54 //设置指定ADC的规则组通道,一个序列,采样时间
55 ADC_RegularChannelConfig(ADC1, ch, 1, ADC_SampleTime_239Cycles5); //ADC1,ADC通道,239.5个周期,提高采样时间可以提高精确度
56
57 for(t=0;t<times;t++)
58 {
59 ADC_SoftwareStartConvCmd(ADC1, ENABLE);//使能指定的ADC1的软件转换启动功能
60 while(!ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC ));//等待转换结束
61 temp_val+=ADC_GetConversionValue(ADC1);
62 delay_ms(5);
63 }
64 return temp_val/times;
65 }
 1 #include "system.h"
2 #include "SysTick.h"
3 #include "led.h"
4 #include "usart.h"
5 #include "adc.h"
6
7
8 /*******************************************************************************
9 * 函 数 名 : main
10 * 函数功能 : 主函数
11 * 输 入 : 无
12 * 输 出 : 无
13 *******************************************************************************/
14 int main()
15 {
16 u8 i=0;
17 u16 value=0;
18 float vol;
19
20 SysTick_Init(72);
21 NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //中断优先级分组 分2组
22 LED_Init();
23 USART1_Init(9600);
24 ADCx_Init();
25
26 while(1)
27 {
28 i++;
29 if(i%20==0)
30 {
31 led1=!led1;
32 }
33
34 if(i%50==0)
35 {
36 value=Get_ADC_Value(ADC_Channel_1,20);
37 printf("检测AD值为:%d\r\n",value);
38 vol=(float)value*(3.3/4096);
39 printf("检测电压值为:%.2fV\r\n",vol);
40 }
41 delay_ms(10);
42 }
43 }

(stm32f103学习总结)—ADC模数转换实验的更多相关文章

  1. STM32学习笔记(七) ADC模数转换测电平(普通和DMA模式)

    嵌入式系统在微控制领域(温度,湿度,压力检测,四轴飞行器)中占据着重要地位,这些功能的实现是由微处理器cpu(如stm32)和传感器以及控制器共同完成的,而连接他们,使它们能够互相正常交流的正是本小节 ...

  2. Keil MDK STM32系列(六) 基于抽象外设库HAL的ADC模数转换

    Keil MDK STM32系列 Keil MDK STM32系列(一) 基于标准外设库SPL的STM32F103开发 Keil MDK STM32系列(二) 基于标准外设库SPL的STM32F401 ...

  3. 【StatLearn】统计学习中knn算法实验(2)

    接着统计学习中knn算法实验(1)的内容 Problem: Explore the data before classification using summary statistics or vis ...

  4. (stm32f103学习总结)—stm32 PMW输出实验

    一.PWM简介 PWM是 Pulse Width Modulation 的缩写,中文意思就是脉冲宽度调 制,简称脉宽调制.它是利用微处理器的数字输出来对模拟电路进行控 制的一种非常有效的技术,其控制简 ...

  5. (stm32f103学习总结)—RTC独立定时器—实时时钟实验

    一.STM32F1 RTC介绍 1.1 RTC简介 STM32 的实时时钟( RTC)是一个独立的定时器. STM32 的 RTC 模 块拥有一组连续计数的计数器,在相应软件配置下,可提供时钟日历的 ...

  6. (stm32f103学习总结)—待机唤醒实验

    一.STM32待机模式介绍 1.1 STM32低功耗模式介绍 很多单片机具有低功耗模式,比如MSP430.STM8L等,我们的STM32 也不例外.默认情况下,系统复位或上电复位后,微控制器进入运行模 ...

  7. Arduino学习笔记⑤ 模拟IO实验

    1.前言     还记得前几个我们都是在讲解数字IO,而其实我们生活中大多数信号都是模拟信号,如声音以及温度变化.在Arduino中,常用0~5v的电压来表示模拟信号. 1.1 模拟输入功能      ...

  8. zju(7)ADC操作实验

    1.实验目的 1.学习和掌握S3C2410下ADC接口的操作方法以及应用程序的编写: 二.实验内容 1.编写EduKit-IV实验箱Linux操作系统下按键ADC的应用程序,并显示ADC的值. 三.主 ...

  9. stm32学习总结)—SPI-FLASH 实验 _

    SPI总线 SPI 简介 SPI 的全称是"Serial Peripheral Interface",意为串行外围接口,是Motorola 首先在其 MC68HCXX 系列处理器上 ...

随机推荐

  1. win7重装系统过程关机 电脑开机黑屏 硬盘无法识别 无法使用u盘启动

    问题:win7重装系统中强制重启导致硬盘无法识别,开机后无法选择使用u盘启动盘启动,电脑黑屏,将硬盘拆掉可以使用u盘启动,使用SATA转接口在win7中有反应但无法识别 无法识别原因:重装系统过程中断 ...

  2. csv 转换为DBF文件的方法

    转至:https://www.cnblogs.com/hssbsw/archive/2012/12/01/2797140.html csv 转换为DBF文件的方法 最近从SQL导出了许多CSV文件发到 ...

  3. WPS:想让一个新标题后总跟着一种特定样式的文字

    只需在这个后续段落样式中修改为你想要的那个样式即可

  4. pandas模块补充

    数据分析模块pandas和matplotlib补充 面向百度式编程 面向百度式工作 遇到没有见过的知识点或者是相关知识点一定不要慌,结合百度和已知的知识点去学习 pandas模块补充 基于numpy构 ...

  5. Kubernetes概念及核心对象

    想学习更多相关知识请看博主的个人博客地址:https://blog.huli.com/ https://blog.huli.com/ 1.kubernetes快速入门 Kubernetes 集群将所有 ...

  6. 基于idea做java程序的本地k8s调试-skaffold(一)

    先介绍下本篇文章是基于ideas下开发微服务的场景,大家都知道微服务嘛,一个个微的服务...很多,先不谈调试,要跑起来都费力,可能的原因有: 环境变量的配置,如果多个项目穿插着来,env变量可能废了, ...

  7. Python模板引擎Jinja2使用简介

    原文链接 背景 最近在项目开发中,需要针对 Jenkins 项目进行配置,Jenkins 的 job 配置采用的是 xml,在维护配置模板的过程中就遇到了问题,因为逐步发现配置灵活性超出了字符串的范畴 ...

  8. ROS路由器DHCP地址不够使用解决办法!

    由于这段时间公司使用ROS6.2+AC控制器+AP的方案做了公WIFI覆盖,但最近发现地址被用完. 如果使用默认的地址192.168.1.1-192.168.8.254,最多只有254个地址可用,但内 ...

  9. LGP5437题解

    呃怎么感觉很裸啊( 题意是让求生成树边权之和的期望,那么我们只需要算出所有生成树的边权之和除以生成树边数即可. 由于是求和,我们只需要计算出每条边对答案的贡献即可. 我们知道一个完全图有 \(n^{n ...

  10. 《前端运维》二、Nginx--1基本概念及安装

    一.Nginx基本概念 简单来说,Nginx就是一个代理服务器,什么是代理服务器呢?也就是当我们访问服务器的时候,请求不会直接请求到服务器,中间会有个代理,代理会预先于服务器处理这些请求,最后由代理决 ...