学习STM32过程中正好看到正点原子STM32的DMA教程,但视频里只讲解了DMA发送串口数据,未讲解DMA接收串口数据,经过多方查找资料,结合网络历程,现将代码分享。
dma.c 的代码如下,与正点原子历程相比, 改动并不多,将DMA模式改为循环模式,实际测试正常模式响应较慢,而且存在丢包现象,改为循环模式后,收发正常。
#include "stm32f4xx.h"
#include "usart.h"
#include "delay.h"
void MYDMA_Enable(DMA_Stream_TypeDef *DMA_Streamx,u16 ndtr);
void USART1_DMAConfig(DMA_Stream_TypeDef *DMA_Streamx,u32 chx,u32 par,u32 mar,u16 ndtr)
{
DMA_InitTypeDef DMA_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
/* 使能DMA2时钟 */
if((u32)DMA_Streamx>(u32)DMA2) //得到当前stream是属于DMA2还是DMA1
{
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2,ENABLE); //DMA2时钟使能
}else
{
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA1,ENABLE); //DMA1时钟使能
}
/* Reset DMA Stream registers (for debug purpose) */
DMA_DeInit(DMA_Streamx);
while (DMA_GetCmdStatus(DMA_Streamx) != DISABLE){}; //等待DMA可配置
/* Configure DMA Stream */
/* 配置 DMA Stream */
DMA_InitStructure.DMA_Channel = chx; //通道选择
DMA_InitStructure.DMA_PeripheralBaseAddr = par; //DMA外设地址
DMA_InitStructure.DMA_Memory0BaseAddr = mar; //DMA 存储器0地址
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory; //存储器到外设模式
DMA_InitStructure.DMA_BufferSize = ndtr; //数据传输量
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_Circular; //使用循环模式
DMA_InitStructure.DMA_Priority = DMA_Priority_Medium; //中等优先级
DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable;
DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_Full;
DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single; //存储器突发单次传输
DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single; //外设突发单次传输
DMA_Init(DMA_Streamx, &DMA_InitStructure); //初始化DMA Stream
USART_DMACmd(USART1,USART_DMAReq_Rx,ENABLE); //使能串口1的DMA接收
MYDMA_Enable(DMA_Streamx,USART_REC_LEN); //开始第1次DMA传输!
}
//开启一次DMA传输
//DMA_Streamx:DMA数据流,DMA1_Stream0~7/DMA2_Stream0~7
//ndtr:数据传输量
void MYDMA_Enable(DMA_Stream_TypeDef *DMA_Streamx,u16 ndtr)
{
DMA_Cmd(DMA_Streamx, DISABLE); //关闭DMA传输
while (DMA_GetCmdStatus(DMA_Streamx) != DISABLE){} //确保DMA可以被设置
DMA_SetCurrDataCounter(DMA_Streamx,ndtr); //数据传输量
DMA_Cmd(DMA_Streamx, ENABLE); //开启DMA传输
}
main函数段如下
#include "stm32f4xx.h"
#include "usart.h"
#include "delay.h"
#include "dma.h"
#include <string.h>
extern u8 USART_RX_BUF[USART_REC_LEN];
int main(void)
{
u32 t=0;
uart_init(115200);
delay_init(84);
USART1_DMAConfig(DMA2_Stream2,DMA_Channel_4,(u32)&USART1->DR,(u32)USART_RX_BUF,USART_REC_LEN);//DMA2通道4,外设为串口1,存储器为SendBuff,长度USART_REC_LEN 200,
printf("DMA IS OK!");
while(1){
if(USART_RX_BUF[0]) //数组0有数据了,说明DMA开始接收一段数据
{
delay_ms(10); //延时10ms,让DMA继续接收后面数据的同时,也能跑跑其它进程
printf("%s\r\n",USART_RX_BUF); //打印
memset(USART_RX_BUF,0,USART_REC_LEN); //清空数组
MYDMA_Enable(DMA2_Stream2,USART_REC_LEN);//开始一次DMA传输!
/*============================================代码优化==================================================
while(1)
{
if(DMA_GetFlagStatus(DMA2_Stream2,DMA_FLAG_TCIF2)!=RESET)//等待DMA2_Steam2传输完成
{
printf("%s\r\n",USART_RX_BUF); //打印
memset(USART_RX_BUF,0,USART_REC_LEN); //清空数组
DMA_ClearFlag(DMA2_Stream2,DMA_FLAG_TCIF2);//清除DMA2_Steam2传输完成标志
MYDMA_Enable(DMA2_Stream2,USART_REC_LEN);//开始一次DMA传输!
break;
}
}
======================================================================================================*/
}
}
}