您好,歡迎進入深圳市穎特新科技有限公司官方網(wǎng)站!
定時器/計數(shù)器 0和1
N76E003系列定時器/計數(shù)器 0和1是2個16位定時器/計數(shù)器。每個都是由兩個8位的寄存器組成的16位計數(shù)寄存器。
對于定時器/計數(shù)器0,高8位寄存器是TH0、 低8位寄存器是TL0。
同樣定時器/計數(shù)器1也有兩個8位寄存器, TH1 和TL1。
TCON 和 TMOD 可以配置定時器/計數(shù)器0和1的工作模式。
通過TMOD中的 位來選擇定時器或計數(shù)器功能。
每個定時器/計數(shù)器都有選擇位,TMOD的第2位選擇定時器/計數(shù)器0功能,TMOD的第6位選擇定時器/計數(shù)器1功能。
將它們設置為定時器后,定時器將對系統(tǒng)時鐘周期計數(shù)。
定時器0通過設置T0M(CKCON.3)位,定時器1通過設置T1M(CKCON.4)位,來選擇定時器時鐘是系統(tǒng)時鐘(FSYS)的12分頻或直接是系統(tǒng)時鐘。
在計數(shù)器模式下,每當檢測到外部輸入腳T0上的下降沿,計數(shù)寄存器的內(nèi)容就會加一。如果在一個時鐘周期采樣到高電平,在下一個時鐘周期采樣到低電平,那么T0或T1引腳就會確認為一個由高到低的跳變。
當有定時器溢出發(fā)生,定時器0和1能配置引腳T0/T1自動翻轉(zhuǎn)輸出。
這個功能通過設P2S寄存器的T0OE和T1OE來設置,分別對應于定時器0和定時器1。當打開這個功能,輸出端口在第一個定時溢出之前輸出邏輯1。為確保此模式功能, 位應該被清除并且選擇系統(tǒng)時鐘作為定時器的時鐘源。
注意:TH0(TH1)和TL0(TL1)是獨立分開訪問。需要特別注意,在模式0或模式1下時,當讀/寫TH0(TH1)和TL0(TL1)之前,必須清除TR0(TR1)來停止計時。否則將產(chǎn)生不可預料的結(jié)果。
模式0(13位定時器)
在模式 0, 定時器/計數(shù)器是13位的計數(shù)器。13位的計數(shù)器由TH0 (TH1) 和TL0 (TL1)的低五位組成。TL0 (TL1)的高三位被忽略。當TR0 (TR1)置位且GATE是0或 是1時,定時器/計數(shù)器使能。GATE設置為1可以通過定時器來計算外部輸入引腳上輸入脈沖的寬度。當13位的定時器計數(shù)值從1FFFH變?yōu)?000H后,定時器溢出標志TF0 (TF1) 置位,如果中斷打開,此時會產(chǎn)生一個定時器中斷。
#define TH0_INIT 0xFC #define TL0_INIT 0x0F #define TH1_INIT 0xE0 #define TL1_INIT 0x00
TMOD = 0XFF; Set_All_GPIO_Quasi_Mode; TIMER0_MODE0_ENABLE; //Timer 0 and Timer 1 mode configuration TIMER1_MODE0_ENABLE; clr_T0M; clr_T1M; TH0 = TH0_INIT; TL0 = TL0_INIT; TH1 = TH1_INIT; TL1 = TL1_INIT; set_ET0; //enable Timer0 interrupt set_ET1; //enable Timer1 interrupt set_EA; //enable interrupts set_TR0; //Timer0 run // set_TR1; //Timer1 run
TMOD = 0XFF;
Set_All_GPIO_Quasi_Mode; 設置引腳模式
#define P14_OpenDrain_Mode P1M1|=SET_BIT4;P1M2|=SET_BIT4
TIMER0_MODE0_ENABLE; //Timer 0 and Timer 1 mode configuration
#define TIMER0_MODE0_ENABLE TMOD&=0xF0
//-------------------- Timer1 function define -------------------- #define TIMER0_MODE0_ENABLE TMOD&=0xF0 #define TIMER0_MODE1_ENABLE TMOD&=0xF0;TMOD|=0x01 #define TIMER0_MODE2_ENABLE TMOD&=0xF0;TMOD|=0x02 #define TIMER0_MODE3_ENABLE TMOD&=0xF0;TMOD|=0xF3
clr_T0M;
clr_T1M;
#define clr_PWMCKS CKCON &= ~SET_BIT6 #define clr_T1M CKCON &= ~SET_BIT4 #define clr_T0M CKCON &= ~SET_BIT3 #define clr_CLOEN CKCON &= ~SET_BIT1
TH0 = TH0_INIT;
TL0 = TL0_INIT;
TH1 = TH1_INIT;
TL1 = TL1_INIT;
#define TH0_INIT 0xFC // #define TL0_INIT 0x0F #define TH1_INIT 0xE0 // #define TL1_INIT 0x00
set_TR0; //Timer0 run
由于定時器方式0位13為計數(shù)器,即最多能裝載2的13次方個(8192),當TH0與TL0初始值為零時最多經(jīng)過8192個機器周期該計數(shù)器就會溢出一次,,向CPU申請中斷。
時鐘周期
時鐘周期也稱為振蕩周期,定義為時鐘脈沖的倒數(shù)(可以這樣來理解,時鐘周期就是單片機外接晶振的倒數(shù),例如12M的晶振,它的時間周期就是1/12 us),是計算機中最基本的、最小的時間單位。
在一個時鐘周期內(nèi),CPU僅完成一個最基本的動作。對于某種單片機,若采用了1MHZ的時鐘頻率,則時鐘周期為1us;若采用4MHZ的時鐘頻率,則時鐘周期為250us。由于時鐘脈沖是計算機的基本工作脈沖,它控制著計算機的工作節(jié)奏(使計算機的每一步都統(tǒng)一到它的步調(diào)上來)。顯然,對同一種機型的計算機,時鐘頻率越高,計算機的工作速度就越快。但是,由于不同的計算機硬件電路和器件的不完全相同,所以其所需要的時鐘周頻率范圍也不一定相同。我們學習的8051單片機的時鐘范圍是1.2MHz-12MHz。
在8051單片機中把一個時鐘周期定義為一個節(jié)拍(用P表示),二個節(jié)拍定義為一個狀態(tài)周期(用S表示)。
機器周期
在計算機中,為了便于管理,常把一條指令的執(zhí)行過程劃分為若干個階段,每一階段完成一項工作。例如,取指令、存儲器讀、存儲器寫等,這每一項工作稱為一個基本操作。完成一個基本操作所需要的時間稱為機器周期。一般情況下,一個機器周期由若干個S周期(狀態(tài)周期)組成。8051系列單片機的一個機器周期同6個S周期(狀態(tài)周期)組成。前面已說過一個時鐘周期定義為一個節(jié)拍(用P表示),二個節(jié)拍定義為一個狀態(tài)周期(用S表示),8051單片機的機器周期由6個狀態(tài)周期組成,也就是說一個機器周期=6個狀態(tài)周期=12個時鐘周期。
指令周期
指令周期是執(zhí)行一條指令所需要的時間,一般由若干個機器周期組成。指令不同,所需的機器周期數(shù)也不同。對于一些簡單的的單字節(jié)指令,在取指令周期中,指令取出到指令寄存器后,立即譯碼執(zhí)行,不再需要其它的機器周期。對于一些比較復雜的指令,例如轉(zhuǎn)移指令、乘法指令,則需要兩個或者兩個以上的機器周期。
通常含一個機器周期的指令稱為單周期指令,包含兩個機器周期的指令稱為雙周期指令。
1T、6T、12T這個原本叫 機械周期,現(xiàn)在更多人稱為 指令周期;以前標準51單片機,是12T模式的。后來大量單片機廠家的介入,開始對單片機進行提速,于是就出現(xiàn)了 6T、1T模式的單片機。
時鐘周期:是指振蕩源的周期,如 外部晶振 10MHz(假設有),那么它的時鐘周期就是 1/10MHz=0.1us;(N76E003)
機械周期:單片機執(zhí)行一單位指令所需要的 時鐘周期 個數(shù),如 1T,就表示,需要 1個時鐘周期;12T(AT89C51) 即為 12個時鐘周期。這些都只是一單位指令的時間(如自增、自減等),多單位指令時間進行倍乘(如賦值語句需要2個機械周期,即乘以2倍)
指令周期:早期更多的是用來描述 某條指令執(zhí)行 需要多少個機械周期,(如自增、自減為 1個機械周期,賦值 2個機械周期,判斷 4個機械周期)。隨著C語言的大量普及,現(xiàn)在,更多的人用它來代替 機械周期 這個名詞,而 指令本身的 周期被人們所忽略,不再深討了。
13位的計數(shù)器由TH0 (TH1) 和TL0 (TL1)的低五位組成。也就是說先將TH0向左移五位,在或上TL0,即(0xFC<<5)|0X0F=((11111100)<<5)|00001111=1111110000000|00001111=0001 1111 1000 1111=1F8F(8079)
當13位的定時器計數(shù)值從1FFFH變?yōu)?000H后(這地方需要仔細理解,我花費了好長時間),定時器溢出標志TF0 (TF1) 置位(定時器溢出標志溢出),如果中斷打開,此時會產(chǎn)生一個定時器中斷。N76E003例程里選用了16M,選用16MHZ,然后16/12(clr_t0m,可以不選)=1.3MHZ,也就是1/1300000s,
即(8192-8079)*1/1300000=0.000086923s(即86us)
這里需要說明的是示波器高電平計一次數(shù)低電平計一次數(shù)所以,周期需要除以二就是定時器的正確計時時間
其實也可以按照這種方法來寫
TH0=(8192-X)/32; TL0=(8192-x)%32 這種好處就是更方便計數(shù)。
set_ET1; //enable Timer1 interrupt
#define set_ET1 ET1 = 1
set_EA; //enable interrupts
set_TR0; //Timer0 run
中斷服務函數(shù):
void Timer0_ISR (void) interrupt 1 //interrupt address is 0x000B { TH0 = TH0_INIT; TL0 = TL0_INIT; P12 = ~P12; // GPIO toggle when interrupt }
模式1(16位定時器)
模式1與模式0 非常相似,只是模式1下定時器/計數(shù)器為16位的,就是說是用THx和TLx的全部16位用來計數(shù)。當
計數(shù)值由FFFFH向0000H翻轉(zhuǎn)后,定時器相應的溢出標志TF0(TF1)置1,如果中斷使能則將產(chǎn)生中斷。
#include "N76E003.h" #include "Common.h" #include "Delay.h" #include "SFR_Macro.h" #include "Function_define.h" //***************** The Following is in define in Fucntion_define.h *************************** //****** Always include Function_define.h call the define you want, detail see main(void) ******* //*********************************************************************************************** #if 0 //#define TIMER0_MODE0_ENABLE TMOD&=0x0F //#define TIMER0_MODE1_ENABLE TMOD&=0x0F;TMOD|=0x10 //#define TIMER0_MODE2_ENABLE TMOD&=0x0F;TMOD|=0x20 //#define TIMER0_MODE3_ENABLE TMOD&=0x0F;TMOD|=0x3F //#define TIMER1_MODE0_ENABLE TMOD&=0xF0 //#define TIMER1_MODE1_ENABLE TMOD&=0xF0;TMOD|=0x01 //#define TIMER1_MODE2_ENABLE TMOD&=0xF0;TMOD|=0x02 //#define TIMER1_MODE3_ENABLE TMOD&=0xF0;TMOD|=0xF3 #endif #define TH0_INIT 50000 #define TL0_INIT 50000 #define TH1_INIT 25000 #define TL1_INIT 25000 UINT8 u8TH0_Tmp,u8TL0_Tmp,u8TH1_Tmp,u8TL1_Tmp; /************************************************************************************************************ * TIMER 0 interrupt subroutine ************************************************************************************************************/ void Timer0_ISR (void) interrupt 1 //interrupt address is 0x000B { TH0 = u8TH0_Tmp; TL0 = u8TL0_Tmp; P12 = ~P12; // GPIO1 toggle when interrupt } /************************************************************************************************************ * TIMER 1 interrupt subroutine ************************************************************************************************************/ void Timer1_ISR (void) interrupt 3 //interrupt address is 0x001B { TH1 = u8TH1_Tmp; TL1 = u8TL1_Tmp; P03 = ~P03; //P0.3 toggle when interrupt } /************************************************************************************************************ * Main function ************************************************************************************************************/ void main (void) { Set_All_GPIO_Quasi_Mode; TIMER0_MODE1_ENABLE; TIMER1_MODE1_ENABLE; clr_T1M; //set_T1M; u8TH0_Tmp = (65536-TH0_INIT)/256; u8TL0_Tmp = (65536-TL0_INIT)%256; u8TH1_Tmp = (65536-TH1_INIT)/256; u8TL1_Tmp = (65536-TL1_INIT)%256; TH0 = u8TH0_Tmp; TL0 = u8TL0_Tmp; TH1 = u8TH1_Tmp; TL1 = u8TL1_Tmp; set_ET0; //enable Timer0 interrupt set_ET1; //enable Timer1 interrupt set_EA; //enable interrupts set_TR0; //Timer0 run set_TR1; //Timer1 run while(1); }
u8TH0_Tmp = (65536-TH0_INIT)/256; u8TL0_Tmp = (65536-TL0_INIT)%256;
u8TH1_Tmp = (65536-TH1_INIT)/256; u8TL1_Tmp = (65536-TL1_INIT)%256; TH0 = u8TH0_Tmp; TL0 = u8TL0_Tmp; TH1 = u8TH1_Tmp; TL1 = u8TL1_Tmp;
只是模式1下定時器/計數(shù)器為16位的,就是說是用THx和TLx的全部16位用來計數(shù)。當
計數(shù)值由FFFFH向0000H翻轉(zhuǎn)后,定時器相應的溢出標志TF0(TF1)置1,如果中斷使能則將產(chǎn)生中斷。
模式2(8位自動重裝載定時器)
模式2下定時器/計數(shù)器為自動重裝模式。此模式下TL0(TL1)是一個8位的計數(shù)器,TH0(TH1)保存重裝計數(shù)
值。當TL0(TL1)溢出后,TCON中的TF0(TF1)標志置位且TH0 (TH1)中內(nèi)容重裝至TL0(TL1),然后繼續(xù)計數(shù)過
程。重裝過程中TH0(TH1)內(nèi)的值保持不變.該特征最好地適用于UART波特率發(fā)生器,不需要連續(xù)軟件介入。
void InitialUART0_Timer1(UINT32 u32Baudrate) //T1M = 1, SMOD = 1 { P06_Quasi_Mode; //Setting UART pin as Quasi mode for transmit P07_Quasi_Mode; //Setting UART pin as Quasi mode for transmit SCON = 0x50; //UART0 Mode1,REN=1,TI=1 TMOD |= 0x20; //Timer1 Mode2 set_SMOD; //UART0 Double Rate Enable set_T1M; clr_BRCK; //Serial port 0 baud rate clock source = Timer1 #ifdef FOSC_160000 TH1 = 256 - (1000000/u32Baudrate+1); /*16 MHz */ #endif #ifdef FOSC_166000 TH1 = 256 - (1037500/u32Baudrate); /*16.6 MHz */ #endif set_TR1; set_TI; //For printf function must setting TI = 1 }
SCON = 0x50; //UART0 Mode1,REN=1,TI=1
TMOD |= 0x20; //Timer1 Mode2
#define set_SMOD PCON |= SET_BIT7
#define set_T1M CKCON |= SET_BIT4
clr_BRCK;
#define clr_BRCK T3CON &= ~SET_BIT5
#ifdef FOSC_160000
TH1 = 256 - (1000000/u32Baudrate+1); /*16 MHz */
#endif
#ifdef FOSC_166000
TH1 = 256 - (1037500/u32Baudrate); /*16.6 MHz */
#endif
已知串口0通信方式1下,波特率為115200bps,系統(tǒng)晶振頻率為16MHz,求TL1,TH1中裝入的初值(定時器1方式2)
解:設初值X,則定時器每計256-X個數(shù)溢出一次,每計一個數(shù)的時間為一個機器周期,因為是1T 8051架構(gòu),所以一個機器周期等于1個時鐘周期,由于設置了SMOD 所以計一個數(shù)的時間為(1/16MHZ) us(即1/16000000s),則定時器溢出一次的時間為[256-X]/16MHZ。
通常都是固定的,一般都是根據(jù)所使用的波特率來求定時器初值。方式1的波特率= 即 (2^smod /32)*T1的溢出率,即 ((2^smod /32)*16000000)/(256-x)
通常都是固定的,一般都是根據(jù)所使用的波特率來求定時器初值。
TH1 = 256 - (1000000/u32Baudrate+1);
256-TH1-1=1000000/u32Baudrate
u32Baudrate=1000000/(256-TH1-1)
set_T1M;
clr_BRCK; //Serial port 0 baud rate clock source = Timer1
set_TR1;
set_TI; //For printf function must setting TI = 1
模式3(兩組獨立8位定時器)
定時器0和定時器1的模式3有著不同的工作方式。對定時器/計數(shù)器1來說模式3會將其停用;
對定時器/計數(shù)器0來說,模式3下TL0和TH0是2個獨立的8位計數(shù)寄存器。模式3下TL0使用定時器0的控制位:如 GATE, TR0,TL0也可以用來對T0 腳上的1到0 跳變計數(shù),由 計數(shù)。TH0 只能對時鐘周期計數(shù),并使用定時器/計數(shù)器1的控制位(TR1和TF1)。
當需要額外的8位定時器時可以使用模式3 。
當定時器0配置為模式3時,定時器1可以通過配置其進入或離開模式3的方式來打開或關閉自己。
定時器1依然可以工作在模式0、1、2下,但它的靈活性受到限制。雖然基本功能得以維持,但已不能對TF1和TR1進行控制(由上文可知在該模式下該位由定時器0控制)。此時定時器1依然可以使用GATE腳、T1M。它同樣可以用作串行口的波特率發(fā)生器或其他不需要中斷的應用。也就是說當定時器工作在模式3時,定時器1模式依然可以選擇但是靈活性受限,不能對TF1和TR1進行控制。
/*---------------------------------------------------------------------------------------------------------*/ /* */ /* Copyright(c) 2016 Nuvoton Technology Corp. All rights reserved. */ /* */ /*---------------------------------------------------------------------------------------------------------*/ //*********************************************************************************************************** // Nuvoton Technoledge Corp. // Website: http://www.nuvoton.com // E-Mail : MicroC-8bit@nuvoton.com // Date : Apr/21/2016 //*********************************************************************************************************** //*********************************************************************************************************** // File Function: N76E003 Timer0/1 Mode3 demo code //*********************************************************************************************************** #include "N76E003.h" #include "Common.h" #include "Delay.h" #include "SFR_Macro.h" #include "Function_define.h" //***************** The Following is in define in Fucntion_define.h *************************** //****** Always include Function_define.h call the define you want, detail see main(void) ******* //*********************************************************************************************** #if 0 //#define TIMER0_MODE0_ENABLE TMOD&=0x0F //#define TIMER0_MODE1_ENABLE TMOD&=0x0F;TMOD|=0x10 //#define TIMER0_MODE2_ENABLE TMOD&=0x0F;TMOD|=0x20 //#define TIMER0_MODE3_ENABLE TMOD&=0x0F;TMOD|=0x3F //#define TIMER1_MODE0_ENABLE TMOD&=0xF0 //#define TIMER1_MODE1_ENABLE TMOD&=0xF0;TMOD|=0x01 //#define TIMER1_MODE2_ENABLE TMOD&=0xF0;TMOD|=0x02 //#define TIMER1_MODE3_ENABLE TMOD&=0xF0;TMOD|=0xF3 #endif #define TH0_INIT (256-100) #define TL0_INIT (256-50) #define TH1_INIT 0x00 #define TL1_INIT 0x00 /************************************************************************************************************ * TIMER 0 interrupt subroutine ************************************************************************************************************/ void Timer0_ISR (void) interrupt 1 // interrupt address is 0x000B { TL0 = TL0_INIT; // reload by software P12 = ~P12; // GPIO1 toggle when interrupt } /************************************************************************************************************ * TIMER 1 interrupt subroutine ************************************************************************************************************/ void Timer1_ISR (void) interrupt 3 //interrupt address is 0x001B { TH0 = TH0_INIT; Send_Data_To_UART0(0x54); //print charater "T" means timer interrupt P12 = ~ P12; //Mark UART output to find the real timer interrupt timming. } /************************************************************************************************************ * Main function ************************************************************************************************************/ void main (void) { Set_All_GPIO_Quasi_Mode; InitialUART0_Timer3(115200); TIMER0_MODE3_ENABLE; TIMER1_MODE3_ENABLE; TH0 = TH0_INIT; //initial counter values TL0 = TL0_INIT; TH1 = TH1_INIT; TL1 = TL1_INIT; set_ET0; //enable Timer0 counter interrupt set_ET1; //enable Timer1 counter interrupt set_EA; //enable interrupts set_TR0; //Timer0 run set_TR1; //Timer1 run while(1); }
#define TIMER1_MODE3_ENABLE TMOD&=0xF0;TMOD|=0xF3
#define TH0_INIT (256-100) #define TL0_INIT (256-50) #define TH1_INIT 0x00 #define TL1_INIT 0x00 /************************************************************************************************************ * TIMER 0 interrupt subroutine ************************************************************************************************************/ void Timer0_ISR (void) interrupt 1 // interrupt address is 0x000B { TL0 = TL0_INIT; // reload by software P12 = ~P12; // GPIO1 toggle when interrupt } /************************************************************************************************************ * TIMER 1 interrupt subroutine ************************************************************************************************************/ void Timer1_ISR (void) interrupt 3 //interrupt address is 0x001B { TH0 = TH0_INIT; P11 = ~P11; //P1.1 toggle when interrupt } /************************************************************************************************************ * Main function ************************************************************************************************************/ void main (void) { Set_All_GPIO_Quasi_Mode; TIMER0_MODE3_ENABLE; TIMER1_MODE3_ENABLE; TH0 = TH0_INIT; //initial counter values TL0 = TL0_INIT; TH1 = TH1_INIT; TL1 = TL1_INIT; set_ET0; //enable Timer0 counter interrupt set_ET1; //enable Timer1 counter interrupt set_EA; //enable interrupts set_TR0; //Timer0 run set_TR1; //Timer1 run while(1) { P1 = TH1; //for Timer 1 has no interrupt while Timer 0 in mode 3, show on ports P2 = TL1; } }
對定時器/計數(shù)器0來說,模式3下TL0和TH0是2個獨立的8位計數(shù)寄存器。
模式3下TL0使用定時器0的控制位:如 ,GATE, TR0,,TL0也可以用來對T0 腳上的1到0 跳變計數(shù),由TMOD.2()來決定。TH0 只能對時鐘周期計數(shù),并使用定時器/計數(shù)器1的控制位(TR1和TF1)
模式三情況如下表所示:
TH0 | TL0 | TH1 | TL1 |
8位計數(shù) | 8位計數(shù) | 停用,其他模式可選擇但受限 | 停用,其他模式可選擇但受限 |
定時器1的控制位(TR1,TF1) | 定時器0的控制位 | 其他模式可以控制GATE、、T1M | 其他模式可以控制GATE、、T1M |
當定時器0配置為模式3時,定時器1可以通過配置其進入或離開模式3的方式來打開或關閉自己。定時器1依然可以工作在模
式0、1、2下,但它的靈活性受到限制。雖然基本功能得以維持,但已不能對TF1和TR1進行控制
它同樣可以用作串行口的波特率發(fā)生器或其他不需要中斷的應用。