USART中DMA使用介绍

1 初始化代码分析

1.1 DMA初始化代码

作用是设置对应DMA通道的中断优先级;

void MX_DMA_Init(void)
{
​
  /* DMA controller clock enable */
  __HAL_RCC_DMA1_CLK_ENABLE();
​
  /* DMA interrupt init */
  /* DMA1_Channel4_IRQn interrupt configuration */
  HAL_NVIC_SetPriority(DMA1_Channel4_IRQn, 0, 0);
  HAL_NVIC_EnableIRQ(DMA1_Channel4_IRQn);
  /* DMA1_Channel5_IRQn interrupt configuration */
  HAL_NVIC_SetPriority(DMA1_Channel5_IRQn, 0, 0);
  HAL_NVIC_EnableIRQ(DMA1_Channel5_IRQn);
​
}

1.2 DMA配置以及串口连接初始化

初始化串口IO,以及配置串口与DMA通道相连接;

void HAL_UART_MspInit(UART_HandleTypeDef* uartHandle)
{
​
  GPIO_InitTypeDef GPIO_InitStruct = {0};
  if(uartHandle->Instance==USART1)
  {
  /* USER CODE BEGIN USART1_MspInit 0 */
​
  /* USER CODE END USART1_MspInit 0 */
    /* USART1 clock enable */
    __HAL_RCC_USART1_CLK_ENABLE();
​
    __HAL_RCC_GPIOA_CLK_ENABLE();
    /**USART1 GPIO Configuration
    PA9     ------> USART1_TX
    PA10     ------> USART1_RX
    */
    GPIO_InitStruct.Pin = GPIO_PIN_9;
    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
    HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
​
    GPIO_InitStruct.Pin = GPIO_PIN_10;
    GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
​
    /* USART1 DMA Init */
    /* USART1_RX Init */
    hdma_usart1_rx.Instance = DMA1_Channel5;
    hdma_usart1_rx.Init.Direction = DMA_PERIPH_TO_MEMORY;
    hdma_usart1_rx.Init.PeriphInc = DMA_PINC_DISABLE;  //禁止外设地址递增模式
    hdma_usart1_rx.Init.MemInc = DMA_MINC_ENABLE;      //使能目标地址递增模式
    hdma_usart1_rx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
    hdma_usart1_rx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
    hdma_usart1_rx.Init.Mode = DMA_NORMAL;
    hdma_usart1_rx.Init.Priority = DMA_PRIORITY_LOW;
    if (HAL_DMA_Init(&hdma_usart1_rx) != HAL_OK)
    {
      Error_Handler();
    }
​
    __HAL_LINKDMA(uartHandle,hdmarx,hdma_usart1_rx);   //连接串口和DMA!
    /*__HAL_LINKDMA 的主要作用是传入的uartHandle结构体中的DMA对象设置为目标DMA ; */
​
    /* USART1_TX Init */
    hdma_usart1_tx.Instance = DMA1_Channel4;
    hdma_usart1_tx.Init.Direction = DMA_MEMORY_TO_PERIPH;
    hdma_usart1_tx.Init.PeriphInc = DMA_PINC_DISABLE;
    hdma_usart1_tx.Init.MemInc = DMA_MINC_ENABLE;
    hdma_usart1_tx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
    hdma_usart1_tx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
    hdma_usart1_tx.Init.Mode = DMA_NORMAL;
    hdma_usart1_tx.Init.Priority = DMA_PRIORITY_LOW;
    if (HAL_DMA_Init(&hdma_usart1_tx) != HAL_OK)
    {
      Error_Handler();
    }
​
    __HAL_LINKDMA(uartHandle,hdmatx,hdma_usart1_tx);
​
  /* USER CODE BEGIN USART1_MspInit 1 */
​
  /* USER CODE END USART1_MspInit 1 */
  }
}

2 DMA中断处理函数

当DMA中断标志位置位时,就会进入中断,利用HAL_DMA_IRQHandler中断处理函数处理;

该函数会检测中断标志位,根据相应的中断标志位调用对应的回调函数;

