01:HAL库---时钟

本文详细介绍了STM32F103单片机中时钟源的配置,包括HSI、HSE和PLL,以及如何通过HAL库进行RCC_OscConfig和RCC_ClockConfig。重点讲述了SystemInit函数中对时钟的初始化设置,展示了如何通过不同时钟源驱动系统时钟和RTC模块,以优化功耗。
摘要由CSDN通过智能技术生成

目录

一:前言

1:介绍

2:默认时钟

二:STM32F407

三:SystemInit

A:时钟控制寄存器(RCC_CR)

B:时钟配置寄存器(RCC_CFGR)

C:时钟控制寄存器(RCC_CR)

D:时钟配置寄存器(RCC_CFGR)

E:实验

四:HSL

A:F1

B:F407

五:HSE

A:F1

B:F407

六:HAL设置

仿真设置


一:前言

我们使用的是STM32F103CT86的型号

1:介绍

        时钟在在我们的单片机中非常重要,相当于我们的人类的心脏;简单来说,时钟是具有周期性的脉冲信号,最常用的是占空比50%的方波;

三种不同的时钟源可被用来驱动系统时钟 (SYSCLK)
        ● HSI 振荡器时钟
        ● HSE 振荡器时钟
        ● PLL 时钟
这些设备有以下 2 种二级时钟源:
        ● 40kHz 低速内部 RC ,可以用于驱动独立看门狗和通过程序选择驱动 RTC RTC 用于从停机 /
待机模式下自动唤醒系统。
        ● 32.768kHz 低速外部晶体也可用来通过程序选择驱动 RTC(RTCCLK)
当不被使用时,任一个时钟源都可被独立地启动或关闭,由此优化系统功耗。
HAL_StatusTypeDef HAL_RCC_OscConfig(RCC_OscInitTypeDef *RCC_OscInitStruct)
HAL_StatusTypeDef HAL_RCC_ClockConfig(RCC_ClkInitTypeDef *RCC_ClkInitStruct, uint32_t FLatency)

2:默认时钟

启动文件 SystemInit函数 时钟默认配置使用内部8M HSI
#include "stm32f1xx_hal.h"

int main(void){
	//这个函数用于初始化HAL库;它必须是主程序中执行的第一条指令
	HAL_Init();
	//PA8引脚输出系统时钟
	HAL_RCC_MCOConfig(RCC_MCO1,RCC_MCO1SOURCE_SYSCLK,RCC_MCODIV_1);
}

每个文件都是从汇编文件开始的,

对于我们的单片机而言不管我们上电复位,按键复位,NVIC system ,程序都会进入复位向量; 

可以看到复位向量里面首先调用了SystemInit;然后去__main(多了__,首先做了一些准备的工作,其次才开始调用我们c语言中的mian函数)

二:STM32F407

f4的时钟源和F1相同

简图:

时钟树

挂在APB1总线上面的时钟为:42MHZ。但是定时器时钟为:84MHZ

挂在APB2总线上面的时钟为:84MHZ。但是定时器时钟为:168MHZ

APB2/APB1

外设挂载哪个总线上面:STM32F407VET6数据手册.pdf 17页 

三:SystemInit

        HSI时钟信号由内部8MHz RC 振荡器产生,可直接作为系统时钟或在 2 分频后作为 PLL 输入。
      HSI RC振荡器能够在不需要任何外部器件的条件下提供系统时钟。它的启动时间比 HSE 晶体振
荡器短。然而,即使在校准之后它的时钟频率精度仍较差。

        我们研究源码看看在复位向量第一个调用的SystemInit,SystemInit里面到底做了什么

A:时钟控制寄存器(RCC_CR)

 /* Reset the RCC clock configuration to the default reset state(for debug purpose) */
  /* Set HSION bit */
  RCC->CR |= 0x00000001U; //时钟控制寄存器(RCC_CR)
时钟控制寄存器 (RCC_CR) 或上0x00000001U,其他位不变把最低位置1;就是开启 内部 8MHz 振荡器

