专栏电商日志财经减肥爱情
投稿投诉
爱情常识
搭配分娩
减肥两性
孕期塑形
财经教案
论文美文
日志体育
养生学堂
电商科学
头戴业界
专栏星座
用品音乐

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实验现象

三体中,恒纪元能预测吗在刘慈欣的三体小说中,三体人所生活的行星位于由三颗恒星组成的三体系统之中。当三颗恒星相互远离时,三体行星就会处于漫长的黑夜和寒冷之中,生命会消亡,文明会覆灭当两颗或者三颗恒星靠近时科幻故事火星之旅李明是中国首批参加火星探测任务的宇航员之一,他和其他五名队友乘坐天问号飞船,在经过了八个月的漫长旅程后,终于抵达了火星轨道。他们将在轨道上停留一个月,进行各种科学实验和观测,然后再世界首次!南京造仪器在空间站成功获取航天员皮肤三维图像来源交汇点新闻客户端交汇点讯记者从南京江北新区获悉,近日,神舟十五号航天员乘组使用双光子显微镜,成功获取航天员皮肤表皮及真皮浅层的三维图像。这是目前已知的世界首次,而这款自研仪器来6。2公里!中国卫星两次靠近美国卫星,美媒这颗卫星有替身知名太空新闻网站Space。com近日发表了一篇措辞严厉的文章,称1颗名为TJS3的中国卫星曾两次近距离接近美国卫星,疑似从事监视任务。TJS3卫星为通信技术试验卫星3号,按照文章发人深省的乌托邦实验,560天小白鼠走向灭亡?究竟是宇宙规律吗乌托邦天堂实验自古以来人类都向往天堂一般的生活,物质丰裕,衣来伸手,饭来张口,没有敌人,没有对手,每天生活在富足中,不需要争抢,也不需要工作,更不用为钱而发愁。但是人类至今也没能全阴阳五行运动是宇宙的构成和运行机制宇宙是由阴阳两种状态的能量构成的,既以波的形式存在的能量也可以称之为阳能量,和以原子的形式存在的能量也可以称之为阴能量。这两种能量构成了宇宙。阴阳两种状态的能量还在不停的转换,形成科学家将铟原子穿入纳米纤维束以创造灵活的纳米线铟在纳米结构中的插接有望应用于纳米电路。来自东京都立大学的研究人员已经成功地将金属铟原子穿入过渡金属到纳米纤维束的单个纤维之间。通过将纤维束浸泡在铟气中,成排的原子能够在纤维之间穿中印等8国面临世纪难题,青藏高原冰融化剧增,印巴已经遭殃了综述全球变暖已经成为一个老生常谈的问题,虽然一直被人们所关注,但此问题并没有得到改善,反而越来越严峻,直到今天,地球升温的速度已经突破了历史记录,同时佐证了全球变暖是一个不争的事实显卡1050ti现在都能玩什么大型游戏?根据官方给出的数据,我们可以看到GTX1050Ti相较于GTX1050来说,性能上并没有多少的提升,主要提升的是功耗和效率。但是GTX1050Ti相较于GTX10603G来说性能差大逆转!世界冠军挽救5局点!梁靖崑绝地翻盘夺冠,17岁小将亚军北京时间2023年3月5日晚间,WTT球星挑战赛果阿站迎来收官之日,刚刚,我国选手王艺迪40战胜中华台北队名将郑怡静女单夺冠,王艺迪替补参战这场比赛,顶住压力拿到这个含金量不轻的冠球星赛大结局!5项冠军出炉,国乒拿下2冠,韩国队2冠,日本队1冠乒乓球友您好,我是乒谈。北京时间3月5日晚间,WTT印度站球星挑战赛圆满落下了帷幕,5项冠军已经全部产生。01混双冠军(韩国)混双项目,爆冷不少,头号种子和2号种子都无缘进入决赛,
年轻的时候比谁有钱,老了就比谁更健康(一)前段时间和几位亲近的叔叔阿姨聊了聊天,发现现在中老年人其实都是非常注重健康的,他们说年轻的时候就比谁更有钱,到了老了,还能比什么呢?不就是比谁和你健康嘛,我觉得他们说的特别对。只是本月起从张家口乘飞机出行可抵达13座城市随着张家口邯郸三亚航线正式通航,本月起,从张家口机场乘飞机出行可抵达沈阳大连石家庄邯郸天津上海杭州厦门深圳广州重庆西安三亚13座城市,周计划往返航班量达150架次,市民出行将更加便长沙君悦酒店荣获金树叶级绿色旅游饭店荣誉近日,长沙君悦酒店荣获由湖南省旅游饭店星级评定委员会评定的金树叶级绿色旅游饭店荣誉。长沙君悦酒店俯瞰湘江胜景,致力于打造成为湖南省会乃至华中地区精致美食潮流生活娱乐休闲的时尚坐标。米家新出恒温电水壶2Pro,究竟值不值得入手?斥资249元实测一波头条创作挑战赛Hi,我是山贼95270!承蒙大家喜欢,越来越多的人问我各类小物件值不值得买?说实话,每次看到有人说自从关注了你,反而更省钱了,因为不会再像以前那样乱买了。我就特别开警惕,今年春节将迎来报复性旅游三年的疫情,人们在不断的封控解封静默中度过,积累了多少的愤闷与不平,委屈与心酸。疫情放开后人们又经历了阳了的病痛与煎熬,有不少人又经历了失去亲人的痛苦。感染高峰一经过去,阳了后的人你都去过哪些城市旅游?2022已经过去,回顾去年的新年愿望,我想去旅游这几个大字依然躺在愿望单里,可惜它没能实现。去过北京。故宫,颐和园,长城,天安门都去走了走。印象最深刻的是升旗仪式,有机会一定要去看2023年国际消费电子展博世传感器成就更安全更便捷的生活体验为互联和气候行动打造科技博世集团董事会成员TanjaRckert表示传感器不仅可以改善人们的生活质量,还可以减少我们日常使用智能设备时对环境所造成的影响。移动出行以传感器为基础的创国际乒联官宣,马龙王楚钦新年惊喜,张本智和生涯重创今天让我们共同关注一下中国国乒的最新状况,相信感兴趣的球迷们都知道,国乒内部完成了人员安排工作,在他们的带领下,正式的出征,参加德班的世乒赛的选拔。此场比赛也引起了众多网友们热切的夏斌对扩内需纲要的几点认知来源北大国发院题记2022年12月18日,北大国发院隆重举办第七届国家发展论坛,中石油国家高端智库研究中心联合举办。本文根据国务院参事室原参事当代经济学基金会名誉理事长夏斌的演讲内中小微企业信心怎么样?这份报告这么说中小微企业是国家经济的毛细血管,也是实体经济的重要组成部分。中小微企业既为广大人民群众提供了产品和服务,也是吸纳和调节就业的主力军,对经济发展民生改善社会稳定有着突出贡献。为了深入江西省数字经济发展指数发布来源人民网江西频道人民网南昌12月31日电(记者秦海峰)2022年12月31日,由中国工业经济学会互联网经济与产业创新发展专业委员会和江西省首批重点高端智库现代产业发展研究院等联合
友情链接:快好找快生活快百科快传网中准网文好找聚热点快软网