STM32 DMA学习笔记
1. 实验环境:
开发板:野火指南者(STM32F103VE)
STM32库版本:STM32F10x_StdPeriph_Lib_V3.5.0
IDE:KEIL5(代码编写很不方便,只在编译的时候用到)
代码编写工具:Source Insight 4.0(跟读代码、编写代码的最佳工具)
使用到的串口:USART1
传送方向:内存--->外设
硬件原理图:
实验效果:
2. 新建user_usart.h、user_usart.c、user_dma.h、user_dma.c、main.c 5个文件,并从STM32官方库的例子中将stm32f10x_it.c、stm32f10x_it.h、stm32f10x_conf.h拷贝到自己的工程目录下。
3. 在user_usart.h中添加如下代码
1 #ifndef __USER_USART_H 2 #define __USER_USART_H 3 #include "stm32f10x.h" 4 5 void User_USART_GPIO_Config(void); 6 void User_USART_Config(void); 7 8 9 #endif
4. 在user_usart.c中添加如下代码
1 #include "user_usart.h" 2 3 4 5 void User_USART_Config(void) 6 { 7 USART_InitTypeDef USART_Config; 8 9 RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE); 10 11 USART_Config.USART_BaudRate = 115200; 12 USART_Config.USART_HardwareFlowControl = USART_HardwareFlowControl_None; 13 USART_Config.USART_Mode = USART_Mode_Tx | USART_Mode_Rx; 14 USART_Config.USART_Parity = USART_Parity_No; 15 USART_Config.USART_StopBits = USART_StopBits_1; 16 USART_Config.USART_WordLength = USART_WordLength_8b; 17 18 USART_Init(USART1, &USART_Config); 19 20 USART_Cmd(USART1, ENABLE); 21 22 23 } 24 25 26 void User_USART_GPIO_Config(void) 27 { 28 GPIO_InitTypeDef USART_GPIO_TX,USART_GPIO_RX; 29 30 RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); 31 32 USART_GPIO_TX.GPIO_Mode = GPIO_Mode_AF_PP; 33 USART_GPIO_TX.GPIO_Pin = GPIO_Pin_9; 34 USART_GPIO_TX.GPIO_Speed = GPIO_Speed_50MHz; 35 36 GPIO_Init(GPIOA, &USART_GPIO_TX); 37 38 USART_GPIO_RX.GPIO_Mode = GPIO_Mode_IN_FLOATING; 39 USART_GPIO_RX.GPIO_Pin = GPIO_Pin_10; 40 41 GPIO_Init(GPIOA, &USART_GPIO_RX); 42 43 44 45 46 }
5. 在user_dma.h中添加如下代码
1 #ifndef __USER_DMA_H 2 #define __USER_DMA_H 3 4 #include "stm32f10x.h" 5 6 7 #define USART_DATA_ADRESS (USART1_BASE + 0x04) 8 9 extern char str[]; 10 11 12 13 void User_DMA_Config(void); 14 15 16 17 #endif
6. 在user_dma.c中添加如下代码
1 #include "user_dma.h" 2 3 char str[] = "aahhhhhhhhhh"; 4 5 6 void User_DMA_Config(void) 7 { 8 DMA_InitTypeDef m_DMA; 9 10 RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE); 11 12 m_DMA.DMA_BufferSize = sizeof(str); //此处大小一定要和发送的字符串大小一致,否则多余的部分出现乱码,因为值是未知的 13 m_DMA.DMA_DIR = DMA_DIR_PeripheralDST; 14 m_DMA.DMA_M2M = DMA_M2M_Disable; 15 m_DMA.DMA_MemoryBaseAddr = (uint32_t)str; 16 m_DMA.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte; 17 m_DMA.DMA_MemoryInc = DMA_MemoryInc_Enable; 18 m_DMA.DMA_Mode = DMA_Mode_Circular; 19 m_DMA.DMA_PeripheralBaseAddr = USART_DATA_ADRESS; 20 m_DMA.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte; 21 m_DMA.DMA_PeripheralInc = DMA_PeripheralInc_Disable; 22 m_DMA.DMA_Priority = DMA_Priority_Medium; 23 24 /* 25 串口工具接收来自开发板发送的数据,结合硬件实际物理连接, 26 此处为USART1_TX,即DMA1_Channel 27 */ 28 DMA_Init(DMA1_Channel4, &m_DMA); 29 30 31 //使能实际与之对应的DMA通道, 32 DMA_Cmd(DMA1_Channel4, ENABLE); 33 34 35 }
7. 在main.c中添加如下代码
1 #include "stm32f10x.h" 2 #include "user_dma.h" 3 #include "user_usart.h" 4 5 extern char str[]; 6 7 8 int main(void) 9 { 10 11 12 User_DMA_Config(); 13 User_USART_GPIO_Config(); 14 User_USART_Config(); 15 16 //使能USART的DMA模式,这里操作的寄存器是USART的CR3第7bit,此bit置一为打开 17 USART_DMACmd(USART1, USART_DMAReq_Tx, ENABLE); 18 19 20 while(1) 21 { 22 23 } 24 25 26 return 0; 27 }
实现步骤总结:
1、设置USART硬件中实际使用到的GPIO口,这里为GPIOA的PIN9、PIN10,具体设置如下
1.1、使能GPIO时钟,使用RCC_APB2PeriphClockCmd(uint32_t RCC_APB2Periph, FunctionalState NewState)库函数
1.2、初始化GPIO_InitTypeDef结构体成员,若为输入则不需要初始化GPIO_Speed成员
1.3、将GPIO_InitTypeDef结构体的值写入到对应GPIO寄存器中,使用GPIO_Init(GPIO_TypeDef * GPIOx, GPIO_InitTypeDef * GPIO_InitStruct)库函数
2、设置USART对应的寄存器
2.1、使能USART时钟,使用RCC_APB2PeriphClockCmd(uint32_t RCC_APB2Periph, FunctionalState NewState)库函数,若不是USART1则需要使用RCC_APB1PeriphClockCmd(uint32_t RCC_APB1Periph, FunctionalState NewState)库函数,因为USART1挂载在APB2总线上,USART2~USART5挂载在APB1总线上。
2.2、初始化USART_InitTypeDef结构体成员。一般为8N1,即数据长度为8bit、无校验位、1个停止位
2.3、将USART_InitTypeDef结构体的值写入到对应的USART寄存器中,使用USART_Init(USART_TypeDef * USARTx, USART_InitTypeDef * USART_InitStruct)库函数
2.4、打开对应的中断寄存器来响应中断,即中断到来时可进入对应的中断服务程序,若不需要中断,则不用设置,跳过此不走。本实验使用了数据接收中断,使用USART_ITConfig(USART_TypeDef * USARTx, uint16_t USART_IT, FunctionalState NewState)库函数设置
2.5、使能串口USART1,使其进行工作,使用USART_Cmd(USART_TypeDef * USARTx, FunctionalState NewState)库函数
3、定义要传输的数据
4、设置DMA对应的寄存器
4.1、使能DMA时钟,使用RCC_AHBPeriphClockCmd(uint32_t RCC_AHBPeriph, FunctionalState NewState)库函数
4.2、初始化DMA_InitTypeDef结构体成员
4.3、将DMA_InitTypeDef结构体的值写入DMA对应的寄存器中,使用DMA_Init(DMA_Channel_TypeDef * DMAy_Channelx, DMA_InitTypeDef * DMA_InitStruct)库函数
4.4、使能串口DMA,使其进行工作,使用DMA_Cmd(DMA_Channel_TypeDef * DMAy_Channelx, FunctionalState NewState)库函数
5. 使能USART的DMA模式,使用USART_DMACmd(USART_TypeDef * USARTx, uint16_t USART_DMAReq, FunctionalState NewState)库函数
实验代码:
链接:https://pan.baidu.com/s/19QRoJf6HSdOejX_YIXFc6A
提取码:3xd0