B:时钟配置寄存器(RCC_CFGR)

  /* Reset SW, HPRE, PPRE1, PPRE2, ADCPRE and MCO bits */
#if !defined(STM32F105xC) && !defined(STM32F107xC)
  RCC->CFGR &= 0xF8FF0000U;
#else
  RCC->CFGR &= 0xF0FF0000U;
#endif /* STM32F105xC */   
  
  /* Reset HSEON, CSSON and PLLON bits */
  RCC->CR &= 0xFEF6FFFFU;

  /* Reset HSEBYP bit */
  RCC->CR &= 0xFFFBFFFFU;

  /* Reset PLLSRC, PLLXTPRE, PLLMUL and USBPRE/OTGFSPRE bits */
  RCC->CFGR &= 0xFF80FFFFU;

0xF8FF0000U=1111 1000 1111 1111 0000 0000 0000 0000;

与操作--清零;用于清除需要的 BIT位(0),不影响其他位(1)

时钟的选择由时钟配置寄存器 (RCC_CFGR) 中的 MCO[2:0] 位控制。就是位1:0,把单刀三制拨到

C:时钟控制寄存器(RCC_CR)

时钟控制寄存器(RCC_CR)操作的2次

/* Reset HSEON, CSSON and PLLON bits */
  RCC->CR &= 0xFEF6FFFFU;

  /* Reset HSEBYP bit */
  RCC->CR &= 0xFFFBFFFFU;

0xFEF6FFFFU=1111 1110 1111 0110 1111 1111 1111 1111


第二次操作:RCC->CR &= 0xFFFBFFFFU;-----18位清零

我们可以看到只要失能HSEBYP的前提是关闭振荡器;所以操作RCC->CR寄存器才会分2次写,第一次:关闭振荡器;第二次:失能HSEBYP

D:时钟配置寄存器(RCC_CFGR)

RCC->CFGR &= 0xFF80FFFFU;

在上面配置过了CFGP寄存器为什么还要在配置一遍;因为和上面的CR寄存器一样,关闭某个东西是有前提的

E:实验

#include "stm32f1xx_hal.h"

uint32_t GetPCLK1Freq;
uint32_t GetPCLK2Freq;
uint32_t GetHCLKFreq;
int main(void){
	//这个函数用于初始化HAL库;它必须是主程序中执行的第一条指令
	HAL_Init();
	//PA8引脚输出系统时钟
	HAL_RCC_MCOConfig(RCC_MCO1,RCC_MCO1SOURCE_SYSCLK,RCC_MCODIV_1);
	SystemCoreClockUpdate();
	
	GetHCLKFreq=HAL_RCC_GetHCLKFreq();
	GetPCLK1Freq=HAL_RCC_GetPCLK1Freq();
	GetPCLK2Freq=HAL_RCC_GetPCLK2Freq();
}
 

开启仿真

可以看到HSL系统默认的时钟为----0x007A1200=8000000=8MHZ;可以验证我们的实验正确。

