目录
[1. 系统嘀嗒定时器的基本概念](#1. 系统嘀嗒定时器的基本概念)
[2. Systick基本应用](#2. Systick基本应用)
[3. Systick定时器的时钟频率分析](#3. Systick定时器的时钟频率分析)
[5. 时钟源详解](#5. 时钟源详解)
[6.从时钟树框图分析Sys tick](#6.从时钟树框图分析Sys tick)
继上文文末提及到的"延时消抖",本章节就来解析"延时"和"计算时间"。
1. 系统嘀嗒定时器的基本概念
定时器是STM32中常用的外设,一般定时器的基本功能就是定时。
在Cortex M3/M4内核中包含一个简单的系统嘀嗒定时器(Systick) ,它属于CM4内核的一个外设 ,++++内嵌在NVIC中++++,所有基于Cortex-M3/M4内核的MCU中都包含这个Systick定时器,所以在不同的硬件中移植起来非常方便。



2. Systick基本应用
- 裸机开发 :编写专门的延时函数,实现微秒、毫秒级别的延时,如作为闹钟或者**++++延时++++**。
- 操作系统 :可以为RTOS实时操作系统的任务调度提供时钟节拍,RTOS的架构是并行的。
3. Systick定时器的时钟频率分析
利用Systick定时器进行定时,则必须清楚Systick定时器 的时钟频率。
++++定时器是挂载在总线下,而不同的总线的频率是不同的,而总线的频率是由时钟源提供,而时钟源的提供者又各不相同,所以必须要提前了解时钟源的区别++++。
4.时钟源的概述
一般情况下一款MCU有多种时钟源 (时钟源用于提供时钟信号****)
|---------------------------------------|---------------|
| 时钟源分为两类 每种时钟源的频率各不相同。 | 内部时钟源 |
| 时钟源分为两类 每种时钟源的频率各不相同。 | 外部时钟源 |
结论: 不清楚时钟源的频率,就无法计算总线的频率(因为总线的频率也是靠时钟源提供),从而无法计算挂载在总线下外设的频率。
++++定时器属于外设,外设在总线身上, 总线的频率由时钟源提供。++++
5. 时钟源详解
|-----|--------|-----------|
| HSE | 高速外部时钟 | 8MHz |
| HSI | 高速内部时钟 | 16MHz |
| LSE | 低速外部时钟 | 32.768KHz |
| LSI | 低速内部时钟 | 32KHz |
| PPL | 倍频锁相环 ||
MCU提供5种时钟源,分别是HSI、HSE、LSI、LSE、PLL,每种时钟源的频率都是不同的。
(1)HSE高速外部时钟

设计晶振电路的注意事项:晶振电路要尽可能靠近芯片。
|-------------------------------------------------------------------------------------------------------------------------|
| Q:为什么晶振电路要尽可能靠近芯片? A :让它容易振荡,容易起振。(振得快) 减小误差。(振得准) 因为石英有压电效应,把电能转换为机械能。机械能开始振荡。如果振得不稳,就有问题。 |
晶振
晶振全称叫做晶体振荡器,一般是++采用石英晶体进行制作++ ,石英品体必须经过高精度的角度切割,才可以用于制作晶振,++采用石英晶体是因为石英具体机电效应++ ,可以把机械能和电能进行转换 ,石英晶体通电之后会开始振荡,并且单位时间内振荡的频率是固定的,比如有8MHZ、12MHZ、25MHZ....并且石英晶休的损耗很小,是高度稳定的。
(2)HSI高速内部时钟

(3)LSE低速外部时钟

(4)LSI低速内部时钟

(5)PLL倍频锁相环

作用:频率放大器,可以通过锁相环回路把一个较低的频率进行倍频,可以放大。
PLL由 HSE 或 HSI 振荡器提供时钟信号。
PLL 使能后配置参数不可更改,所以对 PLL进行配置,然后再使能(选择 HSI 或 HSE 振荡器作为 PLL 时钟源,并配置分频系数 M、N、P 和 Q)。
由于当前STM32F407芯片的PLL是HSE(8MHz)提供时钟信号(用于PLL可以把较低的HSE时钟频率进行放大),则需要用户修改工程中的PLL参数 以及修改工程中的HSE_VALUE和PLL_M。
|------------------------------------|
| 修改system_stm32f4xx.c的PLL_M,从25修改为8 |
| 修改stm32f4xx.h的HSE_VALUE,从25修改为8 |
MCU主频的计算 = ( HSE_VALUE / PLL_M * PLL_N ) / PLL_P
= (8MHz / 8 * 336) / 2
= 168MHz !!!!
6.从时钟树框图分析Systick

当前STM32F407时钟树框图中生成Systick的时钟源是HSE,STM32F407的HSE是8MHz。8MHz的HSE通过PPL倍频到168MHz,并且给到AHB总线,所以AHB总线的频率是168MHz。Systick定时器的++内部时钟(FCLK)的频率是168MHZ++ ,外部时钟++(STCLK)的频率经过8分频是168MHZ/8 = 21MHZ 。++
(1)内部时钟
如果选择使用内部时钟(168MHZ)作为系统嘀嗒定时器的时钟源,则嘀嗒定时器的计数周期:1000000us生成168000000个脉冲,意味着 ++++1us可以生成168个脉冲++++ ,所以++++计数周期等于1/168us。++++
(2)外部时钟
如果选择使用外部时钟(21MHZ)作为系统嘀嗒定时器的时钟源,则嘀嗒定时器的计数周期:1000000us生成21000000个脉冲,意味着 ++++1us可以生成21个脉冲++++ ,所以++++计数周期等于1/21us++++。
内部时钟计数周期等于1/168us,外部时钟计数周期等于1/21us,相较而言,计数一样多的次数,外部时钟可以获得更大的时间。
7.控制方式
#define SysTick ((SysTick_Type *) SysTick_BASE )
typedef struct{
__IO uint32_t CTRL; /*!<SysTick Control and Status Register */
__IO uint32_t LOAD; /*!<SysTick Reload Value Register */
__IO uint32_t VAL; /*!<SysTick Current Value Register */
__I uint32_t CALIB; /*!<SysTick Calibration Register */
} SysTick_Type;



注意:尽管使用21MHz的外部时钟,最多也只能延时798ms。因为Systick是个24bit的递减计时器,计数 "2的24次方" 下,最多可以延时798ms。
程序设计
需求:使用外部时钟(21MHz)生成 "延时毫秒ms"、"延时微妙"、"延时秒"
cpp
void delay_us(uint32_t nus)
{
SysTick->CTRL = 0; // 关闭systick的控制状态寄存器------该寄存器的bit0置0
SysTick->LOAD = ( 21 * nus - 1); // systick的重载寄存器------计数时长 = 计数周期 * 计数次数
SysTick->VAL = 0; // 清空systick的当前数值寄存器
SysTick->CTRL = 1; // 使能systick的控制状态寄存器------该寄存器的bit0置1
while ((SysTick->CTRL & 0x00010000)==0);// 递减计数到了则控制状态寄存器的bit16为1,计数次数没到则bit16为0.
SysTick->CTRL = 0; //关闭systick的控制状态寄存器
}
void delay_ms(uint32_t nms)
{
SysTick->CTRL = 0; // 关闭systick的控制状态寄存器------该寄存器的bit0置0
SysTick->LOAD = ( 21*1000*nms - 1); // systick的重载寄存器------计数时长 = 计数周期 * 计数次数
SysTick->VAL = 0; // 清空systick的当前数值寄存器
SysTick->CTRL = 1; // 使能systick的控制状态寄存器------该寄存器的bit0置1
while ((SysTick->CTRL & 0x00010000)==0);// 递减计数到了则控制状态寄存器的bit16为1,计数次数没到则bit16为0.
SysTick->CTRL = 0; //关闭systick的控制状态寄存器
}
void delay_s(uint32_t ns)
{
while(ns--)
{
delay_ms(500);
delay_ms(500);
}
}