STM32正点原子与野火笔记-时钟应用详解

目录

一、stm32F103时钟树

1、stm32F103时钟系统图:

1.1stm32五个时钟源

1.2A~E讲解:

2、stm32F103时钟系统配置-HAL库

2.1HAL 库的 SystemInit 函数-代码略

2.2在工程 SYSTEM 分组下面定义的 sys.c文件中的时钟初始化函数 Stm32_Clock_Init:

2.3结构体 RCC_OscInitTypeDef 的定义:

3、STM32F1 时钟使能和配置

4、端口复用和重映射

4.1端口复用

 4.2串口1复用功能的一般步骤


一、stm32F103时钟树

1、stm32F103时钟系统图:

1.1stm32五个时钟源


STM32
中,有五个时钟源,为
HSI

HSE

LSI

LSE

PLL
。从时钟频率来分可以分为

高速时钟源和低速时钟源,HIS、HSE 以及 PLL 是高速时钟,LSI 和 LSE 是低速时钟。

从来源可分为外部时钟源和内部时钟源,外部时钟源就是从外部通过接晶振的方式获取时

钟源,其中
HSE

LSE
是外部时钟源,其他的是内部时钟源。

标记:H-high S-speed I-inter E-external L-low 


HSI
是高速内部时钟,
RC
振荡器,频率为
8MHz


HSE
是高速外部时钟,可接石英
/
陶瓷谐振器,或者接外部时钟源,频率范围
4MHz~16MHz

正点原子的开发板接的是
8M
的晶振。


LSI
是低速内部时钟,
RC
振荡器,频率为
40kHz
。独立看门狗的时钟源只能是
LSI
,同


LSI
还可以作为
RTC
的时钟源。


LSE
是低速外部时钟,接频率为
32.768kHz
的石英晶体。这个主要是
RTC
的时钟源。


PLL
为锁相环倍频输出,其时钟输入源可选择为
HSI/2

HSE
或者
HSE/2
。倍频可选择为

2~16
倍,但是其输出频率最大不得超过
72MHz

1.2A~E讲解:

A. MCO 是
STM32
的一个时钟输出
IO(PA8)
,它可以选择一个时钟信号输出,可以

选择为
PLL
输出的
2
分频、
HSI

HSE
、或者系统时钟。这个时钟可以用来给外

部其他系统提供时钟源。

B. 这里是 RTC
时钟源,从图上可以看出,
RTC
的时钟源可以选择
LSI

LSE
,以及

HSE

128
分频。

C. 从图中可以看出 C

USB
的时钟是来自
PLL
时钟源。
STM32
中有一个全速功能


USB
模块,其串行接口引擎需要一个频率为
48MHz
的时钟源。该时钟源只能


PLL
输出端获取,可以选择为
1.5
分频或者
1
分频,也就是,当需要使用
USB

模块时,
PLL
必须使能,并且时钟频率配置为
48MHz

72MHz

D. D 处就是
STM32
的系统时钟
SYSCLK
,它是供
STM32
中绝大部分部件工作的时

钟源。系统时钟可选择为
PLL
输出、
HSI
或者
HSE
。系统时钟最大频率为
72MHz

当然你也可以超频,不过一般情况为了系统稳定性是没有必要冒风险去超频的。

E. 这里的 E
处是指其他所有外设了。从时钟图上可以看出,其他所有外设的时钟最

终来源都是
SYSCLK

SYSCLK
通过
AHB
分频器分频后送给各模块使用。这些模块包

括:

①、
AHB
总线、内核、内存和
DMA
使用的
HCLK
时钟。

②、通过
8
分频后送给
Cortex
的系统定时器时钟,也就是
systick
了。

③、直接送给
Cortex
的空闲运行时钟
FCLK

④、送给
APB1
分频器。
APB1
分频器输出一路供
APB1
外设使用
(PCLK1
,最大

频率
36MHz)
,另一路送给定时器
(Timer)2

3

4
倍频器使用。

⑤、送给
APB2
分频器。
APB2
分频器分频输出一路供
APB2
外设使用
(PCLK2

最大频率
72MHz)
,另一路送给定时器
(Timer)1
倍频器使用。

需要理解的是
APB1

APB2
的区别,
APB1
上面连接的是低速外设,包括电源接口、

备份接口、
CAN

USB

I2C1

I2C2

UART2

UART3
等等,
APB2
上面连接的是高速外设包


UART1

SPI1

Timer1

ADC1

ADC2
、所有普通
IO

(PA~PE)
、第二功能
IO
口等。居宁

老师的《稀里糊涂玩
STM32
》资料里面教大家的记忆方法是
2>1

APB2
下面所挂的外设的时钟要比 APB1
的高。

简要概括:可以使用三种不同的时钟源来驱动系统时钟 (SYSCLK):

● HSI 振荡器时钟

● HSE 振荡器时钟

● 主 PLL (PLL) 时钟

器件具有以下两个次级时钟源:

