串口DMA方式发送&接收

2020-07-04来源: eefocus关键字:串口  DMA方式  发送&接收

串口DMA方式收发

笔者使用的是STM32F407VET6,共包含6路串口,页尾处程序已将全部串口的DMA收发配置完成,本文仅以串口1为例进行讲解。(查看代码可直接跳至第二节或页尾处下载)


1 STM32F4 DMA  简介

DMA,全称为:Direct Memory Access,即直接存储器访问。DMA 传输方式无需 CPU 直接控制传输,也没有中断处理方式那样保留现场和恢复现场的过程,通过硬件为 RAM 与 I/O 设备开辟一条直接传送数据的通路,能使 CPU 的效率大为提高。


STM32F4 最多有 2 个 DMA 控制器(DMA1 和 DMA2),共 16 个数据流(每个控制器 8 个),每一个 DMA 控制器都用于管理一个或多个外设的存储器访问请求。每个数据流总共可以有多达 8个通道(或称请求)。每个数据流通道都有一个仲裁器,用于处理 DMA 请求间的优先级。


它可以处理一下事务:


外设到储存器的传输

储存器到外设的传输

储存器到储存器的传输

注意:DMA1 控制器 AHB 外设端口与 DMA2 控制器的情况不同,不连接到总线矩阵,因此,仅 DMA2 数据流能够执行存储器到

存储器的传输。


其中,数据流的多通道选择,是通过 DMA_SxCR 寄存器控制的,如图1所示:

图1 通道选择


上图可以看出,DMA_SxCR 控制数据流到底使用哪一个通道,每个数据流有 8 个通道可供选择,但每次只能选择其中一个通道进行 DMA 传输,DMA2 的各数据流通道映射表,如表 1 所示


表1 DMA2数据流映射表

上表就列出了 DMA2 所有可能的选择情况,来总共 64 种组合,比如本章我们要实现串口1的 DMA 发送,即USART1_TX,就必须选择 DMA2 的数据流 7,通道 4,来进行 DMA 传输。这里注意一下,有的外设(比如 USART1_RX)可能有多个通道可以选择,随意选择一个就可以。


重要寄存器简介

(1) DMA 中断状态寄存器


该寄存器总共有 2 个:DMA_LISR 和 DMA_HISR,每个寄存器管理 4 数据流(总共 8 个),DMA_LISR 寄存器用于管理数据流 0~3,而 DMA_HISR 用于管理数据流 4~7。如果开启了 DMA_LISR 中这些位对应的中断,则在达到条件后就会跳到中断服务函数里面去,即使没开启,也可以通过查询这些位来获得当前 DMA 传输的状态。这里常用的是 TCIFx位,即数据流 x 的 DMA 传输完成与否标志。


注意:此寄存器为只读寄存器,所以在这些位被置位之后,只能通过【中断标志清除寄存器】来清除。


(2)DMA 中断标志清除寄存器


该寄存器同样有 2 个:DMA_LIFCR 和 DMA_HIFCR,同样是每个寄存器控制 4 个数据流。该寄存器为只写寄存器,其各位就是用来清除 【中断状态寄存器】的对应位的,通过写 1 清除。


(3) DMA 数据流 x 配置寄存器(DMA_SxCR)


该寄存器控制着 DMA 的很多相关信息,包括数据宽度、外设及存储器的宽度、优先级、增量模式、传输方向、中断允许、使能等都是通过该寄存器来设置的。所以 DMA_ SxCR 是 DMA 传输的核心控制寄存器。


(4)DMA 数据流 x 数据项数寄存器(DMA_SxNDTR)


这个寄存器控制 DMA 数据流 x 的每次传输所要传输的数据量。其设置范围为 0~65535。并且该寄存器的值会随着传输的进行而减少,当该寄存器的值为 0 的时候就代表此次数据传输已经全部发送完成了。所以可以通过这个寄存器的值来知道当前DMA 传输的进度。


注意:这里是数据项数目,而不是指的字节数。比如设置数据位宽为 16 位,那么传输一次(一个项)就是 2 个字节


(5)DMA 数据流 x 的外设地址寄存器(DMA_SxPAR)


