七、STM32F429IGT6 DMA

一、 DMA 简介

  • DMA,即Direct Memory Access(直接存储区访问),是一种能够实现在外设寄存器与存储器之间或存储器与存储器之间高速传输数据的方法。
  • DMA传输数据时,不需要任何CPU操作控制。

二、 DMA 工作模式

  • STM32F4中DMA的工作模式分为外设到存储器传输存储器到外设传输存储器到存储器传输三种。
  • 这里的外设通常指外设的数据寄存器,如USART、ADC、SPI、I2C等外设的数据寄存器。存储器通常指片内SRAM、片内Flash、片外存储器等。
外设到存储器传输把外设数据寄存器中的数据传输至指定的内存空间
存储器到外设传输把特定存储区内的数据传输至外设的数据寄存器,多用于外设的发送通信
存储器到存储器传输把指定存储区的内容拷贝到另一个存储区空间

二、 DMA 功能框图

  • STM32F4有两个DMA控制器,即DMA1和DMA2。
    在这里插入图片描述
1. 数据流与通道
  • 每个DMA控制器都有8个数据流,每个数据流都有8个外设通道。
  • 在实现DMA传输前,DMA控制器会通过DMA数据流x配置寄存器DMA_SxCR(x为0~7,对应8个DMA数据流)的CHSEL[2:0]位确定一个外设通道:
    在这里插入图片描述
    在这里插入图片描述
  • 选择外设通道的意义在于确定该数据流的源地址或目标地址。
  • DMA1和DMA2的请求映射参考STM32F4xx中文参考手册
    在这里插入图片描述
    在这里插入图片描述
2.仲裁器
  • 仲裁器用于裁决多个数据流的优先级。
    在这里插入图片描述
  • 仲裁器管理数据流分为软件阶段和硬件阶段。
  • 软件阶段即通过寄存器配置数据流的优先级。具体涉及DMA_SxCR寄存器的PL[1:0]位,可设为非常高、高、中和低四个级别:
    在这里插入图片描述
    在这里插入图片描述
  • 若两个及以上的数据流优先级软件设置一样,则通过数据流编号取决优先级,编号越低优先级越高,即数据流2的优先级高于数据流3。
3.FIFO

在这里插入图片描述

  • 每个数据流都独立拥有四级32位FIFO(先进先出存储器缓冲区),即大小为4个字。
  • DMA传输具有直接模式和FIFO模式。
直接模式立即响应DMA传输请求,把数据传过去
FIFO模式临时存储数据,待数据量达到阈值级别时,再发送数据
  • FIFO模式在源地址和目标地址数据宽度不同的情况下十分有用。如源数据是源源不断的字节数据,目标地址要求输出字宽度的数据,此时可以使用FIFO功能先把数据缓存起来,然后根据需要输出数据。
  • FIFO 模式也可用于突发(burst)传输。

四、 应用

目标1:通过 DMA 把 STM32 内部 FLASH 的数据传输到内部 SRAM
  • dma.c
#include "dma.h"

/* 定义 aSRC_Const_Buffer 数组作为 DMA 传输数据源,
	 const关键字 使该数组为常量类型 */
const uint32_t aSRC_Const_Buffer[BUFFER_SIZE]= {
                                    0x01020304,0x05060708,0x090A0B0C,0x0D0E0F10,
                                    0x11121314,0x15161718,0x191A1B1C,0x1D1E1F20,
                                    0x21222324,0x25262728,0x292A2B2C,0x2D2E2F30,
                                    0x31323334,0x35363738,0x393A3B3C,0x3D3E3F40,
                                    0x41424344,0x45464748,0x494A4B4C,0x4D4E4F50,
                                    0x51525354,0x55565758,0x595A5B5C,0x5D5E5F60,
                                    0x61626364,0x65666768,0x696A6B6C,0x6D6E6F70,
                                    0x71727374,0x75767778,0x797A7B7C,0x7D7E7F80};

