游戏电视苹果数码历史美丽
投稿投诉
美丽时装
彩妆资讯
历史明星
乐活安卓
数码常识
驾车健康
苹果问答
网络发型
电视车载
室内电影
游戏科学
音乐整形

GD32开发实战指南第11章CPU的高级代理DMA

  开发环境:
  MDK:Keil5。30
  开发板:GD32F207IEVAL
  MCU:GD32F207IK11。1DMA工作原理11。1。1DMA介绍
  DMA(DirectMemoryAccess,直接存储器存取),是一种可以大大减轻CPU工作量的数据存取方式,DMA传输将数据从一个地址空间复制到另一个地址空间,提供在外设和存储器之间或者存储器和存储器之间的高速数据传输,因而被广泛地使用。早在8086的应用中就已经有Intel的8237这种典型的DMA控制器,而GD32的DMA则是以类似外设的形式添加到Cortex内核之外的。可以说,DMA就是CPU的高级代理,DMA大大减轻了CPU的负担。
  在硬件系统中,主要由CPU(内核)、外设、内存(SRAM)、总线等结构组成,数据经常要在内存与外设之间转移,或从外设A转移到外设B。例如:当CPU需要处理由ADC外设采集回来的数据时,CPU首先要把数据从ADC外设的寄存器读取到内存中(变量),然后进行运算处理,这是一般的处理方法。
  在转移数据的过程中会占用CPU十分宝贵的资源,所以我们希望CPU更多地被用在数据运算或响应中断之中,而数据转移的工作交由其他部件完成,是不是能够更好的利用CPU的资源呢?DMA正是为CPU分担了数据转移的工作。因为DMA的存在CPU才被解放出来,它可以在DMA转移数据的过程中同时进行数据运算、响应中断,大大提高效率。再次总结下DMA,DMA用来提供在外设和存储器之间或者存储器和存储器之间的高速数据传输。无须CPU的干预,通过DMA数据可以快速地移动。这就节省了CPU的资源来做其他操作。DMA的作用就是实现数据的直接传输,而去掉了传统数据传输需要CPU寄存器参与的环节。
  图1DMA数据传输示意图
  DMA数据传输主要涉及三种情况的数据传输,但本质上是一样的,都是从内存的某一区域传输到内存的另一区域(外设的数据寄存器本质上就是内存的一个存储单元)。三种情况的数据传输分别时:外设到内存、内存到外设、内存到内存。11。1。2GD32的DMA主要特征
  GD32F2系列的MCU一般有两个DMA控制器有14个通道(DMA0有7个通道,DMA1有7个通道),每个通道专门用来管理来自于一个或多个外设对存储器访问的请求。还有一个仲裁器来协调各个DMA请求的优先权。
  要使用DMA,需要确定一系列的控制参数,如外设数据的地址、内存地址、传输方向等,在开启DMA传输前还要先发出DMA请求。
  DMA的主要特点如下:
  14个独立的可配置的通道(请求):DMA0有7个通道,DMA1有7个通道
  每个通道都直接连接专用的硬件DMA请求,每个通道都同样支持软件触发。这些功能通过软件来配置。
  在同一个DMA模块上,多个请求间的优先权可以通过软件编程设置(共有四级:很高、高、中等和低),优先权设置相等时由硬件决定(请求0优先于请求1,依此类推)。
  独立数据源和目标数据区的传输宽度(字节、半字、全字),模拟打包和拆包的过程。源和目标地址必须按数据传输宽度对齐。
  支持循环的缓冲器管理
  每个通道都有3个事件标志(DMA半传输、DMA传输完成和DMA传输出错),这3个事件标志逻辑或成为一个单独的中断请求。
  支持外设到存储器,存储器到外设,存储器到存储器的数据传输
  闪存、SRAM、外设的SRAM、APB1、APB2和AHB外设均可作为访问的源和目标。
  可编程的数据传输数目:最大为6553511。1。3GD32的DMA请求映像
  从外设(TIMERx〔x0、1、2、3〕、ADC0、SPI0、SPII2S1、I2Cx〔x0、1〕和USARTx〔x0、1、2〕)产生的7个请求,通过逻辑或输入到DMA0控制器,这意味着同时只能有一个请求有效。参见下图的DMA0请求映像。
  图2DMA1请求映射
  外设的DMA请求,可以通过设置相应外设寄存器中的控制位,被独立地开启或关闭。
  表1各个通道的DMA0通道
  从外设(TIMERx〔4、5、6、7〕、ADC2、SPII2S2、UART3、DAC等7个请求,经逻辑或输入到DMA1控制器,这意味着同时只能有一个请求有效。参见下图的DMA1请求映像。
  图3DMA1请求映射
  外设的DMA请求,可以通过设置相应外设寄存器中的DMA控制位,被独立地开启或关闭。
  表2各个通道的DMA1通道
  当DMA控制器在同一时间接收到多个外设请求时,仲裁器将根据外设请求的优先级来决定响应哪一个外设请求。优先级包括软件优先级和硬件优先级,优先级规则如下:
  软件优先级:分为4级,低,中,高和极高。可以通过寄存器DMACHxCTL的PRIO位域来配置。
  硬件优先级:当通道具有相同的软件优先级时,编号低的通道优先级高。例:通道0和通道2配置为相同的软件优先级时,通道0的优先级高于通道2。11。1。4GD32的DMA工作过程
  下图为GD32的DMA的系统框图。
  图4GD32F2DMA框图
  我们可以看到GD32内核,存储器,外设及DMA的连接,这些硬件最终通过各种各样的线连接到总线矩阵中,硬件结构之间的数据转移都经过总线矩阵的协调,使各个外设和谐的使用总线来传输数据。
  如果不使用DMA,CPU传输数据还要以内核作为中转站,比如要将USART0的数据转移到SRAM中,这个过程是这样的:
  第一步:内核经过总线矩阵协调,从获取AHB存储的外设USART0的数据。
  第二步:内核再经过总线矩阵协调把数据存放到内存SRAM中。
  图5GD32F2不使用DMA工作工作过程
  如果使用DMA的话,数据传输需要以下步骤:
  1。DMA传输时外设对DMA控制器发出请求。DMA控制器收到请求,触发DMA工作。
  2。DMA控制器从AHB外设获取USART0的数据,存储到DMA通道中
  3。DMA控制器的DMA总线与总线矩阵协调,使用AHB把外设USART0的数据经由DMA通道存放到SRAM中,这个数据的传输过程中,完全不需要内核的参与,也就是不需要CPU的参与。
  图6GD32F2使用DMA工作工作过程
  在发生一个事件后,外设向DMA控制器发送一个请求信号。DMA控制器根据通道的优先权处理请求。当DMA控制器开始访问发出请求的外设时,DMA控制器立即发送给它一个应答信号。当从DMA控制器得到应答信号时,外设立即释放它的请求。一旦外设释放了这个请求,DMA控制器同时撤销应答信号。DMA传输结束,如果有更多的请求时,外设可以启动下一个周期。
  DMA控制器数据流都能够提供源和目标之间的单向传输链路。每个数据流配置后都可以执行以下事务:
  常规类型事务:存储器到外设、外设到存储器或存储器到存储器的传输。
  双缓冲区类型事务:使用存储器的两个存储器指针的双缓冲区传输(当DMA正在进行自至缓冲区的读写操作时,应用程序可以进行至自其它缓冲区的写读操作)。
  要传输的数据量(多达65535)可以编程,并与连接到外设AHB端口的外设(请求DMA传输)的源宽度相关。每个事务完成后,包含要传输的数据项总量的寄存器都会递减。
  总之,每次DMA传送由3个操作组成:
  1。从外设数据寄存器或者从当前外设存储器地址寄存器指示的存储器地址取数据,第一次传输时的开始地址是DMACHxPADDR或DMACHxMADDR寄存器指定的外设基地址或存储器单元;
  2。存数据到外设数据寄存器或者当前外设存储器地址寄存器指示的存储器地址,第一次传输时的开始地址是DMACHxPADDR或DMACHxMADDR寄存器指定的外设基地址或存储器单元;
  3。执行一次DMACHxCNT寄存器的递减操作,该寄存器包含未完成的操作数目。11。2DMA的寄存器描述
  第一个是DMA中断状态寄存器(DMAINTF)。该寄存器的各位描述如下图所示。我们如果开启了DMAINTF中这些中断,在达到条件后就会跳到中断服务函数里面去,即使没开启,我们也可以通过查询这些位来获得当前DMA传输的状态。这里我们常用的是FTFIFx,即通道DMA传输完成与否的标志。注意此寄存器为只读寄存器,所以在这些位被置位之后,只能通过其他的操作来清除。
  图7DMAINTF寄存器各位描述
  每个DMA通道都可以在DMA传输过半、传输完成和传输错误时产生中断。为应用的灵活性考虑,通过设置寄存器的不同位来打开这些中断。
  表3DMA中断请求
  使能开启,我们也可以通过查询这些位来获得当前DMA传输的状态。这里我们常用的是FTFIFx位,即数据流x的DMA传输完成与否标志。
  第二个是DMA中断标志清除寄存器(DMAINTC)。该寄存器的各位描述如下图所示。DMAIFCR的各位就是用来清除DMAISR的对应位的,通过写0清除。在DMAISR被置位后,我们必须通过向该位寄存器对应的位写入0来清除。
  图8DMAINTC寄存器各位描述
  第三个是DMA通道x配置寄存器(DMACCRx)(x17,下同)。该寄存器的我们在这里就不贴出来了,见《GD32参考手册》。该寄存器控制着DMA的很多相关信息,包括数据宽度、外设及存储器的宽度、通道优先级、增量模式、传输方向、中断允许、使能等都是通过该寄存器来设置的。所以DMACCRx是DMA传输的核心控制寄存器。
  第四个是DMA通道x传输数据量寄存器(DMACHxCTL)。这个寄存器控制DMA通道x的每次传输所要传输的数据量。其设置范围为065535。并且该寄存器的值会随着传输的进行而减少,当该寄存器的值为0的时候就代表此次数据传输已经全部发送完成了。所以可以通过这个寄存器的值来知道当前DMA传输的进度。
  第五个是DMA通道x的外设地址寄存器(DMACHxPADDR)。该寄存器用来存储GD32外设的地址,比如我们使用串口0,那么该寄存器必须写入0x40013804(其实就是USART00x04)。如果使用其他外设,就修改成相应外设的地址就行了。
  最后一个是DMA通道x的存储器地址寄存器(DMACHxMADDR),该寄存器和DMACHxPADDR差不多,是用来放存储器的地址的。比如我们使用SendBuf〔5200〕数组来做存储器,那么我们在DMACHxMADDR中写入SendBuff就可以了。11。3DMA实例11。3。1DMA发送数据
  本节我们要用到串口0的发送,属于DMA0的通道3,接下来我们就介绍库函数下DMA1通道3的配置步骤:
  1)使能DMA时钟rcuperiphclockenable(RCUDMA0);使能DMA时钟
  2)初始化DMA通道3参数
  前面讲解过,DMA通道配置参数种类比较繁多,包括内存地址,外设地址,传输数据长度,数据宽度,通道优先级等等。这些参数的配置在库函数中都是在函数DMAInit中完成,下面我们看看函数定义:voiddmainit(uint32tdmaperiph,dmachannelenumchannelx,dmaparameterstructinitstruct)
  函数的第一个参数是指定初始化的DMA,这里有两个选择,DMA0和DMA1;第二个参数是通道号,这个很容易理解,每个DMA有7个通道,这里使用的是通道3;第二个参数通过初始化结构体成员变量值来达到初始化的目的,下面我们来看看dmaparameterstruct结构体的定义:DMAinitializestructuretypedefstruct{uint32tperiphaddr;!peripheralbaseaddressuint32tperiphwidth;!transferdatasizeofperipheraluint32tmemoryaddr;!memorybaseaddressuint32tmemorywidth;!transferdatasizeofmemoryuint32tnumber;!channeltransfernumberuint32tpriority;!channelpriorityleveluint8tperiphinc;!peripheralincreasingmodeuint8tmemoryinc;!memoryincreasingmodeuint8tdirection;!channeldatatransferdirection}dmaparameterstruct;
  这个结构体的成员比较多,这里我们一一做个介绍。
  第一个参数periphaddr用来设置DMA传输的外设基地址,比如要进行串口DMA传输,那么外设基地址为串口接受发送数据存储器USART00x04的地址。
  第二个参数periphwidth用来设置外设的数据长度是为字节传输(8bits),半字传输(16bits)还是字传输(32bits),这里我们是8位字节传输,所以值设置为DMAPERIPHERALWIDTH8BIT。
  第三个参数memoryaddr为内存基地址,也就是我们存放DMA传输数据的内存地址。
  第四个参数memorywidth是用来设置内存的数据长度,和第二个参数意思接近,这里我们同样设置为字节传输DMAMEMORYWIDTH8BIT。
  第五个参数number设置一次传输数据量的大小,这个很容易理解。
  第六个参数priority是设置DMA通道的优先级,有低,中,高,超高四种模式,这个在前面讲解过,这里我们设置优先级别为中级,所以值为DMAPRIORITYMEDIUM。如果要开启多个通道,那么这个值就非常有意义。
  第七个参数periphinc设置传输数据的时候外设地址是不变还是递增。如果设置为递增,那么下一次传输的时候地址加1,这里因为我们是一直往固定外设地址USART00x04发送数据,所以地址不递增,值为DMAPERIPHINCREASEDISABLE;
  第八个参数memoryinc设置传输数据时候内存地址是否递增。这个参数和periphinc意思接近,只不过针对的是内存。这里我们的场景是将内存中连续存储单元的数据发送到串口,毫无疑问内存地址是需要递增的,所以值为DMAMEMORYINCREASEENABLE。
  第九个参数direction设置数据传输方向,决定是从外设读取数据到内存还送从内存读取数据发送到外设,也就是外设是源地还是目的地,这里我们设置为从内存读取数据发送到串口,所以外设自然就是目的地了,所以选择值为DMAMEMORYTOPERIPHERAL。
  这里我们给出上面场景的实例代码:定义一个DMA配置结构体dmaparameterstructdmainitstruct;使能DMA时钟rcuperiphclockenable(RCUDMA0);初始化DMA0通道3dmadeinit(DMA0,DMACH3);dmainitstruct。directionDMAMEMORYTOPERIPHERAL;存储器到外设方向dmainitstruct。memoryaddr(uint32t)UART0TXBUF;存储器基地址dmainitstruct。memoryincDMAMEMORYINCREASEENABLE;存储器地址自增dmainitstruct。memorywidthDMAMEMORYWIDTH8BIT;存储器位宽为8位dmainitstruct。numberUART0TXLEN;传输数据个数dmainitstruct。periphaddr((uint32t)(USART00X04));外设基地址,即USART数据寄存器地址dmainitstruct。periphincDMAPERIPHINCREASEDISABLE;外设地址固定不变dmainitstruct。periphwidthDMAPERIPHERALWIDTH8BIT;外设数据位宽为8位dmainitstruct。priorityDMAPRIORITYMEDIUM;软件优先级为极高dmainit(DMA0,DMACH3,dmainitstruct);
  3)DMA模式配置
  我们要从内存中采集64个字节发送到串口,如果设置为重复采集,那么它会在64个字节采集完成之后继续从内存的第一个地址采集,如此循环。这里我们设置为一次连续采集完成之后不循环。因此需要关闭循环发送。
  在我们下面的实验中,如果设置此参数为循环采集,那么你会看到串口不停的打印数据,不会中断,大家在实验中可以修改这个参数测试一下。循环模式可用于处理循环缓冲区和连续数据流(例如ADC扫描模式)。可以使用DMASxCR寄存器中的CIRC位使能此特性。当激活循环模式时,要传输的数据项的数目在数据流配置阶段自动用设置的初始值进行加载,并继续响应DMA请求。
  还需设置是否是存储器到存储器模式传输,这里设置为不使用存储器到存储器模式。DMA循环模式配置,不使用循环模式dmacirculationdisable(DMA0,DMACH3);DMA存储器到存储器模式模式配置,不使用存储器到存储器模式dmamemorytomemorydisable(DMA0,DMACH3);
  4)使能DMA0通道3,启动传输。
  接着就要使能DMA传输通道。dmachannelenable(DMA0,DMACH3);
  5)使能串口DMA发送
  进行DMA配置之后,我们就要开启串口的DMA发送功能,使用的函数是:
  usartdmaenable(USART0,USARTDMATRANSMIT);
  如果是要使能串口DMA接受,那么第二个参数修改为USARTDMARECEIVE即可。
  这样,我们就可以启动一次USART0的DMA传输了。
  6)查询DMA传输状态
  在DMA传输过程中,我们要查询DMA传输通道的状态,使用的函数是:FlagStatusdmaflagget(uint32tdmaperiph,dmachannelenumchannelx,uint32tflag)
  比如我们要查询DMA通道3传输是否完成,方法是:dmaflagget(DMA0,DMACH3,DMAFLAGFTF);
  这里还有一个比较重要的函数就是获取当前剩余数据量大小的函数:uint32tdmatransfernumberget(uint32tdmaperiph,dmachannelenumchannelx)
  比如我们要获取DMA通道3还有多少个数据没有传输,方法是:dmatransfernumberget(DMA0,DMACH3);
  最后看看UART0的DMA整体配置。briefUSART0TXDMA配置,内存到外设(USART00x04)paramNoneretvalNonevoidusart0dmainit(void){定义一个DMA配置结构体dmaparameterstructdmainitstruct;使能DMA时钟rcuperiphclockenable(RCUDMA0);初始化DMA0通道3dmadeinit(DMA0,DMACH3);dmainitstruct。directionDMAMEMORYTOPERIPHERAL;存储器到外设方向dmainitstruct。memoryaddr(uint32t)SendBuff;存储器基地址dmainitstruct。memoryincDMAMEMORYINCREASEENABLE;存储器地址自增dmainitstruct。memorywidthDMAMEMORYWIDTH8BIT;存储器位宽为8位dmainitstruct。numberBUFFSIZE;传输数据个数dmainitstruct。periphaddr((uint32t)(USART00X04));外设基地址,即USART数据寄存器地址dmainitstruct。periphincDMAPERIPHINCREASEDISABLE;外设地址固定不变dmainitstruct。periphwidthDMAPERIPHERALWIDTH8BIT;外设数据位宽为8位dmainitstruct。priorityDMAPRIORITYMEDIUM;软件优先级为极高dmainit(DMA0,DMACH3,dmainitstruct);DMA循环模式配置,不使用循环模式dmacirculationdisable(DMA0,DMACH3);DMA存储器到存储器模式模式配置,不使用存储器到存储器模式dmamemorytomemorydisable(DMA0,DMACH3);DMA0通道3中断优先级设置并使能nvicirqenable(DMA0Channel3IRQn,0,0);使能DMA0通道3传输完成、传输错误中断dmainterruptenable(DMA0,DMACH3,DMAINTFTFDMAINTERR);使能DMA0通道3dmachannelenable(DMA0,DMACH3);}
  主函数如下所示:briefmainfunctionparam〔in〕noneparam〔out〕noneretvalnoneintmain(void){inti;填充将要发送的数据for(i0;iBUFFSIZE;i){SendBuff〔i〕Y;}systickinitsysTickinit();LED1initledinit(LED1);usartinit1152008N1cominit(COM1,115200);DMAconfigusart0dmainit();printf(USART0DMATestr);USARTDMA发送使能usartdmaenable(USART0,USARTDMATRANSMIT);while(1){ledtoggle(LED1);delayms(1000);}}
  主函数很简单,初始化串口,DMA后,向DMA发出请求即可进行数据传输了,这时CPU就可以干其他事情了。
  将程序编译好后下载到板子中,通过串口助手可以看到在接收区有Y不断的打印输出,同时LED1不停闪烁。
  图9实验现象
  【注】在本例中串口是DMA操作的,而LED的闪烁是CPU控制,请读者朋友注意。11。3。2DMA中断接收数据
  前面讲解了DMA的接收,接下来讲解DMA的接收。接收和发送差不多,对于USART0,DMA的接收通道为DMACH4,因此USART0DMA的接收和发送配置如下所示。briefUSART0TXRXDMA配置paramNoneretvalNonevoidusart0dmainit(void){定义一个DMA配置结构体dmaparameterstructdmainitstruct;使能DMA时钟rcuperiphclockenable(RCUDMA0);初始化DMA0通道4dmadeinit(DMA0,DMACH4);dmainitstruct。directionDMAPERIPHERALTOMEMORY;外设到存储器方向dmainitstruct。memoryaddr(uint32t)RecvBuff;存储器基地址dmainitstruct。memoryincDMAMEMORYINCREASEENABLE;存储器地址自增dmainitstruct。memorywidthDMAMEMORYWIDTH8BIT;存储器位宽为8位dmainitstruct。numberBUFFSIZE;传输数据个数dmainitstruct。periphaddr((uint32t)(USART00X04));外设基地址,即USART数据寄存器地址dmainitstruct。periphincDMAPERIPHINCREASEDISABLE;外设地址固定不变dmainitstruct。periphwidthDMAPERIPHERALWIDTH8BIT;外设数据位宽为8位dmainitstruct。priorityDMAPRIORITYMEDIUM;软件优先级为极高dmainit(DMA0,DMACH4,dmainitstruct);DMA循环模式配置,不使用循环模式dmacirculationdisable(DMA0,DMACH4);DMA存储器到存储器模式模式配置,不使用存储器到存储器模式dmamemorytomemorydisable(DMA0,DMACH4);初始化DMA0通道3dmadeinit(DMA0,DMACH3);dmainitstruct。directionDMAMEMORYTOPERIPHERAL;存储器到外设方向dmainitstruct。memoryaddr(uint32t)SendBuff;存储器基地址dmainitstruct。number0;传输数据个数dmainit(DMA0,DMACH3,dmainitstruct);DMA0通道4中断优先级设置并使能nvicirqenable(DMA0Channel4IRQn,0,0);使能DMA0通道4传输完成、传输错误中断dmainterruptenable(DMA0,DMACH4,DMAINTFTFDMAINTERR);使能DMA0通道4dmachannelenable(DMA0,DMACH4);使能DMA0通道3dmachannelenable(DMA0,DMACH3);}
  上述配置中在DMA的发送的基础上新增了DMA中断接收,因此需要增加DMA接收的NVIC,其配置如下。DMA0通道4中断优先级设置并使能nvicirqenable(DMA0Channel4IRQn,0,0);使能DMA0通道4传输完成、传输错误中断dmainterruptenable(DMA0,DMACH4,DMAINTFTFDMAINTERR);
  值得注意的,这里需要打开DMA的接收中断,对应的寄存器是DMACHxCTL,前面已经讲过了。
  最后,还需要编写USART0的DMA中断接收函数。!briefthisfunctionhandlesDMA0Channel4exceptionparam〔in〕noneparam〔out〕noneretvalnonevoidDMA0Channel4IRQHandler(void){uint8tRecvLen;if(dmainterruptflagget(DMA0,DMACH4,DMAINTFLAGFTF)!RESET){dmainterruptflagclear(DMA0,DMACH4,DMAINTFLAGFTF);清除传输完成中断标志位总的buf长度减去剩余buf长度,得到接收到数据的长度RecvLensizeof(RecvBuff)dmatransfernumberget(DMA0,DMACH4);usart0dmarxclear();清空DMA接收通道usart0sendarray(RecvBuff,RecvLen);使用DMA发送数据memset(RecvBuff,,sizeof(RecvBuff));清空接收缓冲区}}
  中断接收中封装了两个函数,当USART0DMA接收中断到了后,将接收的数据放入缓存区,然后需要清除DMA的接收通道,具体函数如下。brief清除DMA的传输数量寄存器paramNoneretvalNonevoidusart0dmarxclear(void){关闭DMA0通道4dmachanneldisable(DMA0,DMACH4);重新写入要传输的数据数量dmatransfernumberconfig(DMA0,DMACH4,sizeof(RecvBuff));使能DMA0通道4dmachannelenable(DMA0,DMACH4);}
  然后就是将接收的数据通过USART0DMA发送出去,其函数如下。brief串口0DMA发送paramuint8tarr,uint8tlenretvalNonevoidusart0sendarray(uint8tarr,uint8tlen){if(len0)return;uint8tsendLenlensizeof(SendBuff)?sizeof(SendBuff):len;while(dmatransfernumberget(DMA0,DMACH3));检查DMA发送通道内是否还有数据if(arr){memcpy(SendBuff,arr,sendLen);}开启UARTTXDMAdmachanneldisable(DMA0,DMACH3);dmatransfernumberconfig(DMA0,DMACH3,sendLen);重新写入要传输的数据数量dmachannelenable(DMA0,DMACH3);启动DMA发送}
  接下来看看主函数的代码。briefmainfunctionparam〔in〕noneparam〔out〕noneretvalnoneintmain(void){systickinitsysTickinit();ledinitledinit(LED1);usartinit1152008N1cominit(COM1,115200);DMAconfigusart0dmainit();printf(USART0DMATestr);USARTDMA发送使能usartdmaenable(USART0,USARTDMATRANSMIT);USARTDMA接收使能usartdmaenable(USART0,USARTDMARECEIVE);while(1){ledtoggle(LED1);delayms(1000);}}
  主函数主要增加了串口DMA接收请求,其他的和上一个实例是一样的。
  最后编译下载固件,打开串口助手,这里发送一些数据,效果如下所示。
  图10实验现象

