1.系统定时器介绍
总体概述
SysTick 定时器被捆绑在 NVIC 中,用于产生SysTick异常(异常号:15)。
SysTick 中断对系统尤其重要,操作系统提供的各种定时功能都与这个滴答定时器有关。因此。需要一个定时器来产生周期性的中断,而且最好让用户不能随意访问它的寄存器以维持系统“心跳”的节律。
SysTick 定时器能产生中断,CM3 为它专门开出一个异常类型,并且在向量表中有它的一席之地。它使操作系统和其他系统软件在 CM3 器件之间的移植变得简单,因为在所有的 CM3 产品中,SysTick的处理方式都是相同的。SysTick定时器不仅能服务于操作系统,还能用于延时,闹钟以及测量时间。
原理分析
SysTick 是一个24位的寄存器,因此它一次最多可以计数2的24次方个时钟脉冲。
用户定义一个时钟脉冲的值之后,这个值被送入计数寄存器中,每收到一个脉冲,这个值就减1,当这个值减小到0时就触发异常。
2.程序代码
程序目的:使用 SysTick 延时控制 LED 灯的闪烁。
<------------------------------------------------------------->
systick.h源代码:
#ifndef __SYSTICK_H
#define __SYSTICK_H
#include "stm32f10x.h"
void SysTick_Init(void);
void Delay_ms( __IO u32 nTime );
#endif
systick.c源代码:
/***************************************
程序的本意是想在初始化时关闭滴答定时器
在每次使用延时函数时再把它打开
这两句代码去掉,程序也可以正常运行
***************************************/
#include "stm32f10x.h"
#include "systick.h"
static __IO u32 TimingDelay;
void SysTick_Init(void)
{
/**********************************
StstemFrequency / 1000 1ms
StstemFrequency / 100000 10us
StstemFrequency / 1000000 1us
***********************************/
if( SysTick_Config( SystemCoreClock / 1000 ) ) //ST3.5.0 库版本
{
/* Capture error */
while ( 1 );
}
/* 关闭滴答定时器 */
//SysTick->CTRL &= ~ SysTick_CTRL_ENABLE_MSK;
}
void Delay_ms( __IO u32 nTime )
{
TimingDelay = nTime;
/* 使能滴答定时器 */
//SysTick->CTRL |= SysTick_CTRL_ENABLE_MSK;
while( TimingDelay != 0 );
}
void TimingDelay_Decrement(void)
{
if( TimingDelay != 0x00 )
{
TimingDelay --;
}
}
stm32f103x_it.c源代码:
/******************************************************************
在stm32f103x_it.c文件中可以找到 SysTick_Handler 函数
这个函数是系统定义好的,在里面调用 TimingDelay_Decrement 函数即可
因为 TimingDelay_Decrement 函数是在别的地方定义的
所以要在 stm32f103x_it.c 中加上以下声明:
extern void TimingDelay_Decrement(void);
******************************************************************/
void SysTick_Handler(void)
{
TimingDelay_Decrement();
}
主函数main.c源代码:
#include "stm32f10x.h"
#include "led.h"
#include "systick.h"
int main(void)
{
LED_Init();
SysTick_Init();
LED2(ON);
while(1)
{
Delay_ms(200);
LED2_REV;
LED3_REV;
}
}
3.补充
在延时的函数中我们会发现 TimingDelay 这个变量,它的定义是这样的:
static __IO u32 TimingDelay;
static:
static 修饰符好理解,它用来声明静态变量,相当于全局变量。
我们知道,C/C++的变量都有一个作用域。举个例子,一个函数声明的变量只存在于它的执行过程中,这时变量保存在栈里。一旦退出函数,变量也就死亡了。而用 static 修饰的变量是存储在堆里的,知道整个程序结束它才会消失。
因此在我们进行延时的时候,需要让延时剩下的脉冲数一直存在于程序中,这样才能完成延时。
__IO:
__IO 本身是不存在于 C 语言中的,它是一个另一个修饰符的宏定义:
#define __IO volatile
如果一个值有可能会被意想不到的改变,那么它有必要被定义为 volatile。
这样,编译器就不会去假设这个变量的值了。精确地说就是,优化器在用到这个变量时必须每次都小心地重新读取这个变量的值,而不是使用保存在寄存器里的备份。