/* 定义 DMA 传输目标存储器 */																		
uint32_t aDST_Buffer[BUFFER_SIZE];																		
						
												
void MtoM_DMA_Config(void) 
{
		DMA_InitTypeDef  DMA_InitStructure;
		__IO uint32_t    Timeout = TIMEOUT_MAX;
	
		RCC_AHB1PeriphClockCmd(DMA_STREAM_CLOCK, ENABLE);           								// 开启 DMA2 时钟

		/* 1. 复位初始化 DMA 数据流 */
		DMA_DeInit(DMA_STREAM);
		while(DMA_GetCmdStatus(DMA_STREAM) != DISABLE);             								// 确保 DMA 数据流复位完成
	
		/* 2. 配置 DMA 初始化结构体 */
		DMA_InitStructure.DMA_Channel 			 = DMA_CHANNEL;
		DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t) aSRC_Const_Buffer;    // 源地址
		DMA_InitStructure.DMA_Memory0BaseAddr    = (uint32_t) aDST_Buffer;  	    // 目标地址
		DMA_InitStructure.DMA_DIR 				 = DMA_DIR_MemoryToMemory;          // 存储器到存储器模式 
		DMA_InitStructure.DMA_BufferSize 		 = (uint32_t)BUFFER_SIZE;           // 待传输数据数目
		DMA_InitStructure.DMA_PeripheralInc      = DMA_PeripheralInc_Enable;        // 使能地址递增                  
		DMA_InitStructure.DMA_MemoryInc          = DMA_MemoryInc_Enable;            // 使能地址递增  
		DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Word;     // 源数据是字大小(32 位)
		DMA_InitStructure.DMA_MemoryDataSize     = DMA_MemoryDataSize_Word;			// 目标数据是字大小(32 位)
		DMA_InitStructure.DMA_Mode               = DMA_Mode_Normal;                 // 一次传输模式,存储器到存储器模式 不能使用循环传输
		DMA_InitStructure.DMA_Priority           = DMA_Priority_High;               // DMA 数据流优先级为高
		DMA_InitStructure.DMA_FIFOMode           = DMA_FIFOMode_Disable;            // 禁用 FIFO 模式
		DMA_InitStructure.DMA_FIFOThreshold      = DMA_FIFOThreshold_Full; 
		DMA_InitStructure.DMA_MemoryBurst        = DMA_MemoryBurst_Single;          // 单次模式
		DMA_InitStructure.DMA_PeripheralBurst    = DMA_PeripheralBurst_Single;
		
		DMA_Init(DMA_STREAM, &DMA_InitStructure);
		
		DMA_Cmd(DMA_STREAM, ENABLE);                                                // 使能 DMA 数据流,开始 DMA 数据传输

		Timeout = TIMEOUT_MAX;
		while ((DMA_GetCmdStatus(DMA_STREAM) != ENABLE) && (Timeout-- > 0));        // 检测 DMA 数据流是否有效(带有超时检查功能)

		if (Timeout == 0)                                                           // 判断是否超时
		{
				while (1)
				{      
						LED0_TOGGLE;											    // 超时则使红灯一直闪烁
						delay_ms(500);
				}
		} 
}


/**
  * @brief  判断两个指定长度的数据源是否完全相同
  * @param  pBuffer1    :uint32_t类型指针(指向数据为常量)
  * @param  pBuffer2    : uint32_t类型指针
  * @param  BufferLength: 比较数据个数
  * @retval 完全相同返回1;不完全相同返回0
  */
uint8_t Buffercmp(const uint32_t* pBuffer1, 
                  uint32_t* pBuffer2, uint16_t BufferLength)
{
  
  while(BufferLength--)                                                         // 数据长度递减
  {
    
    if(*pBuffer1 != *pBuffer2)                                                  // 判断两个数据源是否相同
    {
      return 0;						                                            // 不同则立即返回0
    }

    pBuffer1++;		                                                            // 递增两个数据源的指针
    pBuffer2++;
  }

  return 1;  	                                                     		    // 完成判断,且对应数据相同,返回1
}
  • dma.h
#ifndef __DMA_H
#define __DMA_H

#include "stm32f4xx.h"
#include "delay.h"
#include "led.h"

/* -------------------------- FLASH to SRAM --------------------------- */

#define DMA_STREAM               DMA2_Stream0
#define DMA_CHANNEL              DMA_Channel_0
#define DMA_STREAM_CLOCK         RCC_AHB1Periph_DMA2 
#define DMA_FLAG_TCIF            DMA_FLAG_TCIF0