void DMA1_Channel4_IRQHandler(void)
{
  /* USER CODE BEGIN DMA1_Channel4_IRQn 0 */
​
  /* USER CODE END DMA1_Channel4_IRQn 0 */
  HAL_DMA_IRQHandler(&hdma_usart1_tx);
  /* USER CODE BEGIN DMA1_Channel4_IRQn 1 */
​
  /* USER CODE END DMA1_Channel4_IRQn 1 */
}
​
​
void HAL_DMA_IRQHandler(DMA_HandleTypeDef *hdma)
{
  uint32_t flag_it = hdma->DmaBaseAddress->ISR; //读取中断标志位寄存器
  uint32_t source_it = hdma->Instance->CCR;     //读取DMA通道配置寄存器
  
  /* Half Transfer Complete Interrupt management ******************************/
  if (((flag_it & (DMA_FLAG_HT1 << hdma->ChannelIndex)) != RESET) && ((source_it & DMA_IT_HT) != RESET))
  {
    /* Disable the half transfer interrupt if the DMA mode is not CIRCULAR */
    if((hdma->Instance->CCR & DMA_CCR_CIRC) == 0U)
    {
      /* Disable the half transfer interrupt */
      __HAL_DMA_DISABLE_IT(hdma, DMA_IT_HT);
    }
    /* Clear the half transfer complete flag */
    __HAL_DMA_CLEAR_FLAG(hdma, __HAL_DMA_GET_HT_FLAG_INDEX(hdma));
​
    /* DMA peripheral state is not updated in Half Transfer */
    /* but in Transfer Complete case */
​
    if(hdma->XferHalfCpltCallback != NULL)
    {
      /* Half transfer callback */
      hdma->XferHalfCpltCallback(hdma);
    }
  }
​
  /* Transfer Complete Interrupt management ***********************************/
  else if (((flag_it & (DMA_FLAG_TC1 << hdma->ChannelIndex)) != RESET) && ((source_it & DMA_IT_TC) != RESET))
  {
    if((hdma->Instance->CCR & DMA_CCR_CIRC) == 0U)
    {
      /* Disable the transfer complete and error interrupt */
      __HAL_DMA_DISABLE_IT(hdma, DMA_IT_TE | DMA_IT_TC);  
​
      /* Change the DMA state */
      hdma->State = HAL_DMA_STATE_READY;
    }
    /* Clear the transfer complete flag */
      __HAL_DMA_CLEAR_FLAG(hdma, __HAL_DMA_GET_TC_FLAG_INDEX(hdma));
​
    /* Process Unlocked */
    __HAL_UNLOCK(hdma);
​
    if(hdma->XferCpltCallback != NULL)
    {
      /* Transfer complete callback */
      hdma->XferCpltCallback(hdma);
    }
  }
​
  /* Transfer Error Interrupt management **************************************/
  else if (( RESET != (flag_it & (DMA_FLAG_TE1 << hdma->ChannelIndex))) && (RESET != (source_it & DMA_IT_TE)))
  {
    /* When a DMA transfer error occurs */
    /* A hardware clear of its EN bits is performed */
    /* Disable ALL DMA IT */
    __HAL_DMA_DISABLE_IT(hdma, (DMA_IT_TC | DMA_IT_HT | DMA_IT_TE));
​
    /* Clear all flags */
    hdma->DmaBaseAddress->IFCR = (DMA_ISR_GIF1 << hdma->ChannelIndex);
​
    /* Update error code */
    hdma->ErrorCode = HAL_DMA_ERROR_TE;
​
    /* Change the DMA state */
    hdma->State = HAL_DMA_STATE_READY;
​
    /* Process Unlocked */
    __HAL_UNLOCK(hdma);
​
    if (hdma->XferErrorCallback != NULL)
    {
      /* Transfer error callback */
      hdma->XferErrorCallback(hdma);
    }
  }
  return;
}

3 DMA使用

3.1 DMA传输函数(HAL_UART_Transmit_DMA)

调用该函数后,由于在DMA的初始化中调用过__HAL_LINKDMA(uartHandle,hdmarx,hdma_usart1_rx);即将UART_HandleTypeDef结构体中的DMA对象变量设置为目标DMA,这样当调用HAL_UART_Transmit_DMA函数时,该函数就会将目标DMA中的中断回调函数注册好,当传输中断(传输完成或其他情况)发生时在DMA中断服务函数HAL_DMA_IRQHandler会调用相应回调函数;

