第六章--系统滴答定时器
简介:系统滴答定时器是内核(这里指M4)定时器使用的是内核时钟源168MZ或可以选择外部时钟源21MZ
应用场合:
为UCOS系统提供时钟节拍
作为简单的定时器延时使用 //最大延时798ms
作为定时器中断使用
=======================================================
1.sTick定时器简介
SysTick定时器被捆绑在NVIC中,用于产生SYSTICK异常(异常号: 15)。在以前,大多操作系统需要一个硬件定时器来产生操作系统需要的滴答中断,作为整个系统的时基。例如,为多个任务许以不同数目的时间片,确保没有一个任务能霸占系统;或者把每个定时器周期的某个时间范围赐予特定的任务等,还有操作系统提供的各种定时功能,都与这个滴答定时器有关。因此,需要一个定时器来产生周期性的中断,而且最好还让用户程序不能随意访问它的寄存器,以维持操作系统"心跳"的节律。Cortex‐M3处理器内部包含了一个简单的定时器。因为所有的CM3芯片都带有这个定时器,软件在不同 CM3器件间的移植工作得以化简。该定时器的时钟源可以是内部时钟(FCLK,CM3上的自由运行时钟),或者是外部时钟( CM3处理器上的STCLK信号)。不过, STCLK的具体来源则由芯片设计者决定,因此不同产品之间的时钟频率可能会大不相同,你需要检视芯片的器件手册来决定选择什么作为时钟源。SysTick定时器能产生中断, CM3为它专门开出一个异常类型,并且在向量表中有它的一席之地。它使操作系统和其它系统软件在CM3器件间的移植变得简单多了,因为在所有CM3产品间对其处理都是相同的。
1.1有4个寄存器控制SysTick定时器,功能如表8.9至表8.12所示
-----------------------------------------------------------------------------------------------
2.系统滴答定时器框图:
分析框图写程序看要用到些什么
1. 先看框图左边有一个2选1选择器这是选择滴答定时器的时钟源的分内核时钟和外部时钟源
再看2选1选择器对过来是Sys Tick当前值寄存器 VAL 为24位向下计数器,可以存放的最大值为 2^24=16777216,如你写进100,SysTick控制及状态寄存器CTRL使能计数器后,当前值寄存器向下计数(100减到0),从而达到定时效果,当计数到0后产生一个中断信号Sys Tick控制及状态寄存器CTRL的状态标志位自动置1,如果使能中断则会产生中断,不关闭计数器重装载值寄存器LOAD就会把预先的值写进当前值寄存器VAL重新计数
时钟分析:
内核时钟源:168M
168M=168000 000/s=168/us
当前值寄存器写进16777216则最大延时时间99ms
16777216 /168 = 99864us = 99ms
外部时钟源:21M
21M=21000 000/s = 21/us
当前值寄存器写进16777216则最大延时时间798ms
16777216 / 21 = 798915us = 798ms
-----------------------------------------------------------------------------------------------
2. 分析框图可知要用到的相关寄存器及位如下
SysTik->CTRL :状态及控制寄存器
第2 位:时钟源选择
写0:外部时钟源(STCLK) 21M 系统时钟8分频
写1:内核时钟(FCLK)168M
第0 位:计数器使能
写0:禁止计数
写1:使能计数
第16位:当计数器自动计数到零的时候,此位自动置1(读取该位如果为0,定时时间未到,如果为1,定时时间到)此位需要软件清零
①通过读此位就会清零 SysTik->CTRL
②对当前值寄存器写任意值,此位也会清零 SysTick->VAL = 0xff
当前值寄存器 = 随便写一个数 ;//对状态控制寄存器的16位清零
SysTik->VAL :当前值寄存器
1)当使能计数器后,开始向下计数,当SysTik->VAL为0时,即计数到0时
控制及状态寄存器16位自动置1;
2)对当前值寄存器写操作,它自己本身也清零,状态控制寄存器的16位清零
SysTik->LOAD : 重装载值寄存器
根据要定时多长时间,可以把定时的时间,加载到当前值寄存器中,当计数器的计数值向下计数到了后如果不关闭计数器,那么LOAD的重装载值就会自动加载到计数器中,重新开始向下计数。
注意:最大值 21M 798ms
-----------------------------------------------------------------------------------------------
3.滴答定时器延时配置步骤:
1.选择时钟源->21M/168M
2.清零当前值寄存器->写进任意一个数据
3.向重装载值寄存器写进一个定时值
4.使能计数器
5.等待计数完成
6.关闭计数器
/************************************************
*函数名 :SysTick_us
*函数功能 :系统滴答定时器实现微妙级别延时
*函数参数 :u32 us
*函数返回值:无
*函数描述 :将需要延时的时间写入到参数中
***************************************************/
void SysTick_us(u32 us)
{
//时钟源选择21M //控制及状态寄存器的2位写 0外部时钟
SysTick->CTRL &= ~(1 << 2);
SysTick->VAL = 0xff; //将当前值寄存器清零 //随便写一个数据进入
SysTick->LOAD = us * 21; //将要计时的数据写入到重装载值寄存器
SysTick->CTRL |= 1 << 0; //开始计数//开计数器使能
while(!(SysTick->CTRL & 1 << 16)); // (16位为0) 等待计数完成为1计数完成
SysTick->CTRL &= ~(1 << 0); //关闭计数器
}
-------------------------------------------------------------------------------------
3.滴答定时器中断配置步骤:
1.选择时钟源->21M/168M
2.清零当前值寄存器->写进任意一个数据
3.向重装载值寄存器写进一个定时值
4.使能计数器
5.等待计数完成
4.系统滴答中断
注意:系统滴答属于系统中断,不需要使能NVIC中断响应通道系统滴答延时函数 不能同系统滴答中断一起使用
/************************************************
*函数名 :SysTick_ms_interrupt_init
*函数功能 :系统滴答定时器毫秒级别定时中断初始化
*函数参数 :u16 ms
*函数返回值:无
*函数描述 :将需要定时的时间写入到参数中
***************************************************/
void SysTick_ms_interrupt_init(u16 ms)
{
u32 pri;
/*系统滴答定时器配置*/
SysTick->CTRL &= ~(1 << 2); //时钟源选择21M控制及状态寄存器的2位写 0外部时钟
SysTick->VAL = 0xff; //将当前值寄存器清零->随便写一个数据进入
SysTick->LOAD = ms * 21000; //将要计时的数据写入到重装载值寄存器
SysTick->CTRL |= 1 << 1; //定时中断使能
/*NVIC控制器配置*/
//中断优先级分组(抢占和响应的位数) //抢占2位 响应 2位在主函数中
//中断优先级编码值(抢占和响应的具体级别)
pri = NVIC_EncodePriority(5,2,1);
NVIC_SetPriority(SysTick_IRQn,pri); //将优先级编码值写入到具体中断源中
SysTick->CTRL |= 1 << 0; //开始计数 //开计数器使能
}
/************************************************
*函数名 :SysTick_Handler
*函数功能 :
*函数参数 :无
*函数返回值:无
*函数描述 :
***************************************************/
void SysTick_Handler(void)
{
SysTick->VAL = 0xff; //向VAL寄存器写入一个值清除中断标志位
GPIOF->ODR ^= 1 << 8; //每次触发中断蜂鸣器响取反一次
}