该寄存器用来存储 STM32F4 外设的地址,比如使用串口 1,那么该寄存器必须写入 0x40011004(其实就是&USART1_DR)。


(6) DMA 数据流 x 的存储器地址寄存器


由于 STM32F4 的 DMA 支持双缓存,所以存储器地址寄存器有两个:DMA_SxM0AR 和 DMA_SxM1AR,其中 DMA_SxM1AR 仅在双缓冲模式下,才有效。比如使用 USART1_TX_BUF[USART_LEN] 数组来做存储器,那么在DMA_SxM0AR 中写入 &USART1_TX_BUF 就可以了。


2 收发配置

2.1串口配置(使能DMA收发)

重点:使能串口1的接收、发送和串口1的DMA接收、发送并使能串口1的空闲中断


/*------------------------------------------------

* 函数名:void Init_USART1(u32 pclk2,u32 bound)

* 功  能:初始化IO 串口1

* 参  数:pclk2: PCLK2时钟频率(Mhz)

      bound: 波特率 

* 返回值: 无

------------------------------------------------*/

void Init_USART1(u32 pclk2,u32 bound)

{   

float temp;

u16 mantissa;

u16 fraction;    

temp=(float)(pclk2*1000000)/(bound*16);//得到USARTDIV@OVER8=0

mantissa=temp; //得到整数部分

fraction=(temp-mantissa)*16; //得到小数部分@OVER8=0 

        mantissa<<=4;

mantissa+=fraction; 

RCC->AHB1ENR|=1<<0;    //使能PORTA口时钟  

RCC->APB2ENR|=1<<4;  //使能串口1时钟 

GPIO_Set(GPIOA,PIN9|PIN10,GPIO_MODE_AF,GPIO_OTYPE_PP,GPIO_SPEED_50M,GPIO_PUPD_PU);//PA9,PA10,复用功能,上拉输出

  GPIO_AF_Set(GPIOA,9,7); //PA9,AF7

GPIO_AF_Set(GPIOA,10,7);//PA10,AF7     

//波特率设置

  USART1->BRR=mantissa; //波特率设置  

USART1->CR1&=~(1<<15); //设置OVER8=0 

USART1->CR1|=1<<3;  //串口发送使能 

USART1->CR3|=1<<7;      //使能串口1的DMA发送

#if EN_USART1_RX   //如果使能了接收

USART1->CR1|=1<<2;  //串口接收使能

USART1->CR3|=1<<6;      //使能串口1的DMA接收  

USART1->CR1|=1<<4;    //使能空闲中断    

MY_NVIC_Init(3,3,USART1_IRQn,2);//组2,最低优先级 

#endif

USART1->CR1|=1<<13;  //串口使能

}


2.2两个变量

发送和接收的数据都将以如下两个变量为指定储存器。


#define USART_LEN  50  //定义最大接收字节数 50

u8 USART1_TX_BUF[USART_LEN];

u8 USART1_RX_BUF[USART_LEN];


2.3 DMA配置

(1)使能DMA2时钟,并等待数据流可配置 。


(2)设置外设地址


(3)设置储存器地址


(4)设置传输数据量


(5)设置数据流7的配置信息


(6)开启数据流7的传输完成中断


/*------------------------------------------------

* 函数名:void MYDMA_Config(DMA_Stream_TypeDef *DMA_Streamx,u8 chx,u32 par,u32 mar,u16 ndtr,u8 dir)

* 功  能:配置DMA

* 参  数:DMA_Streamx: DMA数据流(DMA1_Stream0~7/DMA2_Stream0~7)

     chx: DMA通道选择(范围:0~7)

     par: 外设地址

mar: 存储器地址

ndtr: 数据传输量

dir: 数据传输方向(DMA_DIR_PeripheralToMemory / DMA_DIR_MemoryToPeripheral / DMA_DIR_MemoryToMemory)

* 返回值: 无

------------------------------------------------*/

void MYDMA_Config(DMA_Stream_TypeDef *DMA_Streamx,u8 chx,u32 par,u32 mar,u16 ndtr,u8 dir)

DMA_TypeDef *DMAx;

u8 streamx;

if((u32)DMA_Streamx>(u32)DMA2)//得到当前stream是属于DMA2还是DMA1