此外,HAL_UART_Transmit_DMA中调用了HAL_DMA_Start_IT函数,该函数的的作用配置目标DMA参数,并启动传输,在执行完HAL_DMA_Start_IT函数后(即传输完成),会做一些寄存器的位操作;HAL_DMA_Start_IT详见后面解释;

注1:不能重复调用HAL_UART_Transmit_DMA ( ) ; 会漏掉数据,因为在传输的过程中huart->gState会被设置成HAL_UART_STATE_BUSY_TX,因此如果在DMA工作(数据搬移)期间再次调用该函数,则会漏发!最好是在DMA传输完成的回调函数void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart)里再去注册传输,或者利用标志位;DMA的回调函数在DMA中断中的HAL_DMA_IRQHandler( )中断处理函数里面调用!

⭐注2:若要使用HAL_UART_Transmit_DMA ( ) ; 一定要在建立工程的时候使能串口全局中断 ! ! !

由下述代码可知,在没有使能USART串口全局中断的情况下,当第一次调用HAL_UART_Transmit_DMA ( ) ;时,由于HAL库中默认使能DMA的半传输中断,DMA完成一次传输的一半后,会触发一次DMA的传输中断,此时DMA会进入中断服务函数HAL_DMA_IRQHandler(&hdma_usart1_tx);并执行半传输中断的服务函数;

UART_DMATxHalfCplt( ) ; 这个函数执行的就是串口半传输回调函数HAL_UART_TxHalfCpltCallback(huart);

在处理完半传输中断后,中断服务函数还要再处理DMA的传输完成中断;这个时候HAL_DMA_IRQHandler()中会调用UART_DMATransmitCplt( );传输完成回调函数(该函数在DMA单次传输模式下不会调用串口发送完成回调函数,只有在循环模式下才会),单次传输模式下该函数会失能USART的DMA传输功能(RESET_BIT(huart->Instance->CR3, USART_CR3_DMAT);),这样一次DMA传输的中断处理流程就结束了;而当再次调用HAL_UART_Transmit_DMA ( ) ;如果串口状态是HAL_UART_STATE_READY则会在这个函数最后打开USART的DMA传输功能(SET_BIT(huart->Instance->CR3, USART_CR3_DMAT); ) , 但是由于第一次调用HAL_UART_Transmit_DMA ( ) ;时,将huart->gState = HAL_UART_STATE_BUSY_TX;,而后面的代码都没由解除huart->gState的繁忙状态,因此第一次调用HAL_UART_Transmit_DMA ( ) ;后在调用时该函数就会返回HAL_BUSY;这也是为什么网上很多人问HAL_UART_Transmit_DMA ( ) ;调用一次后无法再次调用启动传输;

解决方法1:能串口全局中断;

对应USART数据发送有两个中断标志,一个是TXE = 发送数据寄存器空,另一个是TC = 发送结束;当TDR中的数据传送到移位寄存器后,TXE被设置,此时移位寄存器开始向TX信号线按位传输数据,但因为TDR已经变空,程序可以把下一个要发送的字节(操作USART_DR)写入TDR中,而不必等到移位寄存器中所有位发送结束,所有位发送结束时(送出停止位后)硬件会设置TC标志。

在程序初始化完成阶段,串口的TXEIE与TCIE是默认为0的,同时DMA调用HAL_UART_Transmit_DMA ( ) ; 函数中会执行 __HAL_UART_CLEAR_FLAG(huart, UART_FLAG_TC);清除TC位,也就是说在DMA传输完成期间,串口发送中断是不会被触发的;(注:调用串口中断接收或发送函数才会置位这些发送或接收中断使能位!)

​​

当DMA单次传输模式下完成一次传输后,在DMA中断服务函数中调用UART_DMATransmitCplt( )传输完成回调函数,该函数中会调用SET_BIT(huart->Instance->CR1, USART_CR1_TCIE);使能串口的发送中断,这样就会触发一次串口接收中断进入串口服务函数HAL_UART_IRQHandler(&huart1);

