目的:用DMA发送数据到USART1并同时点亮LED灯,熟悉DMA配置过程
配置文件:#include "stm32f10x_dma.h"
#include "stm32f10x_gpio.h"
#include "stm32f10x_rcc.h"
#include "stm32f10x_usart.h"
结构体定义:
typedef struct
{
uint32_t DMA_PeripheralBaseAddr; //DMA传输目标地址
uint32_t DMA_MemoryBaseAddr; //DAM传输源地址
uint32_t DMA_DIR; //DMA传输方向
uint32_t DMA_BufferSize; //DMA传输大小
uint32_t DMA_PeripheralInc; //外设是否开启地址自增
uint32_t DMA_MemoryInc; //内存是否开启地址自增/
uint32_t DMA_PeripheralDataSize;//外设数据单元
uint32_t DMA_MemoryDataSize; //内存数据单元,与前者须一致
uint32_t DMA_Mode; //DMA模式,可循环,也可不循环
uint32_t DMA_Priority; //DMA优先级,多个DMA申请出现时需考虑
uint32_t DMA_M2M; //内存到内存传输
}DMA_InitTypeDef;
其中DMA_DIR有宏定义如下:
#define DMA_DIR_PeripheralDST ((uint32_t)0x00000010)外设为目标
#define DMA_DIR_PeripheralSRC ((uint32_t)0x00000000)内存为目标
DMA_PeripheralInc;有宏定义如下:
#define DMA_PeripheralInc_Enable ((uint32_t)0x00000040)开启自增
#define DMA_PeripheralInc_Disable ((uint32_t)0x00000000)关闭自增
DMA_MemoryInc有宏定义如下:
#define DMA_MemoryInc_Enable ((uint32_t)0x00000080)开启自增
#define DMA_MemoryInc_Disable ((uint32_t)0x00000000)关闭自增
DMA_PeripheralDataSize有宏定义如下:
#define DMA_PeripheralDataSize_Byte ((uint32_t)0x00000000)字节
#define DMA_PeripheralDataSize_HalfWord ((uint32_t)0x00000100)半字
#define DMA_PeripheralDataSize_Word ((uint32_t)0x00000200)字
DMA_MemoryDataSize有宏定义如下:
#define DMA_MemoryDataSize_Byte ((uint32_t)0x00000000)
#define DMA_MemoryDataSize_HalfWord ((uint32_t)0x00000400)
#define DMA_MemoryDataSize_Word ((uint32_t)0x00000800)
DMA_Priority有宏定义如下:
#define DMA_Priority_VeryHigh ((uint32_t)0x00003000)
#define DMA_Priority_High ((uint32_t)0x00002000)
#define DMA_Priority_Medium ((uint32_t)0x00001000)
#define DMA_Priority_Low ((uint32_t)0x00000000)
DMA_Mode有宏定义如下:
#define DMA_Mode_Circular ((uint32_t)0x00000020)
#define DMA_Mode_Normal ((uint32_t)0x00000000)
DMA_M2M有宏定义如下:
#define DMA_M2M_Enable ((uint32_t)0x00004000)
#define DMA_M2M_Disable ((uint32_t)0x00000000)
注意,DMA使用重点就在于该结构体的参数配置,需认真掌握。
库函数:
DMA_Init(DMA_Channel_TypeDef* DMAy_Channelx, DMA_InitTypeDef* DMA_InitStruct)初始化DMA函数,参数:DMA通道号码,DMA结构体DMA_InitTypeDef。其中通道号注意需要查阅参考手册,不同外设对应着指定的通道号。
DMA_Cmd(DMA_Channel_TypeDef* DMAy_Channelx, FunctionalState NewState)DMA使能函数,参数:DMA通道号,使能or不使能
USART_DMACmd(USART_TypeDef* USARTx, uint16_t USART_DMAReq, FunctionalState NewState)USART向DMA发出申请的函数,参数:USART号,发送or接收申请,使能or不使能。其中有宏定义如下:
#define USART_DMAReq_Tx ((uint16_t)0x0080)发送申请
#define USART_DMAReq_Rx ((uint16_t)0x0040)接收申请
此函数是在USART中设定的,并不是DMA中设定的。 stm32f10x_usart.c
程序代码比较简单,有两个核心,第一个是配置USART,参阅USART,第二个就是配置DMA,其核心又是配置其初始化结构体。先只须分析DMA配置即可。
void USART1_DMA_Config(void)
{
DMA_InitTypeDef DMA_InitStructure;
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);//开启DMA1时钟
DMA_InitStructure.DMA_PeripheralBaseAddr = USART1_DR_Base;//设置目标地址
DMA_InitStructure.DMA_MemoryBaseAddr = (u32)SendBuff;//设置源地址
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST; //外设为目标
DMA_InitStructure.DMA_BufferSize = SENDBUFF_SIZE;//大小为5000,自己可写宏定义定义SENDBUFF_SIZE
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; //外设地址不自增
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; //内存地址自增
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;//单位字节
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte; //单位字节
//DMA_InitStructure.DMA_Mode = DMA_Mode_Normal ;
DMA_InitStructure.DMA_Mode = DMA_Mode_Circular; //循环发送
DMA_InitStructure.DMA_Priority = DMA_Priority_Medium; //优先级为中
DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;//禁止内存到内存
DMA_Init(DMA1_Channel4, &DMA_InitStructure); 初始化,注意USART1对应的为DMA1的通道4
DMA_Cmd (DMA1_Channel4,ENABLE); //DMA使能
//DMA_ITConfig(DMA1_Channel4,DMA_IT_TC,ENABLE);
}
注意:1、目标地址怎么算,传输的是USART1的数据寄存器地址,用USART1的基地址加上数 据寄存器地址的偏移量可得
2、源地址怎么算,这里我们开的是一个数组,数组名本身就是基地址,可直接作为参 数写入,无须加指针
3、内存地址为什么自增,因为在读取数组的时候,我们需要把数组一位一位的读取出来,指针要从基地址开始不断后移然后读数,自然需要地址自增。
4、外设地址为什么不自增,外设地址为USART1的数据寄存器,其地址固定不变的,受到数据后USART1将会自动发送到移位寄存器发送出去,所以不自增。