{

DMAx=DMA2;

RCC->AHB1ENR|=1<<22;//DMA2时钟使能 

}else 

{

DMAx=DMA1; 

  RCC->AHB1ENR|=1<<21;//DMA1时钟使能 

}

while(DMA_Streamx->CR&0X01);//等待DMA可配置 

streamx=(((u32)DMA_Streamx-(u32)DMAx)-0X10)/0X18; //得到stream通道号

  if(streamx>=6)DMAx->HIFCR|=0X3D<<(6*(streamx-6)+16); //清空之前该stream上的所有中断标志

else if(streamx>=4)DMAx->HIFCR|=0X3D<<6*(streamx-4);    //清空之前该stream上的所有中断标志

else if(streamx>=2)DMAx->LIFCR|=0X3D<<(6*(streamx-2)+16);//清空之前该stream上的所有中断标志

else DMAx->LIFCR|=0X3D<<6*streamx; //清空之前该stream上的所有中断标志

DMA_Streamx->PAR=par; //DMA外设地址

DMA_Streamx->M0AR=mar; //DMA存储器0地址

DMA_Streamx->NDTR=ndtr; //n个数据项

DMA_Streamx->CR=0; //先全部复位CR寄存器值 

 

switch(dir)

{

case DMA_DIR_PeripheralToMemory: //外设到存储器模式

DMA_Streamx->CR&=~(1<<6);

DMA_Streamx->CR&=~(1<<7);

break;

case DMA_DIR_MemoryToPeripheral: 

DMA_Streamx->CR|=1<<6;

DMA_Streamx->CR&=~(1<<7);

break;

case DMA_DIR_MemoryToMemory: 

DMA_Streamx->CR&=~(1<<6);

DMA_Streamx->CR|=1<<7;

break;

default:break;

}

DMA_Streamx->CR|=0<<8; //非循环模式(即使用普通模式)

DMA_Streamx->CR|=0<<9; //外设非增量模式

DMA_Streamx->CR|=1<<10; //存储器增量模式

DMA_Streamx->CR|=0<<11; //外设数据长度:8位

DMA_Streamx->CR|=0<<13; //存储器数据长度:8位

DMA_Streamx->CR|=1<<16; //中等优先级

DMA_Streamx->CR|=0<<21; //外设突发单次传输

DMA_Streamx->CR|=0<<23; //存储器突发单次传输

DMA_Streamx->CR|=(u32)chx<<25;//通道选择

//DMA_Streamx->FCR=0X21; //FIFO控制寄存器

 

        DMA2_Stream7->CR|=1<<4; //使能传输完成中断

        MY_NVIC_Init(2,1,DMA2_Stream7_IRQn,2);

}


2.4 设置MDA状态标志

注意:如果连续运行两个发送函数,如下,则可能在第一个还未发送完成时就会直接执行第二次发送。


myDMAprintf(USART1,"usart = %dtch = %frn",1,1.567);

myDMAprintf(USART1,"usart = %dtch = %frn",1,1.567);

其运行效果如图1所示,第一次仅发送了"us"即被第二次发送覆盖了。

运行效果

图1 运行效果


故需设置相应的标志位,对每次发送的状态进行标记,若正在进行传输,则等待,实现如下:


typedef enum 

[1] [2]
关键字:串口  DMA方式  发送&接收 编辑:什么鱼 引用地址:http://news.eeworld.com.cn/mcu/ic502129.html 本网站转载的所有的文章、图片、音频视频文件等资料的版权归版权所有人所有,本站采用的非本站原创文章及图片等内容无法一一联系确认版权者。如果本网所选内容的文章作者及编辑认为其作品不宜公开自由传播,或不应无偿使用,请及时通过电子邮件或电话通知我们,以迅速采取适当措施,避免给双方造成不必要的经济损失。

上一篇:通过DMA向串口发送数据
下一篇:STM32F10x 学习笔记之USART实现串口通讯 DMA 方式

关注eeworld公众号 快捷获取更多信息
关注eeworld公众号
快捷获取更多信息
关注eeworld服务号 享受更多官方福利
关注eeworld服务号
享受更多官方福利

推荐阅读

