看野火的视频,用正点原子的板子(STM32F4探索者)做DMA实验

该实验使用STM32的DMA2_Stream7通道4,实现了存储器到存储器的数据复制以及存储器到串口USART1的数据传输。通过初始化DMA和串口,设置传输参数,然后在main函数中进行数据验证和发送。实验结果显示数据传输成功。
摘要由CSDN通过智能技术生成

1. 实验目的

使用DMA完成存储器到存储器的数据传输和存储器到外设的数据传输;

关于存储器到存储器的数据传输实验: 就是把一个数组的数据通过DMA复制到另一个数组中去。

关于存储器到外设的数据传输:就是把一个数据中的数据通过DMA传输到串口的数据寄存器中(USART_DR),串口把数据发送出来,通过串口助手展示。

2. 实验流程

这里使用的是DMA2_Stream7,通道4,串口是USART1。
在这里插入图片描述
具体流程步骤:
初始化DMA;
初始化串口;
编写main函数。

2.1 初始化DMA(M TO M)

#define BUFFER_SIZE 32    //数组长度
//定义数组
const uint32_t aSRC_Const_Buffer[BUFFER_SIZE] = {
	  0X01020304,0X05060708,0X090A0B0C,0X0D0E0F10,
	  0X11121314,0X15161718,0X191A1B1C,0X1D1E1F20,
	  0X21222324,0X25262728,0X292A2B2C,0X2D2E2F30,
	  0X31323334,0X35363738,0X393A3B3C,0X3D3E3F40,
      0X41424344,0X45464748,0X494A4B4C,0X4D4E4F50,
      0X51525354,0X55565758,0X595A5B5C,0X5D5E5F60,
      0X61626364,0X65666768,0X696A6B6C,0X6D6E6F70,
	  0X71727374,0X75767778,0X797A7B7C,0X7D7E7F80
};
//目标数组
uint32_t aDST_Buffer[BUFFER_SIZE];
//DMA初始化
void MtM_DMA_Config(void){
	DMA_InitTypeDef  DMA_InitStruct;
	//初始化时钟
	RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2,ENABLE);                    //DMA2时钟使能 
	DMA_InitStruct.DMA_Channel = DMA_Channel_4;                            //DMA通道
	DMA_InitStruct.DMA_PeripheralBaseAddr = (uint32_t)aSRC_Const_Buffer;   //DMA 外设地址
	DMA_InitStruct.DMA_Memory0BaseAddr = (uint32_t)aDST_Buffer;            //DMA 存储器 0 地址
	DMA_InitStruct.DMA_DIR =   DMA_DIR_MemoryToMemory;                     //方向:存储器到存储器(这里不能选外设到存储器)
	DMA_InitStruct.DMA_BufferSize = BUFFER_SIZE;                           //传输大小32个
	DMA_InitStruct.DMA_PeripheralInc = DMA_PeripheralInc_Enable;           //外设(内部的FLASH)地址递增   
	DMA_InitStruct.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Word;   //外设数据单位,word代表4个字节,32位
	DMA_InitStruct.DMA_MemoryInc = DMA_MemoryInc_Enable;                   //外设(内部的FLASH)地址递增 
    DMA_InitStruct.DMA_MemoryDataSize = DMA_MemoryDataSize_Word;             //内存数据单位
	DMA_InitStruct.DMA_Mode = DMA_Mode_Normal;                             //DMA模式,一次或者循环模式,这里是只发送一次
    DMA_InitStruct.DMA_Priority = DMA_Priority_High;                       //优先级:高
    DMA_InitStruct.DMA_FIFOMode = DMA_FIFOMode_Enable;                     //MtoM
	DMA_InitStruct.DMA_FIFOThreshold = DMA_FIFOThreshold_Full;
	DMA_InitStruct.DMA_MemoryBurst = DMA_MemoryBurst_Single;               //单次传输
	DMA_InitStruct.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;       //外设突发单次传输
  DMA_Init(DMA2_Stream7, &DMA_InitStruct);                               //初始化 DMA Stream
  DMA_Cmd(DMA2_Stream7,ENABLE);                                          //使能DMA
}
//写一个比较函数,来验证是否数据转移成功
/*
  判断指定长度的两个数据源是否完全相等
  如果完全相等就返回1,只要其中一对数据不相等返回0
*/
  uint8_t Buffercmp(const uint32_t *pBuffer, uint32_t *pBuffer1, uint16_t BufferLength){		
		//数据长度递减
		while(BufferLength--){
			//判断两个数据源是否对应相等
			if(*pBuffer != *pBuffer1){
			//对应的数据源不相等,退出函数,并返回0
			 return 0;
			}
		 pBuffer++;
		 pBuffer1++;
		}
		//对应的位置相等
		return 1;
	}

