STM32:DMA实例之串口(USART)通信

硬件平台:stm32f10xZET6
开发环境:keil MDK uVision v4.10
开发语言:C、ST_lib_3.5固件库

/* 代码演示 main.c */
#include "stm32f10x.h"
#include "bsp_usart1.h"
#include "bsp_led.h"

extern uint8_t SendBuff[SENDBUFF_SIZE];
static void Delay(__IO u32 nCount); 

/**
  * @brief  主函数
  */
int main(void)
{
		/* USART1 config 115200 8-N-1 */
		USART1_Config();
	
		USART1_DMA_Config();
	
		LED_GPIO_Config();
	
		printf ("\r\n usart1 DMA TX test... \r\n");
	
		{
			uint16_t i;
			/*填充将要发送的数据*/
			for(i=0;i<SENDBUFF_SIZE;i++)
			{
				SendBuff[i]	 = 'a'; // 打字母a仅做演示
			}
		}
		
		/* USART1 向 DMA发出TX请求 */
		USART_DMACmd(USART1, USART_DMAReq_Tx, ENABLE);

		/* 此时CPU是空闲的,可以干其他的事情 */
		
		//例如同时控制LED
		for(;;)
		{
			LED1(ON);
			Delay(0xFFFFF);
			LED1(OFF);
			Delay(0xFFFFF);
		}
}

static void Delay(__IO uint32_t nCount)	 //简单的延时函数
{
	for(; nCount != 0; nCount--);
}
/* 中断处理函数 stm32f10x_it.c line:157 */
void DMA1_Channel4_IRQHandler(void)
{
	//判断是否为 DMA 发送完成中断
	if (DMA_GetFlagStatus(DMA1_FLAG_TC4)==SET)
	{
		//LED 关闭
		LED1(OFF);


		DMA_ClearFlag(DMA1_FLAG_TC4);
	}
}
/* 代码演示 bsp_usart1模块 */
#ifndef __USART1_H
#define	__USART1_H


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


#define USART1_DR_Base  0x40013804		// 0x40013800 + 0x04 = 0x40013804
#define SENDBUFF_SIZE   5000


void USART1_Config(void);
void USART1_DMA_Config(void);


#endif /* __USART1_H */
// ------------------------------------------------------
#include "bsp_usart1.h"


uint8_t SendBuff[SENDBUFF_SIZE];


/**
  * @brief  USART1 GPIO 配置,工作模式配置。115200 8-N-1
  * @param  无
  * @retval 无
  */
void USART1_Config(void)
{
		GPIO_InitTypeDef GPIO_InitStructure;
		USART_InitTypeDef USART_InitStructure;
		
		/* config USART1 clock */
		RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1 | RCC_APB2Periph_GPIOA, ENABLE);
		
		/* USART1 GPIO config */
		/* Configure USART1 Tx (PA.09) as alternate function push-pull */
		GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
		GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
		GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
		GPIO_Init(GPIOA, &GPIO_InitStructure);    
		/* Configure USART1 Rx (PA.10) as input floating */
		GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
		GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
		GPIO_Init(GPIOA, &GPIO_InitStructure);
			
		/* USART1 mode config */
		USART_InitStructure.USART_BaudRate = 115200;
		USART_InitStructure.USART_WordLength = USART_WordLength_8b;
		USART_InitStructure.USART_StopBits = USART_StopBits_1;
		USART_InitStructure.USART_Parity = USART_Parity_No ;
		USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
		USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;


		USART_Init(USART1, &USART_InitStructure); 
		USART_Cmd(USART1, ENABLE);
}


/**
  * @brief  USART1 TX DMA 配置,内存到外设(USART1->DR)
  * @param  无
  * @retval 无
  */
void USART1_DMA_Config(void)
{
		DMA_InitTypeDef DMA_InitStructure;
	
		/*开启DMA时钟*/
		RCC_AHBPeriphClockCmd (RCC_AHBPeriph_DMA1, ENABLE);


		/*传输大小DMA_BufferSize=SENDBUFF_SIZE*/	
		DMA_InitStructure.DMA_BufferSize = SENDBUFF_SIZE;  // 此处是发送的buffer的配置
		/*方向:从内存到外设*/		
		DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;
		/*禁止内存到内存的传输	*/
		DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;


		/*内存地址(要传输的变量的指针)*/
		DMA_InitStructure.DMA_MemoryBaseAddr = (u32)SendBuff;
		/*内存数据单位 8bit*/
		DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
		/*内存地址自增*/
		DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;


		/*DMA模式:不断循环*/
		DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;	 
						 
		/* 设置DMA源:串口数据寄存器地址 */
		DMA_InitStructure.DMA_PeripheralBaseAddr = USART1_DR_Base;
		/* 外设数据单位:字节 */	
		DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;			   
 		/* 外设地址不增 */	    
		DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; 


		/*优先级:中*/	
		DMA_InitStructure.DMA_Priority = DMA_Priority_Medium;  


		/*配置DMA1的4通道*/		   
		DMA_Init(DMA1_Channel4, &DMA_InitStructure); 	   
		
		/*使能DMA*/
		DMA_Cmd (DMA1_Channel4,ENABLE);					
		//DMA_ITConfig(DMA1_Channel4, DMA_IT_TC,ENABLE);  // 配置DMA发送完成后产生中断
}


