ADC、DMA、EXTI、定时器、NVIC等片上外设篇

不知是否是干货,有什么问题,欢迎留言,看见都会答复的

目录

1. 首先呢,放一个STM32芯片框图,这样心里有底 2

2. 第一呢,我们闲聊聊中断 2

2.1什么叫做中断 2

2.2为什么我们要引入NVIC外设 3

2.3 NVIC主要做了那些工作呢 3

2.3.1 NVIC管理时用到的寄存器 3

2.4 NVIC编程 4

3. 说完NVIC,我们就来聊聊外部中断EXTI(IO上的中断) 4

3.1EXTI 功能框图 4

3.2中断/事件线 5

3.3 编程 5

3.3.1EXTI结构体(库函数) 5

3.3.2 编程要点 5

4 .TIM定时器 6

4.1基本定时器的原理 6

4.2基本定时器的基本初始化结构体 7

4.3 编程要点 7

5. 聊聊ADC 8

5.1 ADC原理详解 8

5.1.1①电压输入范围 8

5.1.2 ②输入通道 9

5.1.3 ③转换顺序 9

5.1.4 ④触发源 10

5.1.5 ⑤转换时间 10

5.1.6 ⑥数据寄存器 11

5.1.7 ⑦中断 12

5.1.8 ⑧电压转换 12

5.2 ADC 初始化结构体详解 12

5.3 编程要点 13

6. 说完了ADC,就在说下,ARM公司设计的DMA, 13

6.1简介: 13

6.2 要想真正的了解一个外设,必要看懂他的原理框图 14

6.3 我们在使用DMA的时候,我们会考虑的: 15

6.3.2 要传多少,单位是什么 ,什么时候传输完成 15

6.4 DMA 初始化结构体详解 16

6.5 编程要点 17

 

  1. 首先呢,放一个STM32芯片框图,这样心里有底

 

这里要是想了解STM32,就需要了解他的内部结构,随意推荐去看野火的视频,链接如下:

https://www.bilibili.com/video/BV1yW411Y7Gw?from=search&seid=15398269326892868602的P6、P7。

  1. 第一呢,我们闲聊聊中断

2.1什么叫做中断

官方解释:Cortex-M3 处理器和嵌套向量中断控制器( NVIC)对所有异常按优先级进行排序并处理。所有异常都在处理模式中操作。出现异常时,自动将处理器状态保存到堆栈中,并在中断服务程序( ISR)结束时自动从堆栈中恢复。在状态保存的同时取出向量快速地进入中断。处理器支持末尾连锁( tail-chaining)中断技术,它能够在没有多余的状态保存和恢复指令的情况下执行背对背中断( back-to-back interrupt)。

我理解的:当CPU正在处理一段程序的时候,如果某个时刻,中断触发,哪么此刻CPU会保存当时正在处理的程序而去执行中断服务函数里的程序,当中断服务函数里面的程序执行完毕后,在恢复现场,回来继续的执行中断打断前的程序。

F103 在内核水平上搭载了一个异常响应系统 ,其中支持众多系统异常(中断)和外部中断。

系统中断:10个,如果Reset不可编程 HardFault不可编程)、SysTick(可)

外部中断:60个(可编程的) 

 

2.2为什么我们要引入NVIC外设

所以呢,可以理解为中断的优先级是比普通的顺序执行的优先级高,那么中断就是说是分优先级的,总要东西来控制各个优先级的高低啊有,于是就设计出了一个内核外设NVIC(嵌套向量中断控制器)。那么我们到底是怎么管理中断的呢,下面我们来分析。

2.3 NVIC主要做了那些工作呢

首先,我想说的是任何中断触发后都会经过NVIC来控制中断的优先级问题。

2.3.1 NVIC管理时用到的寄存器

在配置中断的时候我们一般只用 ISERICER IP 这三个寄存器, ISER 用来使能中断,ICER 用来失能中断, IP 用来设置中断优先级 。

1.中断优先级寄存器 NVIC_IPRx :

 

高四位用于控制中断优先级高低,但是M3把这4位分为抢占优先级和响应优先级,就要对优先级分组了。

2.优先级分组

优先级的分组由内核外设 SCB 的应用程序中断及复位控制寄存器 AIRCR
PRIGROUP[10:8]位决定 

 

 

 

2.4 NVIC编程

