使用DMA发送和接收数据

什么是DMA?DMA(直接存储器存储)用来提供在外设和存储器之间或者存储器和存储器之间的高速数据传输。其优点在于不占用CPU,可以无须CPU的干预让数据快速移动。

   

 

从图中可以看出共有两个DMA,为DMA1和DMA2,其中DMA1有7个通道,DMA2有5个通道,他们都挂接在AHB总线上,这就意味着使用他们需要使能AHB中的DMA时钟。

如果要使用DMA传输和接收数据,那么该怎么初始化结构体呢?首先,定义两个数组,用来储存器到存储器的数据和存储器到外设的数据,然后在一步一步进行DMA的结构体初始化,例如使用DMA1来接收USART1传来的数据。DMA的外设地址就需要指向USART1的DR数据寄存器,DMA的存储器地址就需要用到之前创建的数组地址,用来储存DR传输过来的数组;接下来设置数据的传输方向和传输数量,传输方向分为单向传输和双向传输,这里设置为单向传输PeripheralSRC((uint32_t)0x00000000),传输数目则是说每次通过DMA通道的数据长度,可自己设置数目。然后是DMA的外设递增模式设置,如果DMA选用的通道有多个外设连接,则需要用到这个模式,只需使能他就行了,这里不需要做使能,因为只用了一个usart1;DMA_MemoryInc(存储器地址递增模式)设置为DMA_MemoryInc_Enable,外设数据宽度和存储器数据局宽度都设置为BYTE模式,DMA模式选择为正常,优先级设为高优先级,最后的存储器到存储器的模式设置为DMA_M2M_Disable,用于两个存储器中的变量数据访问,最后就是使能了,接收USART1数据的通道为DMA1_Channel5,发送数据的通道为DMA1_Channel4,注意:这里一个做了两个通道的初始化,一个用于发送,一个用于接收;传输通道的传输数目配置为1,传输方向选择双向传输。在初始化函数最后将传输完成标志位清零。当然,在这之前还需要配置USART1的USART_DMACmd,开启串口发送DMA。配置代码如下:

     USART_ITConfig(USART1, USART_IT_IDLE, ENABLE);//配置为空闲中断 

     USART_DMACmd(USART1,USART_DMAReq_Tx,ENABLE);

初始化完成之后就需要开始写USART1的中断服务函数,因为我们需要将USART1接收到的数据传送到DMA之中,所以在中断服务函数中需要在这个空闲中断中复制数据到DMA,首先是检查空闲中断标志位是否不为空,是则先关闭通道5,然后将两个数组初始化,最后打开通道5。

 在之后就是DMA打印功能了,其中分为两个函数,一个为打印函数,一个为数据处理函数,打印函数为带字符型指针参数和类型不确定的参数输入,函数名为void debug_printf(char* fmt,...),在函数中定义一个无符号的整形变量,使用va_list定义一个可变参数,使用va_start函数初始化这个参数,赋值为输入的字符指针,使用vsprintf函数将输入的值赋值给一个数组,最后使用va_end将指针置为无效,这就完成了输入形参的取值,再计算数组的长度,调用数据处理函数。数据处理函数为void debug_output(uint8_t* buff,uint16_t length),length为输入数据的长度,数据处理函数的功能是将收到的数据输出到外设,也就是实现打印功能的最后一步,首先失能DMA1的通道4,然后将length的值赋值给DMAI_Channel4->CNDTR,传输数量寄存器,将BUFF的值赋给CMAR寄存器(DMA1_Channel4->CMAR),最后使能DMA1的通道4,这样会使用DMA操控USART1来做打印功能。两个函数的代码如下:

void debug_output(uint8_t* buff,uint16_t length)
{
	DMA_Cmd(DMA1_Channel4, DISABLE);
	/* 设置DMA长度 和 地址 */
	DMA1_Channel4->CNDTR = length;
	DMA1_Channel4->CMAR = (uint32_t)buff;
	DMA_Cmd (DMA1_Channel4,ENABLE);		
}
/***********************************************************************************************************
* @描述	: 
***********************************************************************************************************/
void debug_printf(char* fmt,...) 
{  
	unsigned int length;
	/*可变参数输入*/
	va_list ap;
	va_start(ap,fmt);
	vsprintf(debug_buff,fmt,ap);
	va_end(ap);	
	/*可变参数输入*/
	length=strlen((const char*)debug_buff);
	debug_output((unsigned char*)debug_buff,length);	
}

 接下来只需要在主函数中直接调用debug_printf函数输出就可以实现打印功能了,这里借鉴了巍哥的代码哈,不要介意^_^。

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值