STM32 DMA 学习笔记(二)

一、常用DMA库函数

1.DMA初始化(包括通道和参数配置)

void DMA_Init(DMA_Channel_TypeDef* DMAy_Channelx, DMA_InitTypeDef* DMA_InitStruct);

下面就是结构体参数

typedef struct
{
  uint32_t DMA_PeripheralBaseAddr; //外设基地址
  uint32_t DMA_MemoryBaseAddr; //存储器基地址
  uint32_t DMA_DIR;         //数据传输方向
  uint32_t DMA_BufferSize;  //通道传输数据量
  uint32_t DMA_PeripheralInc;//外设增量模式
  uint32_t DMA_MemoryInc;  //存储器增量模式
  uint32_t DMA_PeripheralDataSize; //外设数据宽度
  uint32_t DMA_MemoryDataSize; //存储器数据宽度
  uint32_t DMA_Mode;  //模式:是否循环
  uint32_t DMA_Priority; //优先级
  uint32_t DMA_M2M;    //是否存储器到存储器方式     
}DMA_InitTypeDef;

  2.使能DMA所指示的通道 

void DMA_Cmd(DMA_Channel_TypeDef* DMAy_Channelx,FunctionalState NewState);

3.设置DMA通道的DMA缓存的大小。即数据量 

void DMA_SetCurrDataCounter(DMA_Channel_TypeDef* DMAy_Channelx,uint16_t DataNumber); 

 二、配置过程

1.使能DMA时钟:RCC_AHBPeriphClockCmd();
2.初始化DMA通道参数:DMA_Init();
3.使能串口DMA发送,串口DMA使能函数:USART_DMACmd();
4.使能DMA1通道,启动传输:DMA_Cmd();
5.查询DMA传输状态DMA_GetFlagStatus();
6.获取/设置通道当前剩余数据量:DMA_GetCurrDataCounter();              DMA_SetCurrDataCounter();
 

#include "dma.h"

u16 DMA1_MEM_LEN;//保存初始化确定的传输数据量,因为初始化只执行一次。

void MYDMA_Config(DMA_Channel_TypeDef*DMA_CHx,u32 cpar,u32 cmar,u16 cndtr)//配置DMA1_CHx
	
{
  
	DMA_InitTypeDef DMA_InitStruct;      //定义DMA配置参量结构体
	
	RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);    //使能DMA1时钟
 
	DMA1_MEM_LEN= cndtr; //记录需要传输的数据量
	
	DMA_DeInit(DMA_CHx);  //将DMA的通道1寄存器重设为默认值
	
	DMA_InitStruct.DMA_BufferSize=cndtr;           //DMA通道的DMA缓存的大小,也就是一次传输的数据量
	DMA_InitStruct.DMA_DIR=DMA_DIR_PeripheralDST;  //数据传输方向,从内存读取发送到外设
	DMA_InitStruct.DMA_M2M=DMA_M2M_Disable ;       //不将DMA通道x设置为内存到内存传输
	DMA_InitStruct.DMA_MemoryBaseAddr=cmar;           //DMA内存基地址
	DMA_InitStruct.DMA_MemoryDataSize=  DMA_MemoryDataSize_Byte;      //数据宽度为8位
	DMA_InitStruct.DMA_MemoryInc= DMA_MemoryInc_Enable;    //内存地址寄存器递增
	DMA_InitStruct.DMA_Mode=DMA_Mode_Normal;        //工作在正常缓存模式,传输一次后就停止传输了
	DMA_InitStruct.DMA_PeripheralBaseAddr= cpar;   //DMA外设基地址 
	DMA_InitStruct.DMA_PeripheralDataSize=DMA_PeripheralDataSize_Byte;   //数据宽度为8位
	DMA_InitStruct.DMA_PeripheralInc=DMA_PeripheralInc_Disable;   //外设地址寄存器不变
	DMA_InitStruct.DMA_Priority=DMA_Priority_VeryHigh;     //DMA通道 x拥有最高优先级
	
	//上面结构体设置的作用是,具体设置DMA某通道的某一功能对应的位,下面的初始化就是将上面的设置相或
  DMA_Init(DMA_CHx,&DMA_InitStruct);       //根据DMA_InitStruct中指定的参数初始化DMA的通道USART1_Tx_DMA_Channel所标识的寄存器
}


void MYDMA_Enable(DMA_Channel_TypeDef*DMA_CHx)//使能DMA1_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 所指示的通道

}

四、使用例程 

#include "key.h"
#include "sys.h"
#include "usart.h"	 
#include "dma.h"
#include "led.h"
#include "delay.h" 


#define SEND_BUF_SIZE 8200  //发送数据长度,最好等于sizeof(TEXT_TO_SEND)+2的整数倍   因为后面加了两个还行字符\n。为了保证打印出来的是完整的句子

u8 SendBuff[SEND_BUF_SIZE];//确定发送数据内存空间

const u8 TEXT_TO_SEND[]={"Welcom to learn DAM 串口实验"};    //定义一个要传输的内容

int main(void)
{
  u16 j,i,mask=0,t;
	float pro=0;         //显示传输进度

	uart_init(115200);  //定义串口波特率为115200
	KEY_Init();        //初始化按键
	LED_Init();
	delay_init();	
	MYDMA_Config(DMA1_Channel4,(u32)&USART1->DR,(u32)SendBuff,SEND_BUF_SIZE);//DMA1配置初始化
	
  j=sizeof(TEXT_TO_SEND);       //求取要传输的字符串长度便于存入一个新的长组数时加入换行符
  for(i=0;i<SEND_BUF_SIZE;i++)	//未存满空间时,不断把小数组的字符移到大数组里 
	{
	   if(t>=j)   //如果一个小数组传输完成
		 {
				 if(mask)
				 {
					SendBuff[i]=0x0a;   //换行符ASCII
					t=0;
				 }
				 else
				 {	 
				SendBuff[i]=0x0d;    //回车键ASCII
					mask++;
				 }
		 }
		else
		{
			mask=0;
			SendBuff[i]=TEXT_TO_SEND[t];  //将字符串传进大数组
			t++;
		}
	}  
	i=0;
	LED0=0;
  while(1)
	{
	  t=KEY_Scan(0);
		if(t==KEY0_PRES)
		{
			LED1=0; //提示案件进入
		  USART_DMACmd(USART1,USART_DMAReq_Tx,ENABLE);  //使能串口1发送端,等待发送
		  MYDMA_Enable(DMA1_Channel4);  //使能DMA1通道4,开始传输

			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;            //传输进度
			}
		}
		
		i++;
		delay_ms(10);
		if(i==20)
		{
			LED0=!LED0;//提示系统正在运行	
			i=0;
		}	
	}


}	
		 
		 
		 

猜你喜欢

转载自blog.csdn.net/seek97/article/details/81409996