1.首先,中断优先级分组: NVIC_SetPriorityGrouping(5);//第五个分组 占--2位 次--2位

2.设置中断优先级:NVIC_SetPriority(USART1_IRQn,5);

3.使能:NVIC_EnableIRQ(USART1_IRQn);

3. 说完NVIC,我们就来聊聊外部中断EXTI(IO上的中断)

3.1EXTI 功能框图 

 

从这个图上可以看出,这里一共有20根中断信号线,也就是说EXTI 管理了20个外部中断(io中断)

3.2中断/事件线

 

3.3 编程

3.3.1EXTI结构体(库函数)

1 typedef struct {
2 uint32_t EXTI_Line; // 中断/事件线
3 EXTIMode_TypeDef EXTI_Mode; // EXTI 模式中断或者事件
4 EXTITrigger_TypeDef EXTI_Trigger; // 触发类型
5 FunctionalState EXTI_LineCmd; // EXTI 使能
6 } EXTI_InitTypeDef; 

我们只需要填充这个结构体就行

3.3.2 编程要点 

(1)初始化用来产生中断的GPIO

(2)将PA0映射到EXTI0

(3)初始化EXTI,就是填充结构体

(4)配置NVIC

(5)编写中断服务函数

 

4 .TIM定时器

定时器一个分为基本、通用、高级定时器定时器

 

4.1基本定时器的原理

  1. 看图

①时钟源 

定时器时钟 TIMxCLK,即内部时钟 CK_INT,经 APB1 预分频器后分频提供,如果
APB1 预分频系数等于 1,则频率不变,否则频率乘以 2,库函数中 APB1 预分频的系
数是 2,即 PCLK1=36M,所以定时器时钟 TIMxCLK=36*2=72M 

②计数器时钟
定时器时钟经过 PSC 预分频器之后,即 CK_CNT,用来驱动计数器计数。 PSC 是一个16 位的预分频器,可以对定时器时钟 TIMxCLK 进行 1~65536 之间的任何一个数进行分频。具体计算方式为: CK_CNT=TIMxCLK/(PSC+1) 

③计数器
计数器 CNT 是一个 16 位的计数器,只能往上计数,最大计数值为 65535。当计数达
到自动重装载寄存器的时候产生更新事件,并清零从头开始计数。 

④自动重装载寄存器
自动重装载寄存器 ARR 是一个 16 位的寄存器,这里面装着计数器能计数的最大数
值。当计数到这个值的时候,如果使能了中断的话,定时器就产生溢出中断。

 

重点:就是在计时的时候,其实是③计数器的值向上加,但是,我们在设置其加到多大的时候,是通过改变④自动重装载寄存器的大小来决定的,也就是说我们以后配置定时时间的时候是根据两点来决定的:1.定时器的时钟频率 2.重装载的值

4.2基本定时器的基本初始化结构体

typedef struct {
2 uint16_t TIM_Prescaler; // 预分频器
3 uint16_t TIM_CounterMode; // 计数模式
4 uint32_t TIM_Period; // 定时器周期
5 uint16_t TIM_ClockDivision; // 时钟分频
6 uint8_t TIM_RepetitionCounter; // 重复计算器
7 } TIM_TimeBaseInitTypeDef; 

TIM_Prescaler 定时器预分频器设置,时钟源经该预分频器才是定时器时钟,它设定
TIMx_PSC 寄存器的值。可设置范围为 0 65535,实现 1 65536 分频。也就是说这里如果设置72,那么就相当于是72MHZ的72倍分频,即72M/72=1M

TIM_CounterMode 基本定时器只能是向上计数

TIM_Period 重装载的值

4.3 编程要点 

1.开启定时器时钟

2.配置定时器(填充定时器结构体)

3.计数器清零

4.开启定时器中断

5.设置NVIC

6.使能定时器

5. 聊聊ADC

AD 转换作用:将模拟量转换为数字量

5.1 ADC原理详解

STM32f103 系列有 3 ADC,精度为 12 位,每个 ADC 最多有 16 个外部通道。其中
ADC1 ADC2 都有 16 个外部通道, ADC3 根据 CPU 引脚的不同通道数也不同,一般都有8 个外部通道。 ADC 的模式非常多,功能非常强大,具体的我们在功能框图中分析每个部分的功能。 

