1.系統(tǒng)定時(shí)器介紹
總體概述
SysTick 定時(shí)器被捆綁在 NVIC 中蜂挪,用于產(chǎn)生SysTick異常(異常號:15)。
SysTick 中斷對系統(tǒng)尤其重要矾柜,操作系統(tǒng)提供的各種定時(shí)功能都與這個(gè)滴答定時(shí)器有關(guān)伏穆。因此。需要一個(gè)定時(shí)器來產(chǎn)生周期性的中斷恨统,而且最好讓用戶不能隨意訪問它的寄存器以維持系統(tǒng)“心跳”的節(jié)律叁扫。
SysTick 定時(shí)器能產(chǎn)生中斷,CM3 為它專門開出一個(gè)異常類型畜埋,并且在向量表中有它的一席之地莫绣。它使操作系統(tǒng)和其他系統(tǒng)軟件在 CM3 器件之間的移植變得簡單,因?yàn)樵谒械?CM3 產(chǎn)品中悠鞍,SysTick的處理方式都是相同的对室。SysTick定時(shí)器不僅能服務(wù)于操作系統(tǒng),還能用于延時(shí)咖祭,鬧鐘以及測量時(shí)間掩宜。
原理分析
SysTick 是一個(gè)24位的寄存器,因此它一次最多可以計(jì)數(shù)2的24次方個(gè)時(shí)鐘脈沖么翰。
用戶定義一個(gè)時(shí)鐘脈沖的值之后牺汤,這個(gè)值被送入計(jì)數(shù)寄存器中,每收到一個(gè)脈沖硬鞍,這個(gè)值就減1慧瘤,當(dāng)這個(gè)值減小到0時(shí)就觸發(fā)異常。
2.程序代碼
程序目的:使用 SysTick 延時(shí)控制 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源代碼:
/***************************************
程序的本意是想在初始化時(shí)關(guān)閉滴答定時(shí)器
在每次使用延時(shí)函數(shù)時(shí)再把它打開
這兩句代碼去掉锅减,程序也可以正常運(yùn)行
***************************************/
#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 );
}
/* 關(guān)閉滴答定時(shí)器 */
//SysTick->CTRL &= ~ SysTick_CTRL_ENABLE_MSK;
}
void Delay_ms( __IO u32 nTime )
{
TimingDelay = nTime;
/* 使能滴答定時(shí)器 */
//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 函數(shù)
這個(gè)函數(shù)是系統(tǒng)定義好的,在里面調(diào)用 TimingDelay_Decrement 函數(shù)即可
因?yàn)?TimingDelay_Decrement 函數(shù)是在別的地方定義的
所以要在 stm32f103x_it.c 中加上以下聲明:
extern void TimingDelay_Decrement(void);
******************************************************************/
void SysTick_Handler(void)
{
TimingDelay_Decrement();
}
主函數(shù)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.補(bǔ)充
在延時(shí)的函數(shù)中我們會發(fā)現(xiàn) TimingDelay 這個(gè)變量伐坏,它的定義是這樣的:
static __IO u32 TimingDelay;
static:
static 修飾符好理解怔匣,它用來聲明靜態(tài)變量,相當(dāng)于全局變量桦沉。
我們知道每瞒,C/C++的變量都有一個(gè)作用域。舉個(gè)例子纯露,一個(gè)函數(shù)聲明的變量只存在于它的執(zhí)行過程中剿骨,這時(shí)變量保存在棧里。一旦退出函數(shù)埠褪,變量也就死亡了浓利。而用 static 修飾的變量是存儲在堆里的挤庇,知道整個(gè)程序結(jié)束它才會消失。
因此在我們進(jìn)行延時(shí)的時(shí)候贷掖,需要讓延時(shí)剩下的脈沖數(shù)一直存在于程序中嫡秕,這樣才能完成延時(shí)。
__IO:
__IO 本身是不存在于 C 語言中的苹威,它是一個(gè)另一個(gè)修飾符的宏定義:
#define __IO volatile
如果一個(gè)值有可能會被意想不到的改變昆咽,那么它有必要被定義為 volatile。
這樣牙甫,編譯器就不會去假設(shè)這個(gè)變量的值了掷酗。精確地說就是,優(yōu)化器在用到這個(gè)變量時(shí)必須每次都小心地重新讀取這個(gè)變量的值腹暖,而不是使用保存在寄存器里的備份汇在。