×
单片机 > 单片机程序设计 > 详情

STM32系列第21篇--DMA

发布时间:2020-08-31 发布时间:
|

简介:

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=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;
        }          
    }
}





『本文转载自网络,版权归原作者所有,如有侵权请联系删除』

热门文章 更多
ARM 汇编的必知必会