参考:
1.正点原子
2.https://openatomworkshop.csdn.net/6673ddaba1e8811a9781de12.html
3.https://devpress.csdn.net/hefei/6462fb143399b617f0c02487.html (暂时未看)
1.ADC简述
ADC 即模拟数字转换器,英文详称 Analog-to-digital converter,可以将外部的模拟信号转换为数字信号。
STM32F4xx 系列芯片拥有 3 个 ADC,这些 ADC 可以独立使用,其中 ADC1 和 ADC2 还可以组成双重模式(同步或者协同采样)。STM32 的 ADC 是 12 位逐次逼近型的模拟数字转换器。它有 19 个通道,可测量 16 个外部和 2 个内部信号源和 Vbat 通道的信号, ADC 中的各个通道的A/D 转换可以单次、连续、扫描或间断模式执行。ADC 的结果可以以左对齐或者右对齐存储在16 位数据寄存器中。ADC 具有模拟看门狗的特性,允许应用检测输入电压是否超过了用户自定义的阈值上限或下限。
STM32F407 的 ADC 主要特性可以总结为以下几条:
1、可配置 12 位、10 位、8 位或 6 位分辨率;
2、转换结束、注入转换结束和发生模拟看门狗事件时产生中断
3、单次和连续转换模式
4、自校准
5、带内嵌数据一致性的数据对齐
6、采样间隔可以按通道分别编程
7、规则转换和注入转换均有外部触发选项
8、间断模式
9、双重模式(带 2 个或以上 ADC 的器件)
10、ADC 转换时间:最大转换速率为 2.4MHz,转换时间为 0.41us
11、ADC 供电要求:2.4V 到 3.6V
12、ADC 输入范围:VREF–≤VIN≤VREF+
13、规则通道转换期间有 DMA 请求产生
2.ADC原理
下面来介绍 ADC 的框图:
① 输入电压
在前面 ADC 的主要特性也对输入电压有所提及,ADC 输入范围 VREF–≤VIN≤VREF+,最终还是由 VREF–、VREF+、VDDA和 VSSA决定的。这几个参数的关系,如图所示:
从上图可以知道,VDDA 和 VREF+接 VCC3.3,而 VSSA和 VREF-是接地,所以 ADC 的输入范围即 0~3.3V。R55 默认焊接,R54 默认不焊接。
② 输入通道
在确定好了 ADC 输入电压后,如何把外部输入的电压输送到 ADC 转换器中呢,在这里引入了 ADC 的输入通道,在前面也提及到了 ADC1 有 16 个外部通道和 3 个内部通道,而 ADC2和 ADC3 只有 16 个外部通道。ADC1 的外部通道是通道 17、通道 18 和通道 19,分别连接到内部温度传感器、内部Vrefint和Vbat。外部通道对应的是图中的ADCx_IN0、ADCx_IN1…ADCx_IN15(下图没有描述内部通道)。 ADC 通道表见表所示:
③ 转换顺序
当任意 ADCx 多个通道以任意顺序进行一系列转换就诞生了成组转换(也就是多个通道的序列),这里就有两种成组转换类型:规则组和注入组。规则组就是图上的规则通道,注入组也就是图上的注入通道。为了避免大家对输入通道加上规则通道和注入通道理解有所模糊,后面规则通道以规则组来代称,注入通道以注入组来代称。规则组允许最多 16 个输入通道进行转换,而注入组允许最多 4 个输入通道进行转换。这里讲解一下规则组和注入组。
规则组(规则通道)
规则组,按字面理解,“规则”就是按照一定的顺序,相当于正常运行的程序,平常用到最多也是规则组。
注入组(注入通道)
注入组,按字面理解,“注入”就是打破原来的状态,相当于中断。当程序执行的时候,中断是可以打断程序的执行。同这个类似,注入组转换可以打断规则组的转换。假如在规则组转换过程中,注入组启动,那么注入组被转换完成之后,规则组才得以继续转换。
便于理解,下面看一下规则组和注入组的对比图,如图所示:
在了解了规则组和注入组后,现在了解一下它们两者的转换顺序。
规则序列
规则组是允许 16 个通道进行转换的,那么就需要安排通道转换的次序即 规则序列。规则序列寄存器有 3 个,分别为 SQR1、SQR2 和 SQR3。SQR3 控制规则序列中的第 1 个到第 6 个转换的通道;SQR2 控制规则序列中第 7 个到第 12 个转换的通道;SQR1 控制规则序列中第 13 个到第 16 个转换的通道。规则序列寄存器 SQRx 详表如表所示:
从上表可以知道,当我们想把 ADC 的输入通道 1 安排到第 1 个转换,那么只需要在 SQR3寄存器中的 SQ1[4:0]位写入该 ADC 输入通道 即写 1 处理即可。SQR1 的 SQL[3:0]决定了具体使用多少个通道。
注入序列
注入序列,跟规则序列差不多,都是有顺序的安排。由于注入组最大允许 4 个通道输入,所以这里就使用了一个寄存器 JSQR。注入序列寄存器 JSQR 详表如表所示:
④ 触发源
在配置好输入通道以及转换顺序后,就可以进行触发转换了。ADC 的触发转换有两种方法:
分别是通过软件或外部事件(也就是硬件)触发转换。我们先来看看通过写软件触发转换的方法。方法是:通过写 ADC_CR2 寄存器的 ADON 这个位来控制,写 1 就开始转换,写 0 就停止转换,这个控制 ADC 转换的方式非常简单。另一种就是通过外部事件触发转换的方法,有定时器和输入引脚触发等等。这里区分规则组和注入组。方法是:通过 ADC_CR2 寄存器的 EXTSET[2:0]选择规则组的触发源,JEXTSET[2:0]选择注入组的触发源。通过 ADC_CR2 的 EXTTRIG 和 JEXTTRIG 这两位去激活触发源。ADC3的触发源和 ADC1/2 不同,这里需要注意,那么在框图里已经标记出来了。
⑤ 转换时间
STM32F407 的 ADC 总转换时间的计算公式如下:
TCONV = 采样时间 + 12 个周期
采样时间可通过 ADC_SMPR1 和 ADC_SMPR2 寄存器中的 SMP[2:0]位编程,ADC_SMPR2
控制的是通道 0~9,ADC_SMPR1 控制的是通道 10~18。所有通道都可以通过编程来控制使用不同的采样时间,可选采样时间值如下:
⚫ SMP = 000:3 个 ADC 时钟周期
⚫ SMP = 001:15 个 ADC 时钟周期
⚫ SMP = 010:28 个 ADC 时钟周期
⚫ SMP = 011:56 个 ADC 时钟周期
⚫ SMP = 100:84 个 ADC 时钟周期
⚫ SMP = 101:112 个 ADC 时钟周期
⚫ SMP = 110:144 个 ADC 时钟周期
⚫ SMP = 111:480 个 ADC 时钟周期
12 个周期是 ADC 输入时钟 ADC_CLK 决定的。ADC_CLK 是由 APB2 经过分频产生,分频系数是由 RCC_CFGR 寄存器中的 PPRE2[2:0]进行设置,有 2/4/6/8/16 分频选项。
采样时间最小是 3 个时钟周期,这个采样时间下,我们可以得到最快的采样速度。举个例子,我们采用最高的采样速率,使用采样时间为 3 个 ADC 时钟周期,那么得到:
TCONV = 3 个 ADC 时钟周期 + 12 个 ADC 时钟周期 = 15 个 ADC 时钟周期, 一般 APB2 的时钟是 84MHz,经过 ADC 分频器的 4 分频后,ADC 时钟频率就为 21MHz。
通过换算可得到:
TCONV = 15 个 ADC 时钟周期 = (1/21 000 000) ∗ 15 s = 0.71us
⑥ 数据寄存器
ADC 转换完成后的数据输出寄存器。根据转换组的不同,规则组的完成转换的数据输出到ADC_DR 寄存器,注入组的完成转换的数据输出到 ADC_JDRx 寄存器。假如是使用双重模式,规则组的数据也是存放在 ADC_DR 寄存器。这两个寄存器的讲解将会在后面讲解,这里就不列出来了。
⑦ 中断
规则和注入组转换结束时能产生中断,当模拟看门狗状态位被设置时也能产生中断。它们在 ADC_SR 中都有独立的中断使能位,后面讲解 ADC_SR 寄存器时再进行展开。这里讲解一下,模拟看门狗中断以及 DMA 请求。
模拟看门狗中断
模拟看门狗中断发生条件:首先通过ADC_LTR和ADC_HTR寄存器设置低阈值和高阈值,然后开启了模拟看门狗中断后,当被 ADC 转换的模拟电压低于低阈值或者高于高阈值时,就会产生中断。例如我们设置高阈值是 3.0V,那么模拟电压超过 3.0V 的时候,就会产生模拟看门狗中断,低阈值的情况类似。
DMA 请求
规则组和注入组的转换结束后,除了产生中断外,还可以产生 DMA 请求,把转换好的数据存储在内存里面,防止读取不及时数据被覆盖。
3.ADC的HAL库驱动函数
4.单通道 ADC 采集
(软件启动转换方式-轮询)
STM32F407 的 ADC 可以进行很多种不同的转换模式,在《STM32F4xx 参考手册_V4(中文版).pdf》的第 11 章也都有详细介绍。本实验我们来学习使用规则单通道的单次转换模式。
STM32F407 的 ADC 在单次转换模式下(CONT 位为 0),只执行一次转换,该模式可以通过 ADC_CR2 寄存器的 ADON 位(只适用于规则通道)启动,也可以通过外部触发启动(适用于规则通道和注入通道,但是必须先设置 EXTTRIG/JEXTTRIG 位)。
以规则通道为例,一旦所选择的通道转换完成,转换结果将被存在 ADC_DR 寄存器中,EOC(转换结束)标志将被置位,如果设置了 EOCIE,则会产生中断。然后 ADC 将停止,直到下次启动。
函数HAL_ADC_Start()用于以软件方式启动ADC常规通道的转换,软件启动转换后,需要调用函数HAL_ADC_PollForConversion()查询转换是否完成,转换完成后可用函数HAL_ADC_GetValue()读出常规转换结果寄存器的32位数据。若要再次转换,需要再次使用这3个函数启动转换、查询转换是否完成、读出转换结果。使用函数HAL_ADC_Stop()停止ADC常规通道转换。
这种软件启动转换的模式适用于单通道、低采样率的ADC转换。这几个函数原型定义如下:
HAL_StatusTypeDef HAL_ADC_Start(ADC_HandleTypeDef* hadc); //软件启动转换HAL_StatusTypeDef
HAL_ADC_Stop(ADC_HandleTypeDef* hadc); //停止转换HAL_StatusTypeDef
HAL_ADC_PollForConversion(ADC_HandleTypeDef* hadc, uint32_t Timeout);
uint32_t HAL_ADC_GetValue(ADC_HandleTypeDef* hadc); //读取转换结果寄存器的32位数据
其中,参数hadc是ADC外设对象指针,Timeout是超时等待时间(单位是ms)。
4.1 ADC 寄存器
(寄存器简单的也看下,万一出现bug,debug的时候可以查看寄存器状态)
下面,我们介绍执行规则通道的单次转换,需要用到的一些 ADC 寄存器。
⚫ ADC 控制寄存器 1(ADC_CR1)
ADC 控制寄存器 1 描述如图所示:
该寄存器本章用到 SCAN 位,用于设置扫描模式,由软件设置和清除,如果设置为 1,则使用扫描模式,如果为 0,则关闭扫描模式。在本章实验中使用的是非扫描模式。在扫描模式下,由 ADC_SQRx 或 ADC_JSQRx 寄存器选中的通道被转换。如果设置了 EOCIE 或 JEOCIE,只会在最后一个通道转换完成后才会产生 EOC 或 JEOC 中断。
SCAN 位只适合使用在 >=2的通道场景,单通道不适用。
⚫ ADC 控制寄存器 2(ADC_CR2)
ADC 控制寄存器 2 描述如图所示:
该寄存器我们针对性的介绍一些位:
ADON 位用于开关 AD 转换器。
CONT 位用于设置是否进行连续转换,我们使用单次转换,所以 CONT 位必须为 0。
ALIGN 用于设置数据对齐,一般使用右对齐,所以该位设置为 0。
EXTSEL[3:0]用于选择启动规则转换组转换的外部事件,我们这里使用的是软件触发(SWSTART),所以这里设置这3 位为 111。SWSTART 位用于开始规则通道的转换,我们每次转换(单次转换模式下)都需要向该位写 1。
⚫ ADC 采样事件寄存器 1(ADC_SMPR1)
ADC 采样事件寄存器 1 描述如图所示:
ADC 采样事件寄存器 2(ADC_SMPR2)
ADC 采样事件寄存器 2 描述如图所示
这里结合两个 ADC 采样事件寄存器进行讲解,这两个寄存器用于设置通道 0~18 的采样事件,每个通道占用 3 个位。对于每个要转换的通道,采样事件建议尽量长一点,以获得较高的准确度,但是这样会降低 ADC 的转换速率。
⚫ ADC 规则序列寄存器 1
ADC 规则序列寄存器共有 3 个,这几个寄存器的功能都差不多,这里我们仅介绍一下 ADC规则序列寄存器 1(ADC_SQR1),描述如图所示:
L[3:0]:用于存储规则序列的长度,取值范围:015,我们这里只用了一个,所以设置这几位的值为0。其他的SQ13SQ16则存储了规则序列中的第1316通道的编号(编号范围:018)。
另外两个规则序列寄存器同 ADC_SQR1 大同小异,这里就不再介绍了,要说明一点的是:我们选择的是单次转换,所以只有一个通道在规则序列里,这个序列就是 SQ1,通过 ADC_SQR3 的最低 5 位(也就是 SQ1)设置。
⚫ ADC 规则数据寄存器(ADC_DR)
ADC 规则数据寄存器描述如图所示
在规则序列中 AD 转换结果都将被存在这个寄存器里面,而注入通道的转换结果被保存在ADC_JDRx 里面。该寄存器的数据可以通过 ADC_CR2 的 ALIGN 位设置左对齐还是右对齐。在读取数据的时候要注意。
⚫ ADC 状态寄存器(ADC_SR)
ADC 状态寄存器描述如图所示:
该寄存器保存了 ADC 转换时的各种状态。这里我们要用到的是 EOC 位,我们通过该位来决定是否此次规则通道的 AD 转换已经完成,如果完成我们就从 ADC_DR 中读取转换结果,否则等待转换完成。
4.2 ADC转换结果电压计算
ADC转换的结果是一个数字量,与实际的模拟电压之间的计算关系 由VERF+和转换精度位数确定。
例如,转换精度位12位,VERF+ 为3.3V,ADC转换结果位12位数字量(0xF FF = 4095, 0到4095就是4096)对应的整数为X,则实际电压为
Voltage = (3.3 * X) / 4096 V
比如ADC采集电压采集到的数值为2000,则实际对应的电压应该为
Voltage = (3.3 * 2000)/ 4096 = 1.61 V
4.3 关键结构体
1. HAL_ADC_Init 函数
HAL_StatusTypeDef HAL_ADC_Init(ADC_HandleTypeDef *hadc);:
重要结构体1:ADC_InitTypeDef 类型,结构体 ADC_InitTypeDef 定义为:
typedef struct {
uint32_t ClockPrescaler; /* 设置预分频系数,即 PRESC[3:0]位 */
uint32_t Resolution; /* 配置 ADC 的分辨率 */
uint32_t ScanConvMode; /* 扫描模式 */
uint32_t EOCSelection; /* 转换完成标志位 */
FunctionalState ContinuousConvMode; /* 开启连续转换模式否则就是单次转换模式 */
uint32_t NbrOfConversion; /* 设置转换通道数目 */
FunctionalState DiscontinuousConvMode; /* 单次转换模式选择 */
uint32_t NbrOfDiscConversion; /* 单次转换通道的数目 */
uint32_t ExternalTrigConv; /* ADC 外部触发源选择 */
uint32_t ExternalTrigConvEdge; /* ADC 外部触发极性*/
FunctionalState DMAContinuousRequests; /* DMA 转换请求模式*/
} ADC_InitTypeDef;
ClockPrescaler:ADC 预分频系数选择,可选的分频系数为 2、4、6、8。由于 ADC 最大时钟不得超过 36Mhz,我们这里配置 4 分频,即 ADC 的时钟频率为:84 / 4 = 21Mhz。
Resolution:配置 ADC 的分辨率,可选的分辨率有 12 位、10 位、8 位和 6 位。分辨率越高,转换数据精度越高,转换时间也越长;反之分辨率越低,转换数据精度越低,转换时间也越短。
ScanConvMode:配置是否使用扫描。如果是单通道转换使用 ADC_SCAN_DISABLE,如果是多通道转换使用 ADC_SCAN_ENABLE。
EOCSelection:可选参数为 ADC_EOC_SINGLE_CONV 和 ADC_EOC_SEQ_CONV,指定转换结束时是否产生 EOS 中断或事件标志。
ContinuousConvMode:可选参数为 ENABLE 和 DISABLE,配置自动连续转换还是单次转换。使用 ENABLE 配置为使能自动连续转换;使用 DISABLE 配置为单次转换,转换一次后停止需要手动控制才重新启动转换。
NbrOfConversion:设置常规转换通道数目,范围是:1~16。
DiscontinuousConvMode:配置是否使用不连续的采样模式,比如要转换的通道有 1、2、5、7、8、9,那么第一次触发会进行通道 1 与通道 2,下次触发就是转换通道 5 与通道 7,这样不连续的转换,依次类推。此参数只有将 ScanConvMode 使能,还有 ContinuousConvMode失能的情况下才有效,不可同时使能。
NbrOfDiscConversion:不连续采样通道数。
ExternalTrigConv:外部触发方式的选择,如果使用软件触发,那么外部触发会关闭。
ExternalTrigConvEdge:外部触发极性选择,如果使用外部触发,可以选择触发的极性,可选有禁止触发检测、上升沿触发检测、下降沿触发检测以及上升沿和下降沿均可触发检测。
DMAContinuousRequests:指定 DMA 请求是否以一次性模式执行(当达到转换次数时,DMA传输停止)或在连续模式下(DMA 传输无限制,无论转换的数量)。注:在连续模式下,DMA 必须配置为循环模式。否则,当达到 DMA 缓冲区最大指针时将触发溢出。注意:当常规组和注入组都没有转换时(禁用 ADC,或启用 ADC,没有连续模式或可以启动转换的外部触发器),必须修改此参数。该参数可设置为“启用”或“禁用”。
2. HAL_ADC_ConfigChannel 函数
HAL_StatusTypeDef HAL_ADC_ConfigChannel(ADC_HandleTypeDef *hadc, ADC_ChannelConfTypeDef *sConfig);
调用 HAL_ADC_Init 函数配置了相关的功能后,就可以调用此函数进行配置 ADC 具体通道复用。
形参 1 是 ADC_HandleTypeDef 结构体类型指针变量。
形参 2 是 ADC_ChannelConfTypeDef 结构体类型指针变量,用于配置 ADC 采样时间,使用的通道号,单端或者差分方式的配置等。该结构体定义如下:
重要结构体2:ADC_ChannelConfTypeDef
typedef struct {
uint32_t Channel; /* ADC 转换通道*/
uint32_t Rank; /* ADC 转换顺序 */
uint32_t SamplingTime; /* ADC 采样周期 */
uint32_t Offset; /* ADC 偏移量 */
} ADC_ChannelConfTypeDef;
Channel:ADC 转换通道,范围:0~19。
Rank:在常规转换中的常规组的转换顺序,可以选择 1~16。
SamplingTime:ADC 的采样周期,最大 480 个 ADC 时钟周期,要求采样周期尽量大,以减少误差。
通过STM32CubeMX配置:
1.表示选择了外部IN5这个通道,对应的是PA5管脚。
2.独立模式,当把ADC0和ADC1等多个ADC同步使用的时候就选多重模式,不过一般也选不了。
3.当单个通道转换结束的时候就设置EOC标志位。也有其他选项一组转换完了再设置EOC标志位,目前还不知道什么场景使用这个选项。
4.规则组里面Rank表示序列1被设置为了channel 5.
/**
* @brief 获得 ADC 转换后的结果
* @param ch: 通道值 0~17,取值范围为:ADC_CHANNEL_0~ADC_CHANNEL_17
* @retval 无
*/
uint32_t adc_get_result(uint32_t ch)
{
/* 设置通道,序列和采样时间,初始化的时候已经配置了*/
//adc_channel_set(&hadc1, ch, 1, ADC_SAMPLETIME_480CYCLES);
HAL_ADC_Start(&hadc1); /* 开启 ADC */
HAL_ADC_PollForConversion(&hadc1, 10); /* 轮询转换 */
/* 返回最近一次 ADC1 规则组的转换结果 */
return (uint16_t)HAL_ADC_GetValue(&hadc1);
}
/**
* @brief 获取通道 ch 的转换值,取 times 次,然后平均
* @param ch : 通道号, 0~17
* @param times : 获取次数
* @retval 通道 ch 的 times 次转换结果平均值
*/
uint32_t adc_get_result_average(uint32_t ch, uint8_t times)
{
uint32_t temp_val = 0;
uint8_t t;
for (t = 0; t < times; t++) /* 获取 times 次数据 */
{
temp_val += adc_get_result(ch);
}
return temp_val / times; /* 返回平均值 */
}
代码:
git clone git@gitee.com:xiaoliangliangcong/stm32.git
STM32F407ZGT6/3.ADC/single_ADC目录下:
最后运行代码的结果:
5. 中断转换方式
当ADC设置为用定时器或外部信号触发转换时,函数HAL_ADC_Start_IT()用于启动转换,这会开启ADC的中断。当ADC转换完成时会触发中断,在中断服务程序里,可以用HAL_ADC_GetValue()读取转换结果寄存器里的数据。函数HAL_ADC_Stop_IT()可以关闭中断,停止ADC转换。开启和停止ADC中断方式转换的两个函数的原型定义如下:
HAL_StatusTypeDef HAL_ADC_Start_IT(ADC_HandleTypeDef* hadc);
HAL_StatusTypeDef HAL_ADC_Stop_IT(ADC_HandleTypeDef* hadc);
ADC1、ADC2和ADC3共用一个中断号,ISR名称是ADC_IRQHandler()。ADC有4个中断事件源,中断事件类型的宏定义如下(在stm32f4xx_hal_adc.h中):
#define ADC_IT_EOC ((uint32_t)ADC_CR1_EOCIE) //规则通道转换结果结束(EOC)事件
#define ADC_IT_AWD ((uint32_t)ADC_CR1_AWDIE) //模拟看门狗触发事件
#define ADC_IT_JEOC ((uint32_t)ADC_CR1_JEOCIE) //注入通道转换结束事件
#define ADC_IT_OVR ((uint32_t)ADC_CR1_OVRIE) //数据溢出事件、即转换结果未被及时读出
ADC中断通用处理函数是HAL_ADC_IRQHandler(),它内部会判断中断事件类型,并调用相应的回调函数。ADC的4个中断事件类型及其对应的回调函数如表所示。
用户可以设置为在转换完一个通道后就产生EOC事件,也可以设置为转换完规则通道组的所有通道之后产生EOC事件。但是规则组只有一个转换结果寄存器,如果有多个转换通道,设置为 转换完规则组的所有通道之后产生EOC,会导致数据溢出。一般设置为在转换外一个通道后就产生EOC事件。所以,中断方式转换适用于单通道或采样频率不高的场合。
暂时没有测试代码。
6.DMA方式转换
ADC只有一个DMA请求,方向是外设到存储器。DMA在ADC中是非常有用,它可以处理多通道、高采样频率的情况。函数HAL_ADC_Start_DMA()以DM方式启动ADC,其原型定义如下
HAL_StatusTypeDef HAL_ADC_Start_DMA(ADC_HandleTypeDef* hadc, uint32_t* pData, uint32_t Length);
其中,参数hadc是ADC外设对象指针;参数pData是uint32_t类型缓冲区指针,因为ADC转换结果寄存器是32位的(实测16位也是可以的),所以DMA数据宽度是32位;参数Length是缓冲区长度,单位是字(4字节)。
停止DMA方式采集的函数是
HAL_ADC_Stop_DMA();
其原型定义如下:
HAL_StatusTypeDef HAL_ADC_Stop_DMA(ADC_HandleTypeDef* hadc);
DMA流的主要中断事件与ADC的回调函数之间的关系如表所示。一个外设使用DMA传输方式时,DMA流的事件中断一般使用外设的事件中断回调函数。
6.1 单通道 ADC 采集(DMA 读取)
本实验我们来学习使用规则单通道的连续转换模式,并且使用 DMA 读取 ADC 的数据。
6.1.1 ADC & DMA 寄存器
⚫ ADC 配置寄存器(ADC_CR2)
ADCx 配置寄存器描述如图 31.3.1.1 所示:
ADC_CR2 寄存器中我们主要跟前面设置不同的有两个位,分别如下:DMA 位,用于配置 DMA 使用。单通道 ADC 采集实验我们是默认设置为 0,不使用 DMA模式,规则转换数据仅存储在 ADC_DR 中,然后通过软件去 ADC_DR 数据寄存器读取。本实验我们要设置为 1:使用 DMA 模式,这样启动一次 DMA 传输,DMA 就会自动读取一次数据。CONT 位,用于设置转换模式。单通道 ADC 采集实验单次转换模式,本实验中我们要设置为连续转换模式,所以该位设置为 1。
下面介绍 DMA 一些比较重要的寄存器配置。
⚫ DMA 数据流 x 外设地址寄存器(DMA_SxPAR)
DMA 数据流 x 外设地址寄存器描述如图 所示:
DMA_SxPAR 寄存器(部分)该寄存器存放的是 DMA 读或者写数据的外设数据寄存器的基址。本实验,我们需要通过DMA 读取 ADC 转换后存放在 ADC 规则数据寄存器 (ADC_DR) 的结果数据。所以我们需要给 DMA_SxPAR 寄存器写入 ADC_DR 寄存器的地址。这样配置后,DMA 就会从 ADC_DR 寄存器的地址读取 ADC 的转换后的数据到某个内存空间。这个内存空间地址需要我们通过DMA_SxM0AR 寄存器来设置,比如定义一个变量,把这个变量的地址值写入该寄存器。注意:DMA_SxPAR 寄存器受到写保护,只有 DMA_SxCR 寄存器中的 EN 为“0”时才可
以写入,即先要禁止数据流传输才可以写入。
⚫ DMA 数据流 x 存储器地址寄存器(DMA_SxM0AR)
DMA 数据流 x 存储器地址寄存器描述如图所示:
DMA_SxM0AR 寄存器(部分)该寄存器存放的是 DMA 读或者写数据的目标存放的地址。如果用到双缓冲区模式我们还需要用到 DMA_SxM1AR 寄存器。
⚫ DMA 数据流 x 数据项数寄存器(DMA_SxNDTR)
DMA 数据流 x 数据项数寄存器描述如图所示:
DMA_SxNDTRDMA_SxPAR 寄存器是传输的源地址,DMA_SxM0AR 寄存器是传输的目的地址,DMA_SxNDTR 寄存器则是要传输的数据项数目(0 到 65535)。并且该寄存器的值会随着传输的进行而减少,当该寄存器的值为 0 的时候就代表此次数据传输已经全部发送完成了。所以可
以通过这个寄存器的值来知道当前 DMA 传输的进度。特别注意,这里是数据项数目,而不是指的字节数。比如设置数据位宽为 16 位,那么传输一次(一个项)就是 2 个字节。
6.1.2 CubeMX的配置
使用DMA,需要把Continuous Conversion Mode 设置为Enable,使用连续转换。
DMA Continuous Requests 设置为Enable。每次转换完成之后,转换结果都被DMA传输到目的地址了。
Mode 设置为Circular,使用循环模式,那么ADC连续转换的结果都可以通过DMA传输。
代码:
git clone git@gitee.com:xiaoliangliangcong/stm32.git
STM32F407ZGT6/3.ADC/single_ADC_DMA这个目录下:
串口打印效果:
6.2多通道ADC DMA采集
本实验我们来学习使用规则多通道的连续转换模式,并且使用 DMA 读取 ADC 的数据。
6.2.1 ADC 寄存器
ADC 规则序列寄存器有四个(ADC_SQR1~ADC_SQR3),具体怎么配置,需要看我们用多少个通道,比如本实验我们使用 3 个通道同时采集 ADC 数据,具体配置如下:
⚫ ADC 规则序列寄存器 1(ADC_SQR1)
ADC 规则序列寄存器 1 描述如图 所示:
首先确认是使用六个通道,L[3:0]位:用于存储规则序列的长度,取值范围:016,表示规则序列长度为:116。我们这里使用了 3 个通道,所以设置这几个位的值为 3 即可。SQ13~SQ16 表示规则序列中的第 13~16 个序列的转换通道(0~17),每个规则序列的转换通道,可以由 SQx(x=1~16)指定,比如我们设置:SQ13[4:0]=1,就表示规则序列 13 的转换通道为 1(ADC1/2/3_CH1)。SQ1~SQ12 由寄存器 ADC_SQR2~3 控制。SQ1~SQ16 的用法,下面我们来看看本实验是怎么设置的:SQ1 位赋值为 0、SQ2 位赋值为 1、SQ3 位赋值为 1、SQ4 位赋值为 3、SQ5 位赋值为 4、SQ6 位赋值为 5,即规则序列 1 到6 分别对应的通道是 0 到 5。SQ1~SQ6 位都是在 ADC_SQR3 寄存器中配置。
CubeMX配置:
Scan conversion mode enbled ,多通道需要使能,扫描。
Number of Conversion 规则转换数据设置为4,4个Rank分别设置相应的值。
代码:
git clone git@gitee.com:xiaoliangliangcong/stm32.git
STM32F407ZGT6/3.ADC/mul_ADC_DMA目录下
运行效果:
————————————————
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
原文链接:https://blog.csdn.net/yeweiliang_93/article/details/144434429
|