STM32CubeMX生成代码问题

STM32CubeMX 可以直观的选择 STM32 微控制器、配置微控制器、自动处理引脚冲突、动态设置确定时钟树、动态确定参数设置的外围和中间件模式和初始化。STM32CubeMX 生成的代码可以在 KEIL、IAR、GCC 等编程软件上面使用。所以简单地说STM32CubeMX 本身就是一个工具软件,我们只要在上面通过图形化配置就可以生成STM32 功能代码工程,这个代码工程已经包括了必要的外设初始化程序,这样节省我们的工作量,把工作重点放在项目逻辑层、应用层的实现。
当然STM32CubeMX 生成的代码也会遇到一些问题:

1.外部低频晶振(LSE)不起振

选择外部低频晶振
STM32CubeMX生成代码问题_第1张图片
RTC选择外部晶振作为时钟源头
STM32CubeMX生成代码问题_第2张图片
配置完成后生成代码RTC正常工作,但是使用示波器发现外部低频晶振未起振(硬件检查时发现,软件工程师认为RTC正常工作,应该是外部未起振之后系统启用了内部晶振(LSI))。
查看STM32CubeMX 生成的配置代码:

void SystemClock_Config(void)
{
  RCC_OscInitTypeDef RCC_OscInitStruct = {0};
  RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
  RCC_PeriphCLKInitTypeDef PeriphClkInit = {0};

  /** Configure the main internal regulator output voltage
  */
  HAL_PWREx_ControlVoltageScaling(PWR_REGULATOR_VOLTAGE_SCALE1);
  /** Configure LSE Drive Capability
  */
  HAL_PWR_EnableBkUpAccess();
  //这里RCC_LSEDRIVE_LOW需要改为RCC_LSEDRIVE_HIGH
  __HAL_RCC_LSEDRIVE_CONFIG(RCC_LSEDRIVE_LOW);
  /** Initializes the RCC Oscillators according to the specified parameters
  * in the RCC_OscInitTypeDef structure.
  */
  RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_LSI|RCC_OSCILLATORTYPE_HSE
                              |RCC_OSCILLATORTYPE_LSE;
  RCC_OscInitStruct.HSEState = RCC_HSE_ON;
  RCC_OscInitStruct.LSEState = RCC_LSE_ON;
  RCC_OscInitStruct.LSIState = RCC_LSI_ON;
  RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
  RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
  RCC_OscInitStruct.PLL.PLLM = RCC_PLLM_DIV1;
  RCC_OscInitStruct.PLL.PLLN = 16;
  RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2;
  RCC_OscInitStruct.PLL.PLLR = RCC_PLLR_DIV2;
  if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
  {
    Error_Handler();
  }
  /** Initializes the CPU, AHB and APB buses clocks
  */
  RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
                              |RCC_CLOCKTYPE_PCLK1;
  RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
  RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
  RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1;

  if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK)
  {
    Error_Handler();
  }
  /** Initializes the peripherals clocks
  */
  PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_RTC|RCC_PERIPHCLK_USART1
                              |RCC_PERIPHCLK_USART2|RCC_PERIPHCLK_I2C1
                              |RCC_PERIPHCLK_ADC;
  PeriphClkInit.Usart1ClockSelection = RCC_USART1CLKSOURCE_PCLK1;
  PeriphClkInit.Usart2ClockSelection = RCC_USART2CLKSOURCE_PCLK1;
  PeriphClkInit.I2c1ClockSelection = RCC_I2C1CLKSOURCE_PCLK1;
  PeriphClkInit.AdcClockSelection = RCC_ADCCLKSOURCE_SYSCLK;
  PeriphClkInit.RTCClockSelection = RCC_RTCCLKSOURCE_LSE;

  if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit) != HAL_OK)
  {
    Error_Handler();
  }
}

上述代码中有这么一句代码

  __HAL_RCC_LSEDRIVE_CONFIG(RCC_LSEDRIVE_LOW);

我们将其改为

  __HAL_RCC_LSEDRIVE_CONFIG(RCC_LSEDRIVE_HIGH);

之后运行系统,使用示波器测量发现LSE正常起振。

2023.03.01更新
经过测试发现,LSE的驱动能力较弱,当将示波器测试头放到晶振管脚时,会导致晶振不起振;
测试现象为:
1.设备不开机,将示波器测试头放到晶振管脚,然后开机,发现机器无法开机,卡在时钟初始化(LSE无法起振);
2,设备开机后,将示波器测试头放到晶振管脚,发现RTC时钟不走了;
综上,当我们配置为

  __HAL_RCC_LSEDRIVE_CONFIG(RCC_LSEDRIVE_LOW);

实际上时钟时起振了,只是利用这种方式测量不到。

2.USART自锁问题

串口测试时会发现,串口无法进入中断,从串口线查看传感器数据正常,但是MCU调试无法进入中断;
尝试过很多方法,从网上找到一种说法:串口锁死导致无法进入中断。
原因是发送函数

HAL_StatusTypeDef HAL_UART_Transmit(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size, uint32_t Timeout)

和中断接收函数:

HAL_StatusTypeDef HAL_UART_Transmit_IT(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size)

中都有锁定的操作:

__HAL_LOCK(huart);

注释掉代码中的这一句话,运行正常。

你可能感兴趣的:(MCU,stm32,单片机,嵌入式硬件)