/// 重定向c库函数printf到USART1
int fputc(int ch, FILE *f)
{
		/* 发送一个字节数据到USART1 */
		USART_SendData(USART1, (uint8_t) ch);
		
		/* 等待发送完毕 */
		while (USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET);		
	
		return (ch);
}


/// 重定向c库函数scanf到USART1
int fgetc(FILE *f)
{
		/* 等待串口1输入数据 */
		while (USART_GetFlagStatus(USART1, USART_FLAG_RXNE) == RESET);


		return (int)USART_ReceiveData(USART1);
}
/* 代码演示 bsp_led模块 */
#ifndef __LED_H
#define	__LED_H


#include "stm32f10x.h"


/** the macro definition to trigger the led on or off 
  * 1 - off
  *0 - on
  */
#define ON  0
#define OFF 1


/* 带参宏,可以像内联函数一样使用 */
#define LED1(a)	if (a)	\
					GPIO_SetBits(GPIOB,GPIO_Pin_0);\
					else		\
					GPIO_ResetBits(GPIOB,GPIO_Pin_0)

#define LED2(a)	if (a)	\
					GPIO_SetBits(GPIOF,GPIO_Pin_7);\
					else		\
					GPIO_ResetBits(GPIOF,GPIO_Pin_7)

#define LED3(a)	if (a)	\
					GPIO_SetBits(GPIOF,GPIO_Pin_8);\
					else		\
					GPIO_ResetBits(GPIOF,GPIO_Pin_8)

void LED_GPIO_Config(void);

#endif /* __LED_H */
//---------------------------------------------------------
#include "bsp_led.h"   


 /**
  * @brief  初始化控制LED的IO
  * @param  无
  * @retval 无
  */
