HAL库使用的外部晶振频率是多少?

HAL库默认使用内部RC,因为它不想让编程人员接触和硬件有关的东西,因此HAL库没有使用外部晶振,但提供了相关配置函数。使用外部晶振是由后期设计工程模板的的人自己写了一个SystemClock_Config()来实现的。看到SystemClock_Config()没有带“HAL_”前缀,你就明白了,它不是来自HAL库。PY32F003F18P和STM32F334R8的HALL库,就是如此,其它CPU不知道是否是如此,为了体现HAL库的优势,HAL库不会自己否定自己,因此,它不会去写这种函数,好比写议论文一样,为了支持自己的观点,啥都不要了。举例说明如下:

1、PY32F003F18P的官方模板是这么切换时钟的,如下:

void APP_SystemClockConfig(void)
{
  RCC_OscInitTypeDef RCC_OscInitStruct = {0};
  RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};

  /* 振荡器配置 */
  RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;

/* 选择RCC振荡器为HSE */
  RCC_OscInitStruct.HSIState = RCC_HSI_ON;  /* 开启HSI */
  RCC_OscInitStruct.HSIDiv = RCC_HSI_DIV4;  /* 4分频 */
  RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_8MHz;

/* 配置HSI输出时钟为8MHz */
  RCC_OscInitStruct.HSEState = RCC_HSE_ON; /* 开启HSE */
  RCC_OscInitStruct.HSEFreq = RCC_HSE_16_24MHz;  /* HSE晶振工作频率16M~32M */
  RCC_OscInitStruct.LSIState = RCC_LSI_OFF;  /* 准备关闭LSI */

  /* 配置振荡器 */
  if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
  {
    Error_Handler();
  }

  /* 时钟源配置 */
  RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_SYSCLK | RCC_CLOCKTYPE_PCLK1; /* 选择配置时钟 HCLK,SYSCLK,PCLK1 */
  RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_HSE;

/* 准备选择HSE作为系统时钟 */
  RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;     /* AHB时钟 1分频 */
  RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1;      /* APB时钟 1分频 */
  /* 配置时钟源 */
  if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_1) != HAL_OK)
  {
    Error_Handler();
  }
}


void Error_Handler(void)
{
  /* 无限循环 */
  while (1)
  {
  }
}

PY32F003F18P的HAL库提供的部分函数如下:

HAL_RCC_OscConfig()

HAL_RCC_ClockConfig()

注意:没有HAL_RCCEx_PeriphCLKConfig();

下面的是工程模板提供的:

#if !defined  (HSE_VALUE) 
  #define HSE_VALUE              ((uint32_t)24000000) /*!< Value of the External oscillator in Hz */
#endif /* HSE_VALUE */

注意:PY32F003F18P没有PLL这个功能 

2、STM32F334R8的官方模板是这么切换时钟的,如下:

//函数功能:系统时钟使用HSE+PLL
void SystemClock_Config_HSE(void)
{
   RCC_OscInitTypeDef RCC_OscInitStruct = {0};
  RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
  RCC_PeriphCLKInitTypeDef PeriphClkInit = {0};

  /** Initializes the CPU, AHB and APB busses clocks 
  */

  RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;//RCC_OSCILLATORTYPE_HSE=0x00000001U
  RCC_OscInitStruct.HSEState = RCC_HSE_ON;//RCC_HSE_ON=0x00010000
  RCC_OscInitStruct.HSEPredivValue = RCC_HSE_PREDIV_DIV1;

//设置RCC->CFGR寄存器的PLLXTPRE=0,HSE分频器设置为1
  RCC_OscInitStruct.HSIState = RCC_HSI_ON;//RCC_HSI_ON=0x00000001
  RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;

//设置RCC->CFGR寄存器的SW=2,设置PLL作为系统时钟
  RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
    //设置RCC->CFGR寄存器的PLLSRC=1,PLL使用HSE作为输入时钟源
  RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL6;
    //设置RCC->CFGR寄存器的PLLMUL[3:0]=0100B,即PLL乘法因子为6
    //由于PLL乘法因子为6,外部晶振频率为12MHz,因此当AHB分频器为1时,系统时钟就是72MHz

  if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
  {//设置PLL时钟进入工作状态
    Error_Handler();
  }
  /** Initializes the CPU, AHB and APB busses clocks 
  */

  RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
                              |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
  RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;

//使用PLL作为系统时钟源
  RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;//AHB分频器设置为1
  RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2;

//APB1分频器设置为2,则PCLK1=36MHz,TIM2CLK,TIM3CLK,TIM6CLK,TIM7CLK为72MHz
  RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;

//APB2分频器设置为1,则PCLK2=72MHz,TIM1CLK,TIM15CLK,TIM16CLK,TIM17CLK为72MHz

  if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK)
  {//根据RCC_ClkInitStruct结构变量初始化系统时钟
    Error_Handler();
  }
  PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_HRTIM1|RCC_PERIPHCLK_USART1;
  PeriphClkInit.Usart1ClockSelection = RCC_USART1CLKSOURCE_PCLK1;
  PeriphClkInit.Hrtim1ClockSelection = RCC_HRTIM1CLK_PLLCLK;
  if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit) != HAL_OK)
  {
    Error_Handler();
  }

    SystemCoreClockUpdate();//根据系统时钟开关状态更新SystemCoreClock的值
}
void Error_Handler(void)
{
    while(1);
}