2.2 初始化串口

 void EXTI_NVIC_Config(void){
	//NVIC初始化结构体
	NVIC_InitTypeDef  NVIC_InitStruct;
	//设置中断优先级的分组
	//就是设置主抢占优先级和子抢占优先级各是几,这里是分组为1,代表主优先级可以是0和1(就是1个位来设置主优先级),子优先级是0-7,是2的3次方
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);
	//配置USART为中断源
	NVIC_InitStruct.NVIC_IRQChannel = USART1_IRQn;
	//配置抢占优先级
	NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 1;
	//配置子优先级
	NVIC_InitStruct.NVIC_IRQChannelSubPriority = 1;
	//使能中断
	NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;
	NVIC_Init(&NVIC_InitStruct);
}
void USART_Config(void){
	//1.初始化GPIO(PA9(接串口1的TX引脚),这里是PA10(接串口1的RX引脚))
	//初始化结构体 GPIO_InitStruct(取的一个随机的名字)
	//里面是GPIO的速度,上下拉,输出类型等
	 GPIO_InitTypeDef   GPIO_InitStruct;
	//USART结构体
	 USART_InitTypeDef   USART_InitStruct;
	//打开GPIOA时钟(一般开时钟要放到前面的位置,然后再是设置上拉,输出这些)
	 RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA,ENABLE);  //使能时钟必须放到前面,不然后面的操作不会使灯点亮
	//打开USART1时钟
	 RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE);//使能USART1时钟
	//复位串口1
	GPIO_PinAFConfig(GPIOA, GPIO_PinSource9, GPIO_AF_USART1); //PA9 复用为 USART1
	GPIO_PinAFConfig(GPIOA, GPIO_PinSource10, GPIO_AF_USART1); //PA10 复用为 USART1
	//驱动是哪个引脚  PA9/PA10
	GPIO_InitStruct.GPIO_Pin  = GPIO_Pin_9|GPIO_Pin_10;
	//模式是复用功能
	GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF;
	//输出的速度
	GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
	//推挽复用输出
	GPIO_InitStruct.GPIO_OType = GPIO_OType_PP;
	//上拉
	GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_UP;
	//变量获取它的指针,取地址就行(&)
	GPIO_Init(GPIOA,&GPIO_InitStruct);
	//2.初始化串口
	//使能串口时钟 (放在最上面了)
	//配置波特率
	USART_InitStruct.USART_BaudRate = 115200;  //设置波特率115200
	//配置针数据字长
	USART_InitStruct.USART_WordLength = USART_WordLength_8b; //字长为8位数据格式
	//配置停止位
	USART_InitStruct.USART_StopBits = USART_StopBits_1;     //设置为一个停止位
	//配置校验位
	USART_InitStruct.USART_Parity = USART_Parity_No;     //无奇偶校验位
	//配置硬件流控制
	USART_InitStruct.USART_HardwareFlowControl = USART_HardwareFlowControl_None; //不使用硬件流控制
	//配置工作模式
	USART_InitStruct.USART_Mode =  USART_Mode_Rx|USART_Mode_Tx;  //收发模式
	//完成串口的初始化配置
	USART_Init(USART1,&USART_InitStruct);
	//串口中断优先级配置(初始化)
	EXTI_NVIC_Config();
	//使能串口接收中断(中断配置函数)  这是使能哪种中断,比如在接收到数据的时候(RXNE 读数据寄存器非空),我们要产生中断
	USART_ITConfig(USART1,USART_IT_RXNE,ENABLE);  //生成串口中断   接收到数据就产生了中断
	USART_ITConfig(USART1, USART_IT_IDLE, ENABLE);	// 开启空闲中断
	//使能串口(串口使能函数)
	USART_Cmd(USART1,ENABLE);
}

