STM32基础设计(4)---DMA通信

前面几篇文章介绍了STM32 F103C8的 GPIO口操作,串口的操作,中断的操作,今天这篇文章简单介绍STM32的DMA操作。

本文通过一个小的设计来进行讲解,将STM32内部存储的一个数组中的数据,通过DMA操作复制到第二个数组里,并用USART1串口将第二个数组中的数据输出到电脑端,进行检查,看是否复制成功。

首先总结全文,,使用STM32进行DMA操作的主要过程如下:

1,初始化GPIO

2,初始化串口

3,初始化DMA

4,编写主函数

下面介绍详细步骤:

(步骤1,2前几篇博客有详细讲,请读者翻阅。)

1,初始化GPIO

void IO_Init()
{
	GPIO_InitTypeDef Uart_A; RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
	Uart_A.GPIO_Pin = GPIO_Pin_9;
	Uart_A.GPIO_Speed = GPIO_Speed_50MHz;
	Uart_A.GPIO_Mode = GPIO_Mode_AF_PP;
	GPIO_Init(GPIOA,&Uart_A);
	
	Uart_A.GPIO_Pin = GPIO_Pin_10;
	Uart_A.GPIO_Speed = GPIO_Speed_50MHz;
	Uart_A.GPIO_Mode = GPIO_Mode_IN_FLOATING; //page 110
	GPIO_Init(GPIOA,&Uart_A);
	
}

2,初始化USART1

void Usart1_Init()
{
	USART_InitTypeDef Uart;
	
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE);
	Uart.USART_BaudRate = 115200;
	Uart.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
	Uart.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
	Uart.USART_Parity = USART_Parity_No;
	Uart.USART_StopBits = USART_StopBits_1;
	Uart.USART_WordLength = USART_WordLength_8b;
	USART_Init(USART1,&Uart);
	
	USART_Cmd(USART1,ENABLE);
	USART_ClearFlag(USART1,USART_FLAG_TC); //page 540
}


3,初始化DMA

库函数中DMA的结构体如下:

typedef struct
{
  uint32_t DMA_PeripheralBaseAddr; /*!< Specifies the peripheral base address for DMAy Channelx. */

  uint32_t DMA_MemoryBaseAddr;     /*!< Specifies the memory base address for DMAy Channelx. */

  uint32_t DMA_DIR;                /*!< Specifies if the peripheral is the source or destination.
                                        This parameter can be a value of @ref DMA_data_transfer_direction */

  uint32_t DMA_BufferSize;         /*!< Specifies the buffer size, in data unit, of the specified Channel. 
                                        The data unit is equal to the configuration set in DMA_PeripheralDataSize
                                        or DMA_MemoryDataSize members depending in the transfer direction. */

  uint32_t DMA_PeripheralInc;      /*!< Specifies whether the Peripheral address register is incremented or not.
                                        This parameter can be a value of @ref DMA_peripheral_incremented_mode */

  uint32_t DMA_MemoryInc;          /*!< Specifies whether the memory address register is incremented or not.
                                        This parameter can be a value of @ref DMA_memory_incremented_mode */

  uint32_t DMA_PeripheralDataSize; /*!< Specifies the Peripheral data width.
                                        This parameter can be a value of @ref DMA_peripheral_data_size */

  uint32_t DMA_MemoryDataSize;     /*!< Specifies the Memory data width.
                                        This parameter can be a value of @ref DMA_memory_data_size */

  uint32_t DMA_Mode;               /*!< Specifies the operation mode of the DMAy Channelx.
                                        This parameter can be a value of @ref DMA_circular_normal_mode.
                                        @note: The circular buffer mode cannot be used if the memory-to-memory
                                              data transfer is configured on the selected Channel */

  uint32_t DMA_Priority;           /*!< Specifies the software priority for the DMAy Channelx.
                                        This parameter can be a value of @ref DMA_priority_level */

  uint32_t DMA_M2M;                /*!< Specifies if the DMAy Channelx will be used in memory-to-memory transfer.
                                        This parameter can be a value of @ref DMA_memory_to_memory */
}DMA_InitTypeDef;
DMA_DIR

这个是定义DMA的传输方向,DMA传输总共有三个方向,外设到内存,内存到外设,内存到内存(关于外设和内存可以这样简单理解,相当于一条路的两头)

库函数中有两个定义:

#define DMA_DIR_PeripheralDST              ((uint32_t)0x00000010)
#define DMA_DIR_PeripheralSRC              ((uint32_t)0x00000000)

以DST结尾的那个,表示,以外设为目的地,以SRC结尾的那个,表示,以外设为起始点。

 uint32_t DMA_PeripheralBaseAddr;这个是用来定义外设地址的
uint32_t DMA_MemoryBaseAddr;这个是用来定义内存地址的
uint32_t DMA_BufferSize;这个是指DMA通道的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的优先级,有非常高,高,中,低四种。

uint32_t DMA_M2M; 这个是用来设置是否进行 内存到内存传输

初始化函数如下:

void Dma_Init()
{
	DMA_InitTypeDef dma;
	RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1,ENABLE);//老规矩,先开心脏
	dma.DMA_MemoryBaseAddr = (u32)zimu;内存地址
	dma.DMA_PeripheralBaseAddr = (u32)zimu_1;外设地址
	dma.DMA_DIR = DMA_DIR_PeripheralDST;外设为目的地,即zimu_1数组为目的地
	
	dma.DMA_BufferSize = 26;缓冲区大小
	dma.DMA_MemoryDataSize = DMA_PeripheralDataSize_Byte;数据宽度
	dma.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;同上
	
	dma.DMA_MemoryInc = DMA_MemoryInc_Enabl;内存地址自增
	dma.DMA_PeripheralInc = DMA_PeripheralInc_Enable;外设地址自增
	
	dma.DMA_Mode = DMA_Mode_Normal;单次模式
	dma.DMA_Priority = DMA_Priority_High;优先级为高
	dma.DMA_M2M = DMA_M2M_Enable;设置为内存到内存传输
	
	DMA_Init(DMA1_Channel6,&dma);寄存器初始化
	DMA_Cmd(DMA1_Channel6,ENABLE);DMA使能
}

4,编写主函数

int main()
{
	void printf_string(char* a);
	IO_Init();GPIO初始化
	Usart1_Init();USART1初始化
	Dma_Init();DMA初始化
	while(DMA_GetFlagStatus(DMA1_FLAG_TC6) == RESET){}//等待DMA操作完成,在参考手册的149页可以仔细看这个寄存器
	
	while(1){
	    if(USART_GetFlagStatus(USART1,USART_FLAG_TXE))判断是否能用串口输出
	        {
		    printf_string(zimu_1);输出zimu_1数组
		    delay(3000);延时
	        }
	}
}
void printf_string(char* a)
{
	while(*a != '\0')直到数组末尾
	{
		USART1->DR = *a;赋值给USART的数据寄存器
		while(!USART_GetFlagStatus(USART1,USART_FLAG_TC));等待发送成功
		a++;地址加一
	}
}

本文到此结束,因博主水平有限,如有错误,敬请指出,不胜感激!

亲测,可运行。详细代码如下:

#include<stm32f10x.h>
#define uint unsigned int
#define uchar unsigned char
	
char zimu[]={'a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z'};
char zimu_1[32]={'.'};
void delay(uint n)
{
	int i,j;
	for(i=0;i<n;i++)
	for(j=0;j<8500;j++);
}

void IO_Init()
{
	GPIO_InitTypeDef Uart_A;
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
	
	Uart_A.GPIO_Pin = GPIO_Pin_9;
	Uart_A.GPIO_Speed = GPIO_Speed_50MHz;
	Uart_A.GPIO_Mode = GPIO_Mode_AF_PP;
	GPIO_Init(GPIOA,&Uart_A);
	
	Uart_A.GPIO_Pin = GPIO_Pin_10;
	Uart_A.GPIO_Speed = GPIO_Speed_50MHz;
	Uart_A.GPIO_Mode = GPIO_Mode_IN_FLOATING; //page 110
	GPIO_Init(GPIOA,&Uart_A);
	
}
void Usart1_Init()
{
	USART_InitTypeDef Uart;
	
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE);
	Uart.USART_BaudRate = 115200;
	Uart.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
	Uart.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
	Uart.USART_Parity = USART_Parity_No;
	Uart.USART_StopBits = USART_StopBits_1;
	Uart.USART_WordLength = USART_WordLength_8b;
	USART_Init(USART1,&Uart);
	
	USART_Cmd(USART1,ENABLE);
	USART_ClearFlag(USART1,USART_FLAG_TC); //page 540
}

void Dma_Init()
{
	DMA_InitTypeDef dma;
	RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1,ENABLE);
	dma.DMA_MemoryBaseAddr = (u32)zimu;
	dma.DMA_PeripheralBaseAddr = (u32)zimu_1;
	dma.DMA_DIR = DMA_DIR_PeripheralDST;
	
	dma.DMA_BufferSize = 26;
	dma.DMA_MemoryDataSize = DMA_PeripheralDataSize_Byte;
	dma.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
	
	dma.DMA_MemoryInc = DMA_MemoryInc_Enable;
	dma.DMA_PeripheralInc = DMA_PeripheralInc_Enable;
	
	dma.DMA_Mode = DMA_Mode_Normal;
	dma.DMA_Priority = DMA_Priority_High;
	dma.DMA_M2M = DMA_M2M_Enable;
	
	DMA_Init(DMA1_Channel6,&dma);
	DMA_Cmd(DMA1_Channel6,ENABLE);
}
int main()
{
	void printf_string(char* a);
	IO_Init();
	Usart1_Init();
	Dma_Init();
	
	GPIOC->BSRR = GPIO_Pin_13;
	
	while(DMA_GetFlagStatus(DMA1_FLAG_TC6) == RESET){}
	
	while(1){
	if(USART_GetFlagStatus(USART1,USART_FLAG_TXE))
	{
		printf_string(zimu_1);
		delay(3000);
	}
	}
}
void printf_string(char* a)
{
	//USART1->CR1 &= ~USART_CR1_TXEIE;
	USART1->CR1 |= USART_CR1_TXEIE;
	while(*a != '\0')
	{
		USART1->DR = *a;
		while(!USART_GetFlagStatus(USART1,USART_FLAG_TC));
		a++;
	}
}















猜你喜欢

转载自blog.csdn.net/aa867734398/article/details/79667245