#define BUFFER_SIZE              32
#define TIMEOUT_MAX              10000
																		
extern const uint32_t aSRC_Const_Buffer[BUFFER_SIZE];
extern uint32_t aDST_Buffer[BUFFER_SIZE];

void MtoM_DMA_Config(void);
uint8_t Buffercmp(const uint32_t* pBuffer1, 
                  uint32_t* pBuffer2, uint16_t BufferLength);																		

#endif
  • main.c
#include "stm32f4xx.h"
#include "dma.h"
#include "usart.h"

int main(void) 
{
		uint8_t TransferStatus;
		
		LED_Config(); 
		USART1_Config(); 
		MtoM_DMA_Config();	
		
		while (DMA_GetFlagStatus(DMA_STREAM, DMA_FLAG_TCIF)==DISABLE);   // 等待 DMA 传输完成
		
		TransferStatus = Buffercmp(aSRC_Const_Buffer, aDST_Buffer, BUFFER_SIZE);
		if( TransferStatus == 0) 
		{
			printf("数据发送错误~");
		}
		else
		{
			printf("数据发送无误~");
		}
 
		while(1)
		{
		
		}
}
目标2:通过 DMA 把 STM32 内部 SRAM 的数据传输到 USART2, 再通过 USART2 接收中断把数据转发到上位机。
  • dma.c
#include "dma.h"

/* 定义 aSRC_Const_Buffer 数组作为 DMA 传输数据源,
	 const关键字 使该数组为常量类型 */
const uint32_t aSRC_Const_Buffer[BUFFER_SIZE]= {
                                    0x01020304,0x05060708,0x090A0B0C,0x0D0E0F10,
                                    0x11121314,0x15161718,0x191A1B1C,0x1D1E1F20,
                                    0x21222324,0x25262728,0x292A2B2C,0x2D2E2F30,
                                    0x31323334,0x35363738,0x393A3B3C,0x3D3E3F40,
                                    0x41424344,0x45464748,0x494A4B4C,0x4D4E4F50,
                                    0x51525354,0x55565758,0x595A5B5C,0x5D5E5F60,
                                    0x61626364,0x65666768,0x696A6B6C,0x6D6E6F70,
                                    0x71727374,0x75767778,0x797A7B7C,0x7D7E7F80};

/* 定义 DMA 传输目标存储器 */																		
uint32_t aDST_Buffer[BUFFER_SIZE];
																		
uint8_t SendBuff[SENDBUFF_SIZE];																		
						
												
void MtoM_DMA_Config(void) 
{
		DMA_InitTypeDef  DMA_InitStructure;
		__IO uint32_t    Timeout = TIMEOUT_MAX;
	
		RCC_AHB1PeriphClockCmd(DMA_STREAM_CLOCK, ENABLE);           				// 开启 DMA2 时钟

		/* 1. 复位初始化 DMA 数据流 */
		DMA_DeInit(DMA_STREAM);
		while(DMA_GetCmdStatus(DMA_STREAM) != DISABLE);             				// 确保 DMA 数据流复位完成
	
		/* 2. 配置 DMA 初始化结构体 */
		DMA_InitStructure.DMA_Channel 			 = DMA_CHANNEL;
		DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t) aSRC_Const_Buffer;    // 源地址
		DMA_InitStructure.DMA_Memory0BaseAddr    = (uint32_t) aDST_Buffer;  		// 目标地址
		DMA_InitStructure.DMA_DIR 				 = DMA_DIR_MemoryToMemory;          // 存储器到存储器模式 
		DMA_InitStructure.DMA_BufferSize 		 = (uint32_t)BUFFER_SIZE;           // 待传输数据数目
		DMA_InitStructure.DMA_PeripheralInc      = DMA_PeripheralInc_Enable;        // 使能地址递增                  
		DMA_InitStructure.DMA_MemoryInc          = DMA_MemoryInc_Enable;            // 使能地址递增  
		DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Word;     // 源数据是字大小(32 位)
		DMA_InitStructure.DMA_MemoryDataSize     = DMA_MemoryDataSize_Word;			// 目标数据是字大小(32 位)
		DMA_InitStructure.DMA_Mode               = DMA_Mode_Normal;                 // 一次传输模式,存储器到存储器模式 不能使用循环传输
		DMA_InitStructure.DMA_Priority           = DMA_Priority_High;               // DMA 数据流优先级为高
		DMA_InitStructure.DMA_FIFOMode           = DMA_FIFOMode_Disable;            // 禁用 FIFO 模式
		DMA_InitStructure.DMA_FIFOThreshold      = DMA_FIFOThreshold_Full; 
		DMA_InitStructure.DMA_MemoryBurst        = DMA_MemoryBurst_Single;          // 单次模式
		DMA_InitStructure.DMA_PeripheralBurst    = DMA_PeripheralBurst_Single;
		
		DMA_Init(DMA_STREAM, &DMA_InitStructure);
		
		DMA_Cmd(DMA_STREAM, ENABLE);                                                // 使能 DMA 数据流,开始 DMA 数据传输

		Timeout = TIMEOUT_MAX;
		while ((DMA_GetCmdStatus(DMA_STREAM) != ENABLE) && (Timeout-- > 0));        // 检测 DMA 数据流是否有效(带有超时检查功能)

		if (Timeout == 0)                                                           // 判断是否超时
		{
				while (1)
				{      
						LED0_TOGGLE;																												// 超时则使红灯一直闪烁
						delay_ms(500);
				}
		} 
}