void LED_GPIO_Config(void)
{		
		/*定义一个GPIO_InitTypeDef类型的结构体*/
		GPIO_InitTypeDef GPIO_InitStructure;


		/*开启GPIOB和GPIOF的外设时钟*/
		RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOB|RCC_APB2Periph_GPIOF, ENABLE); 


		/*选择要控制的GPIOB引脚*/															   
		GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;	


		/*设置引脚模式为通用推挽输出*/
		GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;   


		/*设置引脚速率为50MHz */   
		GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; 


		/*调用库函数,初始化GPIOB0*/
		GPIO_Init(GPIOB, &GPIO_InitStructure);	
		
		/*选择要控制的GPIOF引脚*/															   
		GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7;


		/*调用库函数,初始化GPIOF7*/
		GPIO_Init(GPIOF, &GPIO_InitStructure);
		
		/*选择要控制的GPIOF引脚*/															   
		GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8;


		/*调用库函数,初始化GPIOF7*/
		GPIO_Init(GPIOF, &GPIO_InitStructure);			  


		/* 关闭所有led灯	*/
		GPIO_SetBits(GPIOB, GPIO_Pin_0);
		
		/* 关闭所有led灯	*/
		GPIO_SetBits(GPIOF, GPIO_Pin_7|GPIO_Pin_8);	 
}
*注:LED灯的管脚Pin根据开发板的不同,实际去调整即可。

  • 0
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
好的,下面是一个简单的示例代码,使用STM32F407标准库,实现USART2的DMA乒乓缓冲传输。 首先需要在CubeMX中配置USART2和DMA的相关参数,具体步骤如下: 1. 打开CubeMX软件,选择对应的芯片型号; 2. 在Pinout选项卡中配置USART2的引脚,将其映射到相应的GPIO口; 3. 在Configuration选项卡中配置USART2的参数,比如波特率、数据位数、停止位等; 4. 在DMA选项卡中配置DMA的参数,比如传输模式、数据大小、通道等。 接下来是示例代码: ```c #include "stm32f4xx.h" #include "stdio.h" #define BUFFER_SIZE 64 uint8_t buffer1[BUFFER_SIZE]; uint8_t buffer2[BUFFER_SIZE]; uint8_t* tx_buffer; uint8_t* rx_buffer; void USART2_DMA_Init(void) { DMA_InitTypeDef DMA_InitStruct; // 使能DMA2时钟 RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2, ENABLE); // 配置DMA2 Stream5通道4,用于USART2_RX DMA_DeInit(DMA2_Stream5); DMA_InitStruct.DMA_Channel = DMA_Channel_4; DMA_InitStruct.DMA_PeripheralBaseAddr = (uint32_t)&USART2->DR; DMA_InitStruct.DMA_Memory0BaseAddr = (uint32_t)&buffer1; DMA_InitStruct.DMA_DIR = DMA_DIR_PeripheralToMemory; DMA_InitStruct.DMA_BufferSize = BUFFER_SIZE; DMA_InitStruct.DMA_PeripheralInc = DMA_PeripheralInc_Disable; DMA_InitStruct.DMA_MemoryInc = DMA_MemoryInc_Enable; DMA_InitStruct.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte; DMA_InitStruct.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte; DMA_InitStruct.DMA_Mode = DMA_Mode_Circular; DMA_InitStruct.DMA_Priority = DMA_Priority_VeryHigh; DMA_InitStruct.DMA_FIFOMode = DMA_FIFOMode_Disable; DMA_InitStruct.DMA_FIFOThreshold = DMA_FIFOThreshold_Full; DMA_InitStruct.DMA_MemoryBurst = DMA_MemoryBurst_Single; DMA_InitStruct.DMA_PeripheralBurst = DMA_PeripheralBurst_Single; DMA_Init(DMA2_Stream5, &DMA_InitStruct); // 配置DMA2 Stream6通道4,用于USART2_TX DMA_DeInit(DMA2_Stream6); DMA_InitStruct.DMA_Channel = DMA_Channel_4; DMA_InitStruct.DMA_PeripheralBaseAddr = (uint32_t)&USART2->DR; DMA_InitStruct.DMA_Memory0BaseAddr = (uint32_t)&buffer2; DMA_InitStruct.DMA_DIR = DMA_DIR_MemoryToPeripheral; DMA_InitStruct.DMA_BufferSize = BUFFER_SIZE; DMA_InitStruct.DMA_PeripheralInc = DMA_PeripheralInc_Disable; DMA_InitStruct.DMA_MemoryInc = DMA_MemoryInc_Enable; DMA_InitStruct.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte; DMA_InitStruct.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte; DMA_InitStruct.DMA_Mode = DMA_Mode_Normal; DMA_InitStruct.DMA_Priority = DMA_Priority_VeryHigh; DMA_InitStruct.DMA_FIFOMode = DMA_FIFOMode_Disable; DMA_InitStruct.DMA_FIFOThreshold = DMA_FIFOThreshold_Full; DMA_InitStruct.DMA_MemoryBurst = DMA_MemoryBurst_Single; DMA_InitStruct.DMA_PeripheralBurst = DMA_PeripheralBurst_Single; DMA_Init(DMA2_Stream6, &DMA_InitStruct); // 使能USART2的DMA接收和发送 USART_DMACmd(USART2, USART_DMAReq_Rx|USART_DMAReq_Tx, ENABLE); // 启动DMA传输 DMA_Cmd(DMA2_Stream5, ENABLE); DMA_Cmd(DMA2_Stream6, DISABLE); // 初始化缓冲区指针 tx_buffer = buffer2; rx_buffer = buffer1; } void USART2_IRQHandler(void) { if (USART_GetITStatus(USART2, USART_IT_IDLE) != RESET) { // 读取数据长度,并清除IDLE标志 uint16_t len = USART2->SR; len = USART2->DR; len = DMA_GetCurrDataCounter(DMA2_Stream5); // 停止DMA接收 DMA_Cmd(DMA2_Stream5, DISABLE); // 切换缓冲区 uint8_t* tmp = tx_buffer; tx_buffer = rx_buffer; rx_buffer = tmp; // 启动DMA传输 DMA_SetCurrDataCounter(DMA2_Stream6, len); DMA_Cmd(DMA2_Stream5, ENABLE); DMA_Cmd(DMA2_Stream6, ENABLE); } } int main(void) { // 初始化USART2和DMA USART2_DMA_Init(); while (1) { // 在这里处理接收到的数据 // rx_buffer中存放的是上一个接收到的数据 // 如果需要实时处理数据,可以在DMA传输完成中断中处理 } } ``` 上面的代码中使用了双缓冲区,当USART2接收到数据后,会停止DMA接收,然后切换缓冲区,启动DMA传输。这样可以保证数据不会丢失,同时可以实现无间断地接收和发送数据。 需要注意的是,由于采用了DMA方式传输数据,因此在USART2接收到数据后,并不会立即进入中断处理函数。需要等待DMA传输完成后,才会进入中断处理函数。因此,如果需要实时处理数据,可以在DMA传输完成中断中处理。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

姜源Jerry

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值