STM32F407ZGT6(正点原子探索者)DMA串口数据接收

学习STM32过程中正好看到正点原子STM32的DMA教程,但视频里只讲解了DMA发送串口数据,未讲解DMA接收串口数据,经过多方查找资料,结合网络历程,现将代码分享。


dma.c 的代码如下,与正点原子历程相比, 改动并不多,将DMA模式改为循环模式,实际测试正常模式响应较慢,而且存在丢包现象,改为循环模式后,收发正常。

#include "stm32f4xx.h"
#include "usart.h"
#include "delay.h"

void MYDMA_Enable(DMA_Stream_TypeDef *DMA_Streamx,u16 ndtr);
void USART1_DMAConfig(DMA_Stream_TypeDef *DMA_Streamx,u32 chx,u32 par,u32 mar,u16 ndtr)
{
	DMA_InitTypeDef  DMA_InitStructure;
	NVIC_InitTypeDef NVIC_InitStructure;
	/* 使能DMA2时钟 */
	if((u32)DMA_Streamx>(u32)DMA2)										//得到当前stream是属于DMA2还是DMA1
	{
	  RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2,ENABLE);				//DMA2时钟使能 
		
	}else 
	{
	  RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA1,ENABLE);				//DMA1时钟使能 
	}
	
	/* Reset DMA Stream registers (for debug purpose) */
	DMA_DeInit(DMA_Streamx);
	
	while (DMA_GetCmdStatus(DMA_Streamx) != DISABLE){};	  				//等待DMA可配置
	/* Configure DMA Stream */
	/* 配置 DMA Stream */
	DMA_InitStructure.DMA_Channel = chx;  										//通道选择
	DMA_InitStructure.DMA_PeripheralBaseAddr = par;								//DMA外设地址
	DMA_InitStructure.DMA_Memory0BaseAddr = mar;								//DMA 存储器0地址
	DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory;						//存储器到外设模式
	DMA_InitStructure.DMA_BufferSize = ndtr;									//数据传输量 
	DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;			//外设非增量模式
	DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;						//存储器增量模式
	DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;		//外设数据长度:8位
	DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;				//存储器数据长度:8位
	DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;								//使用循环模式 
	DMA_InitStructure.DMA_Priority = DMA_Priority_Medium;						//中等优先级
	DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable;         
	DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_Full;
	DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;					//存储器突发单次传输
	DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;			//外设突发单次传输
	DMA_Init(DMA_Streamx, &DMA_InitStructure);									//初始化DMA Stream
	
	USART_DMACmd(USART1,USART_DMAReq_Rx,ENABLE); //使能串口1的DMA接收
    MYDMA_Enable(DMA_Streamx,USART_REC_LEN);     //开始第1次DMA传输!

}

//开启一次DMA传输
//DMA_Streamx:DMA数据流,DMA1_Stream0~7/DMA2_Stream0~7 
//ndtr:数据传输量  
void MYDMA_Enable(DMA_Stream_TypeDef *DMA_Streamx,u16 ndtr)
{
 
	DMA_Cmd(DMA_Streamx, DISABLE);                      //关闭DMA传输 
	
	while (DMA_GetCmdStatus(DMA_Streamx) != DISABLE){}	//确保DMA可以被设置  
		
	DMA_SetCurrDataCounter(DMA_Streamx,ndtr);          //数据传输量  
 
	DMA_Cmd(DMA_Streamx, ENABLE);                      //开启DMA传输 
}	  

main函数段如下

#include "stm32f4xx.h"
#include "usart.h"
#include "delay.h"
#include "dma.h"
#include <string.h>
extern u8  USART_RX_BUF[USART_REC_LEN]; 
int main(void)
{
	u32 t=0;
	uart_init(115200);
	delay_init(84);
	USART1_DMAConfig(DMA2_Stream2,DMA_Channel_4,(u32)&USART1->DR,(u32)USART_RX_BUF,USART_REC_LEN);//DMA2通道4,外设为串口1,存储器为SendBuff,长度USART_REC_LEN 200,
    printf("DMA IS OK!");
  while(1){
	  if(USART_RX_BUF[0])    //数组0有数据了,说明DMA开始接收一段数据
			{
			delay_ms(10); //延时10ms,让DMA继续接收后面数据的同时,也能跑跑其它进程
 			printf("%s\r\n",USART_RX_BUF); //打印
			memset(USART_RX_BUF,0,USART_REC_LEN);    //清空数组
			MYDMA_Enable(DMA2_Stream2,USART_REC_LEN);//开始一次DMA传输!
/*============================================代码优化==================================================
				while(1)
				{
					if(DMA_GetFlagStatus(DMA2_Stream2,DMA_FLAG_TCIF2)!=RESET)//等待DMA2_Steam2传输完成
					{ 
						printf("%s\r\n",USART_RX_BUF); //打印
						memset(USART_RX_BUF,0,USART_REC_LEN);    //清空数组
						DMA_ClearFlag(DMA2_Stream2,DMA_FLAG_TCIF2);//清除DMA2_Steam2传输完成标志
						MYDMA_Enable(DMA2_Stream2,USART_REC_LEN);//开始一次DMA传输!
						break; 
					}
				}
======================================================================================================*/
			}	
	}
}

以下是一个基本的 STM32F407ZGT6 串口空闲中断的代码示例: ```c #include "stm32f4xx.h" // 定义串口接收缓冲区大小 #define RX_BUFFER_SIZE 100 // 定义接收缓冲区和索引变量 uint8_t rx_buffer[RX_BUFFER_SIZE]; uint8_t rx_index = 0; // 串口空闲中断处理函数 void USART_IRQHandler(void) { // 检查是否是空闲中断 if (USART_GetITStatus(USART1, USART_IT_IDLE) != RESET) { // 清除空闲中断标志位 USART_ReceiveData(USART1); // 保存接收数据长度 uint16_t rx_length = RX_BUFFER_SIZE - USART_GetFlagStatus(USART1, USART_FLAG_RXNE); // 处理接收到的数据 // ... // 清空接收缓冲区和索引变量 memset(rx_buffer, 0, RX_BUFFER_SIZE); rx_index = 0; // 重新使能接收中断 USART_ITConfig(USART1, USART_IT_IDLE, ENABLE); } } int main(void) { // 初始化串口和空闲中断 USART_InitTypeDef USART_InitStruct; USART_InitStruct.USART_BaudRate = 9600; USART_InitStruct.USART_WordLength = USART_WordLength_8b; USART_InitStruct.USART_StopBits = USART_StopBits_1; USART_InitStruct.USART_Parity = USART_Parity_No; USART_InitStruct.USART_Mode = USART_Mode_Rx; USART_InitStruct.USART_HardwareFlowControl = USART_HardwareFlowControl_None; USART_Init(USART1, &USART_InitStruct); // 使能接收和空闲中断 USART_ITConfig(USART1, USART_IT_RXNE, ENABLE); USART_ITConfig(USART1, USART_IT_IDLE, ENABLE); // 启用串口和中断 USART_Cmd(USART1, ENABLE); NVIC_EnableIRQ(USART1_IRQn); while (1) { // 主循环 // ... } } ``` 这段代码使用了 USART1 作为示例串口,可以根据具体需求进行修改。在空闲中断处理函数中,可以根据接收到的数据长度进行数据处理,并在处理完成后重新使能接收中断。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值