HT66F018定時器0(STM)定時器/計數器功能使用教學

2020-10-07 16:01:56


一、定時器介紹

1、標準型 TM – STM

合泰微控制器HT66F018有三個定時器,定時器0即標準型TM-STM是一個16位元的定時器。本篇部落格主要講的是TM0的定時器/計數器功能,深度剖析技術檔案,從暫存器到中斷一路詳細介紹,再到完成程式編寫。

在這裡插入圖片描述
在這裡插入圖片描述


2、暫存器介紹

標準型 TM 的所有工作模式由一系列暫存器控制。一對唯讀暫存器用來存放 16位元計數器的值,一對讀 / 寫暫存器存放 16 位 CCRA 的值。一個讀 / 寫暫存器存放 8 位 CCRP 的值,剩下兩個控制暫存器設定工作模式。
在這裡插入圖片描述

①、TM0C0暫存器

TM0C0暫存器我們需要用到它的6、5、4、3位。
在這裡插入圖片描述

②、TM0C1暫存器

由於我們著重介紹的定時器/計數器功能,所以TM0C1暫存器我們只需要看7、6、0位。

在這裡插入圖片描述
在這裡插入圖片描述

③、TM0DL和TM0DH暫存器

在這裡插入圖片描述

④、TM0AL和TM0AH暫存器

在這裡插入圖片描述
在這裡插入圖片描述

⑤、TM0RP暫存器

由於我們這裡沒用到P匹配,不展開介紹。
在這裡插入圖片描述

3、暫存器工作模式

①、定時/計數器模式

定時 / 計數器模式與比較輸出模式操作方式相同,併產生同樣的中斷請求標誌。不同的是,在定時 / 計數器模式下 TM 輸出腳未使用。因此,比較匹配輸出模式中的描述和時序圖可以適用於此功能。該模式中未使用的 TM 輸出腳用作普通 I/O 腳或其它功能。
在這裡插入圖片描述

②、比較匹配輸出模式

在這裡插入圖片描述

③、比較匹配輸出模式(A匹配注意事項)

在這裡插入圖片描述


4、中斷介紹

①、中斷暫存器

在這裡插入圖片描述

②、中斷操作

在這裡插入圖片描述

③、中斷向量表

從中斷向量表中可以看出來,TM0中斷屬於多功能中斷。
在這裡插入圖片描述


④、多功能中斷和TM中斷

當多功能中斷中任何一種中斷請求標誌 MF0F~MF2F 被置位,多功能中斷請求產生。當中斷使能,堆疊未滿,包括在多功能中斷中的任意一箇中斷髮生時,將呼叫多功能中斷向量中的一個子程式。當響應中斷服務子程式時,相關的多功能請求標誌位會自動復位且 EMI 位會自動清零以除能其它中斷。

在中斷響應時,雖然多功能中斷標誌會自動復位,但多功能中斷源的請求標誌位,即 TM 中斷,LVD 中斷和 EEPROM 中斷的請求標誌位不會自動復位,必須由應用程式清零

在這裡插入圖片描述
在這裡插入圖片描述

⑤、INTC0 暫存器

在這裡插入圖片描述

⑥、MFI0 暫存器

在這裡插入圖片描述

5、系統時鐘

SMOD暫存器
在這裡插入圖片描述
在這裡插入圖片描述


二、程式編寫

有了以上的基礎知識後,就可以開始我們的程式編寫了。

1、系統初始化

新建main.c,必須匯入HT66F018.h

#include "HT66F018.h"

設定選項中,Vdd選擇的是5V,OSC我選擇的是internal RC + IO1/IO2(內部RC振盪器),HIRC選擇的是8MHz @Vdd=5V,fsub選擇的是LIRC
進行系統初始化,如選擇系統時鐘源。

//fH = 8MHz
//fLIRC = 32kHz
_wdtc = 0xA8;	//關閉看門狗
_hlclk = 1;		//系統時鐘8MHz@Vdd=5V,系統時鐘不分頻,檢視SMOD暫存器
_acerl = 0x00;	//禁止所有AD

_pbc0 = 0;		//pb0設定為輸出,用於演示輸出效果

2、TM0初始化

定時器0初值計算方法:
1、需要定時 time = 1ms = 1000us
2、系統時鐘不分頻,所以 fsys = 8MHz
3、TM0 計數時鐘位為 fsys / 4,所以 Tfreq = 8 / 4 = 2MHz
4、定時器初值TM0A = Tfreq * time(us) = 2 * 1000 = 2000
5、_tm0al = 2000 & 0x00FF;         _tm0ah = 2000 >> 8;