void SystemInit (void)
{
  /* Reset the RCC clock configuration to the default reset state(for debug purpose) */
  /* Set HSION bit */
  RCC->CR |= 0x00000001U;

  /* Reset SW, HPRE, PPRE1, PPRE2, ADCPRE and MCO bits */
#if !defined(STM32F105xC) && !defined(STM32F107xC)
  RCC->CFGR &= 0xF8FF0000U;
#else
  RCC->CFGR &= 0xF0FF0000U;
#endif /* STM32F105xC */   
  
  /* Reset HSEON, CSSON and PLLON bits */
  RCC->CR &= 0xFEF6FFFFU;

  /* Reset HSEBYP bit */
  RCC->CR &= 0xFFFBFFFFU;

  /* Reset PLLSRC, PLLXTPRE, PLLMUL and USBPRE/OTGFSPRE bits */
  RCC->CFGR &= 0xFF80FFFFU;

#if defined(STM32F105xC) || defined(STM32F107xC)
  /* Reset PLL2ON and PLL3ON bits */
  RCC->CR &= 0xEBFFFFFFU;

  /* Disable all interrupts and clear pending bits  */
  RCC->CIR = 0x00FF0000U;

  /* Reset CFGR2 register */
  RCC->CFGR2 = 0x00000000U;
#elif defined(STM32F100xB) || defined(STM32F100xE)
  /* Disable all interrupts and clear pending bits  */
  RCC->CIR = 0x009F0000U;

  /* Reset CFGR2 register */
  RCC->CFGR2 = 0x00000000U;      
#else
  /* Disable all interrupts and clear pending bits  */
  RCC->CIR = 0x009F0000U;
#endif /* STM32F105xC */
    
#if defined(STM32F100xE) || defined(STM32F101xE) || defined(STM32F101xG) || defined(STM32F103xE) || defined(STM32F103xG)
  #ifdef DATA_IN_ExtSRAM
    SystemInit_ExtMemCtl(); 
  #endif /* DATA_IN_ExtSRAM */
#endif 

#ifdef VECT_TAB_SRAM
  SCB->VTOR = SRAM_BASE | VECT_TAB_OFFSET; /* Vector Table Relocation in Internal SRAM. */
#else
  SCB->VTOR = FLASH_BASE | VECT_TAB_OFFSET; /* Vector Table Relocation in Internal FLASH. */
#endif 
}

四:HSL

A:F1

目的:得到64M的系统时钟-------选择内部高速时钟(HSL)做为时钟源,通过PLL的倍率调节为64MHZ;同时PLL锁相环做为系统时钟源

#include "stm32f1xx_hal.h"


void RCC_Clock_HSLInit(void)
{
		RCC_OscInitTypeDef RCC_OscInitType;
		RCC_ClkInitTypeDef RCC_ClkInitType;
		
		//选择HSL做为时钟源
		RCC_OscInitType.OscillatorType=RCC_OSCILLATORTYPE_HSI;
		RCC_OscInitType.HSIState=RCC_HSI_ON;
		RCC_OscInitType.HSICalibrationValue=RCC_HSICALIBRATION_DEFAULT;
		RCC_OscInitType.PLL.PLLState=RCC_PLL_ON;         
		RCC_OscInitType.PLL.PLLSource=RCC_PLLSOURCE_HSI_DIV2;
		RCC_OscInitType.PLL.PLLMUL=RCC_PLL_MUL16;
		HAL_RCC_OscConfig(&RCC_OscInitType);
		
		//PLL做为系统时钟源
		RCC_ClkInitType.ClockType=(RCC_CLOCKTYPE_SYSCLK|RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2);
		RCC_ClkInitType.SYSCLKSource=RCC_SYSCLKSOURCE_PLLCLK;
		RCC_ClkInitType.AHBCLKDivider=RCC_SYSCLK_DIV1;
		RCC_ClkInitType.APB1CLKDivider=RCC_HCLK_DIV2;
		RCC_ClkInitType.APB2CLKDivider= RCC_HCLK_DIV1;
		
		HAL_RCC_ClockConfig(&RCC_ClkInitType,FLASH_LATENCY_2);
	
}


#include "stm32f1xx_hal.h"
#include "rcc.h"

uint32_t GetPCLK1Freq;
uint32_t GetPCLK2Freq;
uint32_t GetHCLKFreq;

int main(void)
{

	//这个函数用于初始化HAL库;它必须是主程序中执行的第一条指令
	HAL_Init();
	RCC_Clock_HSLInit();
	//SystemClock_Config();
	//PA8引脚输出系统时钟
	HAL_RCC_MCOConfig(RCC_MCO1,RCC_MCO1SOURCE_SYSCLK,RCC_MCODIV_1);
	SystemCoreClockUpdate();
	
	GetHCLKFreq=HAL_RCC_GetHCLKFreq();
	GetPCLK1Freq=HAL_RCC_GetPCLK1Freq();
	GetPCLK2Freq=HAL_RCC_GetPCLK2Freq();
	
	
}


        频率越高,系统会越来越稳定;所以一般情况下我们选择使用外部的HSE,通过PLL可以转变为72HZ; 除非在外部晶振坏了或者考虑成本的情况下才会不会使用内部的晶振。

     

  根据仿真可以得到: HCLK=64Mhz

                                    PCLK2=64MhZ

                                      PCLK2=32MHZ

