记STM32运用HAL库系统时钟配置API的一个坑

记STM32运用HAL库配置系统时钟的一个坑

踩坑背景

	最近在一个全新项目中,硬件同事让我弄一个测试验证模块的电路,使用的是f1系列单片机,过程中发现外部晶振电
	路有问题,所以转而使用内部8M的HSI作为PLL时钟源,一顿操作弄完后发现,UART通讯出了点问题,示波器抓取
	通讯波形正常,但是程序打印出来部分数据帧却是乱码,具体的现象是乱码的数据帧中每个byte的最高有效位应该为
	0,但大都被解析成了1,导致乱码。
	在分析原因时第一时间就在想是不是时钟的问题,但是在Keil下使用J-Link(盗版货,能提供5V供电^_^)调试时发现
	竟然数据帧竟然正常了,接着发现只要在VDD供电上提供一个5V的电源(错误做法哈,大家还是要接单片机适配电
	压),uart通讯竟然都保持正常了。然后放弃了对时钟的追究,花里胡哨研究一番,还是没有结果,以为是什么玄学
	问题,就放在一边了。待到硬件同事改好外部晶振电路后,uart通讯正常了。我就在想,可能HSI配置的应该是有问
	题,毕竟HAL库的苦头吃过几次了,赶紧review下配置过程。

分析过程

   进入用户main函数前,启动文件中调用System_Init 将HSI作为系统时钟,此时系统时钟频率只有8M。在main函数
   中,调用HAL库API重新配置时钟,此函数对HSI、LSI、HSE、HSI和PLL分别配置,下面截取了我们需要的HSI配置
   过程,这里面会调用一个叫__HAL_RCC_HSI_CALIBRATIONVALUE_ADJUST的函数去改变寄存器RCC->CR中的
   bit7:3,也就是对应HSI的校准值(RCC_OscInitStruct->HSICalibrationValue),画重点是这个默认值不是0,而是
   0x16。根据实际使用的温度和电压调整,一般不需要动它。
   恰巧的是,我并没有对形参RCC_OscInitStruct中的每个成员都考虑到(PS:一般用HSE,用不
   到.HSICalibrationValue这个成员),导致最终配置了一个错误的值。只要将这个成员赋值为0x16,问题就解决了。

感悟

   一定要吸取教训,大家在使用HAL库开发时,即使不看源码,最起码也要弄清楚InitType形参配置的每个成员。出了
   Bug也一定要首先看源码,HAL库的坑,个人感觉还是挺多的。希望大家可以在遇到类似的问题时,可以从我这篇笔记
   中找到灵感。
   我用CSDN很久了,但是之前都是当成百度在用,这是第一次在CSDN上认真地记录笔记,以后我会经常分享学习心得
  	或者日常开发工作中的问题笔记,希望能给各位伙伴们带来一些有用的记录。
   最后,仍然让我疑惑的点就是:为什么在时钟不准确的情况下,VDD加一个5V供电,UART数据帧就正常了呢?

在这里插入图片描述