由此同理可得:
1、需要定時 time = 0.3ms = 300us
2、fH = 12MHz,系統時鐘4分頻,所以 fsys = 12 / 4 = 3MHz
3、TM0 計數時鐘位為 fsys,所以 Tfreq = fsys = 3MHz
4、定時器初值TM0A = Tfreq * time(us) = 3 * 300 = 900
5、_tm0al = 900 & 0x00FF;         _tm0ah = 900 >> 8;

//定時器0初始化函數
void tm0_init(void)
{
    _t0ck2 = 0; _t0ck1 = 0; _t0ck0 = 0;	//選擇TM0計數時鐘位為fsys/4

    _t0m0 = 1;//定時/計數器模式
    _t0m1 = 1;
    _t0cclr = 1;//A匹配

    //fH=8MHz@Vdd=5V, fsys=不分頻, TM 時鐘源 = fsys/4, 定時器初值 = ((fsys=不分頻) / 4 * (1000us))
    //此處例程定時時間為1ms
    _tm0al = 2000 & 0x00FF; //設定定時器0的A匹配低八位值	
    _tm0ah = 2000 >> 8;	//高八位值


    _t0af = 0;//中斷請求標誌位
    _t0on = 1;//定時器開始計時
    _mf0e = 1;//多功能中斷請求標誌
    _t0ae = 1;//中斷使能
}

3、TM0中斷服務程式

//定時器0中斷
void __attribute((interrupt(0x0C))) Timer0_ISR(void)
{
	if(1 == _t0af){	//TM0的A匹配中斷
		_t0af = 0;	//手動清除T0中斷標誌位
    	count++;
    	if(count == 500){
    		count = 0;
    		_pb0 = ~_pb0;
    	}
	}
    //一旦中斷子程式被響應,系統將自動清除EMI位,所有其它的中斷將被遮蔽
    _emi = 1;   //手動開啟總中斷

}

4、主函數

//主函數
void main()
{
	//fH = 8MHz
	//fLIRC = 32kHz
	_wdtc = 0xA8;	//關閉看門狗
	_hlclk = 1;	//系統時鐘8MHz@Vdd=5V
	_acerl = 0x00;	//禁止所有AD

	_pbc0 = 0;		//pb0作為演示效果IO,可以外接一個LED檢視效果
	tm0_init();

	//開啟總中斷
	_emi = 1;

	//使用者程式碼
	while(1);


}

5、完整程式碼

#include "HT66F018.h"

volatile unsigned int count = 0;	//中斷計數器


//定時器0初始化函數
void tm0_init(void)
{
    _t0ck2 = 0; _t0ck1 = 0; _t0ck0 = 0;	//選擇TM0計數時鐘位為fsys/4

    _t0m0 = 1;//定時/計數器模式
    _t0m1 = 1;
    _t0cclr = 1;//A匹配

    //fH=8MHz@Vdd=5V, fsys=不分頻, TM 時鐘源 = fsys/4, 定時器初值 = ((fsys=不分頻) / 4 * (1000us))
    //此處例程定時時間為1ms
    _tm0al = 2000 & 0x00FF; //設定定時器0的A匹配低八位值	
    _tm0ah = 2000 >> 8;	//高八位值


    _t0af = 0;//中斷請求標誌位
    _t0on = 1;//定時器開始計時
    _mf0e = 1;//多功能中斷請求標誌
    _t0ae = 1;//中斷使能
}

//主函數
void main()
{
	//fH = 8MHz
	//fLIRC = 32kHz
	_wdtc = 0xA8;	//關閉看門狗
	_hlclk = 1;	//系統時鐘8MHz@Vdd=5V
	_acerl = 0x00;	//禁止所有AD

	_pbc0 = 0;
	tm0_init();

	//開啟總中斷
	_emi = 1;

	//使用者程式碼
	while(1);


}

//定時器0中斷
void __attribute((interrupt(0x0C))) Timer0_ISR(void)
{
	if( 1 == _t0af){	//T0的A匹配中斷
		_t0af = 0;		//手動清除T0中斷標誌位
    	count++;
    	if(count == 500){	//500ms反轉一次pb0的電平
    		count = 0;
    		_pb0 = ~_pb0;
    	}
	}
    //一旦中斷子程式被響應,系統將自動清除EMI位,所有其它的中斷將被遮蔽
    _emi = 1;   //手動開啟總中斷

}