STM32——时钟树与滴答计时器

STM32——时钟树与滴答计时器

使用的开发板为stm32F407VET6的芯片,主要介绍stm32的时钟树与滴答计时器的一些理论和一个自己编写的delay函数。

时钟树的结构图可以在STM32F4xx中文参考手册.pdf中的时钟这块找到。而滴答计时器是内核资源,需要到Cortex M3与M4权威指南.pdf.

一、 时钟树

1.1 时钟源的介绍

在 STM32F4 中,有5 个最重要的时钟源,为 HSI、HSE、LSI、LSE、PLL

其中 PLL 实际是分为两个时钟源,分别为主 PLL 和专用 PLL。

时钟频率来分可以分为高速时钟源低速时钟源,
在这 5 个中 HSIHSE 以及 PLL高速时钟;
==LSI ==和 LSE低速时钟

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

器件具有以下两个次级时钟源:
● 32 kHz 低速内部 RC (LSI RC),该 RC 用于驱动独立看门狗,也可选择提供给 RTC 用
于停机/待机模式下的自动唤醒。
● 32.768 kHz 低速外部晶振(LSE 晶振),用于驱动 RTC 时钟 (RTCCLK)
在这里插入图片描述

1.2 速时钟输出 PLLP 的计算方法

主要要知道的就是主 PLL 时钟第一个高速时钟输出 PLLP 的计算方法。
在这里插入图片描述

上图中,主 PLL 时钟的时钟源要先经过一个分频系数为 M 的分频器,然后经过倍频系数为 N 的倍频器出来之后的时候还需要经过一个分频系数为 P(第一个输出 PLLP)或者 Q(第二个输出 PLLQ)的分频器分频之后,最后才生成最终的主 PLL 时钟。

例如我们的外部晶振选择 8MHz。同时我们设置相应的分频器 M=8,倍频器倍频系数 N=336,分频器分频系数 P=2,那么主 PLL 生成的第一个输出高速时钟 PLLP 为:

PLL=8MHz * N/ (MP)=8MHz 336 /(8*2) = 168MHz
如果选择HSE为PLL时钟源,同时SYSCLK时钟源为PLL,那么SYSCLK时钟为 168MHz。

在SystemInit()函数中设置的系统时钟大小:

SYSCLK(系统时钟) =168MHz
AHB 总线时钟(HCLK=SYSCLK) =168MHz
APB1 总线时钟(PCLK1=SYSCLK/4) =42MHz
APB2 总线时钟(PCLK2=SYSCLK/2) =84MHz
PLL 主时钟 =168MHz

二、 滴答计时器(SysTick 定时器)

2.1 滴答计时器的介绍

CM4 内核的处理和 CM3 一样,内部都包含了一个 SysTick 定时器,SysTick 是一个 24 位倒计数定时器,当计到 0 时,将从 RELOAD 寄存器中自动重装载定时初值。只要不把它在 SysTick 控制及状态寄存器中的使能位清除,就永不停息。

SysTick 在《STM32xx 中文参考手册》里面基本没有介绍,其详细介绍,请参阅《STM32F3与 F4 系列Cortex M4内核编程手册》第230 页。我们就是利用 STM32的内部 SysTick来实现延时的,这样既不占用中断,也不占用系统定时器。

滴答计时器属于内核,使一个精确度很高的定时器,所以在内核资料中。

因为stm32F407VET6是M4的内核,所以在M4的权威手册中可以找到滴答计时器的相关寄存器。
在这里插入图片描述

在这里插入图片描述

控制寄存器如下:
在这里插入图片描述
在这里插入图片描述

设计内核的函数在misc.c中

定时器的本质是数脉冲的个数
来一个脉冲,数值就会加一或者减一,由于晶振产生的脉冲是固定的,也就是每一次脉冲时间是一样的,就可以通过对脉冲计数来记录时间
关键:知道一个脉冲是多少时间

频率:单位时间内产生脉冲的次数 21MHZ(延迟更长,168主频延时的时间短不利于定时)

所以一个脉冲的时间是 1/21MHZ = 1/(211000 000)=4.76110^(-8)s 【得到的数值,单位是s】–>转换一下大概就是多少us

1/21=。。us,所以可以使用us为最小单位

通过这个us来进行次数的累加来定时/计时。

如果计数器达到0,从上次读寄存器开始读为1;清楚当读取或当前计数器值被清除时自动O

2.2 延迟函数

下面是自己写的一个延迟函数,不过一般使用的都是移植的。


void my_delay()
{
   
 u32 temp;//定义一个临时变量
 
//选择systick的时钟源 选择8分频的时钟,分频之后是21MHZ
SysTick_CLKSourceConfig(SysTick_CLKSource_HCLK_Div8);
//配置定时时间
 SysTick->LOAD = 21*1000*500;//500ms
 SysTick->VAL=0x00;//清空计数器的值
 
 //启动定时器
 //SysTick->CTRL |=0x00000001;//使能位
 SysTick->CTRL |=SysTick_CTRL_ENABLE_Msk;
 do
 {
   
 temp=SysTick->CTRL;
 }
 while((temp&0X01)&& !(temp&(1<<16)));//等待计时完成,1.判断16位是否在工作,并且判断状态寄存器的状态位是否为0(跳出)
 
 SysTick->CTRL &= ~SysTick_CTRL_ENABLE_Msk; //关闭计数器
 
 SysTick->VAL=0x00;//清空计数器的值
 
}

相关推荐

  1. stm32定时器普通定时器的区别

    2023-12-19 08:16:04       44 阅读

最近更新

  1. TCP协议是安全的吗?

    2023-12-19 08:16:04       19 阅读
  2. 阿里云服务器执行yum,一直下载docker-ce-stable失败

    2023-12-19 08:16:04       19 阅读
  3. 【Python教程】压缩PDF文件大小

    2023-12-19 08:16:04       20 阅读
  4. 通过文章id递归查询所有评论(xml)

    2023-12-19 08:16:04       20 阅读

热门阅读

  1. 测试中调用别人的服务,单元测试写法

    2023-12-19 08:16:04       40 阅读
  2. Redis整合Lua脚本

    2023-12-19 08:16:04       43 阅读
  3. Ansible

    Ansible

    2023-12-19 08:16:04      35 阅读
  4. 服务器过载有哪些情况

    2023-12-19 08:16:04       41 阅读
  5. 第一次使用ThreadPoolExecutor遇到的问题

    2023-12-19 08:16:04       46 阅读
  6. 聊聊reactor-logback的AsyncAppender

    2023-12-19 08:16:04       39 阅读
  7. Scrapy+Selenium项目实战--携程旅游信息爬虫

    2023-12-19 08:16:04       31 阅读