STM32时钟小结


title: STM32时钟小结
date: 2021-12-04 20:53:53
tags: 嵌入式

引言

最近三天在学习STM32时钟的部分,我认为这里应该做个小结。一个嵌入式系统的时钟就相当于“人”的脉搏,在写外设驱动的时候首先就是要进行时钟的初始化,因此稳定的时钟对系统的平稳运行具有重要的意义。该时钟部分参考正点原子的课程!

STM32时钟系统+SystemInit()函数解读

在理解STM32时钟之前我们首先是要对参考手册给出的时钟系统框图,如图1进行一个详细的解读。

图1.STM32F10xx时钟系统框图

从图1我们可以清楚的看到时钟源有四个分别为:HSI(高速内置时钟源(RC振荡器))、HSE(高速外置时钟源)、LSE(低速外置时钟源)、LSI(低速内置时钟源)。首先我们从上至下进行分析:HSI可以提供一个8MHz的频率给SYSCLK或者经过2分频通过PLL(锁相环‘这个也得写一篇博客介绍一下!’)再经过一个选择器就可以作为系统的时钟了。HSE在正点原子开发板上是8MHz的晶振,可以直接经过选择器或者二分频后经过选择器通过锁相环再被用作为系统时钟,当然也可以直接将该晶振作为系统时钟的输入。系统时钟这里可以用作为AHB的时钟主要包括了APB1(低速):HCLK(系统嘀嗒定时器)、通用定时器、APB2(高速):TIM1定时器、ADC的时钟。LSE外部晶振的频率为32.768KHz用于RTC(实时)时钟改时钟源还可来自于外部8MHz的128分频,内部LSI近似为40KHz其可以作为RTC的时钟源,更重要的是其作为独立看门狗的时钟,对于维护系统的稳定性具有重要的意义。USB的时钟来自于PLL其频率为48MHz,如果在应用中使用USB的接口PLL必须设置为48MHz或者72MHz。图中MCO为可以将系统内外部的时钟输出的PA8引脚上。

上述讲述完了具体的外部硬件电路图;下面主要介绍在具体的编程中如何使用它们:在具体操作使用中主要是操作RCC来达到控制初始化时钟的目的。我们在MDK5中打开stm32f10x.h和stm32f10x.c文件。查看stm32f10x.h注释:该文件夹包含了RCC所有的固件库,这里大致浏览一下表示定义的东西比较多,这里转到stm32f10x.c:该文件提供了所有的RCC函数功能。只见这里定义了超多要使用的变量,具体使用参照其前面的brief简介可以做到很好的了解。具体函数参见图2.

图上总结的函数在鼠标右击后均可转到对应的函数块。下面我以配置GPIOA和GPIOE为例简要的叙述一下如何进行配置:易知GPIOA和GPIOE挂在APB2上,打开RCC_APB2PeriphClockCmd()函数显示如下图所示:

这里我们要配置两个参数,一个是RCC_APB2Periph和 FunctionalState NewState,打开RCC_APB2Periph所定义的具体参数如下图所示:

其实具体配置的的就是具体的地址参数,我们在这里只需要用到RCC_APB2Periph_GPIOA、RCC_APB2Periph_GPIOE,然后配置FunctionalState NewState为ENABLE,这里都是函数内部定义好的,只需调用就可以了。时钟初始化完毕后就可以再初始化具体的端口了。

系统时钟SystemInit()函数剖析

系统时钟对于整个系统的平稳运行具有很重要的作用。初始化系统时钟函数在system_stm32f10x.c文件中,为SystemInit()其主要功能是设置系统时钟(系统的时钟源、PLL参数、AHB/APBx预分频器、FLASH)这个函数必须复位后或者执行main()函数前调用。这里调用将在‘startup_stm32f10x_xx.s’文件中用汇编函数来实现。#define SYSCLK_FREQ_72MHz 72000000这里有一个定义下面分析函数均是基于这个定义下的函数。定义了系统的时钟频率为72MHz,然后进入static void SetSysClockTo72(void);函数中执行操作,这个函数在复位后会被调用。函数中具体编程思路为:先配置RCC_CR寄存器使能HSE,然后等待HSE准备就绪若超时(超过计数的值1280)则调用HSI,若HSE没有超时则启用预取缓冲区,然后利用RCC_CFGR配置HCLK、PCLK2、PCLK1.下面调用SystemInit()设置RCC_CR寄存器。紧接着后面的设置的函数都和上面调用的SetSysClockTo72(void)差不多。

