• 解决了个bug,想说点啥但又难以启齿


    说起来这个bug,让我想起来了前几个月一个入职的实习生小伙伴,小伙伴被安排了一个小任务,做一个小工装,按照公司的私有协议实现一些数据的读取、转发,用的是最常用的串口通讯。

    小伙子也是满怀斗志,计划使用cubemx和HAL库开发,底层勾勾点点,只把应用层移植过来,简单快速。但是,有时候理想和显示总是差一点“运气”和细心…

    一切准备就绪,代码移植过来,呵,不出意外的话肯定有意外…不但通讯没成功,点个灯都灭了,然后开始仿真、屏蔽代码,一部分一部分排除法…最终定位在了串口中断上,不管有没有数据来,都会疯狂的进中断

    继续仿真,进入到了这个错误,来看看是什么错误

    校验位错误,看起来很奇怪,外部串口已经断开了,理论上不会再进中断了才是,现在还报了个校验位错误,然后开始疯狂百度,找不到头绪了,可把孩子急坏了

    然后开始新建工程,先验证串口收发,自己写的基本的验证收发都没问题呀,怎么就移植过来别人的代码就跑崩了呀,费解…

    最后实在是没办法了,就帮小伙子调试一下吧,不调不信,一调差点给我整崩溃了,这不最近调蓝牙模组,突然又遇到这个问题了,忽然想起来这个事情,就简单记录一下,希望可以帮助一些小伙伴排忧解难,特别是用hal库的小伙伴

    一般我们使用cubemx配置串口的时候,仅仅是配置了一些参数、IO等,串口号名称不能像IO口一样定义label

    然后初始化代码如下:

    void MX_USART2_UART_Init(void)
    {
    
      /* USER CODE BEGIN USART2_Init 0 */
    
      /* USER CODE END USART2_Init 0 */
    
      /* USER CODE BEGIN USART2_Init 1 */
    
      /* USER CODE END USART2_Init 1 */
      huart2.Instance = USART2;
      huart2.Init.BaudRate = 115200;
      huart2.Init.WordLength = UART_WORDLENGTH_8B;
      huart2.Init.StopBits = UART_STOPBITS_1;
      huart2.Init.Parity = UART_PARITY_NONE;
      huart2.Init.Mode = UART_MODE_TX_RX;
      huart2.Init.HwFlowCtl = UART_HWCONTROL_NONE;
      huart2.Init.OverSampling = UART_OVERSAMPLING_16;
      huart2.Init.OneBitSampling = UART_ONE_BIT_SAMPLE_DISABLE;
      huart2.Init.ClockPrescaler = UART_PRESCALER_DIV1;
      huart2.AdvancedInit.AdvFeatureInit = UART_ADVFEATURE_NO_INIT;
      if (HAL_UART_Init(&huart2) != HAL_OK)
      {
        Error_Handler();
      }
      /* USER CODE BEGIN USART2_Init 2 */
    
      /* USER CODE END USART2_Init 2 */
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30

    结构体句柄采用的是系统自定义的:

    UART_HandleTypeDef huart2;
    
    • 1

    然后中断是这样的:

    /**
      * @brief This function handles USART2 global interrupt / USART2 wake-up interrupt through EXTI line 26.
      */
    void USART2_IRQHandler(void)
    {
      /* USER CODE BEGIN USART2_IRQn 0 */
    	#if 1
      /* USER CODE END USART2_IRQn 0 */
      HAL_UART_IRQHandler(&huart2);
      /* USER CODE BEGIN USART2_IRQn 1 */
    #else
    	HAL_UART_IRQHandler(&BluetoothUart);
    #endif
      /* USER CODE END USART2_IRQn 1 */
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    这样全采用HAL库的配置是完全没有问题的,那么为什么会出现上面所说的那个问题呢?且往下看

    相信不少同学在开发的时候,对于一些定义命名都喜欢“顾名思义”,也是变量命名的一种最基本要求,加入用了4个串口,各自负责不同的功能,这样命名,谁看得出来哪个串口是干什么用的:

    UART_HandleTypeDef huart1;
    UART_HandleTypeDef huart2;
    UART_HandleTypeDef huart3;
    UART_HandleTypeDef huart4;
    
    • 1
    • 2
    • 3
    • 4

    一般都会命名为具体的功能描述:

    UART_HandleTypeDef ble_uart;
    UART_HandleTypeDef print_uart;
    UART_HandleTypeDef gsm_uart;
    UART_HandleTypeDef gps_uart;
    
    • 1
    • 2
    • 3
    • 4

    然后串口在初始化的时候,就会重新初始化,写成自己的函数:

    static void BluetoothUartInit(void)
    {
    	BluetoothUart.Instance = USART2;
    	BluetoothUart.Init.BaudRate = 115200;
    	BluetoothUart.Init.WordLength = UART_WORDLENGTH_8B;
    	BluetoothUart.Init.StopBits = UART_STOPBITS_1;
    	BluetoothUart.Init.Parity = UART_PARITY_NONE;
    	BluetoothUart.Init.Mode = UART_MODE_TX_RX;
    	BluetoothUart.Init.HwFlowCtl = UART_HWCONTROL_NONE;
    	BluetoothUart.Init.OverSampling = UART_OVERSAMPLING_16;
    	if (HAL_UART_Init(&BluetoothUart) != HAL_OK)
    	{
    		Error_Handler();
    	}
    	HAL_UART_Receive_IT(&BluetoothUart, &ble_com.recbyte, 1);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    这时候我们开始运行代码,看一下huart2和BluetoothUart的值

    BluetoothUart->Instance = 0x400044000;
    
    
    • 1
    • 2

    huart2->Instance = 0;
    
    
    • 1
    • 2

    再来看下USART2对应的值是多少,加起来不正是上面的值吗,也就是说huart2实际上是没有被赋予正确的值的:

    
    #define PERIPH_BASE           (0x40000000UL)  /*!< Peripheral base address */
    #define APBPERIPH_BASE        (PERIPH_BASE)
    #define USART2_BASE           (APBPERIPH_BASE + 0x00004400UL)
    
    • 1
    • 2
    • 3
    • 4

    当然其他值也是没有被正确赋值的:

    至于为什么仿真会报PE错误,继续看看报这个错误的原因:

      uint32_t isrflags   = READ_REG(huart->Instance->ISR);
      uint32_t cr1its     = READ_REG(huart->Instance->CR1);
      uint32_t cr3its     = READ_REG(huart->Instance->CR3);
    
      uint32_t errorflags;
      uint32_t errorcode;
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    主要看ISR、CR1和USART_ISR_PE、USART_CR1_PEIE这几个寄存器

    #define USART_ISR_PE_Pos             (0U)
    #define USART_ISR_PE_Msk             (0x1UL << USART_ISR_PE_Pos)               /*!< 0x00000001 */
    #define USART_ISR_PE                 USART_ISR_PE_Msk                          /*!< Parity Error */
    
    #define USART_CR1_PEIE_Pos           (8U)
    #define USART_CR1_PEIE_Msk           (0x1UL << USART_CR1_PEIE_Pos)             /*!< 0x00000100 */
    #define USART_CR1_PEIE               USART_CR1_PEIE_Msk                        /*!< PE Interrupt Enable */
    
    CR1 = 0x20001160;
    ISR = 0;
    
    //最终计算
    isrflags & USART_ISR_PE = 0&1 = 0;
    cr1its & USART_CR1_PEIE = 0x20001160&1<<8= 0x100;
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    触发PE错误条件是,当然满足了,我觉得触发这个错误可能纯属偶然…

        /* UART parity error interrupt occurred -------------------------------------*/
        if (((isrflags & USART_ISR_PE) != 0U) && ((cr1its & USART_CR1_PEIE) != 0U))
        {
          __HAL_UART_CLEAR_FLAG(huart, UART_CLEAR_PEF);
    
          huart->ErrorCode |= HAL_UART_ERROR_PE;
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    最终如何解决呢,很简单,还是上面说到的,你用cubemx配套生成的,肯定不会出问题,当然了,你改为自己的,肯定也不会出问题,一个用一半显然是不行的啦

    为了不受cubemx生成代码影响,可以采取宏定义的方法:

    void USART2_IRQHandler(void)
    {
      /* USER CODE BEGIN USART2_IRQn 0 */
    	#if 0
      /* USER CODE END USART2_IRQn 0 */
      HAL_UART_IRQHandler(&huart2);
      /* USER CODE BEGIN USART2_IRQn 1 */
    #else
    	HAL_UART_IRQHandler(&BluetoothUart);
    #endif
      /* USER CODE END USART2_IRQn 1 */
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    问题就到这里了,问题不大,却需要多多留心!

  • 相关阅读:
    线程邮箱.
    工业物联网:基于数字孪生的车间物流与制造智能同步制造系统
    迎战秋招计划
    uniapp手机一键登录,微信授权登陆
    ShanDong Multi-University Training #3
    Pikachu靶场练习——CSRF
    uniapp实现下载图片到本地
    机器学习的线性回归与非线性回归
    帅呆了!Kafka移除了Zookeeper!
    助力项目快捷实现国际化,造个多语言轮子
  • 原文地址:https://blog.csdn.net/qq_16519885/article/details/126375645