stm32---DMA基础

DMA,意思为直接存储器访问。
DMA 可 用于实现外设与存储器之间或者存储器与存储器之间数据高效传输。
因为 DMA 传输数据移动过程无需 CPU 直接操作,这样节省的 CPU 资 源就可供其它操作使用。
从硬件层面来理解,DMA 就好像是 RAM 与 I/O 设备间数 据传输的通路,外设与存储器之间或者存储器与存储器之间可以直接在这条通路 上进行数据传输。
这里说的外设一般指外设的数据寄存器,比如 ADC、SPI、I2C、 DCMI 等外设的数据寄存器,存储器一般是指片内 SRAM、外部存储器、片内 Flash 等。


STM32F1 最多有 2 个 DMA 控制器,DMA1 有 7 个通道。 DMA2 有 5 个通道。每个通道专门用来管理来自于一个或多个外设 对存储器访问的请求。还有一个仲裁器来协调各个 DMA 请求的优先权。


13367077-ee5e1f2bae24bd30.PNG
DMA1通道对应外设请求

13367077-714e52391639eba1.PNG
DMA2通道对应外设请求

DMA就像一个中转站一样,里面有源地址和目标地址,多通道并用可以配置优先级,
只要开启DMA就可以直接实现源地址里的内容传送给目标地址,不需要CPU来管理,它就像个通道一样,开启就传输。


dma.c

#include "dma.h"


/*******************************************************************************
* 函 数 名         : DMAx_Init
* 函数功能         : DMA初始化函数
* 输    入         : 
                     DMAy_Channelx:DMA通道选择,@ref DMA_channel DMA_Channel_0~DMA_Channel_7
                     par:外设地址
                     mar:存储器地址
                     buff_size:数据传输量
* 输    出         : 无
*******************************************************************************/ 
void DMAx_Init(DMA_Channel_TypeDef* DMA1_Channelx,u32 par,u32 mar,u16 buff_size)
{
    DMA_InitTypeDef DMA_InitStructure;
    
    //1*开启相应时钟
    RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1,ENABLE);
    
    //2*DMA结构体配置
    DMA_InitStructure.DMA_PeripheralBaseAddr = par;  //外设目标地址
    DMA_InitStructure.DMA_MemoryBaseAddr = mar;   //存储器源地址
    DMA_InitStructure.DMA_DIR =DMA_DIR_PeripheralDST ;  //方向是DMA存储器到外设寄存器。方向还有外设到存储器,存储器到存储器
    DMA_InitStructure.DMA_BufferSize = buff_size; //传输的字节数目
    DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; //外设寄存器地址自递增,外设通常是一个不需要递增
    DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryInc_Enable;  //传输数据多字节时需要地址自增,实现开启就全部传输完
    DMA_InitStructure.DMA_Mode = DMA_Mode_Normal; //DMA传输模式,单次传输
    DMA_InitStructure.DMA_Priority = DMA_Priority_Medium;  //优先级配置,用于多通道时
    DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;  //存储器到存储器时打开
    DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte; //存储器数据长度为1Byte,8位
    DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte; //外设接收数据长度为必须要存储器发送数据长度一样
    DMA_Init(DMA1_Channelx,&DMA_InitStructure);
    
}

/*******************************************************************************
* 函 数 名         : DMAx_Enable
* 函数功能         : 开启一次DMA传输
* 输    入         : DMAy_Channelx:DMA通道选择,@ref DMA_channel DMA_Channel_0~DMA_Channel_7
                     buff_size:数据传输量,传输时再赋值一遍防止出错
* 输    出         : 无
*******************************************************************************/ 
//3*开启DMA
void DMAx_ENABLE(DMA_Channel_TypeDef* DMA1_Channelx,u16 buff_size)
{

    DMA_Cmd(DMA1_Channelx,DISABLE);   //先关闭DMA使能来赋
    DMA_SetCurrDataCounter(DMA1_Channelx,buff_size);
    DMA_Cmd(DMA1_Channelx,ENABLE);
}

dma.h

#ifndef _dma_H
#define _dma_H

#include "system.h"


void DMAx_Init(DMA_Channel_TypeDef* DMA1_Channelx,u32 par,u32 mar,u16 buff_size);

void DMAx_ENABLE(DMA_Channel_TypeDef* DMA1_Channelx,u16 buff_size); 


#endif

main.c

#include "systick.h"
#include "led.h"
#include "system.h"
#include "key.h"
#include "usart.h"
#include "dma.h"

#define data_size 5000
u8 data[data_size];

//数组赋值专用函数
void Data_zhuang(u8 *p)
{
    u16 i;
    for(i=0;i<data_size;i++)
    {
        *p = '5';
        p++;

    }
}


int main()
{
    u8 i=0;
    u8 key;
    
    SysTick_Init(72);  //系统时钟初始
    LED_INIT(); 
    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); 
    USART1_Init(9600);
    KEY_INIT();
    
    Data_zhuang(data); //给数组赋值
    DMAx_Init(DMA1_Channel4,(u32)&USART1->DR,(u32)data,data_size); //DMA初始化,(u32)&USART1->DR是串口1的数据寄存器,(u32)data是我们在内存中造的数组
    
    while(1)
    { 
        key = KEY_Scan(0);
        if(key==KEY_UP)
        {
            USART_DMACmd(USART1,USART_DMAReq_Tx,ENABLE); //是哪个外设就开启哪个的DMA功能
            DMAx_ENABLE(DMA1_Channel4,data_size);  //使能DMA
            
            while(1)
            {
                if(DMA_GetFlagStatus(DMA1_FLAG_TC4)==1) //判断DMA1的通道4是否传输完成
                {
                    DMA_ClearFlag(DMA1_FLAG_TC4);  //清除传输完成标志
                    break;
                }
                led2=!led2;
                delay_ms(300);
            }   
        }
    
        i++;
        if(i%20==0) //200ms变换一次
        {
            led1=!led1;
        }
    
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值