5.1.1①电压输入范围
ADC 输入范围为: VREF- VIN VREF+。由 VREF-VREF+ VDDA VSSA、这四个外部引脚决定。
我们在设计原理图的时候一般把 VSSA VREF-接地,把 VREF+VDDA 3V3,得到
ADC 的输入电压范围为: 0~3.3V
如果我们想让输入的电压范围变宽,去到可以测试负电压或者更高的正电压,我们可
以在外部加一个电压调理电路,把需要转换的电压抬升或者降压到 0~3.3V,这样 ADC 就可以测量。 

5.1.2 ②输入通道 

外部的 16 个通道在转换的时候又分为规则通道和注入通道,其中规则通道最多有 16
路,注入通道最多有 4 路。那这两个通道有什么区别?在什么时候使用? 

规则通道
规则通道:顾名思意,规则通道就是很规矩的意思,我们平时一般使用的就是这个通
道,或者应该说我们用到的都是这个通道,没有什么特别要注意的可讲。

注入通道
注入,可以理解为插入,插队的意思,是一种不安分的通道。它是一种在规则通道转
换的时候强行插入要转换的一种。如果在规则通道转换过程中,有注入通道插队,那么就要先转换完注入通道,等注入通道转换完成后,再回到规则通道的转换流程。这点跟中断程序很像,都是不安分的主。所以,注入通道只有在规则通道存在时才会出现。  

5.1.3 ③转换顺序 

规则序列 

这里呢,主要就是SQR三个寄存器来控制各个ADC通道的的转化顺序

比如说,SQR3中的,5位控制一个转换的通道,就是说,比如,你想让你想让那个通道放在第几个转化,就配置那个SQ

5.1.4 ④触发源 

通道选好了,转换的顺序也设置好了,那接下来就该开始转换了, 我们一般用的是软件中断,即ADC_CR2 ADON 这个位来控制 ,1 的时候开始转换,写 0 的时候停止转换,

这个是最简单也是最好理解的开启 ADC 转换的控制方式,理解起来没啥技术含量 。除了这种庶民式的控制方法, ADC 还支持触发转换,这个触发包括内部定时器触发和
外部 IO 触发。触发源有很多,具体选择哪一种触发源,由 ADC 控制寄存器 2:ADC_CR2 EXTSEL[2:0]JEXTSEL[2:0]位来控制。 EXTSEL[2:0]用于选择规则通道的触发源,JEXTSEL[2:0]用于选择注入通道的触发源。选定好触发源之后,触发源是否要激活,则由ADC 控制寄存器 2:ADC_CR2 EXTTRIG JEXTTRIG 这两位来激活。其中 ADC3 的规则转换和注入转换的触发源与 ADC1/2 的有所不同,在框图上已经表示出来 

5.1.5 ⑤转换时间 

ADC 时钟 

ADC是挂载在APB2,即ADC的时钟是由PCLK2(72MHZ)分频产生的,最大时14MHZ,RCC 时钟配置寄存器 RCC_CFGR 的位 15:14 ADCPRE[1:0]设置,可以是 2/4/6/8 分频 

采样时间

ADC使用若干个ADC_CLK 周期 对电压进行采样的,那么每一个通道的采样周期数时通过什么来控制的呢,是通过ADC_SMPR1 ADC_SMPR2 中的 SMP[2:0]位设置 ,ADC_SMPR2 控制的是通道 0~9ADC_SMPR1 控制的是通道 10~17 每个通道可以分别用不同的时间采样。其中采样周期最小是 1.5 个,即如果我们要达到最快的采样,那么应该设置采样周期为 1.5个周期 

 

ADC 的转换时间跟 ADC 的输入时钟和采样时间有关,公式为: Tconv = 采样时间 +
12.5 个周期。 当 ADCLK = 14MHZ (最高),采样时间设置为 1.5 周期(最快),那么总的转换时间(最短) Tconv = 1.5 周期 + 12.5 周期 = 14 周期 = 1us 

一般我们设置 PCLK2=72M,经过 ADC 预分频器能分频到最大的时钟只能是 12M,采
样周期设置为 1.5 个周期,算出最短的转换时间为 1.17us,这个才是最常用的 

5.1.6 ⑥数据寄存器 

一切准备就绪后, ADC 转换后的数据根据转换组的不同,规则组的数据放在 ADC_DR
寄存器,注入组的数据放在 JDRx 这里,我们聊聊规则组,如果日后用到注入组的话,自己再去细看。

