|
本帖最后由 quhaton 于 2020-12-27 04:54 编辑
本文只讨论HAL库串口接收中断解决方案,所以不提DMA的方案。之所以讨论HAL库串口接收中断,原因有:
1.HAL库的串口封装逻辑有点复杂,逻辑不够简洁,2.HAL库封装的串口接收回调是“接收定长数据”后回调,所以串口接收不定长数据就成了问题。
解决方案之一:自己实现串口接收中断处理,即可简化逻辑,又可实现不定长数据接收。
void USART1_IRQHandler(void)
{
/* USER CODE BEGIN USART1_IRQn 0 */
if(__HAL_UART_GET_FLAG(&huart1,UART_FLAG_RXNE)!= RESET)
{
buff[index++]=huart1.Instance->DR;//不同的芯片不同的库版本,DR寄存器的名字可能不一样;此处为了简洁,暂时未作数组溢出限制
return;
}
__HAL_UART_CLEAR_PEFLAG(&huart1);//此处清除多种中断,包括常见的 UART_FLAG_ORE: Overrun Error flag,不同的芯片不同的库版本,清楚中断标志的函数/宏可能不一样
return;
/* USER CODE END USART1_IRQn 0 */
//HAL_UART_IRQHandler(&huart1);//不能让这个自动生成的函数执行,上面的语句已经加了 return,所以这一行屏蔽不屏蔽都无所谓
/* USER CODE BEGIN USART1_IRQn 1 */
/* USER CODE END USART1_IRQn 1 */
}
如此,便跳过了HAL_UART_IRQHandler对串口的各种操作,完全自己控制接收,可以利用以前 使用标志库时的处理方法。
这里还有一个问题:何时知道一包数据接收完成?
解决方案是:开启串口空闲中断 或者 开启一个定时器(开启定时器的作用是检测串口接收数据空闲了多久),传输结束一定的时间,在中断里做个标志。
说说利用空闲中断吧,代码如下:
开启空闲中断部分:
MX_GPIO_Init();
MX_USART1_UART_Init();
/* USER CODE BEGIN 2 */
__HAL_UART_ENABLE_IT(&huart1, UART_IT_RXNE); //开启接收中断
__HAL_UART_ENABLE_IT(&huart1, UART_IT_IDLE); //开启空闲中断
/* USER CODE END 2 */
中断处理部分:
void USART1_IRQHandler(void)
{
/* USER CODE BEGIN USART1_IRQn 0 */
if(__HAL_UART_GET_FLAG(&huart1,UART_FLAG_RXNE)!= RESET)
{
buff[index++]=huart1.Instance->DR;//不同的芯片不同的库版本,DR寄存器的名字可能不一样;此处为了简洁,暂时未作数组溢出限制
return;
}
if(__HAL_UART_GET_FLAG(&huart1,UART_FLAG_IDLE)!= RESET)
{
__HAL_UART_CLEAR_PEFLAG(&huart1);
receive_over_flag=1;
return;
}
__HAL_UART_CLEAR_PEFLAG(&huart1);//此处清除多种中断,包括常见的 UART_FLAG_ORE: Overrun Error flag,不同的芯片不同的库版本,清除中断标志的函数/宏可能不一样
return;
/* USER CODE END USART1_IRQn 0 */
//HAL_UART_IRQHandler(&huart1);//不能让这个自动生成的函数执行,上面的语句已经加了 return,所以这一行屏蔽不屏蔽都无所谓
/* USER CODE BEGIN USART1_IRQn 1 */
/* USER CODE END USART1_IRQn 1 */
}
以上方案经验证,可行。
解决方案之二:使用HAL库提供的API实现串口接收中断处理,可实现不定长数据接收。
网上许多人说HAL库的串口接收只能接收定长数据,他们这么说的原因是:串口buff数据存满时才调用回调函数HAL_UART_RxCpltCallback()。
这是对HAL库串口接收逻辑的误解,我们完全可以在任意时刻提取数据加以处理,不必理会回调函数HAL_UART_RxCpltCallback()。
那么什么时候处理数据?还是利用空闲中断或者定时器,得到一包数据接收完成的信息,然后随时可以处理接收到的数据,而不必等待回调函数HAL_UART_RxCpltCallback()的执行。
需要注意的是:串口buff数据存满时会会关闭串口中断,然后调用HAL_UART_RxCpltCallback(),所以,程序中必须要做相应的处理,方法有两种:一种是限制接收计数器(huart的成员变量之一)的值,以防止触发 关闭中断 ,另一种是在HAL_UART_RxCpltCallback()中重新开启中断,可以调用函数 HAL_UART_Receive_IT(),代码如下:
void HAL_UART_RxCpltCallback(UART_HandleTypeDef*UartHandle)//处理:接收缓冲区满了,中断被关闭了
{
HAL_UART_Receive_IT(&huart1, (uint8_t *)RxBuff, 100); //复位多种标志,重新开启中断
}
分享一点思想经验,写的很乱,见谅。
|
|