stm32串口HAL库的DMA发送问题

本文使用stm32f411ret的串口1的DMA方式发送数据,刚开始调试的时候发现串口只能发送一次数据,之后就把系统hang住了。通过网上搜资料和不断尝试,发现问题是中断回调函数没有写的原因。

使用HAL库的DMA,需要同时实现DMA中断回调函数串口中断回调函数。

void DMA2_Stream7_IRQHandler(void)
{
    HAL_DMA_IRQHandler(Uart1Handle.hdmatx);
}

void USART1_IRQHandler(void)
{
  HAL_NVIC_ClearPendingIRQ(USART1_IRQn);
  HAL_UART_IRQHandler(&Uart1Handle);
}

下面附上我的dma配置和串口配置函数

dma配置

void HAL_UART1_dma_Init(void)
{
  static DMA_HandleTypeDef hdma_tx;

  __HAL_RCC_DMA2_CLK_ENABLE();                //打开DMA2时钟
  /*##-3- Configure the DMA streams ##########################################*/
  /* Configure the DMA handler for Transmission process */
  hdma_tx.Instance                 = DMA2_Stream7;      
  hdma_tx.Init.Channel             = DMA_CHANNEL_4;        //串口1发送属于stream7、channel4,可在参考手册的DMA章节查到
  hdma_tx.Init.Direction           = DMA_MEMORY_TO_PERIPH;    //数据发送方向:内存->外设
  hdma_tx.Init.PeriphInc           = DMA_PINC_DISABLE;        //外设为串口,地址不需要增加
  hdma_tx.Init.MemInc              = DMA_MINC_ENABLE;        //存储需要增加
  hdma_tx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;    //串口为字节
  hdma_tx.Init.MemDataAlignment    = DMA_MDATAALIGN_BYTE;    //与串口设置要一致
  hdma_tx.Init.Mode                = DMA_NORMAL;              //一次发送,如果设置为循环模式,会一直不停的发 
  hdma_tx.Init.Priority            = DMA_PRIORITY_LOW;        //低优先级
  hdma_tx.Init.FIFOMode            = DMA_FIFOMODE_DISABLE;    
  hdma_tx.Init.FIFOThreshold       = DMA_FIFO_THRESHOLD_FULL;
  hdma_tx.Init.MemBurst            = DMA_MBURST_INC4;
  hdma_tx.Init.PeriphBurst         = DMA_PBURST_INC4;
  
  HAL_DMA_Init(&hdma_tx);   
  
  /* Associate the initialized DMA handle to the the UART handle */
  __HAL_LINKDMA(&Uart1Handle, hdmatx, hdma_tx);            //将dma的发送handle赋值给串口1的hdmatx成员
  /*##-4- Configure the NVIC for DMA #########################################*/
  /* NVIC configuration for DMA transfer complete interrupt (USARTx_TX) */
  HAL_NVIC_SetPriority(DMA2_Stream7_IRQn, 0, 1);           //设置dma中断优先级
  HAL_NVIC_EnableIRQ(DMA2_Stream7_IRQn);                   //使能dma中断
}

串口引脚配置

void Init_Usart1(void)
{
	GPIO_InitTypeDef  GPIO_InitStruct;
  
  /*##-1- Enable peripherals and GPIO Clocks #################################*/
  /* Enable GPIO TX/RX clock */
  __HAL_RCC_GPIOA_CLK_ENABLE();  
  /* Enable USARTx clock */
   __HAL_RCC_USART1_CLK_ENABLE();
  
  /*##-2- Configure peripheral GPIO ##########################################*/  
  /* UART TX GPIO pin configuration  */
  GPIO_InitStruct.Pin       = GPIO_PIN_9;
  GPIO_InitStruct.Mode      = GPIO_MODE_AF_PP;
  GPIO_InitStruct.Pull      = GPIO_PULLUP;
  GPIO_InitStruct.Speed     = GPIO_SPEED_FAST;
  GPIO_InitStruct.Alternate = GPIO_AF7_USART1;
  
  HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
    
  /* UART RX GPIO pin configuration  */
  GPIO_InitStruct.Pin = GPIO_PIN_10;
  GPIO_InitStruct.Alternate = GPIO_AF7_USART1;
    
  HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
	
	HAL_NVIC_SetPriority(USART1_IRQn,0,0);
	HAL_NVIC_EnableIRQ(USART1_IRQn);				
	
}

串口配置

void Usart1_Configuration(uint32_t BaudRate)
{								   
  Uart1Handle.Instance          = USART1;
  
  Uart1Handle.Init.BaudRate     = BaudRate;
  Uart1Handle.Init.WordLength   = UART_WORDLENGTH_8B;
  Uart1Handle.Init.StopBits     = UART_STOPBITS_1;
  Uart1Handle.Init.Parity       = UART_PARITY_NONE;
  Uart1Handle.Init.HwFlowCtl    = UART_HWCONTROL_NONE;
  Uart1Handle.Init.Mode         = UART_MODE_TX_RX;
  Uart1Handle.Init.OverSampling = UART_OVERSAMPLING_16;
    
  if(HAL_UART_Init(&Uart1Handle) != HAL_OK)
  {
    /* Initialization Error */
    Error_Handler(); 
  }	
    
}

发送数据调用下面的函数即可

HAL_UART_Transmit_DMA(&Uart1Handle, (uint8_t*)aTxBuffer, 32)

实际操作时可以在串口中断中设置一个标志位,用来标记串口发送完成,在主程序中用标志位控制对发送函数的调用。

猜你喜欢

转载自blog.csdn.net/G_Crisis/article/details/81322847