ADC规则数据寄存器(ADC_DR)

 

这里呢,我们可以看到,ADC 规则组数据寄存器 ADC_DR 只有一个,是一个 32 位的寄存器,低 16 位在单 ADC时使用,高 16 位是在 ADC1 中双模式下保存 ADC2 转换的规则数据,双模式就是 ADC1 ADC2 同时使用。在单模式下, ADC1/2/3 都不使用高 16 位。因为 ADC 的精度是 12 位,无论 ADC_DR 的高 16 或者低 16 位都放不满,只能左对齐或者右对齐,具体是以哪一种方式存放,由 ADC_CR2 11 ALIGN 设置。 

规则通道可以有 16 个这么多,可规则数据寄存器只有一个, 如果使用多通道转换, 那
转换的数据就全部都挤在了 DR 里面,前一个时间点转换的通道数据,就会被下一个时间点的另外一个通道转换的数据覆盖掉,所以当通道转换完成后就应该把数据取走,或者开启 DMA 模式,把数据传输到内存里面,不然就会造成数据的覆盖。 最常用的做法就是开启 DMA 传输。 

while(!ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC )); //等待 前一个时间点转换的通道数据转换完成

 data_adc[0]=ADC_GetConversionValue(ADC1);

5.1.7 ⑦中断 

数据转换完成后,可以产生3种中断,中断分为三种: 规则通道转换结束中断,注入通道转换结束中断,模拟看门口中断,其中转换结束中断好理解,他有中断标志位中断触发,状态位发送变化和中断使能位开启此中断),

模拟看门狗中断 

当被 ADC 转换的模拟电压低于低阈值或者高于高阈值时,就会产生中断,前提是我
们开启了模拟看门狗中断,其中低阈值和高阈值由 ADC_LTR ADC_HTR 设置。例如我们设置高阈值是 2.5V,那么模拟电压超过 2.5V 的时候,就会产生模拟看门狗中断,反之低阈值也一样。  

DMA 请求 

规则和注入通道转换结束后,除了产生中断外,还可以产生 DMA 请求,把转换好的
数据直接存储在内存里面。要注意的是只有 ADC1 ADC3 可以产生 DMA 请求。 

有关DMA 请求需要配合《 STM32F10X-中文参考手册》 DMA 控制器这一章节来学习。一般我们在使用 ADC 的时候都会开启 DMA 传输 

5.1.8 ⑧电压转换 

我们采集到的是数字电压,那么我们需要把数字电压转化位真实的模拟电压,比如,我们我们的ADC的基准电压是3.3V,而我们的ADC是12位的精准度,那么12位的量程是2^12=4096,那么最小单元就是3.3/4096,如果采集到数字电压是X,那么转化位模拟电压就是(3.3/4096)*X

5.2 ADC 初始化结构体详解 

typedef struct
2 {
3 uint32_t ADC_Mode; // ADC 工作模式选择
4 FunctionalState ADC_ScanConvMode; /* ADC 扫描(多通道)
5 或者单次(单通道)模式选择 */
6 FunctionalState ADC_ContinuousConvMode; // ADC 单次转换或者连续转换选择
7 uint32_t ADC_ExternalTrigConv; // ADC 转换触发信号选择
8 uint32_t ADC_DataAlign; // ADC 数据寄存器对齐格式
9 uint8_t ADC_NbrOfChannel; // ADC 采集通道数
10 } ADC_InitTypeDef; 

ADC_Mode配置 ADC 的模式,当使用一个 ADC 时是独立模式,使用两个 ADC
是双模式,在双模式下还有很多细分模式可选,我们一般使用一个 ADC 的独立模式。 

 ADC_ScanConvMode可选参数为 ENABLE DISABLE,配置是否使用扫描。如果是单通道 AD 转换使用 DISABLE,如果是多通道 AD 转换使用 ENABLE 也就是连续不连续。

ADC_ContinuousConvMode可选参数为 ENABLE DISABLE,配置是启动自动连
续转换还是单次转换。使用 ENABLE 配置为使能自动连续转换;使用 DISABLE 配置为单次转换,转换一次后停止需要手动控制才重新启动转换。一般设置为连续转换。 

ADC_ExternalTrigConv外部触发选择, 图 30-1 中列举了很多外部触发条件,可根据
项目需求配置触发来源。实际上,我们一般使用软件自动触发 