和我们实验想要达到的结果一样

B:F407


/**
 * @brief       时钟设置函数
 * @param       plln: 主PLL倍频系数(PLL倍频), 取值范围: 64~432.
 * @param       pllm: 主PLL和音频PLL预分频系数(进PLL之前的分频), 取值范围: 2~63.
 * @param       pllp: 主PLL的p分频系数(PLL之后的分频), 分频后作为系统时钟, 取值范围: 2, 4, 6, 8.(仅限这4个值)
 * @param       pllq: 主PLL的q分频系数(PLL之后的分频), 取值范围: 2~15.
 * @note
 *
 *              Fvco: VCO频率
 *              Fsys: 系统时钟频率, 也是主PLL的p分频输出时钟频率
 *              Fq:   主PLL的q分频输出时钟频率
 *              Fs:   主PLL输入时钟频率, 可以是HSI, HSE等.
 *              Fvco = Fs * (plln / pllm);
 *              Fsys = Fvco / pllp = Fs * (plln / (pllm * pllp));
 *              Fq   = Fvco / pllq = Fs * (plln / (pllm * pllq));
 *
 *              外部晶振为 8M的时候, 推荐值: plln = 336, pllm = 8, pllp = 2, pllq = 7.
 *              得到:Fvco = 8 * (336 / 8) = 336Mhz
 *                   Fsys = pll_p_ck = 336 / 2 = 168Mhz
 *                   Fq   = pll_q_ck = 336 / 7 = 48Mhz
 *
 *              F407默认需要配置的频率如下:
 *              CPU频率(HCLK) = pll_p_ck = 168Mhz
 *              AHB1/2/3(rcc_hclk1/2/3) = 168Mhz
 *              APB1(rcc_pclk1) = pll_p_ck / 4 = 42Mhz
 *              APB1(rcc_pclk2) = pll_p_ck / 2 = 84Mhz
 *
 * @retval      错误代码: 0, 成功; 1, 错误;
 */
uint8_t Clock_HSI_Init(uint16_t PLLM,uint16_t PLLN,uint16_t PLLP,uint16_t PLLQ)
{

	RCC_OscInitTypeDef RCC_OscInit={0};
	RCC_ClkInitTypeDef RCC_ClkInit={0};
	
	
	    __HAL_RCC_PWR_CLK_ENABLE();                                         /* 使能PWR时钟 */

    __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1);      /* 设置调压器输出电压级别,以便在器件未以最大频率工作 */
	 /* 使能HSE,并选择HSE作为PLL时钟源,配置PLL1,开启USB时钟 */
	RCC_OscInit.OscillatorType=RCC_OSCILLATORTYPE_HSI;     /*选择振荡器*/
	RCC_OscInit.HSIState=RCC_HSI_ON;											/*打开HSL*/
	/*然而,由于制造工艺的差异和温度等因素的影响,HSI的实际频率可能会有所偏差。
	为了补偿这种偏差,STM32提供了HSI校准功能,允许用户通过软件设置校准值来调整HSI的频率。*/
	RCC_OscInit.HSICalibrationValue=RCC_HSICALIBRATION_DEFAULT;  /*使用默认的HSE校准值。*/
	RCC_OscInit.PLL.PLLState=RCC_PLL_ON;									/*打开PLL锁相环*/
	RCC_OscInit.PLL.PLLSource=RCC_PLLSOURCE_HSI;					/*选择HSL为锁相环的时钟来源*/
	RCC_OscInit.PLL.PLLM=PLLM;
	RCC_OscInit.PLL.PLLN=PLLN;
	RCC_OscInit.PLL.PLLP=PLLP;
	RCC_OscInit.PLL.PLLQ=PLLQ;

	uint8_t ret=HAL_RCC_OscConfig(&RCC_OscInit);
	if(ret != HAL_OK)
	{
		    return 1; 
	}
	
	RCC_ClkInit.ClockType=RCC_CLOCKTYPE_SYSCLK|RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;  /*配置的时钟*/
	RCC_ClkInit.SYSCLKSource=RCC_SYSCLKSOURCE_PLLCLK;  /*系统时钟源PLL*/
	RCC_ClkInit.AHBCLKDivider=RCC_SYSCLK_DIV1;
	RCC_ClkInit.APB1CLKDivider=RCC_HCLK_DIV4;
	RCC_ClkInit.APB2CLKDivider=RCC_HCLK_DIV2;
	
	ret=HAL_RCC_ClockConfig(&RCC_ClkInit,FLASH_LATENCY_5);

	if(ret!=HAL_OK)
	{
		return 1;
	
	}
	 /* STM32F405x/407x/415x/417x Z版本的器件支持预取功能 */
	if (HAL_GetREVID() == 0x1001)
	{
			__HAL_FLASH_PREFETCH_BUFFER_ENABLE();                    /* 使能flash预取 */
	}
	return 0;
}
#include "sys.h"
#include "usart.h"
#include "delay.h"