STM32F334R8的HAL库提供的部分函数如下:

HAL_RCC_OscConfig()
HAL_RCC_ClockConfig()
HAL_RCCEx_PeriphCLKConfig()

下面是工程模板的:

#if !defined  (HSE_VALUE) 
  #define HSE_VALUE    ((uint32_t)12000000)

/*!< Value of the External oscillator in Hz */
    //外部晶振12000000Hz

#endif /* HSE_VALUE */

SystemCoreClockUpdate()

3、STM32G031F6P6使用的系统时钟,其配置如下:

//函数功能:使用内部HSI+PLL实现系统时钟,得到SystemCoreClock=(16/1)*16/4=64MHz
void SystemClock_Config_HSI(void)
{
  RCC_OscInitTypeDef RCC_OscInitStruct = {0};
  RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
  RCC_PeriphCLKInitTypeDef PeriphClkInit = {0};

  HAL_PWREx_ControlVoltageScaling(PWR_REGULATOR_VOLTAGE_SCALE1);
    //内部稳压为1.2 V,允许系统频率最高为64MHz
    //Configure the main internal regulator output voltage

  /** Initializes the CPU, AHB and APB busses clocks */
  RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI;
  RCC_OscInitStruct.HSIState = RCC_HSI_ON;
  RCC_OscInitStruct.HSIDiv = RCC_HSI_DIV1;
  RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT;
  RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
  RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSI;
  RCC_OscInitStruct.PLL.PLLM = RCC_PLLM_DIV1;
    //PLLM=000b,位于RCC_PLLCFGR寄存器,表示PLL输入时钟分频器的M分频值为1
  //RCC_OscInitStruct.PLL.PLLN = 16;
    //PLLN[6:0]=16,位于RCC_PLLCFGR寄存器,,表示PLL乘法因子为16

  RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2;
  RCC_OscInitStruct.PLL.PLLQ = RCC_PLLQ_DIV2;
  RCC_OscInitStruct.PLL.PLLR = RCC_PLLR_DIV4;//PLLR division factor = 4
    //PLLR[2:0]=011b,位于RCC_PLLCFGR寄存器,表示PLLRCLK输出时钟分频器值为4
//HSI_VALUE为16000000Hz
//fVCO = fPLLIN × (N / M)
//fPLLP = fVCO / P
//fPLLQ = fVCO / Q
//fPLLR = fVCO / R
//PLLM=000b,位于RCC_PLLCFGR寄存器,表示PLL输入时钟分频器的M分频值为1
//PLLN[6:0]=16,位于RCC_PLLCFGR寄存器,,表示PLL乘法因子为16
//fVCO=16000000*(16/1)=256000000Hz
//fPLLR = fPLLIN × (N / M) / R = 16000000*(16/1)/4=64000000Hz
//SystemCoreClock

  if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
  {
    Error_Handler();
  }

  /** Initializes the CPU, AHB and APB busses clocks */
  RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
                              |RCC_CLOCKTYPE_PCLK1;
  RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
//用来设置RCC->CFGR寄存器的SW[2:0],SW[2:0]=010b,表示使用PLLRCLK时钟作为系统时钟
  RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
//用来设置RCC_CFGR寄存器的HPRE[3:0],HPRE[3:0]=0xxxb,表示1分频
  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_USART1|RCC_PERIPHCLK_ADC
                              |RCC_PERIPHCLK_TIM1;
  PeriphClkInit.Usart1ClockSelection = RCC_USART1CLKSOURCE_PCLK1;
  PeriphClkInit.AdcClockSelection = RCC_ADCCLKSOURCE_SYSCLK;
  PeriphClkInit.Tim1ClockSelection = RCC_TIM1CLKSOURCE_PLL;
  if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit) != HAL_OK)
  {
    Error_Handler();
  }
    SystemCoreClockUpdate();
}