void PtoM_DMA_Config(void) 
{
		DMA_InitTypeDef  DMA_InitStructure;
		__IO uint32_t    Timeout = TIMEOUT_MAX;
	
		RCC_AHB1PeriphClockCmd(USART2_DMA_CLK, ENABLE);           					// 开启 DMA1 时钟

		/* 1. 复位初始化 DMA 数据流 */
		DMA_DeInit(USART2_DMA_STREAM);
		while(DMA_GetCmdStatus(USART2_DMA_STREAM) != DISABLE);             			// 确保 DMA 数据流复位完成
	
		/* 2. 配置 DMA 初始化结构体 */
		DMA_InitStructure.DMA_Channel 			 = USART2_DMA_CHANNEL;
		DMA_InitStructure.DMA_PeripheralBaseAddr = USART2_DR_BASE;    				// 外设地址: USART2 数据寄存器地址
	  DMA_InitStructure.DMA_Memory0BaseAddr      = (uint32_t) SendBuff;  			// 内存地址: 要传输的变量的指针
		DMA_InitStructure.DMA_DIR 				 = DMA_DIR_MemoryToPeripheral;      // 存储器到外设模式 
		DMA_InitStructure.DMA_BufferSize 		 = (uint32_t)SENDBUFF_SIZE;         // 待传输数据数目
		DMA_InitStructure.DMA_PeripheralInc      = DMA_PeripheralInc_Disable;       // 外设地址不增                  
		DMA_InitStructure.DMA_MemoryInc          = DMA_MemoryInc_Enable;            // 内存地址递增  
		DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;     // 外设数据单位 1 byte
		DMA_InitStructure.DMA_MemoryDataSize     = DMA_MemoryDataSize_Byte;			// 内存数据单位 1 byte
		DMA_InitStructure.DMA_Mode               = DMA_Mode_Normal;                 // 一次传输模式,存储器到存储器模式 不能使用循环传输
		DMA_InitStructure.DMA_Priority           = DMA_Priority_Medium;             // DMA 数据流优先级为中
		DMA_InitStructure.DMA_FIFOMode           = DMA_FIFOMode_Disable;            // 禁用 FIFO 模式
		DMA_InitStructure.DMA_FIFOThreshold      = DMA_FIFOThreshold_Full; 
		DMA_InitStructure.DMA_MemoryBurst        = DMA_MemoryBurst_Single;          // 单次模式
		DMA_InitStructure.DMA_PeripheralBurst    = DMA_PeripheralBurst_Single;
		
		DMA_Init(USART2_DMA_STREAM, &DMA_InitStructure);
		
		DMA_Cmd(USART2_DMA_STREAM, ENABLE);                                         // 使能 DMA 数据流,开始 DMA 数据传输

		Timeout = TIMEOUT_MAX;
		while ((DMA_GetCmdStatus(USART2_DMA_STREAM) != ENABLE) && (Timeout-- > 0)); // 检测 DMA 数据流是否有效(带有超时检查功能)

		if (Timeout == 0)                                                           // 判断是否超时
		{
				while (1)
				{      
						LED0_TOGGLE;																												// 超时则使红灯一直闪烁
						delay_ms(500);
				}
		}

}