uint32_t HCLK;
uint32_t APB1;
uint32_t APB2;
int main(void)
{
    HAL_Init();                                 /* 初始化HAL库 */
    //sys_stm32_clock_init(336, 8, 2, 7);         /* 设置时钟,168Mhz */
		Clock_HSI_Init(16,336,RCC_PLLP_DIV2,7);
    delay_init(168);                            /* 延时初始化 */
          

		
		
    while(1)
    {
				 HCLK=HAL_RCC_GetHCLKFreq();
				APB1=HAL_RCC_GetPCLK1Freq();
				APB2=HAL_RCC_GetPCLK2Freq();
	
    }
}

仿真: 

HCLK=168MHZ;     APB1=42MHZ ;        APB2=84MHZ。 仿真的结果和我们设置的相同。

和下面的HSE外部高速时钟很像,详情看下面的HSE。

五:HSE

A:F1

外部高速时钟:stm32F1C8T6的外部晶振为8MHZ

*HSE外部高速时钟做为系统时钟*/
void sys_stm32_clock_init(uint32_t plln)
{
		HAL_StatusTypeDef ret = HAL_ERROR;
		RCC_OscInitTypeDef RCC_OscInit = {0};
		RCC_ClkInitTypeDef RCC_ClkInit={0};
		
		//HSE外部时钟做为PLL时钟源
		RCC_OscInit.OscillatorType=RCC_OSCILLATORTYPE_HSE;/*选择振荡器类型*/
		RCC_OscInit.HSEState=RCC_HSE_ON;                  /*选择HSL状态*/
		RCC_OscInit.HSEPredivValue=RCC_HSE_PREDIV_DIV1;		/*HSE的分频系数*/
		RCC_OscInit.PLL.PLLState=RCC_PLL_ON;
		RCC_OscInit.PLL.PLLSource=RCC_PLLSOURCE_HSE;
		RCC_OscInit.PLL.PLLMUL=plln;  //RCC_PLL_MUL9
	
		ret=HAL_RCC_OscConfig(&RCC_OscInit);
		if (ret !=HAL_OK)
		{
			while (1);
			
		}
		
		//PLL做为系统时钟
		RCC_ClkInit.ClockType=RCC_CLOCKTYPE_SYSCLK|RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
		RCC_ClkInit.SYSCLKSource=RCC_SYSCLKSOURCE_PLLCLK;
		RCC_ClkInit.AHBCLKDivider=RCC_HCLK_DIV1;
		RCC_ClkInit.APB1CLKDivider=RCC_HCLK_DIV2;
		RCC_ClkInit.APB2CLKDivider=RCC_HCLK_DIV1;
		
		
		ret=HAL_RCC_ClockConfig(&RCC_ClkInit,FLASH_LATENCY_2);
		if (ret !=HAL_OK)
		{
			while (1);
			
		}		
		
}