● 32 kHz 低速内部 RC (LSI RC),该 RC 用于驱动独立看门狗,也可选择提供给 RTC 用于停机/待机模式下的自动唤醒。

● 32.768 kHz 低速外部晶振(LSE 晶振),用于驱动 RTC 时钟 (RTCCLK) 。对于每个时钟源来说,在未使用时都可单独打开或者关闭,以降低功耗。

2、stm32F103时钟系统配置-HAL库

2.1HAL 库的 SystemInit 函数-代码略

SystemInit
主要做了如下三个方面工作:

1
) 复位
RCC
时钟配置为默认复位值(默认开始了
HIS

2
) 外部存储器配置

3
) 中断向量表地址配置

HAL
库的
SystemInit
函数并没有像标准库的
SystemInit
函数一样进行时钟的初始化配置。
HAL

库的
SystemInit
函数除了打开
HSI
之外,没有任何时钟相关配置,所以使用
HAL
库我们必须编

写自己的时钟配置函数。

2.2在工程 SYSTEM 分组下面定义的 sys.c文件中的时钟初始化函数 Stm32_Clock_Init:

作用是进行时钟系统配置,除了配置 PLL 相关参数确定 SYSCLK 值之外,还配置了 AHB,APB1 和 APB2 的分频系数,也就是确定了 HCLK,PCLK1 和 PCLK2 的时钟值。

//时钟系统配置函数
//PLL:选择的倍频数,RCC_PLL_MUL2~RCC_PLL_MUL16
//返回值:0,成功;1,失败
void Stm32_Clock_Init(u32 PLL)
{
 HAL_StatusTypeDef ret = HAL_OK;
 RCC_OscInitTypeDef RCC_OscInitStructure; 
 RCC_ClkInitTypeDef RCC_ClkInitStructure;
 //的配置内容:
 RCC_OscInitStructure.OscillatorType=RCC_OSCILLATORTYPE_HSE; //时钟源为 HSE
 RCC_OscInitStructure.HSEState=RCC_HSE_ON; //打开 HSE
 RCC_OscInitStructure.HSEPredivValue=RCC_HSE_PREDIV_DIV1; //HSE 预分频
 RCC_OscInitStructure.PLL.PLLState=RCC_PLL_ON; //打开 PLL
 RCC_OscInitStructure.PLL.PLLSource=RCC_PLLSOURCE_HSE;
//PLL 时钟源选择 HSE
 RCC_OscInitStructure.PLL.PLLMUL=PLL; //主 PLL 倍频因子
 ret=HAL_RCC_OscConfig(&RCC_OscInitStructure);//初始化 

 if(ret!=HAL_OK) while(1);

 //选中 PLL 作为系统时钟源并且配置 HCLK,PCLK1 和 PCLK2
 RCC_ClkInitStructure.ClockType=(RCC_CLOCKTYPE_SYSCLK|RCC_CLOCKTYPE_HCLK|
                                 RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2);
//设置系统时钟时钟源为 PLL
 RCC_ClkInitStructure.SYSCLKSource=RCC_SYSCLKSOURCE_PLLCLK;
 RCC_ClkInitStructure.AHBCLKDivider=RCC_SYSCLK_DIV1; //AHB 分频系数为 1
 RCC_ClkInitStructure.APB1CLKDivider=RCC_HCLK_DIV2; //APB1 分频系数为 2
 RCC_ClkInitStructure.APB2CLKDivider=RCC_HCLK_DIV1; //APB2 分频系数为 1
 ret=HAL_RCC_ClockConfig(&RCC_ClkInitStructure,FLASH_LATENCY_2);
//同时设置 FLASH 延时周期为 2WS,也就是 3 个 CPU 周期。
 if(ret!=HAL_OK) while(1);
}

主函数中调用
Stm32_Clock_Init(RCC_PLL_MUL9)
时候设置的入口参数值,我们可以计算出,PLL
时钟为
PLLCLK=HSE*9 =8MHz*9=72MHz
,同时我们选择系统时钟源为 PLL , 所 以 系 统 时 钟
SYSCLK=72MHz

AHB
分频系数为
1
,故其频率为 HCLK=SYSCLK/1=72MHz。
APB1
分频系数为
2
,故其频率为
PCLK1=HCLK/2=36MHz

APB2 分频系数为 1
,故其频率为
PCLK2=HCLK/1=72/1=72MHz
。最后我们总结一下通过调用函Stm32_Clock_Init(RCC_PLL_MUL9)之后的关键时钟频率值:

SYSCLK(系统时钟)                           =72MHz

PLL 主时钟                                        =72MHz

AHB
总线时钟(
HCLK=SYSCLK/1 )
 =72MHz

APB1
总线时钟(
PCLK1=HCLK/2
) =36MHz

APB2
总线时钟(
PCLK2=HCLK/1
) =72MHz

2.3结构体 RCC_OscInitTypeDef 的定义:

