STM32F429 串口1实现DMA接收功能

本文详细介绍了STM32F429的USART1如何使用DMA进行串口数据的接收和发送,包括DMA的初始化、配置以及中断处理过程,特别提到了IDLE和RXNE中断的区别及其应用场景。
摘要由CSDN通过智能技术生成

串口1+dma中断 接收和发送

本实验中的串口1+dma中断是基于串口1的IDLE空闲中断实现的
额外说一句IDLE中断和RXNE中断有什么区别呢
假设上位机给MCU的USART1发送8Byte
1.IDLE:只进入一次中断->最后一个Byte的最后一个bit发送完毕之后,mcu开始计时,假设3ms(这个时间怎么计算,最后讲解)内没有收到任何数据->进入IDLE中断
2.RXNE:进入8次中断,收到每一个Byte后的停止位->进入中断

言归正传

针对STM32F429的USART1的RX dma & TX dma功能。

第一步,初始化DMA->为什么要先初始化DMA,后面会讲到


//下面的定义句柄不要忘记
DMA_HandleTypeDef  UART1RxDMA_Handler; //定义句柄
u8 USART1_DMATX_FLAG=0;

void U1_RX_DMA_Config(void )
{
  
	__HAL_RCC_DMA2_CLK_ENABLE();//DMA2时钟使能	
	__HAL_LINKDMA(&UART1_Handler, hdmarx, UART1RxDMA_Handler);//将rx和dma连接	
   
	//Rx DMA配置
    UART1RxDMA_Handler.Instance = DMA2_Stream5;
    UART1RxDMA_Handler.Init.Channel = DMA_CHANNEL_4;
    UART1RxDMA_Handler.Init.Direction = DMA_PERIPH_TO_MEMORY;
    UART1RxDMA_Handler.Init.PeriphInc = DMA_PINC_DISABLE;
    UART1RxDMA_Handler.Init.MemInc = DMA_MINC_ENABLE;
    UART1RxDMA_Handler.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
    UART1RxDMA_Handler.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
    UART1RxDMA_Handler.Init.Mode = DMA_CIRCULAR;
    UART1RxDMA_Handler.Init.Priority = DMA_PRIORITY_LOW;
    UART1RxDMA_Handler.Init.FIFOMode = DMA_FIFOMODE_DISABLE;
    
	HAL_DMA_DeInit(&UART1RxDMA_Handler);
    HAL_DMA_Init(&UART1RxDMA_Handler);
	
    
  
   __HAL_DMA_ENABLE_IT(&UART1RxDMA_Handler, DMA_IT_TC);   //开启DMA传输完成中断 

   
   HAL_NVIC_SetPriority(DMA2_Stream5_IRQn, 3, 1);
   HAL_NVIC_EnableIRQ(DMA2_Stream5_IRQn);

}
//DMA接收中断处理
void DMA2_Stream5_IRQHandler(void)
{	
	if(__HAL_DMA_GET_FLAG(&UART1RxDMA_Handler, DMA_FLAG_TCIF1_5)) //DMA2_Steam2传输完成
	{		
		__HAL_DMA_CLEAR_FLAG(&UART1RxDMA_Handler, DMA_FLAG_TCIF1_5);//清DMA2_Steam2传输完成标志	
		HAL_UART_DMAStop(&UART1_Handler);	//传输完成以后关闭串口DMA
	}	
	HAL_UART_Receive_DMA(&UART1_Handler, USART1_RX_BUF, USART_REC_LEN);//重新开启DMA接收
	HAL_DMA_IRQHandler(&UART1RxDMA_Handler);//调用中断处理公共函数
}

 
void U1_TX_DMA_Config(void )
{
 
    __HAL_RCC_DMA2_CLK_ENABLE();//DMA2时钟使能	  
    __HAL_LINKDMA(&UART1_Handler,hdmatx,UART1TxDMA_Handler);    //将DMA与USART1联系起来(发送DMA)
    
    //Tx DMA配置
    UART1TxDMA_Handler.Instance=DMA2_Stream7;                            //数据流选择
    UART1TxDMA_Handler.Init.Channel=DMA_CHANNEL_4;                                //通道选择
    UART1TxDMA_Handler.Init.Direction=DMA_MEMORY_TO_PERIPH;             //存储器到外设
    UART1TxDMA_Handler.Init.PeriphInc=DMA_PINC_DISABLE;                 //外设非增量模式
    UART1TxDMA_Handler.Init.MemInc=DMA_MINC_ENABLE;                     //存储器增量模式
    UART1TxDMA_Handler.Init.PeriphDataAlignment=DMA_PDATAALIGN_BYTE;    //外设数据长度:8位
    UART1TxDMA_Handler.Init.MemDataAlignment=DMA_MDATAALIGN_BYTE;       //存储器数据长度:8位
    UART1TxDMA_Handler.Init.Mode=DMA_NORMAL;                            //外设普通模式
    UART1TxDMA_Handler.Init.Priority=DMA_PRIORITY_MEDIUM;               //中等优先级
    UART1TxDMA_Handler.Init.FIFOMode=DMA_FIFOMODE_DISABLE;              
    UART1TxDMA_Handler.Init.FIFOThreshold=DMA_FIFO_THRESHOLD_FULL;      
    UART1TxDMA_Handler.Init.MemBurst=DMA_MBURST_SINGLE;                 //存储器突发单次传输
    UART1TxDMA_Handler.Init.PeriphBurst=DMA_PBURST_SINGLE;              //外设突发单次传输
    
    HAL_DMA_DeInit(&UART1TxDMA_Handler);   
    HAL_DMA_Init(&UART1TxDMA_Handler);
	
	__HAL_DMA_ENABLE_IT(&UART1TxDMA_Handler, DMA_IT_TC); 
	
	HAL_NVIC_SetPriority(DMA2_Stream7_IRQn, 3, 2);
	HAL_NVIC_EnableIRQ(DMA2_Stream7_IRQn);	
	
}