#include "stm32f1xx_hal.h"
#include "rcc.h"

uint32_t GetPCLK1Freq;
uint32_t GetPCLK2Freq;
uint32_t GetHCLKFreq;
#define HSE_VALUE    8000000U
int main(void)
{

	//这个函数用于初始化HAL库;它必须是主程序中执行的第一条指令
	HAL_Init();
	//RCC_Clock_HSLInit();  RCC_PLL_MUL9
	sys_stm32_clock_init(RCC_PLL_MUL9);
	//PA8引脚输出系统时钟
	HAL_RCC_MCOConfig(RCC_MCO1,RCC_MCO1SOURCE_SYSCLK,RCC_MCODIV_1);
	SystemCoreClockUpdate();
	
	GetHCLKFreq=HAL_RCC_GetHCLKFreq();
	GetPCLK1Freq=HAL_RCC_GetPCLK1Freq();
	GetPCLK2Freq=HAL_RCC_GetPCLK2Freq();


}

   HAL_StatusTypeDef 是一个在STM32 HAL (硬件抽象层) 库中定义的类型,用于表示函数调用的状态。这个类型通常用于返回函数执行的结果,以指示操作是否成功或出现了错误。

   HAL_StatusTypeDef 通常定义为一个枚举,其中包含几个可能的值,如 HAL_OKHAL_ERRORHAL_TIMEOUT 等。这些值用于表示函数调用的不同结果。例如,如果函数成功执行,它可能会返回 HAL_OK;如果发生错误,它可能会返回 HAL_ERROR

        在STM32 HAL库中,许多函数都使用 HAL_StatusTypeDef 作为其返回类型。这使得调用者可以轻松地检查函数调用是否成功,并根据需要采取适当的操作。

        关于您提到的具体函数(如 HAL_CAN_ActivateNotificationHAL_CAN_StartHAL_CAN_ConfigFilter 和 HAL_UART_Receive_IT),它们都是STM32 HAL库中的函数,用于配置和管理CAN和UART(通用异步收发传输器)外设。这些函数使用 HAL_StatusTypeDef 作为返回类型,以指示操作是否成功。

        如果您在移植标准库的GPIO功能到HAL库工程时遇到 HAL_StatusTypeDef 未定义的问题,这通常意味着您可能没有正确包含必要的头文件或库文件。确保您已经包含了定义 HAL_StatusTypeDef 的头文件(通常是 stm32fxxx_hal.h),并且您的项目配置正确,以便包含和链接STM32 HAL库。

        此外,请注意,当您在HAL库环境中工作时,您需要遵循HAL库的规范和约定。例如,使用HAL库提供的函数和数据结构来初始化和配置外设,而不是尝试直接使用标准库中的函数或数据结构。这有助于确保您的代码与HAL库兼容,并能够充分利用HAL库提供的功能和优势。

仿真:

        

        PCLK1(APB1)=36MHZ

        PCLK2(APB2)=72MHZ

        HCLK(AHB)=72HMZ

使用仿真查看主频注意:

        在获取我们的主频值的时候我们想要调用:SystemCoreClockUpdate()。刷新一下.因为我们已经改变了主频,需要刷新一下,在获取

        HAL_RCC_ClockConfig(&RCC_ClkInit,FLASH_LATENCY_2);为等待周期,我们设置了72的MHZ,所以需要2个等待周期。

        手册32页

/** @defgroup FLASH_Latency FLASH Latency
  * @{
  */
#define FLASH_LATENCY_0            0x00000000U               /*!< FLASH Zero Latency cycle */
#define FLASH_LATENCY_1            FLASH_ACR_LATENCY_0       /*!< FLASH One Latency cycle */
#define FLASH_LATENCY_2            FLASH_ACR_LATENCY_1       /*!< FLASH Two Latency cycles */