/**
  * @brief  判断两个指定长度的数据源是否完全相同
  * @param  pBuffer1    :uint32_t类型指针(指向数据为常量)
  * @param  pBuffer2    : uint32_t类型指针
  * @param  BufferLength: 比较数据个数
  * @retval 完全相同返回1;不完全相同返回0
  */
uint8_t Buffercmp(const uint32_t* pBuffer1, 
                  uint32_t* pBuffer2, uint16_t BufferLength)
{
  
  while(BufferLength--)                                                         // 数据长度递减
  {
    
    if(*pBuffer1 != *pBuffer2)                                                  // 判断两个数据源是否相同
    {
      return 0;						                                            // 不同则立即返回0
    }

    pBuffer1++;		                                                            // 递增两个数据源的指针
    pBuffer2++;
  }

  return 1;  	                                                     			// 完成判断,且对应数据相同,返回1
}
  • dma.h
#ifndef __DMA_H
#define __DMA_H


#include "stm32f4xx.h"
#include "delay.h"
#include "led.h"

/* -------------------------- FLASH to SRAM --------------------------- */

#define DMA_STREAM               DMA2_Stream0
#define DMA_CHANNEL              DMA_Channel_0
#define DMA_STREAM_CLOCK         RCC_AHB1Periph_DMA2 
#define DMA_FLAG_TCIF            DMA_FLAG_TCIF0

#define BUFFER_SIZE              32
#define TIMEOUT_MAX              10000
																		
/* ----------------------- FLASH to Peripheral ------------------------ */

#define USART2_DR_BASE               (USART2_BASE+0x04)		
#define SENDBUFF_SIZE                5000				//发送的数据量
#define USART2_DMA_CLK               RCC_AHB1Periph_DMA1	
#define USART2_DMA_CHANNEL           DMA_Channel_4
#define USART2_DMA_STREAM            DMA1_Stream6


extern const uint32_t aSRC_Const_Buffer[BUFFER_SIZE];
extern uint32_t aDST_Buffer[BUFFER_SIZE];
extern uint8_t SendBuff[SENDBUFF_SIZE];

void MtoM_DMA_Config(void);
void PtoM_DMA_Config(void);
uint8_t Buffercmp(const uint32_t* pBuffer1, 
                  uint32_t* pBuffer2, uint16_t BufferLength);																		


#endif
  • usart.c
#include "usart.h"


static void USART1_NVIC_Config(void);
static void USART2_NVIC_Config(void);


void USART1_Config(void) 
{
		GPIO_InitTypeDef  GPIO_InitStructure;
		USART_InitTypeDef USART_InitStructure;
	
		RCC_AHB1PeriphClockCmd(USART1_TX_CLK | USART1_RX_CLK, ENABLE);					   				// 使能相应 GPIO 时钟
		RCC_APB2PeriphClockCmd(USART1_CLK, ENABLE);														// 使能 UART1 时钟
	
		/* 1. 配置 GPIO  */
		GPIO_InitStructure.GPIO_Mode  = GPIO_Mode_AF;       										 	// 复用功能模式
		GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;       										 	// 推挽输出 + 上拉电阻,以确保信号稳定和电平匹配
		GPIO_InitStructure.GPIO_PuPd  = GPIO_PuPd_UP;
		GPIO_InitStructure.GPIO_Speed = GPIO_Fast_Speed;     									        // 50MHz
	
		GPIO_InitStructure.GPIO_Pin   = USART1_TX_PIN;
		GPIO_Init(USART1_TX_PORT, &GPIO_InitStructure);
	
		GPIO_InitStructure.GPIO_Pin   = USART1_RX_PIN;
		GPIO_Init(USART1_RX_PORT, &GPIO_InitStructure);
	
		/* 2. 连接 GPIOX_X 到 UARTx  */
		GPIO_PinAFConfig(USART1_TX_PORT, USART1_TX_SOURCE, USART1_TX_AF);
		GPIO_PinAFConfig(USART1_RX_PORT, USART1_RX_SOURCE, USART1_RX_AF);
		
		/* 3. 配置 USART  */
		USART_InitStructure.USART_BaudRate 						= USART1_BAUDRATE;                    // 波特率
		USART_InitStructure.USART_WordLength 					= USART_WordLength_8b;                // 字长 (数据位 + 校验位):8
		USART_InitStructure.USART_Parity  						= USART_Parity_No;                    // 无奇偶校验
		USART_InitStructure.USART_StopBits 						= USART_StopBits_1;                   // 1位停止位
		USART_InitStructure.USART_HardwareFlowControl           = USART_HardwareFlowControl_None;     // 不使用硬件流
		USART_InitStructure.USART_Mode 							= USART_Mode_Rx | USART_Mode_Tx;      // 同时使能发送和接收
		
		USART_Init(USART1, &USART_InitStructure);
		
		/* 4. 配置 USART 中断  */
		USART1_NVIC_Config();
		
		/* 5. 使能 USART 接收中断  */
		USART_ITConfig(USART1, USART_IT_RXNE, DISABLE);                                     // 注:需要使用中断时,应置为ENABLE
		
		/* 6. 使能 USART1 */
		USART_Cmd(USART1, ENABLE);
}