在串口中断函数中又会执行UART_EndTransmit_IT()函数,在这个函数会内恢复串口状态huart->gState = HAL_UART_STATE_READY; 并通过执行 __HAL_UART_DISABLE_IT(huart, UART_IT_TC); 失能TCIE使能接收中断;

HAL_NVIC_SetPriority(USART1_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(USART1_IRQn);
​
void USART1_IRQHandler(void)
{
/* USER CODE BEGIN USART1_IRQn 0 */
​
/* USER CODE END USART1_IRQn 0 */
HAL_UART_IRQHandler(&huart1);
/* USER CODE BEGIN USART1_IRQn 1 */
​
/* USER CODE END USART1_IRQn 1 */
}

解决方法2:由于单次串口DMA发送模式下HAL库不执行串口的传输完成回调函数,因此在半传输回调函数中HAL_UART_TxHalfCpltCallback( )函数内修改huart->gStat状态为HAL_UART_STATE_READY!

void HAL_UART_TxHalfCpltCallback(UART_HandleTypeDef *huart){
    if(huart->Instance == USART1){
        huart->gState = HAL_UART_STATE_READY;//huart1传输完成 变为准备
    }
}

HAL_StatusTypeDef HAL_UART_Transmit_DMA(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size)
{
  uint32_t *tmp;
​
  /* Check that a Tx process is not already ongoing */
  if (huart->gState == HAL_UART_STATE_READY)
  {
    if ((pData == NULL) || (Size == 0U))
    {
      return HAL_ERROR;
    }
​
    /* Process Locked */
    __HAL_LOCK(huart);
​
    huart->pTxBuffPtr = pData;
    huart->TxXferSize = Size;
    huart->TxXferCount = Size;
​
    huart->ErrorCode = HAL_UART_ERROR_NONE;
    huart->gState = HAL_UART_STATE_BUSY_TX;
​
    /* Set the UART DMA transfer complete callback */
    //UART_DMATransmitCplt该函数对单次DMA发送的处理是置零串口的DMAT位即失能串口DMA发送
    //对于循环模式下的DMA则会调用传输完成回调函数
    huart->hdmatx->XferCpltCallback = UART_DMATransmitCplt;
​
    /* Set the UART DMA Half transfer complete callback */
    huart->hdmatx->XferHalfCpltCallback = UART_DMATxHalfCplt;
​
    /* Set the DMA error callback */
    huart->hdmatx->XferErrorCallback = UART_DMAError;
​
    /* Set the DMA abort callback */
    huart->hdmatx->XferAbortCallback = NULL;
​
    /* Enable the UART transmit DMA channel */
    tmp = (uint32_t *)&pData;
    HAL_DMA_Start_IT(huart->hdmatx, *(uint32_t *)tmp, (uint32_t)&huart->Instance->DR, Size);
​
    /* Clear the TC flag in the SR register by writing 0 to it */
    __HAL_UART_CLEAR_FLAG(huart, UART_FLAG_TC);
​
    /* Process Unlocked */
    __HAL_UNLOCK(huart);
​
    /* Enable the DMA transfer for transmit request by setting the DMAT bit
       in the UART CR3 register */
    SET_BIT(huart->Instance->CR3, USART_CR3_DMAT);
​
    return HAL_OK;
  }
  else
  {
    return HAL_BUSY;
  }
}

3.2 DMA启动传输函数(HAL_DMA_Start_IT)

该函数由HAL_UART_Transmit_DMA()函数调用;

将传入的串口地址以及传需要传输的数据源地址通过DMA_SetConfig函数配置进DMA通道中,并根据DMA对象中是否定义了半传输中断回调函数来使能对应中断,最后通过 __HAL_DMA_ENABLE( );函数使能对应的DMA通道,启动传输;

DMA外设会自动从数据源读取数据并写入串口的DR寄存器,而当每一个数据被写入串口DR寄存器后,串口的SR寄存器中的TXE: Transmit data register empty;会被自动置位,会自动触发串口中断进入串口服务函数,在HAL_UART_IRQHandler(&huart1);串口中断服务函数中通过UART_Transmit_IT() 函数与UART_EndTransmit_IT()函数来处理发送;

HAL_StatusTypeDef HAL_DMA_Start_IT(DMA_HandleTypeDef *hdma, uint32_t SrcAddress, uint32_t DstAddress, uint32_t DataLength)
{
  HAL_StatusTypeDef status = HAL_OK;
​
  /* Check the parameters */
  assert_param(IS_DMA_BUFFER_SIZE(DataLength));
​
  /* Process locked */
  __HAL_LOCK(hdma);
  
  if(HAL_DMA_STATE_READY == hdma->State)
  {
    /* Change DMA peripheral state */
    hdma->State = HAL_DMA_STATE_BUSY;
    hdma->ErrorCode = HAL_DMA_ERROR_NONE;
    
    /* Disable the peripheral */
    __HAL_DMA_DISABLE(hdma);
    
    /* Configure the source, destination address and the data length & clear flags*/
    DMA_SetConfig(hdma, SrcAddress, DstAddress, DataLength); 
    
    /* Enable the transfer complete interrupt */
    /* Enable the transfer Error interrupt */
    //根据DMA对象是否定义半传输中断函数来使能相应中断
    if(NULL != hdma->XferHalfCpltCallback)
    {
      /* Enable the Half transfer complete interrupt as well */
      __HAL_DMA_ENABLE_IT(hdma, (DMA_IT_TC | DMA_IT_HT | DMA_IT_TE));
    }
    else
    {
      __HAL_DMA_DISABLE_IT(hdma, DMA_IT_HT);
      __HAL_DMA_ENABLE_IT(hdma, (DMA_IT_TC | DMA_IT_TE));
    }
    /* Enable the Peripheral */
    //启动DMA传输;
    __HAL_DMA_ENABLE(hdma);
  }
  else
  {      
    /* Process Unlocked */
    __HAL_UNLOCK(hdma); 
​
    /* Remain BUSY */
    status = HAL_BUSY;
  }    
  return status;
}

需要注意的是其实DMA的半传输中断发生时,DMA仍然在搬运数据!!!只不过将中断信号发生给了NVIC让CPU去处理中断罢了;

3.3 DMA接收函数(UART_Start_Receive_DMA)

该函数由HAL_UART_Receive_DMA( )函数调用;

该函数主要是先注册DMA传输完成回调函数(其实就是把串口的传输完成回调函数地址赋值给了DMA结构体对象中的回调函数);

要特别注意,不能在HAL_UART_RxCpltCallback( )串口接收完成回调函数中调用UART_Start_Receive_DMA( )函数启动DMA接收;因为在DMA初始化时调用了__HAL_LINKDMA(uartHandle,hdmarx,hdma_usart1_rx);这个函数;因此DMA的传输完成中断回调函数也就被配置成了串口传输完成回调的函数。但是注意,这个DMA的回调函数是在DMA的中断中执行的!!!

也就是说如过在回调函数HAL_UART_RxCpltCallback( )中调用UART_Start_Receive_DMA( ),那么相当于DMA还没有退出接收完成中断,就又在中断里开启了DMA传输,这必然会发生错误!!!会导致程序跑飞~~

HAL_StatusTypeDef UART_Start_Receive_DMA(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size)
{
  uint32_t *tmp;
​
  huart->pRxBuffPtr = pData;
  huart->RxXferSize = Size;
​
  huart->ErrorCode = HAL_UART_ERROR_NONE;
  huart->RxState = HAL_UART_STATE_BUSY_RX;
​
  /* Set the UART DMA transfer complete callback */
  huart->hdmarx->XferCpltCallback = UART_DMAReceiveCplt;
​
  /* Set the UART DMA Half transfer complete callback */
  huart->hdmarx->XferHalfCpltCallback = UART_DMARxHalfCplt;
​
  /* Set the DMA error callback */
  huart->hdmarx->XferErrorCallback = UART_DMAError;
​
  /* Set the DMA abort callback */
  huart->hdmarx->XferAbortCallback = NULL;
​
  /* Enable the DMA stream */
  tmp = (uint32_t *)&pData;
  HAL_DMA_Start_IT(huart->hdmarx, (uint32_t)&huart->Instance->DR, *(uint32_t *)tmp, Size);  
​
  /* Clear the Overrun flag just before enabling the DMA Rx request: can be mandatory for the second transfer */
  __HAL_UART_CLEAR_OREFLAG(huart);
​
  /* Process Unlocked */
  __HAL_UNLOCK(huart);
​
  /* Enable the UART Parity Error Interrupt */
  SET_BIT(huart->Instance->CR1, USART_CR1_PEIE);
​
  /* Enable the UART Error Interrupt: (Frame error, noise error, overrun error) */
  SET_BIT(huart->Instance->CR3, USART_CR3_EIE);
​
  /* Enable the DMA transfer for the receiver request by setting the DMAR bit
  in the UART CR3 register */
  SET_BIT(huart->Instance->CR3, USART_CR3_DMAR);
​
  return HAL_OK;
}

  • 3
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是使用DMA初始化USART8的步骤: 1. 首先,确保你已经使能了DMAUSART8的时钟。 2. 配置USART8的GPIO引脚,使其作为USART8的TX和RX引脚。 3. 配置USART8的USART_InitStruct结构体,包括波特率、数据位、停止位、校验位等信息。 4. 配置DMADMA_InitStruct结构体,包括源地址、目的地址、数据长度、传输方向等信息。 5. 初始化USART8和DMA模块,使用HAL_UART_Init()和HAL_DMA_Init()函数。 6. 配置DMA传输完成后的回调函数,使用HAL_DMA_RegisterCallback()函数。 7. 启动DMA传输,使用HAL_DMA_Start_IT()函数。 以下是代码示例: ``` // 配置USART8的GPIO引脚 GPIO_InitTypeDef GPIO_InitStruct = {0}; GPIO_InitStruct.Pin = GPIO_PIN_1 | GPIO_PIN_0; // USART8_TX, USART8_RX GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; GPIO_InitStruct.Pull = GPIO_NOPULL; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH; GPIO_InitStruct.Alternate = GPIO_AF8_UART8; HAL_GPIO_Init(GPIOE, &GPIO_InitStruct); // 配置USART8的参数 UART_HandleTypeDef USART_InitStruct = {0}; USART_InitStruct.Instance = UART8; USART_InitStruct.Init.BaudRate = 115200; USART_InitStruct.Init.WordLength = UART_WORDLENGTH_8B; USART_InitStruct.Init.StopBits = UART_STOPBITS_1; USART_InitStruct.Init.Parity = UART_PARITY_NONE; USART_InitStruct.Init.Mode = UART_MODE_TX_RX; HAL_UART_Init(&USART_InitStruct); // 配置DMA传输参数 DMA_HandleTypeDef DMA_InitStruct = {0}; DMA_InitStruct.Instance = DMA1_Stream1; DMA_InitStruct.Init.Channel = DMA_CHANNEL_5; DMA_InitStruct.Init.Direction = DMA_MEMORY_TO_PERIPH; DMA_InitStruct.Init.PeriphInc = DMA_PINC_DISABLE; DMA_InitStruct.Init.MemInc = DMA_MINC_ENABLE; DMA_InitStruct.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE; DMA_InitStruct.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE; DMA_InitStruct.Init.Mode = DMA_NORMAL; DMA_InitStruct.Init.Priority = DMA_PRIORITY_HIGH; HAL_DMA_Init(&DMA_InitStruct); // 配置DMA传输完成后的回调函数 HAL_DMA_RegisterCallback(&DMA_InitStruct, HAL_DMA_XFER_CPLT_CB_ID, My_DMA_TxCpltCallback); // 启动DMA传输 HAL_DMA_Start_IT(&DMA_InitStruct, (uint32_t)txBuffer, (uint32_t)&USART8->DR, txSize); ``` 注意:在回调函数,需要重置DMA传输状态并释放USART8的发送锁。例如: ``` void My_DMA_TxCpltCallback(DMA_HandleTypeDef *hdma) { HAL_DMA_Abort(hdma); // 重置DMA传输状态 __HAL_UNLOCK(&huart8); // 释放USART8的发送锁 } ```

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值