typedef struct
{
 uint32_t OscillatorType; //需要选择配置的振荡器类型 
 uint32_t HSEState; //HSE 状态 
 uint32_t HSEPredivValue; // Prediv1 值
 uint32_t LSEState; //LSE 状态 
 uint32_t HSIState; //HIS 状态
 uint32_t HSICalibrationValue; //HIS 校准值
 uint32_t LSIState; //LSI 状态 
 RCC_PLLInitTypeDef PLL; //PLL 配置
}RCC_OscInitTypeDef;

前面几个参数主要是用来选择配置的振荡器类型。比如我们要开启
HSE
, 那么我们会设置 OscillatorType
的值为
RCC_OSCILLATORTYPE_HSE
,然后设置
HSEState
的值为 RCC_HSE_ON
开启
HSE。

成员变量是
PLL
,它是结构体
RCC_PLLInitTypeDef
类型。它的作用是配置
PLL 相关参数,我们来看看它的定义:

typedef struct
{
 uint32_t PLLState; //PLL 状态
 uint32_t PLLSource; //PLL 时钟源
 uint32_t PLLMUL; //PLL VCO 输入时钟的乘法因子
}RCC_PLLInitTypeDef;

该结构体主要用来设置
PLL
时钟源以及相关分频倍频参数。

3、STM32F1 时钟使能和配置

外设时钟使能在
HAL
库中都是通过宏定义标识符来实现的。首先,我们来看看 GPIOA
的外设时钟使能宏定义标识符:

#define __HAL_RCC_GPIOA_CLK_ENABLE() do { \
 __IO uint32_t tmpreg; \
 SET_BIT(RCC->APB2ENR, RCC_APB2ENR_IOPAEN);\
 tmpreg = READ_BIT(RCC->APB2ENR, RCC_APB2ENR_IOPAEN);\
 UNUSED(tmpreg); \
 } while(0U))

//设置寄存器 RCC_APB2ENR 的相关位为 1,哪个位,是由宏定义标识RCC_APB2ENR_IOPAEN 的值决定.

#define RCC_APB2ENR_IOPAEN ((uint32_t)0x00000001)

//设置寄存器
RCC->APB2ENR
寄存器的位
2

1

APB2ENR
寄存器的位
2
描述如下:

位 2 IOPAEN:IO 端口 A 时钟使能
 由软件置 1 和清零
 0:禁止 IO 端口 A 时钟
 1:使能 IO 端口 A 时钟

使用方法为:

__HAL_RCC_GPIOA_CLK_ENABLE();//使能 GPIOA 时钟

几个常用使能外设时钟的宏定义标识符使用方法:

__HAL_RCC_DMA1_CLK_ENABLE();//使能 DMA1 时钟
__HAL_RCC_USART2_CLK_ENABLE();//使能串口 2 时钟
__HAL_RCC_TIM1_CLK_ENABLE();//使能 TIM1 时钟

几个常用的禁止外设时钟的宏定义标识符使用方法:

__HAL_RCC_DMA1_CLK_DISABLE();//禁止 DMA1 时钟
__HAL_RCC_USART2_CLK_DISABLE();//禁止串口 2 时钟
__HAL_RCC_TIM1_CLK_DISABLE();//禁止 TIM1 时钟

4、端口复用和重映射

4.1端口复用

比如说 STM32F103ZET6 有 5 个串口,我们可以查手册知道,串口 1 的引脚对应的 IO 为 PA9,PA10.PA9,PA10 默认功能是 GPIO,所以当 PA9,PA10 引脚作为串口 1 的 TX,RX 引脚使用的时候,那就是端口复用:

4.2串口1复用功能的一般步骤

以串口 1 为例来讲解配置 GPOPA.9,GPIOA.10 口为串口 1 复用功能的一般步骤:

1)先打开对应的 IO 时钟和复用功能外设时钟

——HAL_RCC_GPIOA_CLK_ENABLE(); //使能 GPIOA 时钟
__HAL_RCC_USART1_CLK_ENABLE(); //使能 USART1 时钟
__HAL_RCC_AFIO_CLK_ENABLE(); //使能辅助功能 IO 时钟

2)在 GIPOx_MODER 寄存器中将所需 IO(对于串口 1 是 PA9,PA10)配置为复用功能

3)对 IO 口的其他参数,例如上拉/下拉以及输出速度等进行配置。

上面三步,在我们 HAL 库中是通过
HAL_GPIO_Init
函数来实现的,参考代码如下:

GPIO_InitTypeDef GPIO_Initure;
GPIO_Initure.Pin=GPIO_PIN_9; //PA9
GPIO_Initure.Mode=GPIO_MODE_AF_PP; //复用推挽输出
GPIO_Initure.Pull=GPIO_PULLUP; //上拉
GPIO_Initure.Speed=GPIO_SPEED_FREQ_HIGH;//高速
HAL_GPIO_Init(GPIOA,&GPIO_Initure); //初始化 PA9

通过上面的配置,PA9 复用为串口 1 的发送引脚。

物联沃分享整理
物联沃-IOTWORD物联网 » STM32正点原子与野火笔记-时钟应用详解

发表评论