void USART2_Config(void) 
{
		GPIO_InitTypeDef  GPIO_InitStructure;
		USART_InitTypeDef USART_InitStructure;
	
		RCC_AHB1PeriphClockCmd(USART2_TX_CLK | USART2_RX_CLK, ENABLE);					   	// 使能相应 GPIO 时钟
		RCC_APB1PeriphClockCmd(USART2_CLK, ENABLE);											// 使能 UART2 时钟
	
		/* 1. 配置 GPIO  */
		GPIO_InitStructure.GPIO_Mode  = GPIO_Mode_AF;       								// 复用功能模式
		GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;       								// 推挽输出 + 上拉电阻,以确保信号稳定和电平匹配
		GPIO_InitStructure.GPIO_PuPd  = GPIO_PuPd_UP;
		GPIO_InitStructure.GPIO_Speed = GPIO_Fast_Speed;     								// 50MHz
	
		GPIO_InitStructure.GPIO_Pin   = USART2_TX_PIN;
		GPIO_Init(USART2_TX_PORT, &GPIO_InitStructure);
	
		GPIO_InitStructure.GPIO_Pin   = USART2_RX_PIN;
		GPIO_Init(USART2_RX_PORT, &GPIO_InitStructure);
	
		/* 2. 连接 GPIOX_X 到 UARTx  */
		GPIO_PinAFConfig(USART2_TX_PORT, USART2_TX_SOURCE, USART2_TX_AF);
		GPIO_PinAFConfig(USART2_RX_PORT, USART2_RX_SOURCE, USART2_RX_AF);
		
		/* 3. 配置 USART  */
		USART_InitStructure.USART_BaudRate 						= USART2_BAUDRATE;                    // 波特率
		USART_InitStructure.USART_WordLength 					= USART_WordLength_8b;                // 字长 (数据位 + 校验位):8
		USART_InitStructure.USART_Parity  						= USART_Parity_No;                    // 无奇偶校验
		USART_InitStructure.USART_StopBits 						= USART_StopBits_1;                   // 1位停止位
		USART_InitStructure.USART_HardwareFlowControl           = USART_HardwareFlowControl_None;     // 不使用硬件流
		USART_InitStructure.USART_Mode 							= USART_Mode_Rx | USART_Mode_Tx;      // 同时使能发送和接收
		
		USART_Init(USART2, &USART_InitStructure);
		
		/* 4. 配置 USART 中断  */
		USART2_NVIC_Config();
		
		/* 5. 使能 USART 接收中断  */
		USART_ITConfig(USART2, USART_IT_RXNE, DISABLE); 
		
		/* 6. 使能 USART2 */
		USART_Cmd(USART2, ENABLE);
}