void SystemCoreClockUpdate(void)
{
  uint32_t tmp;
  uint32_t pllvco;
  uint32_t pllr;
  uint32_t pllsource;
  uint32_t pllm;
  uint32_t hsidiv;

  /* Get SYSCLK source -------------------------------------------------------*/
  switch (RCC->CFGR & RCC_CFGR_SWS)
  {
    case RCC_CFGR_SWS_HSE:  /* HSE used as system clock */
      SystemCoreClock = HSE_VALUE;
      break;

    case RCC_CFGR_SWS_LSI:  /* LSI used as system clock */
      SystemCoreClock = LSI_VALUE;
      break;

    case RCC_CFGR_SWS_LSE:  /* LSE used as system clock */
      SystemCoreClock = LSE_VALUE;
      break;

    case RCC_CFGR_SWS_PLL:  /* PLL used as system clock */
      /* PLL_VCO = (HSE_VALUE or HSI_VALUE / PLLM) * PLLN
         SYSCLK = PLL_VCO / PLLR
         */

      pllsource = (RCC->PLLCFGR & RCC_PLLCFGR_PLLSRC);
      pllm = ((RCC->PLLCFGR & RCC_PLLCFGR_PLLM) >> RCC_PLLCFGR_PLLM_Pos) + 1UL;

      if(pllsource == 0x03UL) /* HSE used as PLL clock source */
      {
        pllvco = (HSE_VALUE / pllm);
      }
      else /* HSI used as PLL clock source */
      {
          pllvco = (HSI_VALUE / pllm);
                //内部RC为HSI_VALUE=16MHz,PLLM=1,则pllvco=16/1=16MHz
      }
      pllvco = pllvco * ((RCC->PLLCFGR & RCC_PLLCFGR_PLLN) >> RCC_PLLCFGR_PLLN_Pos);
         //内部RC为HSI_VALUE=16MHz,PLLM=1,PLLN=16,则pllvco=(16/1)*16=256MHz
      pllr = (((RCC->PLLCFGR & RCC_PLLCFGR_PLLR) >> RCC_PLLCFGR_PLLR_Pos) + 1UL);
      SystemCoreClock = pllvco/pllr;
            //内部RC为HSI_VALUE=16MHz,PLLM=1,PLLN=16,PLLR=4,则SystemCoreClock=(16/1)*16/4=64MHz
      break;
      
    case RCC_CFGR_SWS_HSI:  /* HSI used as system clock */
    default:                /* HSI used as system clock */
      hsidiv = (1UL << ((READ_BIT(RCC->CR, RCC_CR_HSIDIV))>> RCC_CR_HSIDIV_Pos));
      SystemCoreClock = (HSI_VALUE/hsidiv);
      break;
  }
  /* Compute HCLK clock frequency --------------------------------------------*/
  /* Get HCLK prescaler */

  tmp = AHBPrescTable[((RCC->CFGR & RCC_CFGR_HPRE) >> RCC_CFGR_HPRE_Pos)];
    //从RCC_CFGR寄存器中读取HPRE[3:0],HPRE[3:0]=0xxxb,表示1分频
  /* HCLK clock frequency */

  SystemCoreClock >>= tmp; //SystemCoreClock=64000000Hz
}

STM32G031F6P6的HAL库提供的部分函数如下:

HAL_RCC_OscConfig()
HAL_RCC_ClockConfig()
HAL_RCCEx_PeriphCLKConfig()

总结:

从上面可以看出:

所有的HAL库均提供了HAL_RCC_OscConfig();  HAL_RCC_ClockConfig();HAL_RCCEx_PeriphCLKConfig();

PY32F003F18P的官方模板是24MHz;

STM32F334R8的官方模板是72MHz;

STM32G031F6P6的官方模板是64MHz;

STM32F103的官方模板是72MHz;这是众所周知的事情,不再叙述。

4、HAL是通用的吗?

HAL库无法做到互相替换,但函数名是一样的,实现的功能大体是一个意思。每个HAL库都要去了解,不是说一通百通,但大体上,是那个意思。

为什么HAL不写全,而让工程模板去实现,是因为各个厂家的CPU是不同的,为了体现兼容性强的特点,它没法去写。。所以,当有人问HALL库使用外部晶振的频率是多少,我很无语,因为这是和工程模板有关的。标准库和CPU有关,所以就不会存在这种问题

如果没有工程模板,自己实现,太难了。千万不要举一反三,CPU变了,HAL库没法保证外部晶振的频率是一样的。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值