一位萌新为参加robomaster所做的前期准备–stm32基础(四)(DMA串口发送)
一、 实验目的:通过按键来控制DMA向串口发送数据,并将数据在pc端打印出来。DMA作用:为CPU减负(串口的发送不需要经过cpu)。
二、 方案:
① 实验需要运用按键,故需配置按键相关引脚(结构体,时钟,参数等)
② 需要串口发送,故需配置串口相关信息(打开串口时钟及发送时钟,串口的相关参数,使能串口)
③ 需要调试DMA相关参数(打开DMA时钟,外设基址,内存基址,传输大小,使能DMA等)
三、 流程图
四、 相关函数
//主函数
int main(void){
key_init(); //配置按键参数,打开按键
port_init(); //配置串口参数,打开串口
MYDMA_Config(); //配置DMA参数
while(1){
if(GPIO_ReadInputDataBit(GPIOE,GPIO_Pin_2)==0){
sw_delay_ms(250);
USART_DMACmd(USART1,USART_DMAReq_Tx,ENABLE);
//打开串口的DMA发送功能
DMA_Enable(); //打开DMA传送
}
}
}
//DMA相关参数配置函数
u8 TEXT_TO_SEND[]={"Hello world!"};
//设置一个数组来存放内存数据
#define TEXT_LENTH sizeof(TEXT_TO_SEND)
//设置变量来储存数据长度
void MYDMA_Config(){
DMA_InitTypeDef DMA_InitStructure;
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1,ENABLE);
//打开DMA时钟
DMA_DeInit(DMA1_Channel4);
//将 DMA 的通道 1 寄存器重设为缺省值(可以省去)
DMA_InitStructure.DMA_PeripheralBaseAddr=(u32)&USART1->DR;
// DMA 外设基地址:(u32)&USART1->DR
DMA_InitStructure.DMA_MemoryBaseAddr=(u32)TEXT_TO_SEND;
// DMA 内存基地址(发送缓冲区首地址)
DMA_InitStructure.DMA_DIR=DMA_DIR_PeripheralDST;
//数据传输方向:内存到外设
DMA_InitStructure.DMA_BufferSize=TEXT_LENTH;
// DMA 通道的 DMA 缓存的大小(需要发送的字节数)
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_Normal;
//模式:单次传输模式,不循环
DMA_InitStructure.DMA_Priority=DMA_Priority_Medium;
//优先级设置(中级)
DMA_InitStructure.DMA_M2M=DMA_M2M_Disable;
//非内存到内存传输
DMA_Init(DMA1_Channel4,&DMA_InitStructure);
//初始化 DMA 的通道
}
void DMA_Enable(void){ //打开DMA
DMA_Cmd(DMA1_Channel4,DISABLE);
//先关闭DMA传送(先设置 DMA 缓存的大小,要关闭通道)
DMA_SetCurrDataCounter(DMA1_Channel4,TEXT_LENTH);
//设置 DMA 缓存的大小
DMA_Cmd(DMA1_Channel4,ENABLE);
//使能 USART1 TX DMA1 所指示的通道
}
五、相关知识
① STM32 最多有 2 个 DMA 控制器(DMA2 仅存在大容量产品中), DMA1 有 7 个通道。 DMA2 有 5个通道。每个通道专门用来管理来自于一个或多个外设对存储器访问的请求。还有一个仲裁起来协调各个 DMA 请求的优先权。在七个请求间的优先权可以通过软件编程设置(共有四级:很高、高、中等和低)
② 独立的源和目标数据区的传输宽度(字节、半字、全字),模拟打包和拆包的过程,源和目标地址必须按数据传输宽度对齐。
③ 每个通道都有 3 个事件标志(DMA 半传输, DMA 传输完成和 DMA 传输出错),这 3 个事件标志逻辑或成为一个单独的中断请求。(该实验没有使用)
④
⑤
1)数据传输的目的地和来源
2)定义DMA通道的DMA缓存的大小
3)外设地址寄存器递增与否
4)内存地址寄存器递增与否
5)设定了外设数据宽度
6)设定了内存数据宽度
7)设置了DMA的工作模式
8)DMA通道的软件优先级
9)使能或关闭DMA通道的内存到内存传输
⑥DMA常用库函数
void DMA_Init()
//初始化DMA
void DMA_Cmd()
//打开DMA通道
void DMA_ITConfig()
//打开DMA中断通道
DMA_SetCurrDataCounter()
//返回当前 DMA 通道 x 剩余的待传输数据数目
USART_DMACmd()
//打开串口的DMA功能
六、 总结
本次实验主要了解了DMA的工作原理,熟悉DMA向串口发送数据的流程及相关配置,本实验关键在于对DMA的参数进行相关配置(外设地址,内存地址,传输大小,传输模式等)
DMA配置程序过程:
① 使能DMA时钟
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1,ENABLE);
② 初始化DMA通道参数
DMA_Init(DMA1_Channel4,&DMA_InitStructure);
③ 使能串口DMA1发送,串口DMA使能函数
USART_DMACmd(USART1,USART_DMAReq_Tx,ENABLE);
④ 使能DMA1通道,启动传输
DMA_Cmd(DMA1_Channel4,ENABLE);