void USART1_NVIC_Config(void)
{
		NVIC_InitTypeDef NVIC_InitStructure;
	
		NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);           						 				// 配置中断优先级分组
	 
		NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;							 			// 主优先级
		NVIC_InitStructure.NVIC_IRQChannelSubPriority        = 1;							 			// 子优先级
		NVIC_InitStructure.NVIC_IRQChannelCmd                = ENABLE;
	
		NVIC_InitStructure.NVIC_IRQChannel                   = USART1_EXTI_IRQ; 						// 中断通道
		NVIC_Init(&NVIC_InitStructure);
}

void USART2_NVIC_Config(void)
{
		NVIC_InitTypeDef NVIC_InitStructure;
	
		NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);           						 				// 配置中断优先级分组
	 
		NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;							 			// 主优先级
		NVIC_InitStructure.NVIC_IRQChannelSubPriority        = 1;							 			// 子优先级
		NVIC_InitStructure.NVIC_IRQChannelCmd                = ENABLE;
	
		NVIC_InitStructure.NVIC_IRQChannel                   = USART2_EXTI_IRQ; 						// 中断通道
		NVIC_Init(&NVIC_InitStructure);
}


/**
  * @brief  通过 USART 发送 8 bit 数据
  * @param  USARTx: 发送数据的USART
  * @param  data  : 待发送的数据
  * @retval 无
  */

void Usart_SendByte(USART_TypeDef* USARTx, uint8_t data) 
{
    USART_SendData(USARTx, data);                                                       // 发送数据
		while (USART_GetFlagStatus(USARTx, USART_FLAG_TXE) == RESET);                   // 等待发送数据寄存器为空
}


/**
  * @brief  通过 USART 发送 16 bit 数据
  * @param  USARTx: 发送数据的USART
  * @param  data  : 待发送的数据
  * @retval 无
  */
void Usart_SendHalfWord(USART_TypeDef* USARTx, uint16_t data)
{
	uint8_t temp_h, temp_l;
	
	temp_h = (data & 0XFF00)>>8;                                                          // 取出高八位
	
	temp_l = data & 0XFF;                                                                 // 取出低八位 
	
	USART_SendData(USARTx,temp_h);	                                                      // 发送高八位
	while (USART_GetFlagStatus(USARTx, USART_FLAG_TXE) == RESET);
	
	USART_SendData(USARTx,temp_l);	                                                      // 发送低八位
	while (USART_GetFlagStatus(USARTx, USART_FLAG_TXE) == RESET);	
}


/**
  * @brief  通过 USART 发送字符串
  * @param  USARTx: 发送数据的USART
  * @param  *str  : 待发送的字符串
  * @retval 无
  */
void Usart_SendString(USART_TypeDef * USARTx, char *str)
{
	unsigned int k=0;
	
  do 
  {
      Usart_SendByte(USARTx, *(str + k) );
      k++;
  } while( *(str + k) != '\0' );
  
  while(USART_GetFlagStatus(USARTx,USART_FLAG_TC)==RESET);
}


/**
  * @brief  重定向c库函数printf到串口,重定向后可使用printf函数
  */
int fputc(int ch, FILE *f)
{
		USART_SendData(USART1, (uint8_t) ch);
		while (USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET);		
	
		return (ch);
}

/**
  * @brief  重定向c库函数scanf到串口,重写向后可使用scanf、getchar等函数
  */
int fgetc(FILE *f)
{
		while (USART_GetFlagStatus(USART1, USART_FLAG_RXNE) == RESET);                      // 等待串口输入数据

		return (int)USART_ReceiveData(USART1);
}
  • usart.h
#ifndef __UART_H
#define __UART_H

#include <stdio.h>
#include "stm32f4xx.h"

/* --------------------- USART1 --------------------- 
   -------------------------------------------------- */
	 
#define USART1_BAUDRATE         115200                     
#define USART1_CLK              RCC_APB2Periph_USART1
#define USART1_EXTI_IRQ         USART1_IRQn
#define USART1_IRQHandler       USART1_IRQHandler


#define USART1_TX_CLK           RCC_AHB1Periph_GPIOA
#define USART1_TX_PORT          GPIOA
#define USART1_TX_PIN           GPIO_Pin_9
#define USART1_TX_SOURCE		GPIO_PinSource9
#define USART1_TX_AF            GPIO_AF_USART1