B:F407

外部高速晶振比内部的更加稳定,有外部就使用外部的。没有的话使用内部的。

/**
 * @brief       时钟设置函数
 * @param       plln: 主PLL倍频系数(PLL倍频), 取值范围: 64~432.
 * @param       pllm: 主PLL和音频PLL预分频系数(进PLL之前的分频), 取值范围: 2~63.
 * @param       pllp: 主PLL的p分频系数(PLL之后的分频), 分频后作为系统时钟, 取值范围: 2, 4, 6, 8.(仅限这4个值)
 * @param       pllq: 主PLL的q分频系数(PLL之后的分频), 取值范围: 2~15.
 * @note
 *
 *              Fvco: VCO频率
 *              Fsys: 系统时钟频率, 也是主PLL的p分频输出时钟频率
 *              Fq:   主PLL的q分频输出时钟频率
 *              Fs:   主PLL输入时钟频率, 可以是HSI, HSE等.
 *              Fvco = Fs * (plln / pllm);
 *              Fsys = Fvco / pllp = Fs * (plln / (pllm * pllp));
 *              Fq   = Fvco / pllq = Fs * (plln / (pllm * pllq));
 *
 *              外部晶振为 8M的时候, 推荐值: plln = 336, pllm = 8, pllp = 2, pllq = 7.
 *              得到:Fvco = 8 * (336 / 8) = 336Mhz
 *                   Fsys = pll_p_ck = 336 / 2 = 168Mhz
 *                   Fq   = pll_q_ck = 336 / 7 = 48Mhz
 *
 *              F407默认需要配置的频率如下:
 *              CPU频率(HCLK) = pll_p_ck = 168Mhz
 *              AHB1/2/3(rcc_hclk1/2/3) = 168Mhz
 *              APB1(rcc_pclk1) = pll_p_ck / 4 = 42Mhz
 *              APB1(rcc_pclk2) = pll_p_ck / 2 = 84Mhz
 *
 * @retval      错误代码: 0, 成功; 1, 错误;
 */
uint8_t Clock_HSE_Init(uint16_t PLLM,uint16_t PLLN,uint16_t PLLP,uint16_t PLLQ)
{

	RCC_OscInitTypeDef RCC_OscInit={0};
	RCC_ClkInitTypeDef RCC_ClkInit={0};
	
	
	    __HAL_RCC_PWR_CLK_ENABLE();                                         /* 使能PWR时钟 */

    __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1);      /* 设置调压器输出电压级别,以便在器件未以最大频率工作 */
	 /* 使能HSE,并选择HSE作为PLL时钟源,配置PLL1,开启USB时钟 */
	RCC_OscInit.OscillatorType=RCC_OSCILLATORTYPE_HSE;     /*选择振荡器*/
	RCC_OscInit.HSEState=RCC_HSE_ON;											/*打开HSE*/
	RCC_OscInit.PLL.PLLState=RCC_PLL_ON;									/*打开PLL锁相环*/
	RCC_OscInit.PLL.PLLSource=RCC_PLLSOURCE_HSE;					/*选择HSE为锁相环的时钟来源*/
	RCC_OscInit.PLL.PLLM=PLLM;
	RCC_OscInit.PLL.PLLN=PLLN;
	RCC_OscInit.PLL.PLLP=PLLP;
	RCC_OscInit.PLL.PLLQ=PLLQ;

	uint8_t ret=HAL_RCC_OscConfig(&RCC_OscInit);
	if(ret != HAL_OK)
	{
		    return 1; 
	}
	
	RCC_ClkInit.ClockType=RCC_CLOCKTYPE_SYSCLK|RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;  /*配置的时钟*/
	RCC_ClkInit.SYSCLKSource=RCC_SYSCLKSOURCE_PLLCLK;  /*系统时钟源=*/
	RCC_ClkInit.AHBCLKDivider=RCC_SYSCLK_DIV1;
	RCC_ClkInit.APB1CLKDivider=RCC_HCLK_DIV4;
	RCC_ClkInit.APB2CLKDivider=RCC_HCLK_DIV2;
	
	ret=HAL_RCC_ClockConfig(&RCC_ClkInit,FLASH_LATENCY_5);

	if(ret!=HAL_OK)
	{
		return 1;
	
	}
	 /* STM32F405x/407x/415x/417x Z版本的器件支持预取功能 */
	if (HAL_GetREVID() == 0x1001)
	{
			__HAL_FLASH_PREFETCH_BUFFER_ENABLE();                    /* 使能flash预取 */
	}
	return 0;
}