void HAL_UART_TxHalfCpltCallback(UART_HandleTypeDef *huart)
{
	//回调函数
	huart->State=HAL_UART_STATE_READY;
} 

//DMA发送中断处理
void DMA2_Stream7_IRQHandler(void)
{	
	if(__HAL_DMA_GET_FLAG(&UART1TxDMA_Handler, DMA_FLAG_TCIF3_7)) //DMA2_Steam7传输完成
	{
		 
		USART1_DMATX_FLAG=1;	 
		__HAL_DMA_CLEAR_FLAG(&UART1TxDMA_Handler, DMA_FLAG_TCIF3_7);
		HAL_UART_DMAStop(&UART1_Handler);      
	}
	//调用中断处理公共函数
	HAL_DMA_IRQHandler(&UART1TxDMA_Handler);
}

void DMA_USART_Transmit(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size)
{
	USART1_DMATX_FLAG=0;
    HAL_DMA_Start(huart->hdmatx, (u32)pData, (uint32_t)&huart->Instance->DR, Size);//开启DMA传输
    
    huart->Instance->CR3 |= USART_CR3_DMAT;//使能串口DMA发送
	while(USART1_DMATX_FLAG==0); 
  
	 
}

第二步,初始化USART1

#define USART_REC_LEN  200
u8 USART_RX_BUF[USART_REC_LEN];     //接收缓冲,最大USART_REC_LEN个字节.
UART_HandleTypeDef UART1_Handler; //UART句柄
u8 USART1_RX_CNT = 0;
u8 USART1_RX_OK = 0;