#define USART1_RX_CLK           RCC_AHB1Periph_GPIOA
#define USART1_RX_PORT          GPIOA
#define USART1_RX_PIN           GPIO_Pin_10
#define USART1_RX_SOURCE		GPIO_PinSource10
#define USART1_RX_AF            GPIO_AF_USART1

/* --------------------- USART2 ---------------------
   -------------------------------------------------- */

#define USART2_BAUDRATE         115200
#define USART2_CLK              RCC_APB1Periph_USART2
#define USART2_EXTI_IRQ         USART2_IRQn
#define USART2_IRQHandler       USART2_IRQHandler


#define USART2_TX_CLK           RCC_AHB1Periph_GPIOA
#define USART2_TX_PORT          GPIOA
#define USART2_TX_PIN           GPIO_Pin_2
#define USART2_TX_SOURCE		GPIO_PinSource2
#define USART2_TX_AF            GPIO_AF_USART2


#define USART2_RX_CLK           RCC_AHB1Periph_GPIOA
#define USART2_RX_PORT          GPIOA
#define USART2_RX_PIN           GPIO_Pin_3
#define USART2_RX_SOURCE		GPIO_PinSource3
#define USART2_RX_AF            GPIO_AF_USART2


void USART1_Config(void); 
void USART2_Config(void); 
void Usart_SendByte(USART_TypeDef* USARTx, uint8_t data);
void Usart_SendHalfWord(USART_TypeDef* USARTx, uint16_t data);
void Usart_SendString(USART_TypeDef * USARTx, char *str);


#endif

  • stm32f4xx_it.c添加 usart2 的中断接收服务函数
void USART2_IRQHandler(void)
{
		uint8_t ucTemp;
		if(USART_GetITStatus(USART2, USART_IT_RXNE) != RESET)
		{		
			ucTemp = USART_ReceiveData(USART2);
			USART_SendData(USART2, ucTemp);    
		}			
}

  • main.c
#include "stm32f4xx.h"
#include "usart.h"
#include "delay.h"
#include "led.h"
#include "dma.h"

int main(void) 
{
		uint16_t i;
	
		LED_Config(); 
		USART2_Config();
		PtoM_DMA_Config();
	
		for(i = 0; i < SENDBUFF_SIZE; i++)             // 准备要发送的数据
		{
				SendBuff[i] = 'Q';
		}
	
		USART_DMACmd(USART2, USART_DMAReq_Tx, ENABLE); // USART2 向 DMA 发出 Tx 请求
 
		while(1)
		{
				delay_ms(500);
				LED0_TOGGLE;

		}
}
STM32F429IGT6是意法半导体(STMicroelectronics)推出的一款高性能的32位微控制器,它拥有许多强大的功能,其中之一是ADC DMA。 ADC是模数转换器(Analog-to-Digital Converter)的缩写,它用于将模拟信号转换成数字信号。而DMA是直接内存访问(Direct Memory Access)的缩写,它允许数据在外设和内存之间直接传输,无需CPU的干预。 STM32F429IGT6的ADC DMA功能允许使用者通过配置DMA通道,实现ADC转换结果的自动传输到指定的内存区域。这种自动传输的特性可以极大地减轻CPU的负担,提高系统性能。 使用ADC DMA的主要步骤如下: 1. 配置ADC模块:设置ADC的采样通道、采样时间、转换模式等参数。 2. 配置DMA通道:选择合适的DMA通道,设置DMA传输模式、传输方向和传输大小等参数。 3. 配置ADC DMA请求:使能ADC的DMA请求,以便触发DMA传输。 4. 配置目标内存区域:选择合适的内存区域作为ADC DMA传输的目标地址。 5. 启动ADC和DMA:启动ADC和DMA传输。 6. 等待转换完成:使用者可以选择通过中断或查询方式等待DMA传输的完成。 7. 处理转换结果:获取转换的结果,对其进行进一步处理或使用。 通过使用STM32F429IGT6的ADC DMA功能,可以实现高效的模拟信号采集和处理,提高系统的实时性和效率。同时,它还可以减少CPU的负担,释放CPU的处理能力用于其他任务。这使得STM32F429IGT6在许多应用领域都得到了广泛应用,例如工业自动化、医疗设备、网络通信等。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值