关于STM32CubeMX+HAL库调试串口的总结

CubeMX版本是5.3.0
芯片是STM32H750
固件版本STM32Cube FW_H7 V1.5.0

主要是花了些时间才调好,才觉得比较珍贵所以要记下来。
共分两部分,一个是串口打印,一个是串口中断接收
串口打印跟标准库的写法一样,不再赘述,只是调用的发送接口是HAL_UART_Transmit。
这里需要注意的是HAL_UART_Transmit接口在调用的时候,不,应该是HAL库很多通信外设接口在调用的时候都应该用while循环等待外设操作OK(HAL_OK),以及使用HAL_UART_GetState等到返回UART句柄状态为HAL_UART_STATE_READY。当然更好的处理方式是在while里面做超时计数,超时则执行error_handle处理,再break掉。
这里还要注意的是在串口初始化的时候,应尽量要放到前面执行,外设初始化应优先于个人用户的初始化操作,否则会导致外设无法使用。

串口中断接收网上讲了很多,包括正点原子的例程也没有问题,只是我的这个要实现的要求不一样,发送频率较快,中断接收随时可能出现,所以网上的方式我都试过没有用。
表现有三种:
一是每次触发中断之后,直接死机,debug发现程序卡死在while循环HAL_UART_GetState不等于HAL_UART_STATE_READY。
二是不加while循环等待,表现为中断仅进去,还在跑,但再也进不去中断了。
三是我调的时候以为是串口接收中断被关闭了,在stm32xxx_it.c文件的串口总中断的HAL_UART_IRQHandler函数后面加了句__HAL_UART_ENABLE_IT(&huart8, UART_IT_RXNE);
会导致程序不停的进入总中断。其实这些UART导出的宏操作,在HAL库的接口里面都整合进去了的,不像标准库那样需要自己写。
比如说HAL_UART_Receive_IT这个接口,大家都知道这句话要在初始化的时候执行一次,用于定义中断接收缓冲区的位置和大小,它还包含了开启接收中断和封装了两层的接收中断回调函数HAL_UART_RxCpltCallback。
说到HAL_UART_RxCpltCallback,再补充一点是写这个函数在别的地方再取一个相同名字的就可以了,编译会以不带__weak的函数为准。因为改HAL库里面的内容后再使用CubeMX生成代码,改动的地方会消失,加/user code begin、end/也没用。

debug之后就会发现,其实根源是程序死在了HAL_UART_Receive_IT里面的__HAL_LOCK(huart)手里,进去发现,这个宏在很多串口操作里面都有,甚至其他外设也有类似的锁。在一些关键操作的时候会锁上,操作完了再解开,当然也包括了串口收发的操作。
于是事情就是这样:我这边串口需要不停发送以更新数据,但接收中断是随时都有可能发生的,如果接收中断发生在发送上锁之后,解锁之前,这样一来接收中断就接收不了数据了,而且__HAL_LOCK(huart)检测已上锁之后会返回HAL状态位BUSY,导致我写的while循环卡死的情况。这样一和二的现象就说得通了。
至于网上说的中断溢出的情况,没遇到。如果遇到了需要用__HAL_UART_CLEAR_IT(&huart8, UART_CLEAR_OREF)清除标志位。

还要补充一点是串口打印不要尽量不要出现在中断处理函数里面,还有就是打印的频率如果太快会导致HAL_UART_Transmit无法返回HAL_OK。

所以这里的解决方式是:

/* USER CODE BEGIN 1 */
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
  if(huart->Instance == UART8)
  {
    uint32_t timeout = 0;
    uint32_t maxDelay = 0x1FFFF;
    while(HAL_UART_Receive_IT(&huart8, Screen.R_Data, 1) != HAL_OK)
    {
      if(HAL_UART_Receive_IT(&huart8, Screen.R_Data, 1) == HAL_BUSY)
      {
        timeout++;//超时处理
        if(timeout > maxDelay) 
        {
          __HAL_UNLOCK(huart);//解锁
        }
      }
      else
      {
        timeout++;//超时处理
        if(timeout > maxDelay) 
        {
          printf("\n ScreenReceiveError! \n");
          break;        
        }
      }
    }
  }
}

你可能感兴趣的:(STM32)