意甲历史半程积分排名前10尤文5席国米3席,本赛季那不勒斯第直播吧1月25日讯本赛季的意甲联赛已战至半程,那不勒斯以50分遥遥领先,德国转会市场统计了意甲改制以来(20042005赛季)半程积分最多的球队,并列出榜单,前10位尤文占5席……口碑要被并进高德,这是要和美团抖音掰手腕?不知道大家还记不记得,一个月之前,传闻阿里系迎来大动作:阿里本地生活业务并入高德。结果没多久,有人就出来辟谣,抓住了一个滑稽的造谣ID,顺便阴阳了一波美团背后捏造消息、编……五菱为什么不能上柳机量产的2。0发动机?五菱柳机2。0LNA没有应用的价值问:为什么五菱宝骏汽车不使用柳机2。03。0LNA(自然吸气)或增压发动机?现在的五菱和宝骏汽车主要使用的是L2BLAR1。……蔚来去年亏了40亿,吉利则赚了43亿,但吉利市值还不到蔚来的蔚来跟吉利两大汽车巨头都公布了自己的2021年的财报,不过魔幻的一幕出现了,蔚来去年亏了40亿,吉利赚了43亿,不过目前蔚来的市值是2700多亿港币,而吉利的市值才1100多亿……又是广西选手!体操世锦赛,广西大包揽,这壮举以后估计很难了2021赛季体操世锦赛落下帷幕,中国体操队在本届世锦赛中表现出色,取得了5枚金牌1枚银牌2枚铜牌的好成绩,是所有参赛国家中成绩最好的。值得注意的是,这也是中国体操队在世锦赛中近……50岁后坚持跑步,究竟是养生还是伤身?跑不跑我认为应因人而异,身体健康,适合跑步的人也可以进行慢跑锻炼身体。本人50岁时每天还坚持晨跑,直到近两年(现马上退休)开始改健走锻炼身体,主要怕到了年龄在跑伤腿。所以怎么锻……宝马5系跟奥迪A6怎么选择?优缺点是什么?我开了宝马530,又开了奥迪A6L,经过一段时间的相处,五味杂陈,终于知道了奥迪为什么越来越不受待见的原因了,奉劝大家选豪华品牌前要三思而行,只有分清它们的优缺点,才能买车不后……别克英朗三缸机和四缸机选哪个好?感谢邀请回答。英朗车在市面上随处可见,已经到了烂大街的地步,主要得益于这款车型的平民化,高配置,今天我们来聊一下目前市面上的英朗车动力搭载总成问题。时尚大气首……网约车到底应不应该存在?网约车只能网约,能不能接到单完全看平台的脸色;出租车既能网约,又能扬招,每个城市还有电话叫车,出租车包含网约车,所以网约车根本就没有存在的必要。网约车是在给城市添堵的……比亚迪汉被大飙车贬低,真实情况到底如何?确实有主观去贬低比亚迪汉,虽然有些说的是事实,一部车的好坏不是拆一两个件就能评判的,更不是用卡尺就能量出来的,很多人认为20多万的车用的是铁质三连杆,拿其他连杆多的车去对比,再……2019年2月份美系轿车销量一览,英朗持续热销,福睿斯跌入谷2019年2月份美系轿车销量排行榜出炉啦,别克英朗以22756辆的销售成绩排在第一位,去年英朗自换代之后,销量曾一度跌出第一梯队,最主要的原因就是其全系搭载的三缸发动机。好在随……救命!现在的手机壳都这么卷了吗?Hi欢迎关注我们!爱美的女孩,谁不爱对着镜子玩自拍呢?比如智秀就时不时来几张,晒衣服、秀发型,展现美的同时还给我们种草了一堆手机壳。接下来相同大家介绍一……
吃红薯需要注意什么?对于那些比较注重健康,比较注重养生的人来说,平时都是比较喜欢吃粗粮的,而且在所有的粗粮当中,红薯可以说是受到了很多人的喜爱。红薯的营养价值非常的高,吃法也非常的简单,可以……盘点美籍韩裔女星金允珍为艺术献身的几部R级电影,附时间线金允珍,1973年出生,美国长大的韩籍演员。1996年出道,期间演过不少作品一直没有起色,直到2002年,先后出演了《迷失》(中饰演的韩国太太、大佬千金白善华)、《密爱》(尽职……二王一马的故事王励勤让球痛失大满贯,王皓无冕之王近些年随着网络信息的高速发达,乒乓球项目在中国被越来越多的网友们所关注,如现役国家队的一些国手樊振东、马龙、刘诗雯、王曼昱等等,都在网络上有着很高的热度。而且很多网友不仅……华为将发布新款折叠屏手机MateXs2,折叠方案引关注新京报贝壳财经讯(记者许诺)4月22日上午,华为终端官方微博宣布将于4月28日举办华为折叠旗舰及全场景新品发布会,发布新款折叠旗舰华为MateXs2。华为常务董事、终端BGCE……红磨坊的高踢腿舞再也看不到内裤了,那还有什么看头?外行人看情色,文化人看艺术红磨坊,每个男人都想去的地方。而你,想不想去看点更有意思的?红磨坊得名于它长得像个磨坊,巨大的风车是它的标志性建筑。抢眼的红色……李梦喜欢每个月的一号,似乎一切美好重新开启09月01日讯女篮球员李梦更新微博表达对刚刚到来的9月的开心之情:喜欢每个月的一号,似乎一切美好重新开启。李梦在微博上这样写道:喜欢每个月的一号,似乎一切美好都可重新开启……输球后炮轰对手,将之形容为业余球员,奥斯塔彭科这是怎么了?球员输球后,通常都会盛赞对手发挥得比自己好,配得上赢取的胜利。可是奥斯塔彭科温网出局后,却不走寻常路,选择了背道而驰,顿时掀起了漫天的非议,将她推向了舆论的风口浪尖。这件……3。8秒超跑名爵木兰纯电动车来了,打比亚迪海豚用力过猛还偏了头条创作挑战赛一,比亚迪海豚的销量凭什么过万不被看好的比亚迪海豚,销量居然还逐月上升都过万了。这其中,比亚迪宣传的刀片电池,以及3。0全新平……从文旅网红到长红,翠亨新区还要走多远?村里的露营产业发展起来之后,游客比以前明显多了!指着不远处太空舱样式的露营基地,中山市南朗街道冲口村党总支部书记梁赐明,兴奋地谈起村子一年多的变化。游人如织的冲口村,为翠……排列五22057期规律走势图万位记录3月8号开奖个人记录。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。……国庆假期北京持续激发消费活力新华社北京10月6日电(记者吉宁杨淑君)今年国庆假期和重阳佳节交汇,北京假期经济消费活力正被持续激发。长假期间,不少人选择走进剧场共赴戏剧之旅。《杜甫》《长椅》北京人民艺……快本五人解散已成定局,其中缘由为哪般?前段时间湖南卫视忠实粉丝的妈妈就跟我说,快乐大本营突然就停播了,再也没在周六见。上网一查才发现确有其事,根据湖南卫视官方回应是说:《快乐大本营》升级改版、更新换代,集中力……
友情链接:易事利快生活快传网聚热点七猫云快好知快百科中准网快好找文好找中准网快软网