ADC_DataAlign转换结果数据对齐模式,可选右对齐 ADC_DataAlign_Right 或者左
对齐 ADC_DataAlign_Left。一般我们选择右对齐模式。 

ADC_NbrOfChannelAD 转换通道数目,根据实际设置即可。 

5.3 编程要点

(1)初始化ADC用到的GPIO

(2)初始化ADC,就是填充结构体

(3)设置好ADC的时钟

(4)设置采样通道的顺序和采样的时间

(5)配置使能 ADC 转换完成中断,在中断内读取转换完数据;

(6)使能ADC

(7)使能软件触发 ADC 转换。 

如果要是想开启DMA,还是需要去设置一下的

  1. 说完了ADC,就在说下,ARM公司设计的DMA,

我们大家都知道,STM32是单片机,就是说只有一个大脑,那么在跑起程序多少比较乏力,那么ARM公司出厂的时候就设计了DMA,可以把DMA看成内核的小弟,只要内核大哥发送一天指令就可以交给一些事情给DMA来做,这样CPU就有时间来做其他的事情,有点类似于多线程,极大的利用的CPU资源,提高速率。

 

6.1简介:

DMA(直接存储器存取),他是单片机外设,他的主要功能就是帮助CPU来搬运数据,但是不需要CPU,DMA支持从(外设数据寄存器-存储器)、(存储器-存储器),这里的存储器可以是SRAM和FLASH。只要两个DMA,其中DMA1有7个通道,DMA2有5个通道,这里的管道可以理解为传输数据的通道,要注意的是 DMA2 只存在于大容量的单片机中 。

6.2 要想真正的了解一个外设,必要看懂他的原理框图

DMA 请求 

如果外设想通过DMA发送数据,首先外设需要给DMA发送请求,然后DMA收到请求后应答外设后,才可以启动DMA传输,知道传输完毕

不同外设想通过DMA传输都是有固定的通道的,所以说,DMA通道是核心,那么具体对应的是:

这里要注意的是虽然每个通道可以接收多个外设的请求,但是同一时间只能接收一个,不能同时接收多个。

②仲裁器 

先不说

6.3 我们在使用DMA的时候,我们会考虑的:

6.3.1 数据的传输方向,(这个传输的方向也是由DMA_CCRX的位4)

1.外设到存储器 

当我们使用从外设到存储器传输时,以 ADC 采集为例。 DMA 外设寄存器的地址对应的就是 ADC 数据寄存器的地址, DMA 存储器的地址就是我们自定义的变量(用来接收存储 AD 采集的数据) 的地址。 方向我们设置外设为源地址。  2 存储器到外设 

当我们使用从存储器到外设传输时,以串口向电脑端发送数据为例。 DMA 外设寄存器的地址对应的就是串口数据寄存器的地址, DMA 存储器的地址就是我们自定义的变量(相当于一个缓冲区,用来存储通过串口发送到电脑的数据) 的地址。方向我们设置外设为目标地址。 

3.存储器到存储器 

当我们使用从存储器到存储器传输时,以内部 FLASH 向内部 SRAM 复制数据为例。DMA 外设寄存器的地址对应的就是内部 FLASH(我们这里把内部 FALSH 当作一个外设来看) 的地址, DMA 存储器的地址就是我们自定义的变量(相当于一个缓冲区,用来存储来自内部 FLASH 的数据)的地址。 方向我们设置外设(即内部 FLASH) 为源地址。 跟上面两个不一样的是,这里需要把 DMA_CCR 14MEM2MEM:存储器到存储器模式配置为 1,启动 M2M 模式。 

6.3.2 要传多少,单位是什么 什么时候传输完成 

当我们配置好数据要从哪里来到哪里去之后,我们还需要知道我们要传输的数据是多少,数据的单位是什么。

1传多少

 首先,我们要传多少的数据量,这里呢,有一个寄存器DMA_CNDTR 配置,这是一个 32 位的寄存器,一次最多只能传输 65535 个数据。

2传输的数据宽度 

