具体串口工程如何使用CubeMX生成,不再赘述,例程很多,本人只关心生成之后需要修改和注意的地方。
完整代码:https://download.csdn.net/download/niu_88/11034265
1. 开启空闲中断和DMA接收
/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_DMA_Init();
MX_UART4_Init();
/* USER CODE BEGIN 2 */
__HAL_UART_ENABLE_IT(&huart4, UART_IT_IDLE);
HAL_UART_Receive_DMA(&huart4, rev_buf, BUFFER_LENGTH);
__HAL_UART_DISABLE_IT(&huart4, UART_IT_ERR);
__HAL_UART_DISABLE_IT(&huart4, UART_IT_PE);
/* USER CODE END 2 */
2. 改写DMA停止接收函数
/**
1. @brief Stop the DMA Receive.
2. @param huart: UART handle.
3. @retval HAL status
*/
HAL_StatusTypeDef HAL_UART_DMAStopRx(UART_HandleTypeDef *huart)
{
/* Stop UART DMA Rx request if ongoing */
if ((huart->RxState == HAL_UART_STATE_BUSY_RX) &&
(HAL_IS_BIT_SET(huart->Instance->CR3, USART_CR3_DMAR)))
{
CLEAR_BIT(huart->Instance->CR3, USART_CR3_DMAR);
/* Abort the UART DMA Rx channel */
if(huart->hdmarx != NULL)
{
HAL_DMA_Abort(huart->hdmarx);
}
//UART_EndRxTransfer(huart);
/* Disable RXNE, PE and ERR (Frame error, noise error, overrun error) interrupts */
CLEAR_BIT(huart->Instance->CR1, (USART_CR1_RXNEIE | USART_CR1_PEIE));
CLEAR_BIT(huart->Instance->CR3, USART_CR3_EIE);
/* At end of Rx process, restore huart->RxState to Ready */
huart->RxState = HAL_UART_STATE_READY;
}
return HAL_OK;
}
3. 处理串口空闲中断
/**
* @brief This function handles UART4 global interrupt.
*/
void UART4_IRQHandler(void)
{
/* USER CODE BEGIN UART4_IRQn 0 */
/* USER CODE END UART4_IRQn 0 */
HAL_UART_IRQHandler(&huart4);
/* USER CODE BEGIN UART4_IRQn 1 */
uint32_t isrflags = READ_REG(huart4.Instance->ISR);
uint32_t cr1its = READ_REG(huart4.Instance->CR1);
if(((isrflags & USART_ISR_IDLE) != RESET) && ((cr1its & USART_CR1_IDLEIE) != RESET)){
__HAL_UART_CLEAR_IDLEFLAG(&huart4);
uint32_t _len_dmarev = BUFFER_LENGTH - __HAL_DMA_GET_COUNTER(huart4.hdmarx);
if(_len_dmarev){
HAL_UART_DMAStopRx(huart4.hdmarx);
/* 接收的到的数据处理,添加自己的处理代码 */
HAL_UART_Receive_DMA(&huart4, rev_buf, BUFFER_LENGTH);
__HAL_UART_DISABLE_IT(&huart4, UART_IT_ERR);
__HAL_UART_DISABLE_IT(&huart4, UART_IT_PE);
}else{
READ_REG(huart4.Instance->RDR);
__HAL_UART_CLEAR_OREFLAG(&huart4);
}
}
/* USER CODE END UART4_IRQn 1 */
}
注意:
最关键的就是中断处理,调用官方给的库函数,发送与接收同时工作时容易出现挂掉等问题,所以需要修改DMA停止接收函数;
进入空闲中断后,首先判断DMA接收到的数据长度是否为0,若为0(即DMA没有接收到数据但进入了空闲中断),则此时串口接收寄存器可能产生了溢出,上一个数据还未读取,则下一个数据立马就来了,产生了溢出中断,需要将RDR寄存器的数据读出来并清掉溢出中断,否则串口再也接收不到数据了,这种情况在传输数据量较频繁、多任务已经在线调试DEBUG情况下很容易发生,可参考手册:
若DMA接收到的数据长度不是为0,则停止DMA接收,自己可做数据缓存区处理,然后再次启动DMA接收。每次启动DMA接收后,我还做了禁止奇偶校验错位中断和错误中断使能,因为启动DMA接收函数将这两个中断都使能,若产生了这两个中断而中断函数又没有相应的处理的话,则程序将卡死在中断里了,可依个人情况而设置。
最近在使用h7,不断的发现库里的bug,很多地方也是经自己修改和完善才能正常使用,哎,慢慢爬坑吧。