2.3 编写main函数(M TO M)

int main(void)
{
	uint8_t status = 0;
	MtM_DMA_Config();
	USART_Config();	
	printf("value0 =%d\r\n",100);
	status = Buffercmp(aSRC_Const_Buffer,aDST_Buffer,BUFFER_SIZE);  //判断是否传输成功
	 if(status == 1){		 
	     printf("SUCCESS\r\n");
	}else{	
	     printf("defeat\r\n");
	}
		printf("value1 =%d\r\n",100);
		while(1){}
}

2.4 初始化DMA(M TO P)

 #define BUFFER_SIZE 5000    //数组大小
uint32_t aDST_Buffer[BUFFER_SIZE];//原数组
//DMA初始化
void MtP_DMA_Config(void){
	DMA_InitTypeDef  DMA_InitStruct;
	//初始化时钟
	RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2,ENABLE);//DMA2时钟使能 
	DMA_InitStruct.DMA_Channel = DMA_Channel_4;                            //配置通道
	DMA_InitStruct.DMA_PeripheralBaseAddr = (u32)&USART1->DR;              //DMA外设地址:串口
	DMA_InitStruct.DMA_Memory0BaseAddr = (uint32_t)aDST_Buffer;            //DMA存储器0地址
	DMA_InitStruct.DMA_DIR = DMA_DIR_MemoryToPeripheral;                   //方向:存储器到外设模式
	DMA_InitStruct.DMA_BufferSize = BUFFER_SIZE;                           //传输大小5000个数据
	DMA_InitStruct.DMA_PeripheralInc = DMA_PeripheralInc_Disable;          //外设地址不需要递增   
	DMA_InitStruct.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;   //外设数据单位,1个字节,8位
	DMA_InitStruct.DMA_MemoryInc = DMA_MemoryInc_Enable;                   //(内部的FLASH)地址递增 
    DMA_InitStruct.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte ;            //内存数据单位,1个字节,8位
	DMA_InitStruct.DMA_Mode = DMA_Mode_Normal;                             //DMA模式,一次或者循环模式,这里是只发送一次
    DMA_InitStruct.DMA_Priority = DMA_Priority_High;                       //优先级:高
    DMA_InitStruct.DMA_FIFOMode = DMA_FIFOMode_Disable;                    //不使用MtoM模式
	DMA_InitStruct.DMA_FIFOThreshold = DMA_FIFOThreshold_Full;
	DMA_InitStruct.DMA_MemoryBurst = DMA_MemoryBurst_Single;               //单次传输
	DMA_InitStruct.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;       //外设突发单次传输
    DMA_Init(DMA2_Stream7, &DMA_InitStruct);                               //初始化 DMA Stream
	DMA_Cmd(DMA2_Stream7,ENABLE);                                          //使能DMA
}

2.5 编写main函数(M TO P)

int main(void)
{
	uint8_t status = 0;
	uint32_t i = 0;
	//往原数组中写数据
	for(i=0;i<BUFFER_SIZE;i++){
	  aDST_Buffer[i] = 'A' ;
	}
	MtP_DMA_Config();  //初始化DMA
	USART_Config();	   //初始化串口
	USART_DMACmd(USART1,USART_DMAReq_Tx,ENABLE);  //使能串口1的DMA发送,串口向DMA发送数据
	while(1){}
}

3. 实验结果

实验1结果如下图所示,可以看到数据传送成功。
在这里插入图片描述实验2结果如下图所示,可以看到数据传送成功。
在这里插入图片描述

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值