STM32 第10讲 时钟系统:认识时钟树/配置时钟系统函数/时钟使能


什么是时钟(CLK)
时钟是具有周期性的脉冲信号,是单片机的脉搏,最常用的的占空比为50%的方波。
以STM32F407系列为例介绍单片的时钟系统。

时钟树

时钟源

在这里插入图片描述

  • 晶体时钟源:成本更高,稳定性更好,精确性更高
  • RC时钟源:成本更低

H–high L–low S–speed I–internal E–external

时钟简图

在这里插入图片描述

时钟原图

在这里插入图片描述
A——时钟源
B——锁相环
C——系统时钟源选择器
D——内核系统时钟和使能单元
E——定时器和外设
F——MCO时钟输出单元

STM32CubeMX 时钟树

在这里插入图片描述

锁相环PLL

锁相环的作用主要有两个部分:输入时钟净化和倍频。前者是利用锁相环电路的反馈机制实现,后者我们用于使芯片在更高且频率稳定的时钟下工作。
在这里插入图片描述

系统时钟

系统时钟 SYSCLK 为整个芯片提供了时序信号。我们已经大致知道 STM32 主控是时序电路链接起来的。对于相同的稳定运行的电路,时钟频率越高,指令的执行速度越快,单位时间能处理的功能越多。STM32 的系统时钟是可配置的,在 STM32F4 系列中,它可以为HSI、PLLCLK、HSE 中的一个,通过 CFGR 的位 SW[1:0]设置。
在这里插入图片描述

外设和定时器

1、 如果 APB 预分频器为 1,定时器时钟频率等于 APB 域的频率;
2、 否则,等于 APB 域的频率的两倍(×2)。
此外,AHB 总线时钟直接作为 GPIO(A\B\C\D\E\F\G\H\I)、以太网、DCMI、FSMC、AHB总线、Cortex 内核、存储器和 DMA 的 HCLK 时钟,并作为 Cortex 内核自由运行时钟 FCLK。

配置系统时钟

1. 配置HSE_VALUE
告诉HAL库外部晶振频率,stm32_hal_conf.h

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

2. 调用SystemInit()函数
在启动文件中调用,system_stm32xxxx.c

void SystemInit(void)
{
 /* FPU settings ------------------------------------------------------------*/
 #if (__FPU_PRESENT == 1) && (__FPU_USED == 1)
 SCB->CPACR |= ((3UL << 10*2)|(3UL << 11*2)); /* set CP10 and CP11 Full 
Access */
 #endif
#if defined (DATA_IN_ExtSRAM) || defined (DATA_IN_ExtSDRAM)
 SystemInit_ExtMemCtl();
#endif /* DATA_IN_ExtSRAM || DATA_IN_ExtSDRAM */
 /* Configure the Vector Table location -------------------------------------*/
#if defined(USER_VECT_TAB_ADDRESS)
 SCB->VTOR = VECT_TAB_BASE_ADDRESS | VECT_TAB_OFFSET; /* Vector Table 
Relocation in Internal SRAM */
#endif /* USER_VECT_TAB_ADDRESS */
}

3. 选择时钟源,配置PLL
通过HAL_RCC_OscConfig()函数配置

HAL_StatusTypeDef HAL_RCC_OscConfig(RCC_OscInitTypeDef  *RCC_OscInitStruct)
/*结构体*/
typedef struct 
{ 
	uint32_t  OscillatorType; 		/* 选择需要配置的振荡器 */ 
	uint32_t  HSEState; 			/* HSE 状态 */ 
	uint32_t  LSEState; 			/* LSE 状态 */ 
	uint32_t  HSIState; 			/* HSI 状态 */ 
	uint32_t  HSICalibrationValue; 	/* HSI 校准微调值,范围0x0~0x1F */ 
	uint32_t  LSIState; 			/* LSI 状态 */ 
	RCC_PLLInitTypeDef  PLL; 		/* PLL 结构体 */ 
}RCC_OscInitTypeDef;
/*PLL结构体*/
typedef struct 
{ 
	uint32_t  PLLState; 		/* PLL 状态 */ 
	uint32_t  PLLSource; 	/* PLL 时钟源 */ 
	uint32_t  PLLM; 		/* PLL 分频系数 M */ 
	uint32_t  PLLN; 		/* PLL 倍频系数 N */ 
	uint32_t  PLLP; 		/* PLL 分频系数 P */ 
	uint32_t  PLLQ; 		/* PLL 分频系数 Q */ 
}RCC_PLLInitTypeDef; 

4. 选择系统时钟源,配置总线分频器
通过HAL_RCC_ClockConfig()函数实现