嘀嗒定时器

Systick定时器,是一个简单的定时器,对于CM3,CM4内核芯片,都有Systick定时器。Systick定时器常用来做延时,或者实时系统的心跳时钟。这样可以节省MCU资源,不用浪费一个定时器。比如UCOS中,分时复用,需要一个最小的时间戳,一般在STM32+UCOS系统中,都采用Systick做UCOS心跳时钟。大多操作系统需要一个硬件定时器来产生操作系统需要的滴答中断,作为整个系统的时基。例如,为多个任务许以不同数目的时间片,确保没有一个任务能霸占系统;或者把每个定时器周期的某个时间范围赐予特定的任务等,还有操作系统提供的各种定时功能,都与这个滴答定时器有关。因此,需要一个定时器来产生周期性的中断,而且最好还让用户程序不能随意访问它的寄存器,以维持操作系统“心跳”的节律。

Systick定时器就是系统滴答定时器,一个24 位的倒计数定时器,计到0 时,将从RELOAD 寄存器中自动重装载定时初值。只要不把它在SysTick 控制及状态寄存器中的使能位清除,就永不停息,即使在睡眠模式下也能工作。

Systick有四个相关的定时器,CTRL_SysTick控制和状态寄存器 、LOAD_SysTick 自动重装载除值寄存器、VAL_SysTick 当前值寄存器、CALIB_SysTick校准值寄存器.对于STM32来讲外部时钟源是HCLK(AHB总线时钟)的八分之一,内核时钟是HCLK时钟。Systick时钟源的选择在misc.c文件中(This file provides all the miscellaneous firmware ‘固件库’ functions),而初始化systick,时钟为HCLK,并开启中断在core_cm3.h文件中。下面具体看一看代码:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-XnCW7usA-1646289365840)(https://cdn.jsdelivr.net/gh/wangfei-tech/IU/img/SysTick_CLKSourceConfig.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-O8ccdfad-1646289365841)(https://cdn.jsdelivr.net/gh/wangfei-tech/IU/img/SyTick_Config()].png)

上述截图为嘀嗒定时器的初始化函数,在具体实例中我们来看一下是如何使用的:这里主要是delay.c的延时函数SysTick_CLKSourceConfig(SysTick_CLKSource_HCLK_Div8); //选择外部时钟 HCLK/8
然后根据这个就可以来计时了。首先设置参数fac_us为系统的晶振频率的八分之一,1s的频率为72MHz/8,故震动一次为1/9us,故要9次才为1us。在不用OS时其us延时函数代码如下:
void delay_us(u32 nus)
{
u32 temp;
SysTick->LOAD=nus*fac_us; //时间加载
SysTick->VAL=0x00; //清空计数器
SysTick->CTRL|=SysTick_CTRL_ENABLE_Msk ; //开始倒数
do
{
temp=SysTick->CTRL;
}while((temp&0x01)&&!(temp&(1<<16))); //等待时间到达
SysTick->CTRL&=~SysTick_CTRL_ENABLE_Msk; //关闭计数器
SysTick->VAL =0X00; //清空计数器
}

这里判断循环结束的条件是(temp&0x01)&&!(temp&(1<<16)),先将SysTick->CTRL控制状态寄存器的值赋给temp,寄存器中若SysTick已经到0,则CTR的第16位位1,temp&0x01为判断是否定时器使能,后面则判断的是计数是否为0,temp&(1<<16)一直为0只有在计数到0时不为0,取反后为0,此时循环终止!
一开始对正点原子的delay.c很是迷惑,果然还是当时知识储备不够!

上述为查询来计时我们还是可以通过中断的方式来进行计时!具体代码框架如下;
static __IO uint32_t TimingDelay;
void Delay(__IO uint32_t nTime)
{
TimingDelay = nTime;
while(TimingDelay != 0);
}
void SysTick_Handler(void)//调用嘀嗒定时器的中断函数
{
if (TimingDelay != 0x00)
{
TimingDelay–;
}
}
int main(void)
{ …
if (SysTick_Config(SystemCoreClock / 1000)) //systick时钟为HCLK,中断时间间隔1ms
{
while (1);
}
while(1)
{ Delay(200);//200ms

}
}

1s振动的次数为SystemCoreClock次则1毫秒的震动次数就为(SystemCoreClock/10000
次。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值