#include "sys.h"
#include "usart.h"
#include "delay.h"

uint32_t HCLK;
uint32_t APB1;
uint32_t APB2;
int main(void)
{
    HAL_Init();                                 /* 初始化HAL库 */
    //sys_stm32_clock_init(336, 8, 2, 7);         /* 设置时钟,168Mhz */
		Clock_HSE_Init(8,336,RCC_PLLP_DIV2,7);
    delay_init(168);                            /* 延时初始化 */
          
		
		
		
    while(1)
    {
				 HCLK=HAL_RCC_GetHCLKFreq();
				APB1=HAL_RCC_GetPCLK1Freq();
				APB2=HAL_RCC_GetPCLK2Freq();
	
    }
}

仿真:

HCLK=168MHZ;     APB1=42MHZ ;        APB2=84MHZ。 仿真的结果和我们设置的相同。

设置调压器输出电压级别

 __HAL_RCC_PWR_CLK_ENABLE();                                         /* 使能PWR时钟 */

    __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1);      /* 设置调压器输出电压级别,以便在器件未以最大频率工作 */

也可以不用写这个:

FLASH的等待周期:

ret=HAL_RCC_ClockConfig(&RCC_ClkInit,FLASH_LATENCY_5);

#define FLASH_LATENCY_0                FLASH_ACR_LATENCY_0WS   /*!< FLASH Zero Latency cycle      */
#define FLASH_LATENCY_1                FLASH_ACR_LATENCY_1WS   /*!< FLASH One Latency cycle       */
#define FLASH_LATENCY_2                FLASH_ACR_LATENCY_2WS   /*!< FLASH Two Latency cycles      */
#define FLASH_LATENCY_3                FLASH_ACR_LATENCY_3WS   /*!< FLASH Three Latency cycles    */
#define FLASH_LATENCY_4                FLASH_ACR_LATENCY_4WS   /*!< FLASH Four Latency cycles     */
#define FLASH_LATENCY_5                FLASH_ACR_LATENCY_5WS   /*!< FLASH Five Latency cycles     */
#define FLASH_LATENCY_6                FLASH_ACR_LATENCY_6WS   /*!< FLASH Six Latency cycles      */
#define FLASH_LATENCY_7                FLASH_ACR_LATENCY_7WS   /*!< FLASH Seven Latency cycles    */

六:HAL设置

仿真设置

        在图 中,选择:Use Simulator,即使用软件仿真。选择:Run to main(),即跳过汇编代码,直接跳转到 main 函数开始仿真。设置下方的:Dialog DLL分别为:DARMSTM.DLL和 TARMSTM.DLL,Parameter 均为:-pSTM32F103C8,用于设置支持 STM32F103C8 的软硬件仿真(即可以通过 Peripherals 选择对应外设的对话框观察仿真结果)。最后点击 OK,完成设

配置好的图:

开始我尝试使用了软件仿真,但是一直不能显示出来,(如果有大佬的话,可以指点一下),我们最后选择了硬件仿真。

注意:硬件仿真,需要我们连接上我们的板子,并把程序下载进去。

本文参考:STM32F10xxx参考手册书写详细文章,请转至参考手册

链接:https://pan.baidu.com/s/1HrL5dzuFoZGTopzMTuQMxQ?pwd=5j2p 
提取码:5j2p 
--来自百度网盘超级会员V2的分享

  • 26
    点赞
  • 30
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值