HAL_StatusTypeDef HAL_RCC_OscConfig(RCC_OscInitTypeDef  *RCC_OscInitStruct)
{
	/*----------------------------- HSI Configuration --------------------------*/ 
  if(((RCC_OscInitStruct->OscillatorType) & RCC_OSCILLATORTYPE_HSI) == RCC_OSCILLATORTYPE_HSI)
  {
    /* Check the parameters */
    assert_param(IS_RCC_HSI(RCC_OscInitStruct->HSIState));
    assert_param(IS_RCC_CALIBRATION_VALUE(RCC_OscInitStruct->HSICalibrationValue));

    /* Check if HSI is used as system clock or as PLL source when PLL is selected as system clock */ 
    if((__HAL_RCC_GET_SYSCLK_SOURCE() == RCC_SYSCLKSOURCE_STATUS_HSI) 
       || ((__HAL_RCC_GET_SYSCLK_SOURCE() == RCC_SYSCLKSOURCE_STATUS_PLLCLK) && (__HAL_RCC_GET_PLL_OSCSOURCE() == RCC_PLLSOURCE_HSI_DIV2)))
    {
      /* When HSI is used as system clock it will not disabled */
      if((__HAL_RCC_GET_FLAG(RCC_FLAG_HSIRDY) != RESET) && (RCC_OscInitStruct->HSIState != RCC_HSI_ON))
      {
        return HAL_ERROR;
      }
      /* Otherwise, just the calibration is allowed */
      else
      {
        /* Adjusts the Internal High Speed oscillator (HSI) calibration value.*/
        __HAL_RCC_HSI_CALIBRATIONVALUE_ADJUST(RCC_OscInitStruct->HSICalibrationValue);
      }
    }
    else
    {
      /* Check the HSI State */
      if(RCC_OscInitStruct->HSIState != RCC_HSI_OFF)
      {
       /* Enable the Internal High Speed oscillator (HSI). */
        __HAL_RCC_HSI_ENABLE();

        /* Get Start Tick */
        tickstart = HAL_GetTick();

        /* Wait till HSI is ready */
        while(__HAL_RCC_GET_FLAG(RCC_FLAG_HSIRDY) == RESET)
        {
          if((HAL_GetTick() - tickstart ) > HSI_TIMEOUT_VALUE)
          {
            return HAL_TIMEOUT;
          }
        }

        /* Adjusts the Internal High Speed oscillator (HSI) calibration value.*/
        __HAL_RCC_HSI_CALIBRATIONVALUE_ADJUST(RCC_OscInitStruct->HSICalibrationValue);
      }
      else
      {
        /* Disable the Internal High Speed oscillator (HSI). */
        __HAL_RCC_HSI_DISABLE();

        /* Get Start Tick */
        tickstart = HAL_GetTick();

        /* Wait till HSI is disabled */
        while(__HAL_RCC_GET_FLAG(RCC_FLAG_HSIRDY) != RESET)
        {
          if((HAL_GetTick() - tickstart ) > HSI_TIMEOUT_VALUE)
          {
            return HAL_TIMEOUT;
          }
        }
      }
    }
  }
}
  • 5
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
### 回答1: STM32F1 的 HAL 库是 ST 公司提供的一组高层次接口,可以使用它来编写 STM32F1 的硬件驱动程序。下面是一个示例代码,该代码演示了如何使用 STM32F1 HAL 库编写 ST7735S 液晶驱动程序。 ``` #include "stm32f1xx_hal.h" #include "st7735s.h" SPI_HandleTypeDef hspi1; void st7735s_init(void) { // configure the SPI peripheral hspi1.Instance = SPI1; hspi1.Init.Mode = SPI_MODE_MASTER; hspi1.Init.Direction = SPI_DIRECTION_1LINE; hspi1.Init.DataSize = SPI_DATASIZE_8BIT; hspi1.Init.CLKPolarity = SPI_POLARITY_LOW; hspi1.Init.CLKPhase = SPI_PHASE_1EDGE; hspi1.Init.NSS = SPI_NSS_SOFT; hspi1.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_2; hspi1.Init.FirstBit = SPI_FIRSTBIT_MSB; hspi1.Init.TIMode = SPI_TIMODE_DISABLE; hspi1.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE; hspi1.Init.CRCPolynomial = 10; HAL_SPI_Init(&hspi1); // send the initialization commands to the ST7735S HAL_GPIO_WritePin(ST7735S_DC_GPIO_Port, ST7735S_DC_Pin, GPIO_PIN_RESET); HAL_SPI_Transmit(&hspi1, (uint8_t *)st7735s_init_cmds, sizeof(st7735s_init_cmds), HAL_MAX_DELAY); HAL_GPIO_WritePin(ST7735S_DC_GPIO_Port, ST7735S_DC_Pin, GPIO_PIN_SET); } void st7735s_draw_pixel(uint16_t x, uint16_t y, uint16_t color) { // set the column and row addresses uint8_t cmd[4] = {0x2A, x >> 8, x & 0xFF, 0x2B}; HAL_GPIO_WritePin(ST7735S_DC_GPIO_Port, ST7735S_DC_Pin, GPIO_PIN_RESET); HAL_SPI_Transmit(&hspi1, cmd, sizeof( ### 回答2: STM32F1 HAL库是针对ST公司的STM32F1系列微控制器的硬件抽象层库,它提供了一系列方便易用的API函数,能够帮助开发者简化STM32F1芯片的驱动程序开发工作。 ST7735S是一种常用的彩色TFT液晶显示屏控制器,它采用串行接口进行数据传输,支持多种分辨率。下面是一个简单的ST7735S的硬件驱动库的设计思路: 1. 引脚初始化:根据ST7735S的引脚定义,将液晶显示屏所需的引脚设置为输出模式,并配置相应的GPIO口。 2. 时钟配置:根据系统时钟频率,配置SPI总线的时钟频率。 3. SPI初始化:根据ST7735S的通信协议,配置SPI相关的寄存器,使其符合ST7735S的通信需求。 4. 命令发送函数:编写函数用于向ST7735S发送命令。根据ST7735S的通信协议,先拉低片选信号,然后发送命令字节到SPI总线。 5. 数据发送函数:编写函数用于向ST7735S发送数据。同样先要拉低片选信号,然后将数据字节发送到SPI总线。 6. 显示初始化:根据ST7735S的初始化流程,调用命令发送函数发送初始化命令,以完成ST7735S的初始化。 7. 写入像素数据:编写函数用于向ST7735S写入像素数据。调用数据发送函数将像素数据发送到SPI总线,实现像素的显示。 8. 清屏函数:编写函数用于清除ST7735S显示屏上的内容。可以通过调用写入像素数据函数,将整个屏幕填充为背景色。 通过以上步骤,我们可以实现一个简单的ST7735S的硬件驱动库。在使用该库时,只需要调用相应的API函数,就可以初始化ST7735S、显示像素数据等功能。这样,开发者可以更加方便地使用STM32F1系列微控制器驱动ST7735S液晶显示屏,加快开发效率。 ### 回答3: ST7735S是一种常用的液晶显示控制器,需要使用STM32F1系列芯片进行硬件驱动。下面是一个简单的HAL库示例,用于驱动ST7735S液晶屏的初始化和显示功能。 首先,需要在STM32F1的工程中添加ST7735S库文件,并引入相关头文件。 接下来,需要定义一些常量来配置ST7735S的寄存器地址和引脚连接。 然后,在初始化函数中,需要进行一系列的配置操作,包括GPIO初始化、SPI初始化以及ST7735S的寄存器配置。其中,SPI用于与ST7735S进行通信。 在显示函数中,可以通过操作SPI向ST7735S传输数据,实现屏幕的显示功能。可以按照需求进行像素点、文本或图形的显示。 最后,在主函数中,调用初始化函数进行ST7735S的初始化,然后可以调用显示函数进行屏幕显示。可以根据需要设置不同的显示模式、颜色等。 总结起来,这个STM32F1 HAL库用于ST7735S的硬件驱动,主要实现了液晶屏的初始化和显示功能,通过SPI与ST7735S进行通信,并根据需要显示相应的内容。希望能够帮助你完成ST7735S硬件驱动的开发工作。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值