void USART1_IRQHandler(void)
{
/* USER CODE BEGIN USART1_IRQn 0 */
/* HAL库好像没有处理空闲中断的代码,需自己添加 */
if(__HAL_UART_GET_FLAG(&UartHandle,UART_FLAG_IDLE))
{
UsartReceive_IDLE(&UartHandle);
}
/* USER CODE END USART1_IRQn 0 */
HAL_UART_IRQHandler(&UartHandle);
/* USER CODE BEGIN USART1_IRQn 1 */
/* USER CODE END USART1_IRQn 1 */
}
查阅DATAsheet,发现修改发送DMA数据发送数寄存器前,需要先关闭DMA。
查到别人代码有在中断中用HAL_UART_DMAStop(huart)关闭中断,Debug后发现这个函数关闭RXDMA的同时关闭了TXDMA,导致串口的接收到数据后会关闭正在执行的发送DMA,会使串口不能同时进行收发数据,故改为 __HAL_DMA_DISABLE(huart->hdmarx); 关闭对应的接收DMA。
/* 串口接收空闲中断 */
void UsartReceive_IDLE(UART_HandleTypeDef *huart)
{
uint16_t i = 0;
if((__HAL_UART_GET_FLAG(huart,UART_FLAG_IDLE) != RESET))
{
if(huart->Instance == USART1)
{
__HAL_UART_CLEAR_IDLEFLAG(huart);
i = RXBUFFERSIZE-hdma_rx.Instance->CNDTR; //indicating the remaining bytes to be transmitted.
__HAL_DMA_DISABLE(huart->hdmarx); //Once the channel is enabled, this register is read-only
/* 此处处理数据,主要是拷贝和置位标志位 */
if(usart1_rx_flag == 0)
{
memcpy(aTxBuffer,aRxBuffer,i); // 字符串拷贝
usart1_rx_flag = 1; //接收完毕
}
/* 清空缓存,重新接收 */
memset(aRxBuffer,0x00,RXBUFFERSIZE); //把从a开始的80个字符全置为0
hdma_rx.Instance->CNDTR=RXBUFFERSIZE; //重装DMA数值
__HAL_DMA_ENABLE(huart->hdmarx);
}
}
}
串口DMA的底层配置
void HAL_UART_MspInit(UART_HandleTypeDef *huart)
{
GPIO_InitTypeDef GPIO_InitStruct;
/*##-1- Enable peripherals and GPIO Clocks #################################*/
/* Enable GPIO TX/RX clock */
USARTx_TX_GPIO_CLK_ENABLE();
USARTx_RX_GPIO_CLK_ENABLE();
/* Enable USARTx clock */
USARTx_CLK_ENABLE();
/* Enable DMA clock */
__HAL_RCC_DMA1_CLK_ENABLE();
/*##-2- Configure peripheral GPIO ##########################################*/
/* UART TX GPIO pin configuration */
GPIO_InitStruct.Pin = USARTx_TX_PIN;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_PULLUP;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
GPIO_InitStruct.Alternate = USARTx_TX_AF;
HAL_GPIO_Init(USARTx_TX_GPIO_PORT, &GPIO_InitStruct);
/* UART RX GPIO pin configuration */
GPIO_InitStruct.Pin = USARTx_RX_PIN;
GPIO_InitStruct.Alternate = USARTx_RX_AF;
HAL_GPIO_Init(USARTx_RX_GPIO_PORT, &GPIO_InitStruct);
/*##-3- Configure the DMA ##################################################*/
/* Configure the DMA handler for Transmission process */
hdma_tx.Instance = DMA1_Channel4;
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.Request = DMA_REQUEST_2;
HAL_DMA_Init(&hdma_tx);
/* Associate the initialized DMA handle to the UART handle */
__HAL_LINKDMA(huart, hdmatx, hdma_tx);
/* Configure the DMA handler for reception process */
hdma_rx.Instance = DMA1_Channel5;
hdma_rx.Init.Direction = DMA_PERIPH_TO_MEMORY;
hdma_rx.Init.PeriphInc = DMA_PINC_DISABLE;
hdma_rx.Init.MemInc = DMA_MINC_ENABLE;
hdma_rx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
hdma_rx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
hdma_rx.Init.Mode = DMA_NORMAL;
hdma_rx.Init.Priority = DMA_PRIORITY_HIGH;
hdma_rx.Init.Request = DMA_REQUEST_2;
HAL_DMA_Init(&hdma_rx);
/* Associate the initialized DMA handle to the the UART handle */
__HAL_LINKDMA(huart, hdmarx, hdma_rx);
/*##-4- Configure the NVIC for DMA #########################################*/
/* NVIC configuration for DMA transfer complete interrupt (USARTx_TX) */
HAL_NVIC_SetPriority(DMA1_Channel4_IRQn, 1, 2);
HAL_NVIC_EnableIRQ(DMA1_Channel4_IRQn);
/* NVIC configuration for DMA transfer complete interrupt (USARTx_RX) */
HAL_NVIC_SetPriority(DMA1_Channel5_IRQn, 1, 3);
HAL_NVIC_EnableIRQ(DMA1_Channel5_IRQn);
/* NVIC for USART, to catch the TX complete */
HAL_NVIC_SetPriority(USART1_IRQn, 1, 4);
HAL_NVIC_EnableIRQ(USART1_IRQn);
}