其次,要是想传输的数据是正确的,源和目标的数据宽度要是一样的,比如说,串口的寄存器的数据宽度是8位,那么我们如果以串口为源的时候,那么目标的区的数据宽度就也要是8位。   这里呢,无论是外设还是自己开辟的目标地址的数据都会分别放到DMA的两个32位的寄存器当中,但是数据的宽度是由:外设的数据宽度由 DMA_CCRx PSIZE[1:0]配置,可以是 8/16/32 位,存储器的数据宽度由 DMA_CCRx MSIZE[1:0]配置,可以是 8/16/32 位。 

(3)源和目标的地址的偏移

DMA 控制器的控制下,数据要想有条不紊的从一个地方搬到另外一个地方,还必须正确设置两边数据指针的增量模式。 外设的地址指针由 DMA_CCRx PINC 配置,存储器的地址指针由 MINC 配置。 以串口向电脑发送数据为例,要发送的数据很多,每发送完一个,那么存储器的地址指针就应该加 1,而串口数据寄存器只有一个,那么外设的地址指针就固定不变。具体的数据指针的增量模式由实际情况决定。  

  1. 数据什么时候传输完成,我们可以通过查询标志位或者通过中断的方式来鉴别。 每个DMA 通道在 DMA 传输过半传输完成传输错误时都会有相应的标志位,如果使能了该类型的中断后,则会产生中断。关各个标志位的详细描述请参考 DMA 中断状态寄存器DMA_ISR 的详细描述。 最大通道7

6.4 DMA 初始化结构体详解 

1 typedef struct
2 {
3 uint32_t DMA_PeripheralBaseAddr; // 外设地址
4 uint32_t DMA_MemoryBaseAddr; // 存储器地址
5 uint32_t DMA_DIR; // 传输方向
6 uint32_t DMA_BufferSize; // 传输数目
7 uint32_t DMA_PeripheralInc; // 外设地址增量模式
8 uint32_t DMA_MemoryInc; // 存储器地址增量模式
9 uint32_t DMA_PeripheralDataSize; // 外设数据宽度
10 uint32_t DMA_MemoryDataSize; // 存储器数据宽度
11 uint32_t DMA_Mode; // 模式选择
12 uint32_t DMA_Priority; // 通道优先级
13 uint32_t DMA_M2M; // 存储器到存储器模式
14 } DMA_InitTypeDef; 

DMA_InitTypeDef DMA_InitStructures;

RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1,ENABLE);

DMA_DeInit(DMA1_Channel4);    //将通道一寄存器设为默认值

DMA_InitStructures.DMA_PeripheralBaseAddr=(u32)&USART1->DR;//USART1外设地址:USART1->DR

DMA_InitStructures.DMA_PeripheralDataSize=DMA_PeripheralDataSize_Byte;//外设数据宽度--8位

DMA_InitStructures.DMA_MemoryBaseAddr=(u32)send_val;//缓存区地址(存储器地址)

DMA_InitStructures.DMA_MemoryDataSize=DMA_MemoryDataSize_Byte;//缓存区地址宽度--8位

DMA_InitStructures.DMA_BufferSize=sizeof(send_val)/sizeof(u8);//传输的数据量--20个

DMA_InitStructures.DMA_DIR=DMA_DIR_PeripheralDST;//DMA传输方向--外设作为目标

DMA_InitStructures.DMA_M2M=DMA_M2M_Disable;//存储器到存储器

DMA_InitStructures.DMA_MemoryInc=DMA_MemoryInc_Enable;//内存地址递增

DMA_InitStructures.DMA_PeripheralInc=DMA_PeripheralInc_Disable;//外设地址保持不变

DMA_InitStructures.DMA_Mode=DMA_Mode_Normal;//单次转换

DMA_InitStructures.DMA_Priority=DMA_Priority_High;//优先级

DMA_Init(DMA1_Channel4,&DMA_InitStructures);//DMA1_IN4初始化

DMA_Cmd(DMA1_Channel4, ENABLE);//启动DMA通道1

USART_DMACmd(USART1,USART_DMAReq_Tx,ENABLE);

//传输出错中断

DMA_ITConfig(DMA1_Channel4,DMA_IT_TE,ENABLE);

NVIC_SetPriority(DMA1_Channel4_IRQn,7);

NVIC_EnableIRQ(DMA1_Channel4_IRQn);

6.5 编程要点

(1)使能DMA时钟

(2)配置DMA,即填充核心结构体

(3)使能 DMA,进行传输;

(4)等待传输完成,并对源数据和目标地址数据进行比较

  • 7
    点赞
  • 36
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值