UART_HandleTypeDef UART1_Handler; //UART句柄
void uart_init1(u32 bound1)
{	
	GPIO_InitTypeDef GPIO_Initure;
	
	__HAL_RCC_GPIOA_CLK_ENABLE();			//使能GPIOA时钟
	__HAL_RCC_USART1_CLK_ENABLE();			//使能USART1时钟
	
	
	UART1_Handler.Instance=USART1;					    //USART1
	UART1_Handler.Init.BaudRate=bound1;				    //波特率
	UART1_Handler.Init.WordLength=UART_WORDLENGTH_8B;   //字长为8位数据格式
	UART1_Handler.Init.StopBits=UART_STOPBITS_1;	    //一个停止位
	UART1_Handler.Init.Parity=UART_PARITY_NONE;		    //无奇偶校验位
	UART1_Handler.Init.HwFlowCtl=UART_HWCONTROL_NONE;   //无硬件流控
	UART1_Handler.Init.Mode=UART_MODE_TX_RX;		    //收发模式
	HAL_UART_Init(&UART1_Handler);					    //HAL_UART_Init()会使能UART1 
	
	GPIO_Initure.Pin=GPIO_PIN_9;			//PA9  TX
	GPIO_Initure.Mode=GPIO_MODE_AF_PP;		//复用推挽输出
	GPIO_Initure.Pull=GPIO_PULLDOWN;			//上拉
	GPIO_Initure.Speed=GPIO_SPEED_FAST;		//高速
	GPIO_Initure.Alternate=GPIO_AF7_USART1;	//复用为USART1
	HAL_GPIO_Init(GPIOA,&GPIO_Initure);	   	//初始化PA9

	GPIO_Initure.Pin=GPIO_PIN_10;			//PA10  RX
	HAL_GPIO_Init(GPIOA,&GPIO_Initure);	   	//初始化PA10
	
	
	HAL_NVIC_SetPriority(USART1_IRQn, 3, 3);   //抢占优先级3,子优先级3
    HAL_NVIC_EnableIRQ(USART1_IRQn);          //使能USART1中断通道

	__HAL_UART_DISABLE_IT(&UART1_Handler,UART_IT_TC);
	
	__HAL_UART_ENABLE_IT(&UART1_Handler,UART_IT_IDLE);		//开启接收中断
	HAL_UART_Receive_DMA(&UART1_Handler, USART1_RX_BUF, USART_REC_LEN);

	
 
	
	
}

void USART1_IRQHandler(void)                	
{ 
 
 if(__HAL_UART_GET_FLAG(&UART1_Handler, UART_FLAG_IDLE) != RESET)  //判断是否为IDLE中断  
  {
  
    __HAL_UART_CLEAR_IDLEFLAG(&UART1_Handler);
		HAL_UART_DMAStop(&UART1_Handler);
    
    USART1_RX_CNT = USART_REC_LEN - UART1RxDMA_Handler.Instance->NDTR;
    USART1_RX_OK = 1;      //标记接收完成
	 	 
	HAL_UART_Receive_DMA(&UART1_Handler, USART1_RX_BUF, USART_REC_LEN);
  }
 
  HAL_UART_IRQHandler(&UART1_Handler);


} 

第三步,调用初始化程序

 int main(void)
{

    HAL_Init();                     
    Stm32_Clock_Init(360,25,2,8);   
    delay_init(180);   
	LED_Init();	
	U1_TX_DMA_Config();
	U1_RX_DMA_Config();
	uart_init1(115200); 
	while (1)
	{
		if(USART1_RX_OK)
		{
			USART1_RX_OK=0;
			LED_PI0=!LED_PI0;
			 
			DMA_USART_Transmit(&UART1_Handler,(uint8_t*)temp_response,230+9);				            
		}
	}	
}

完工

后续1
接下来说说IDLE的超时时间是怎么计算的
假设串口波特率为115200,这代表串口的发送速率为115200bit/s
发送1bit所需时间=1s/115200bit/s = 8.68us
一般来说,超过3-5倍的“发送1bit所需要的时间”即为超时 满打满算,我们算10倍,就是86us 。
后续2
为什么先初始化dma,后初始化串口
参考 https://blog.csdn.net/Anchrx/article/details/118657397
链接: https://blog.csdn.net/Anchrx/article/details/118657397

以上!

  • 10
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值