STM32系列第21篇--DMA

来源:互联网 发布:中文域名交易平台 编辑:程序博客网 时间:2024/06/06 00:47

简介:

DMA全称DirectMemory Access,即直接存储器访问。
比如串口发送用和不用DMA当然都可以发送。不用DMA发送是需要单片机实时参与,由单片机一个一个地发送数据并进行监控。但是如果用DMA,设置了起始地址,数据大小等参数后,就直接由专门的一个DMA模块进行数据发送,发送过程中单片机无需参与。发送完后会产生中断告知单片机。由此可知用DMA可以节省单片机资源,让单片可以在同一时间里干更多事。
STM32最多有2个DMA控制器(DMA2仅存在大容量产品中),DMA1有7个通道(通道1~通道7)。DMA2有5个通道(通道1~通道5)。每个通道专门用来管理来自于一个或多个外设对存储器访问的请求。还有一个仲裁起来协调各个DMA请求的优先权。

请求列表:

DMA1的7个通道的请求列表:
这里写图片描述

DMA2的5个通道的请求列
这里写图片描述

CODE:

用DMA进行串口发送。

//dma.c#include "dma.h"DMA_InitTypeDef DMA_InitStructure;u16 DMA1_MEM_LEN;//保存DMA每次数据传送的长度       //DMA1的各通道配置//这里的传输形式是固定的,这点要根据不同的情况来修改//从存储器->外设模式/8位数据宽度/存储器增量模式//DMA_CHx:DMA通道CHx//cpar:外设地址//cmar:存储器地址//cndtr:数据传输量 void MYDMA_Config(DMA_Channel_TypeDef* DMA_CHx,u32 cpar,u32 cmar,u16 cndtr){    RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);  //使能DMA传输  DMA_DeInit(DMA_CHx);   //将DMA的通道1寄存器重设为缺省值    DMA1_MEM_LEN=cndtr;    DMA_InitStructure.DMA_PeripheralBaseAddr = cpar;  //DMA外设基地址    DMA_InitStructure.DMA_MemoryBaseAddr = cmar;  //DMA内存基地址    DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;  //数据传输方向,从内存读取发送到外设    DMA_InitStructure.DMA_BufferSize = cndtr;  //DMA通道的DMA缓存的大小    DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;  //外设地址寄存器不变    DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;  //内存地址寄存器递增    DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;  //数据宽度为8位    DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte; //数据宽度为8位    DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;  //工作在正常模式    DMA_InitStructure.DMA_Priority = DMA_Priority_Medium; //DMA通道 x拥有中优先级     DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;  //DMA通道x没有设置为内存到内存传输    DMA_Init(DMA_CHx, &DMA_InitStructure);  //根据DMA_InitStruct中指定的参数初始化DMA的通道USART1_Tx_DMA_Channel所标识的寄存器} //开启一次DMA传输void MYDMA_Enable(DMA_Channel_TypeDef*DMA_CHx){     DMA_Cmd(DMA_CHx, DISABLE );  //关闭USART1 TX DMA1 所指示的通道          DMA_SetCurrDataCounter(DMA_CHx,DMA1_MEM_LEN);//DMA通道的DMA缓存的大小    DMA_Cmd(DMA_CHx, ENABLE);  //使能USART1 TX DMA1 所指示的通道 }   main.c#include "led.h"#include "delay.h"#include "key.h"#include "sys.h"#include "lcd.h"#include "usart.h"   #include "dma.h"#define SEND_BUF_SIZE 8200  //发送数据长度,最好等于sizeof(TEXT_TO_SEND)+2的整数倍.u8 SendBuff[SEND_BUF_SIZE]; //发送数据缓冲区const u8 TEXT_TO_SEND[]={"ALIENTEK WarShip STM32F1 DMA 串口实验"}; int main(void) {       u16 i;    u8 t=0;    u8 j,mask=0;    float pro=0;//进度    delay_init();               //延时函数初始化       NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//设置中断优先级分组为组2:2位抢占优先级,2位响应优先级    uart_init(115200);      //串口初始化为115200    LED_Init();                 //初始化与LED连接的硬件接口    LCD_Init();                 //初始化LCD        KEY_Init();                     //按键初始化             MYDMA_Config(DMA1_Channel4,(u32)&USART1->DR,(u32)SendBuff,SEND_BUF_SIZE);//DMA1通道4,外设为串口1,存储器为SendBuff,长度SEND_BUF_SIZE.    POINT_COLOR=RED;            //设置字体为红色     LCD_ShowString(30,50,200,16,16,"WarShip STM32");        LCD_ShowString(30,70,200,16,16,"DMA TEST");     LCD_ShowString(30,90,200,16,16,"ATOM@ALIENTEK");    LCD_ShowString(30,110,200,16,16,"2015/1/15");       LCD_ShowString(30,130,200,16,16,"KEY0:Start");    //显示提示信息        j=sizeof(TEXT_TO_SEND);        for(i=0;i<SEND_BUF_SIZE;i++)//填充数据到SendBuff    {        if(t>=j)//加入换行符        {            if(mask)            {                SendBuff[i]=0x0a;                t=0;            }else             {                SendBuff[i]=0x0d;                mask++;            }           }        else//复制TEXT_TO_SEND语句        {            mask=0;            SendBuff[i]=TEXT_TO_SEND[t];            t++;        }              }            POINT_COLOR=BLUE;//设置字体为蓝色        i=0;    while(1)    {        t=KEY_Scan(0);        if(t==KEY0_PRES)//KEY0按下        {            LCD_ShowString(30,150,200,16,16,"Start Transimit....");            LCD_ShowString(30,170,200,16,16,"   %");//显示百分号            printf("\r\nDMA DATA:\r\n");                  USART_DMACmd(USART1,USART_DMAReq_Tx,ENABLE); //使能串口1的DMA发送                  MYDMA_Enable(DMA1_Channel4);//开始一次DMA传输!                  //等待DMA传输完成,此时我们来做另外一些事,点灯            //实际应用中,传输数据期间,可以执行另外的任务            while(1)            {                if(DMA_GetFlagStatus(DMA1_FLAG_TC4)!=RESET) //判断通道4传输完成                {                    DMA_ClearFlag(DMA1_FLAG_TC4);//清除通道4传输完成标志                    break;             }                pro=DMA_GetCurrDataCounter(DMA1_Channel4);//得到当前还剩余多少个数据                pro=1-pro/SEND_BUF_SIZE;//得到百分比                   pro*=100;      //扩大100倍                LCD_ShowNum(30,170,pro,3,16);                 }                           LCD_ShowNum(30,170,100,3,16);//显示100%                 LCD_ShowString(30,150,200,16,16,"Transimit Finished!");//提示传送完成        }        i++;        delay_ms(10);        if(i==20)        {            LED0=!LED0;//提示系统正在运行               i=0;        }              }}
0 0