HAL_StatusTypeDef HAL_RCC_ClockConfig(RCC_ClkInitTypeDef  *RCC_ClkInitStruct, uint32_t FLatency)
/*结构体*/
typedef struct 
{ 
	uint32_t  ClockType; 		/* 要配置的时钟(SYSCLK/HCLK/PCLK1/PCLK2) */ 
	uint32_t  SYSCLKSource; 		/* 系统时钟源 */ 
	uint32_t  AHBCLKDivider; 		/* AHB  时钟预分频系数 */ 
	uint32_t  APB1CLKDivider; 	/* APB1 时钟预分频系数 */ 
	uint32_t  APB2CLKDivider; 	/* APB2 时钟预分频系数 */ 
}RCC_ClkInitTypeDef;

/*Flash访问等待周期*/
uint32_t FLatency 

#define  FLASH_LATENCY_0   FLASH_ACR_LATENCY_0WS 	/* FLASH 0个等待周期 */ 
#define  FLASH_LATENCY_1   FLASH_ACR_LATENCY_1WS 	/* FLASH 1个等待周期 */ 
#define  FLASH_LATENCY_2   FLASH_ACR_LATENCY_2WS 	/* FLASH 2个等待周期 */ 
... 
#define  FLASH_LATENCY_15   FLASH_ACR_LATENCY_15WS 	/* FLASH 15个等待周期 */ 

在这里插入图片描述

5. 配置扩展外设时钟
通过HAL_RCCEx_PeriphCLKConfig()函数实现

通过sys_stm32_clock_init()函数实现步骤3、4

/**
* @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 sys_stm32_clock_init(uint32_t plln, uint32_t pllm, uint32_t pllp,
uint32_t pllq)
{
 HAL_StatusTypeDef ret = HAL_OK;
 RCC_OscInitTypeDef rcc_osc_init = {0};
RCC_ClkInitTypeDef rcc_clk_init = {0};
 __HAL_RCC_PWR_CLK_ENABLE(); /* 使能 PWR 时钟 */
 
/* 下面这个设置用来设置调压器输出电压级别,以便在器件以最大频率工作时使性能与功耗实现平衡 */
 /* 设置调压器输出电压级别,以便在器件未以最大频率工作 */
 __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1);
 /* 使能 HSE,并选择 HSE 作为 PLL 时钟源,配置 PLL1,开启 USB 时钟 */
 rcc_osc_init.OscillatorType = RCC_OSCILLATORTYPE_HSE;
 rcc_osc_init.HSEState = RCC_HSE_ON; /* 打开 HSE */
 rcc_osc_init.PLL.PLLState = RCC_PLL_ON; /* 打开 PLL */
 rcc_osc_init.PLL.PLLSource = RCC_PLLSOURCE_HSE; /* PLL 时钟源选择 HSE */
 rcc_osc_init.PLL.PLLN = plln;
 rcc_osc_init.PLL.PLLM = pllm;
 rcc_osc_init.PLL.PLLP = pllp;
 rcc_osc_init.PLL.PLLQ = pllq;
 ret = HAL_RCC_OscConfig(&rcc_osc_init_handle); /* 初始化 RCC */
 if(ret != HAL_OK)
 {
 return 1; /* 时钟初始化失败,可以在这里加入自己的处理 */
 }
 /* 选中 PLL 作为系统时钟源并且配置 HCLK,PCLK1 和 PCLK2*/
 rcc_clk_init.ClockType = ( RCC_CLOCKTYPE_SYSCLK \
 | RCC_CLOCKTYPE_HCLK \
 | RCC_CLOCKTYPE_PCLK1 \
 | RCC_CLOCKTYPE_PCLK2);
 /* 设置系统时钟时钟源为 PLL */
 rcc_clk_init.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
 rcc_clk_init.AHBCLKDivider = RCC_SYSCLK_DIV1; /* AHB 分频系数为 1 */
 rcc_clk_init.APB1CLKDivider = RCC_HCLK_DIV4; /* APB1 分频系数为 4 */
 rcc_clk_init.APB2CLKDivider = RCC_HCLK_DIV2; /* APB2 分频系数为 2 */
 /* 同时设置 FLASH 延时周期为 5WS,也就是 6 个 CPU 周期 */
 ret = HAL_RCC_ClockConfig(&rcc_clk_init_handle, 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;
}

外设时钟的使能和失能

使用某外设时必须先使能该外设的时钟

__HAL_RCC_GPIOA_CLK_ENABLE();      		/* 使能 GPIOA 时钟 
__HAL_RCC_GPIOA_CLK_DISABLE();      	/* 禁止 GPIOA 时钟 */
  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值