使用STR730开发产品实现串口ISP在线编程的设计方案
应用程序的固化是嵌入式产品开发和生产过程中一个重要环节。基于ARM的嵌入式系统常用的程序固化方法是,用仿真器通过JTAG口将程序烧录到Flash里,在产品的开发阶段,使用仿真器几乎是必然的;然而到了产品的生产阶段,进行应用程序烧录或升级操作的往往是生产线上的工人,他们不易掌握仿真器的使用方法,而且在生产阶段也需要把JTAG调试口封住以防软件被窥视。在使用意法半导体的STR730开发产品的过程中,设计了一种通过串口进行ISP(In System Programming,在系统编程)的方案。该方案成本低,生产线使用起来也很方便,而且即使升级过程中发生掉电之类的意外也不会影响下一次升级,安全而可靠。1 、硬件连接ISP方案的硬件连接如图
发表于 2020-07-25
使用STR730开发产品实现<font color='red'>串口</font>ISP在线编程的设计方案
实现STMF103串口仿真
代码如下:#include "sys.h"#include "usart.h"  #include "delay.h"#include "led.h"#include "key.h"//串口实验   int main(void){   u8 t;u8 len;u16 times=0;  Stm32_Clock_Init(9); //系统时钟设置delay_init(72);      //延时初始化uart
发表于 2020-07-24
STM32 DHT11串口打印源程序
1.硬件准备:USB转TTL工具一个核心板STM32F103C8T6DHT11传感器2.软件准备:串口调试助手2.硬件连线USB转TTL的RX----32板子上的PA9USB转TTL的TX----32板子上的PA10DHT11的DAT连接PB143.程序源码#include "dht11.h"//////////////////////////////////////////////////////////////////////////////////  #include "delay.h"         
发表于 2020-07-24
STM32 DHT11<font color='red'>串口</font>打印源程序
第13章 1602液晶与串口实用例程
理论上的内容要想逐步消化掌握,必须得通过大量的实践进行巩固,否则时间一长,极容易忘掉。尤其是一些编程的算法相关的技巧,就是靠不停的写程序,不停的参考别人的程序慢慢积累成长起来的。这节课带着大家学习一下1602的例程和实际开发中比较实用的串口程序。13.1 通信时序解析        随着我们对通信技术的深入学习,大家要逐渐在头脑中建立起时序这种概念。所谓“时序”从字面意义上来理解,一是“时间问题”,二是“顺序问题”。先说“顺序问题”,这个相对简单一些。我们在学UART串口通信的时候,先1位起始位,再8位数据位,最后1位停止位,这个先后顺序不能错。我们在学 1602液晶
发表于 2020-07-24
第13章 1602液晶与<font color='red'>串口</font>实用例程
基于stm32f103ze+mpu9250通过官方DMP库串口输出角度
结构体        USART_InitTypeDef  USART_InitStructure;          //串口结构体定义        RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_USART1|RCC_APB2Periph_AFIO,ENABLE);        RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2,ENABLE
发表于 2020-07-23
AVR单片机教程——串口接收
上一讲中,我们实现了单片机开发板向电脑传输数据。在这一讲中,我们将通过电脑向单片机发送指令,让单片机根据指令控制LED。这一次,两端的TX与RX需要交叉连接,单片机TX连接串口工具RX也是需要的,因为程序会根据指令反馈信息。为了简单起见,我们的程序只需要控制4个板载LED。指令包含两个字节:第一个字节为r、y、g、b中的一个,分别表示红、黄、绿、蓝灯;第二个字节为0或1,表示灯不亮或亮。然而,a2这样的指令是没有意义的,却是可能出现的。即使用户已经熟悉了这8条指令,也可能会不小心打错。我们应当记住,用户是世界上最愚蠢的人,我们要把他们可能犯的错误都想到,然后在程序中合理地处理。比如,对于不合法的指令,程序忽略指令,并返回What
发表于 2020-07-22
小广播
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

换一换 更多 相关热搜器件
电子工程世界版权所有 京ICP证060456号 京ICP备10001474号 电信业务审批[2006]字第258号函 京公海网安备110108001534 Copyright © 2005-2020 EEWORLD.com.cn, Inc. All rights reserved