一、SysTick系统时钟滴答定时器的相关概念。
1.SysTick的两大作用。
1.1 可以产生精确延时。(节省定时器)
1.2 可以提供给操作系统一个单独的心跳(时钟)节拍。(主要!)
2.SysTick的定义。
systick定时器是 24位 的,永不停息 的, 递减计数器。
(2^24 =16M ,永不停息是指:只要不清除 systick 控制及状态寄存器中的 使能位 ,systick定时器永不停息,睡眠模式下也工作.)
3.SysTick运行机制。
运行机制:
SysTick设定处置并使能后,每经过一个系统时钟周期,计数值就减1.计数到0时,SysTick计数器自动重装初值并继续计数,同时内部的COUNTFLAG标志会置位,若中断使能就会触发中断。
系统时钟周期:外部晶振为8MHz,9倍频,系统时钟为72MHz,SysTick的最高频率为9MHz(最大为HCLK/8)。
SysTick时钟设置为最大值9MHz(9 000 000),
把SysTick计数值设置为9000,就能够产生1ms的时间基值,即SysTick产生1ms的计数。
把SysTick计数值设置为9,就能够产生1us的时间基值,即SysTick产生1ms的计数.
选择外部时钟时:滴答定时器时钟为9M (意味着 一个us ,值减少9)
要延时1us, 往val装9就可以了
4.SysTick相关寄存器。
下表中的四个寄存器管理了SysTick的运行。
SysTick 重装载数值寄存器->LOAD。(24bit)
这个寄存器是用来装载我们需计数的次数的寄存器。(它给VAL寄存器装作数值)
SysTick 当前值寄存器->VAL。(24bit)
每一个时钟周期,VAL的值自减1。
当VAL值为0时,会重新加载LOAD中的值,并且产生COUNTFLAG标志。(COUNTFLA标志在CTRL寄存器)
SysTick控制和状态寄存器->CTRL。
下表解释的十分详细。
第0位 是定时器使能位。
第1位 是中断使能位,用于决定自减为0后是否执行中断。
第2位 是时钟源选择位 ,可以选择内部时钟或外部时钟作为时钟源。
第16位是计数标志位 ,SysTick自减到0时,该位置1。读取该位后,该位自动清零。
注意点:
COUNTFLAG为计数完毕标志,读取后会自动清零。
TICKINT产生SysTick异常请求意思是产生中断。
SysTick->CALIB。(略)
用来校准计数器的,不常用。
二、Systick初始化。
1.思路:
先失能,关闭中断,再装载值,最后再开启。(固件库的直接调用配置函数SysTick_Config()即可)
2.库函数版代码
3.5固件库版本中库函数与中文手册的有所差异。
配置代码
SysTick_CLKSourceConfig(SysTick_CLKSource_HCLK);
SysTick_Config(72);
使用到的库函数
void SysTick_CLKSourceConfig(uint32_t SysTick_CLKSource)
static __INLINE uint32_t SysTick_Config(uint32_t ticks)
SysTick_CLKSourceConfig():
功能:选择时钟源
操作:改变SysTick 控制和状态寄存器- CTRL 中 第2位段(0,1,2 即第三个位置)的值
入口参数:1 SysTick_CLKSource_HCLK 内部时钟 HCLK 72M
2 SysTick_CLKSource_HCLK_Div8 外部时钟 HCLK/8 9M
返回值:无
`void SysTick_CLKSourceConfig(uint32_t SysTick_CLKSource)
{
/* Check the parameters */
assert_param(IS_SYSTICK_CLK_SOURCE(SysTick_CLKSource));
if (SysTick_CLKSource == SysTick_CLKSource_HCLK)
{
SysTick->CTRL |= SysTick_CLKSource_HCLK;
}
else
{
SysTick->CTRL &= SysTick_CLKSource_HCLK_Div8;
}
}
//SysTick_CLKSource_HCLK_Div8,SysTick_CLKSource_HCLK 的宏定义如下
//#define SysTick_CLKSource_HCLK_Div8 ((uint32_t)0xFFFFFFFB)
//#define SysTick_CLKSource_HCLK ((uint32_t)0x00000004)
SysTick_Config():
功能:1、初始化systick 2、打开systick 3、打开systick的中断并设置优先级
操作:略
入口参数:Uint32_t ticks 即为重装值,
返回值:返回一个0代表成功或1代表失败
//此函数在core_cm3.h定义
//如果参数ticks是 72 的话,1us计数完毕,即1us置COUNTFLAG为1一次。
//如果参数ticks是 72000 的话,1ms计数完毕,即1ms置COUNTFLAG为1一次。
static __INLINE uint32_t SysTick_Config(uint32_t ticks)//static 表示只能在此头文件中实验
{
//判断tick的值是否大于 2^24 ,如果大于,则不符合规则
if (ticks > SysTick_LOAD_RELOAD_Msk) return (1); /* Reload value impossible */
//配置 reload 寄存器的初始值
SysTick->LOAD = (ticks & SysTick_LOAD_RELOAD_Msk) - 1; /* set reload register */
//配置中断优先值,1<<4-1 = 15 v 配置为15,默认为最低的优先级
NVIC_SetPriority (SysTick_IRQn, (1<<__NVIC_PRIO_BITS) - 1); /* set Priority for Cortex-M0 System Interrupts */
//配置 counter 计数器的值
SysTick->VAL = 0; /* Load the SysTick Counter Value */
//配置systick时钟为72M
//使能中断
//使能systick
SysTick->CTRL = SysTick_CTRL_CLKSOURCE_Msk |
SysTick_CTRL_TICKINT_Msk |
SysTick_CTRL_ENABLE_Msk; /* Enable SysTick IRQ and SysTick Timer */
return (0); /* Function successful */
}
3.寄存器版代码
void Systick_us_Config(u16 delay_us)
{
SysTick->CTRL &= ~(0x3);//失能Systick,关闭Systick中断
SysTick->CTRL &= ~(1<<2);//选择时钟,选用外部时钟,HCLK/8
//systemClock*1000/8 = 9000000 = 9MHz;1s 9M,1us 9K
SysTick->LOAD = 9000*delay_us;//装载值
SysTick->VAL = 0x00;
SysTick->CTRL |= 0x1;//使能Systick
}
void Systick_ms_Config(u16 delay_ms)
{
SysTick->CTRL &= ~(0x3);//失能Systick,关闭Systick中断
SysTick->CTRL &= ~(1<<2);//选择时钟,选用外部时钟,HCLK/8
//systemClock*1000/8 = 9000000 = 9MHz;1s 9M,1us 9K
SysTick->LOAD = 9000*delay_us;//装载值
SysTick->VAL = 0x00;
SysTick->CTRL |= 0x1;//使能Systick
}
三、Systick写延迟函数。
1. 回顾:通常实现延时函数的方法。
通常实现延迟函数的方法为:
void delay_ms(int x )
{
int i;
while(x--)
for(i=0;i<x;i++);
}
x - - 对应于N毫秒的循环值。
缺陷:1占用cpu,浪费cpu资源.2中断会打断即时,易出错。
2.Systick定时器延时实现代码。
该代码还是占用了cpu资源。。。待续
//bsp_systick.h文件
#ifndef BSP_SYSTICK_H
#define BSP_SYSTICK_H
#include "stm32f10x.h"//stm32f10x.h定义了 core_cm3.h 中的IRQn_Type
#include "core_cm3.h"//systick在内核,stm32f10x.h是外设的库,core_cm3.h是定义内核中的外设
void SysTick_Delay_us(uint32_t us);
void SysTick_Delay_ms(uint32_t ms);
#endif
//bsp_systick.c文件
#include "bsp_systick.h"
void SysTick_Delay_us(uint32_t us)
{
uint32_t i;
SysTick_Config(72);
for(i=0;i<us;i++)
while(!(SysTick->CTRL&(1<<16)) );
SysTick->CTRL &= ~SysTick_CTRL_ENABLE_Msk;
}
void SysTick_Delay_ms(uint32_t ms)
{
uint32_t i;
SysTick_Config(72000);
for(i=0;i<ms;i++)
while(!(SysTick->CTRL&(1<<16)) );
SysTick->CTRL &= ~SysTick_CTRL_ENABLE_Msk;
}