【51单片机快速入门指南】3.2:定时器/计数器
目錄
- 快速使用
- 硬知識
- 傳統51單片機 CPU 時序的有關知識(12T)
- 51 單片機定時器原理
- 51 單片機定時/計數器結構
- 定時器/計數器0/1
- 定時器/計數器0和1的相關寄存器
- 控制寄存器
- 工作模式寄存器
- 工作模式
- 模式0(13位定時器/計數器)
- 模式1(16位定時器/計數器)
- 模式2(8位自動重裝模式)
- 模式3(兩個8位計數器)
- 古老Intel 8051單片機定時器0/1的應用舉例
- 定時器/計數器2
- 定時器/計數器2的相關寄存器
- 控制寄存器
- 工作模式寄存器
- 工作模式
- 16位自動重裝模式(遞增/遞減計數器)
- 16位捕獲模式
- 串行口波特率發生器模式
- 波特率公式匯總
- 可編程時鐘輸出模式
- 示例程序
- 配置源碼
- TIM.c
- TIM.h
- 定時器0中斷、定時器1中斷、定時器2中斷示例
- main.c
- 修改TIM.c中的中斷服務函數
- 現象
- 定時器2可編程時鐘輸出示例
- main.c
- 現象
普中51-單核-A2
STC89C52
Keil uVision V5.29.0.0
PK51 Prof.Developers Kit Version:9.60.0.0
中斷知識見【51單片機快速入門指南】3:中斷系統
快速使用
???????可利用STC-ISP的計算器直接生成初始化函數
???????傳統51需設置系統頻率=晶振頻率,定時器時鐘設為12T
???????使能6T模式后需將系統頻率x2
???????使用更新的1T芯片則定時器時鐘應改為1T,系統頻率無需x2
硬知識
???????摘自《普中 51 單片機開發攻略》和《STC89C52系列單片機器件手冊》
???????中斷知識見【51單片機快速入門指南】3:中斷系統
傳統51單片機 CPU 時序的有關知識(12T)
① 振蕩周期:為單片機提供定時信號的振蕩源的周期(晶振周期或外加振蕩 周期)。
② 狀態周期:2 個振蕩周期為 1 個狀態周期,用 S 表示。振蕩周期又稱 S 周 期或時鐘周期。
③ 機器周期:1 個機器周期含 6 個狀態周期,12 個振蕩周期。
④ 指令周期:完成 1 條指令所占用的全部時間,它以機器周期為單位。
例如:外接晶振為 12MHz 時,51 單片機相關周期的具體值為: 振蕩周期=1/12us; 狀態周期=1/6us; 機器周期=1us; 指令周期=1~4us;
補充概念
51 單片機定時器原理
???????STC89C5X 單片機內有兩個可編程的定時/計數器 T0、T1 和一個特殊功能定時器 T2。定時/計數器的實質是加 1 計數器(16 位),由高 8 位和低 8 位兩個寄存器 THx 和 TLx 組成。它隨著計數器的輸入脈沖進行自加 1,也就是每來一 個脈沖,計數器就自動加 1,當加到計數器為全 1 時,再輸入一個脈沖就使計數器回零,且計數器的溢出使相應的中斷標志位置 1,向 CPU 發出中斷請求(定時/計數器中斷允許時)。如果定時/計數器工作于定時模式,則表示定時時間已到; 如果工作于計數模式,則表示計數值已滿。可見,由溢出時計數器的值減去計數初值才是加 1 計數器的計數值。
51 單片機定時/計數器結構
???????上圖中的 T0 和 T1 引腳對應的是單片機 P3.4 和 P3.5 管腳。51 單片機定時/計數器的工作由兩個特殊功能寄存器控制。TMOD 是定時/計數器的工作方式寄存器,確定工作方式和功能;TCON 是控制寄存器,控制 T0、T1 的啟動和停止及設置溢出標志。
定時器/計數器0/1
???????STC89C52系列單片機的定時器0和定時器1,與傳統8051的定時器完全兼容,當在定時器1做波特率發生器時,定時器0可以當兩個8位定時器用。
???????STC89C52系列單片機內部設置的兩個16位定時器/計數器TO和T1都具有計數方式和定時方式兩種工作方式。對每個定時器/計數器(T0和T1),在特殊功能寄存器TMOD中都有一控制位——C / T ̄\overline{T}T 來選擇T0或T1為定時器還是計數器。定時器/計數器的核心部件是一個加法(也有減法)的計數器,其本質是對脈沖進行計數。只是計數脈沖來源不同:如果計數脈沖來自系統時鐘,則為定時方式,此時定時器/計數器每12個時鐘或者每6個時鐘得到一個計數脈沖,計數值加1;如果計數脈沖來自單片機外部引腳(T0為P3.4,T1為P3.5),則為計數方式,每來一個脈沖加1。
定時器/計數器0有4種工作模式:
???????模式0(13位定時器/計數器),
???????模式1(16位定時器/計數器模式),
???????模式2(8位自動重裝模式),
???????模式3(兩個8位定時器/計數器)。
定時器/計數器1除模式3外,其他工作模式與定時器/計數器0相同,T1在模式3時無效,停止計數。
定時器/計數器0和1的相關寄存器
控制寄存器
???????TCON為定時器/計數器T0、T1的控制寄存器,同時也鎖存T0、T1溢出中斷源和外部請求中斷源等,TCON格式如下:
工作模式寄存器
???????定時和計數功能由特殊功能寄存器TMOD的控制位C/T ̄\overline{T}T進行選擇,TMOD寄存器的各位信息如下表所列。可以看出,2個定時/計數器有4種操作模式,通過TMOD的M1和M0選擇。2個定時/計數器的模式0、1和2都相同,模式3不同,各模式下的功能如下所述。
工作模式
???????通過對寄存器TMOD中的M1、M0的設置,定時器/計數器0有4種不同的工作模式; 定時器/計數器1有3種不同的工作模式。
模式0(13位定時器/計數器)
???????將定時器x設置成模式0時類似8048定時器,即8位計數器帶32分頻的預分頻器(TLx的低5位用于分頻計數,2的5次方=32)。下圖所示為定時器/計數器x的模式0工作方式。此模式下,定時器x配置為13位的計數器,由TLx的低5位和THx的8位所構成。TLx低5位溢出向THx進位,THx計數溢出置位TCON中的溢出標志位TFx。GATE=0時,如TRx=1,則定時器計數。GATE=1時,允許由外部輸入INT1 ̄\overline{INT1}INT1控制定時器1,INT0 ̄\overline{INT0}INT0控制定時器0,這樣可實現脈寬測量。TRx為TCON寄存器內的控制位,TCON寄存器各位的具體功能描述見TCON寄存器各位的具體功能描述表。
???????當C/T ̄\overline{T}T=0時,多路開關連接到系統時鐘的分頻輸出,Tx對時鐘周期計數,Tx工作在定時方式。當C/T ̄\overline{T}T=1時,多路開關連接到外部脈沖輸入,即Tx工作在計數方式。
???????STC89C52系列單片機的定時器有兩種計數速率:一種是12T模式,每12個時鐘加1,與傳統8051單片機相同;另外一種是6T模式,每6個時鐘加1,速度是傳統8051單片機的2倍。Tx的速率在燒錄用戶程序時在STC-ISP編程器中設置。
模式1(16位定時器/計數器)
???????模式1除了使用了THx及TLx全部16位外,其他與模式0完全相同。即此模式下定時器/計數器0作為16位定時器/計數器,如下圖所示。
???????此模式下,定時器配置為16位定時器/計數器,由TLx的8位和THx的8位所構成。TLx的8位溢出向THx進位,THx計數溢出置位TCON中的溢出標志位TFx。
???????當GATE=0時,如TRx=1,則定時器計數。GATE=1時,允許由外部輸入INTx ̄\overline{INTx}INTx控制定時器x,這樣可實現脈寬測量。TRx為TCON寄存器內的控制位,TCON寄存器各位的具體功能描述見上節 TCON寄存器 的介紹。
???????當C/T ̄\overline{T}T=0時,多路開關連接到系統時鐘的分頻輸出,Tx對時鐘周期計數,Tx工作在定時方式。當C/T ̄\overline{T}T=1時,多路開關連接到外部脈沖輸入,即Tx工作在計數方式。
???????STC89C52系列單片機的定時器有兩種計數速率:一種是12T模式,每12個時鐘加1,與傳統8051單片機相同;另外一種是6T模式,每6個時鐘加1,速度是傳統8051單片機的2倍。Tx的速率在燒錄用戶程序時在STC-ISP編程器中設置。
模式2(8位自動重裝模式)
???????此模式下定時器 / 計數器x作為可自動重裝載的 8 位計數器,如下圖所示
???????TLx的溢出不僅置位TFx ,而且將THx內容重新裝入TLx , THx內容由軟件預置,重裝時THx內容不變。
模式3(兩個8位計數器)
???????對定時器1,在模式3時,定時器1停止計數,效果與將TR1設置為0相同。
???????對定時器0,此模式下定時器0的TL0及TH0作為2個獨立的8位計數器。下圖為模式3時的定時器0邏輯圖。TL0占用定時器0的控制位:C/T ̄\overline{T}T、GATE、TR0、INT0及TF0。TH0限定為定時器功能(計數器周期),占用定時器1的TR1及TF1。此時,TH0控制定時器1中斷。
???????模式3是為了增加一個附加的8位定時器/計數器而提供的,使單片機具有三個定時器/計數器。模式3 只適用于定時器/計數器0 ,定時器T1處于模式3時相當于TR1=0,停止計數,而T0可作為兩個定時器用。
古老Intel 8051單片機定時器0/1的應用舉例
???????8051系列單片機的定時器/計數器0或1是以不斷加1進行計數的,即屬加1計數器,因此,就不能直接將實際的計數值作為計數初值送入計數寄存器THx、TLx中去,而必須將實際計數值以282^828、2132^{13}213、2162^{16}216為模求補,以其補碼作為計數初值設置THx和TLx。
???????設:實際計數值為x,計數器長度為n (n=8、13、16),則應裝入計數器THx、TLx中的計數初值為2n?x2^n-x2n?x,式中2n2^n2n為取模值。例如,工作方式0的計數長度為13位,則n=13,以2132^{13}213為模,工作方式1的計數長度為16,則n=16,以2162^{16}216為模等等。所以,計數初值為 (x)補=2n?x(x)_補=2^{n} - x(x)補?=2n?x。
???????對于定時模式,是對機器周期計數,而機器周期與選定的主頻密切相關。因此,需根據應用系統所選定的主頻計算出機器周期值。現以主頻6MHz為例,則機器周期為:
一個機器周期 = 12/12 /12/ 主振頻率 = 12us/12 us/12us/ (6×106)(6×10^6)(6×106) = 2us2us2us
實際定時時間 Tc=x?TpTc = x·TpTc=x?Tp
???????式中TpTpTp為機器周期,TcTcTc為所需定時時間,xxx為所需計數次數。TpTpTp和TpTpTp一般為已知值,在求出TpTpTp后即可求得所需計數值xxx,再將xxx求補碼,即求得定時計數初值。即
(x)補=2n?x(x)_補=2^{n} - x(x)補?=2n?x
???????例如,設定時時間Tc=5msTc = 5msTc=5ms,機器周期Tp=2μsTp = 2μsTp=2μs,可求得定時計數次數
??????????????x=5ms/2us=2500x = 5ms/2us = 2500x=5ms/2us=2500 次
???????設選用工作方式1,則n=16,則應設置的定時時間計數初值為:
(x)補=216?x=65536?2500=63036(x)_補=2^{16} - x=65536-2500=63036(x)補?=216?x=65536?2500=63036,還需將它分解成兩個8位十六進制數,分別求得低8位為3CH裝入TLx,高8位為F6H裝入THx中。
???????工作方式0、1、2的最大計數次數分別為8192、65536和256。
???????對外部事件計數模式,只需根據實際計數次數求補后變換成兩個十六進制碼即可。
定時器/計數器2
???????定時器2是一個16位定時/計數器。通過設置特殊功能寄存器T2CON中的C/T2 ̄\overline{T2}T2位,可將其作為定時器或計數器(特殊功能寄存器T2CON的描述如下所示)
定時器/計數器2的相關寄存器
控制寄存器
工作模式寄存器
除了波特率發生器模式,T2CON不包括TR2位的設置,TR2位需單獨設置來啟動定時器。如下表列出了T2作為定時器和計數器的具體設置方法。
(1)內部控制:僅當定時器溢出時進行捕獲和重裝。
(2)外部控制:當定時/計數器溢出并且T2EX(P1.1)發生電平負跳變時產生捕獲和重裝(定時器2用于波特率發生器模式時除外)。
工作模式
???????定時器2有4種操作模式:自動重新裝載(遞增或遞減計數)、捕獲、和波特率發生器,以及自動重新裝載模式的衍生——可編程時鐘輸出模式。 前3種模式由T2CON中的位進行選擇(如下表所列)
16位自動重裝模式(遞增/遞減計數器)
???????16位自動重裝模式中,定時器2 可通過C/T2配置為定時器/計數器,編程控制遞增/遞減計數。計數的方向是由DCEN(遞減計數使能位)確定的,DCEN位于T2MOD寄存器中,T2MOD寄存器各位的功能描述如表3 所示。當DCEN=0 時,定時器2 默認為向上計數;當DCEN=1 時,定時器2 可通過T2EX 確定遞增或遞減計數。圖2 顯示了當DCEN=0 時,定時器2 自動遞增計數。在該模式中,通過設置EXEN2位進行選擇。如果EXEN2=0,定時器2 遞增計數到0FFFFH,并在溢出后將TF2置位,然后將RCAP2L和RCAP2H 中的16位值作為重新裝載值裝入定時器2。RCAP2L和RCAP2H的值是通過軟件預設的。
???????如果EXEN2=1,16位重新裝載可通過溢出或T2EX從1 到 0 的負跳變實現。此負跳變同時EXF2置位。如果定時器2中斷被使能,則當TF2或EXF2置1時產生中斷。在圖3中,DCEN=1時,定時器2可增或遞減計數。此模式允許T2EX 控制計數的方向。當T2EX 置1 時,定時器2 遞增計數,計數到0FFFFH后溢出并置位TF2,還將產生中斷(如果中斷被使能)。定時器2的溢出將使RCAP2L 和RCAP2H中的16 位值作為重新裝載值放入TL2和TH2。
???????當T2EX置零時,將使定時器2遞減計數。當TL2和TH2計數到等于RCAP2L和RCAP2H時,定時器產生中斷。
16位捕獲模式
???????在捕獲模式中,通過T2CON中的EXEN2設置2個選項。如果EXEN2=0,定時器2作為一個16位定時器或計數器(由T2CON中C/T2位選擇),溢出時置位TF2(定時器2溢出標志位)。該位可用于產生中斷(通過使能IE寄存器中的定時器2中斷使能位ET2)。如果EXEN2=1,與以上描述相同,但增加了一個特性,即外部輸入T2EX由1變零時,將定時器2中TL2和TH2的當前值各自捕獲到RCAP2L和RCAP2H。另外,T2EX的負跳變使T2CON中的EXF2置位,EXF2也像TF2一樣能夠產生中斷(其向量與定時器2溢出中斷地址相同,定時器2中斷服務程序通過查詢TF2和EXF2來確定引起中斷的事件),捕獲模式如下圖所示。在該模式中,TL2和TH2無重新裝載值,甚至當T2EX產生捕獲事件時,計數器仍以 T2EX 的負跳變或振蕩頻率的 1/12(12T模式)或1/6(6T模式)計數。
串行口波特率發生器模式
???????寄存器T2CON 的位TCLK和(或)RCLK允許從定時器1或定時器2獲得串行口發送和接收的波特率。當TCLK=0時,定時器1作為串行口發送波特率發生器;當TCLK=1時,定時器2作為串行口發送波特率發生器。RCLK對串行口接收波特率有同樣的作用。通過這2位,串行口能得到不同的接收和發送波特率,一個通過定時器1產生,另一個通過定時器2產生。如圖4所示為定時器2工作在波特率發生器模式。與自動重裝模式相似,當TH2溢出時,波特率發生器模式使定時器2寄存器重新裝載來自寄存器RCAP2H 和RCAP2L的16位的值,寄存器RCAP2H和RCAP2L的值由軟件預置。當工作于模式1和模式3時,波特率由下面給出的公式所決定:
??????????????模式 1 和模式 3 的波特率 = 定時器2溢出速率 / 16
???????定時器可配置成“定時”或“計數”方式,在許多應用上,定時器被設置在“定時”方式(C/T2=0)。當定時器2作為定時器時,它的操作不同于波特率發生器。通常定時器2作為定時器,它會在每個機器周期遞增(1/6 或1/12 振蕩頻率)。當定時器2 作為波特率發生器時,它在6 時鐘模式下,以振蕩器頻率遞增(12時鐘模式時為1/12振蕩頻率)。
這時的波特率公式如下:
???????式中:n=16(6時鐘模式)或32(12時鐘模式);[RCAP2H,RCAP2L]是RCAP2H和RCAP2L的內容,為16位無符號整數。
???????如圖4所示,定時器2是作為波特率發生器,僅當寄存器T2CON中的RCLK和(或)TCLK=1時,定時器2作為波特率發生器才有效。注意:TH2溢出并不置位TF2,也不產生中斷。這樣當定時器2 作為波特率發生器時,定時器2中斷不必被禁止。如果EXEN2(T2外部使能標志)被置位,在T2EX中由1 到0 的轉換會置位EXF2(T2 外部標志位),但并不導致(TH2,TL2)重新裝載(RCAP2H,RCAP2L)。
???????當定時器2用作波特率發生器時,如果需要,T2EX可用做附加的外部中斷。當計時器工作在波特率發生器模式下,則不要對TH2和TL2 進行讀/ 寫,每隔一個狀態時間(fosc/2)或由T2 進入的異步信號,定時器2 將加1。在此情況下對TH2 和TH1 進行讀/ 寫是不準確的;可對RCAP2寄存器進行讀,但不要進行寫,否則將導致自動重裝錯誤。當對定時器2或寄存器RCAP進行訪問時,應關閉定時器(清零TR2)。下表列出了常用的波特率和如何用定時器得到這些波特率。
波特率公式匯總
???????定時器2工作在波特率發生器模式,外部時鐘信號由T2腳進入,這時的波特率公式如下:
??????????????模式1和模式3的波特率 = 定時器2溢出速率 / 16
???????如果定時器2采用內部時鐘信號,則波特率公式如下:
???????式中:n=32(12時鐘模式)或16(6 時鐘模式),SYSclk= 振蕩器頻率。自動重裝值可由下式得到:
??????????????RCAP2H, RCAP2L = 65536 -[SYSclk / (n × 波特率)]
可編程時鐘輸出模式
???????STC89C52系列單片機,可設定定時/計數器2,通過P1.0輸出時鐘。P1.0除作通用I/O口外還有兩個功能可供選用:用于定時器/計數器2的外部計數輸入和定時/計數器2時鐘信號輸出。圖5為時鐘輸出和外部事件計數方式示意圖。
???????通過軟件對T2CON.1位C/T2復位為0,對T2MOD.1位T2OE置1就可將定時/計數器2選定為時鐘信號發生器,而T2CON.2位TR2控制時鐘信號輸出開始或結束(TR2為啟/停控制位). 由主振頻率(SYSclk)和定時/計數器2定時、自動再裝入方式的計數初值決定時鐘信號的輸出頻率。其設置公式如下:
n=2,6時鐘/機器周期;
n=4,12時鐘/機器周期
???????從公式可見,在主振頻率(SYSclk)設定后,時鐘信號輸出頻率就取決于定時計數初值的設定。
???????在時鐘輸出模式下,計數器回0 溢出不會產生中斷請求。這種功能相當于定時/計數器2用作波特率發生器,同時又可以作時鐘發生器。但必須注意,無論如何波特率發生器和時鐘發生器不能單獨確定各自不同的頻率。原因是兩者都用同一個陷阱寄存器RCAP2H、RCAP2L,不可能出現兩個計數初值。
示例程序
???????stdint.h見【51單片機快速入門指南】1:基礎知識和工程創建
配置源碼
TIM.c
#include <REGX52.H> #include "TIM.h"#if TIM_USE_STCsfr IPH = 0xb7; #endifuint8_t TL0_Save = 0, TH0_Save = 0; uint8_t TL1_Save = 0, TH1_Save = 0; uint8_t TL2_Save = 0, TH2_Save = 0;void TIM0_Callback() interrupt 1 //定時器0中斷函數 {TL0 = TL0_Save;TH0 = TH0_Save; }void TIM1_Callback() interrupt 3 //定時器1中斷函數 {TL1 = TL1_Save;TH1 = TH1_Save; }void TIM2_Callback() interrupt 5 //定時器2中斷函數 {TL2 = TL2_Save;TH2 = TH2_Save; if(TF2 == 1){TF2 = 0;}if(EXF2 == 1){EXF2 = 0;} }void Timer_Set_Period(uint8_t Timer_ID, uint8_t Timer_Mode, uint32_t CLK_Freq, uint16_t Period_us) {double x = (double)CLK_Freq / 12 / 1000000 * Period_us;uint8_t TLx, THx;if(Timer_ID == TIMER_2 || Timer_Mode == TIMER_MODE_1){if(Timer_ID == TIMER_2 && Timer_Mode == TIMER_MODE_3)x *= 3;x = 65536 - x;TLx = (uint8_t)(x + 0.5);THx = ((uint16_t)x & 0xFF00) >> 8;}else if(Timer_Mode == TIMER_MODE_0){x = 8192 - x;TLx = (uint16_t)(x + 0.5) & 0x1F;THx = (uint16_t)(x + 0.5) >> 5;}else if(Timer_Mode == TIMER_MODE_2 || Timer_Mode == TIMER_MODE_3){x = 256 - x;TLx = (uint8_t)(x + 0.5);THx = (uint8_t)(x + 0.5);}switch(Timer_ID){case TIMER_0:TL0_Save = TLx;TH0_Save = THx;TL0 = TL0_Save; //設置計數初值TH0 = TH0_Save;break;case TIMER_1:TL1_Save = TLx;TH1_Save = THx;TL1 = TL1_Save; //設置計數初值TH1 = TH1_Save;break;case TIMER_2:TL2_Save = TLx;TH2_Save = THx;RCAP2L = TL2_Save; //設置計數初值RCAP2H = TH2_Save;TL2 = TL2_Save; TH2 = TH2_Save; break;} }void Timer_Init(uint8_t Timer_ID, uint8_t Timer_Mode, bit Gate, bit Clock_Source, uint32_t CLK_Freq, uint16_t Period_us, uint8_t Priority) {Timer_Set_Period(Timer_ID, Timer_Mode, CLK_Freq, Period_us);switch(Timer_ID){case TIMER_0:TMOD &= 0xF0;TMOD |= Timer_Mode; //設置工作模式TMOD |= (uint8_t)Clock_Source << 2; //設置時鐘源TMOD |= (uint8_t)Gate << 3; //外部控制相關設置TL0 = TL0_Save; //設置計數初值TH0 = TH0_Save;TF0 = 0; //標志位清0TR0 = 1; //開始計數#if TIM_USE_STCIPH &= ~2; //設置中斷優先級IPH |= (2 & Priority); //設置中斷優先級#endifPT0 = (1 & Priority); //設置中斷優先級ET0 = 1; //打開定時器0中斷允許break;case TIMER_1:TMOD &= 0x0F;TMOD |= (Timer_Mode << 4); //設置工作模式TMOD |= (uint8_t)Clock_Source << 6; //設置時鐘源TMOD |= (uint8_t)Gate << 7; //外部控制相關設置TL1 = TL1_Save; //設置計數初值TH1 = TH1_Save;TF1 = 0; //標志位清0TR1 = 1; //開始計數#if TIM_USE_STCIPH &= ~8; //設置中斷優先級IPH |= (2 & Priority) << 2; //設置中斷優先級#endifPT1 = (1 & Priority); //設置中斷優先級ET1 = 1; //打開定時器1中斷允許break;case TIMER_2:T2MOD = 0; //初始化模式寄存器T2CON = 0; //初始化控制寄存器if(Timer_Mode == TIMER_MODE_3) //設置工作模式T2MOD |= 2;else{CP_RL2 = Timer_Mode & 1;TCLK = (Timer_Mode & 2) >> 1;RCLK = (Timer_Mode & 2) >> 1;}C_T2 = Clock_Source; //設置時鐘源EXEN2 = Gate; //外部控制相關設置RCAP2L = TL2_Save; //設置計數初值RCAP2H = TH2_Save;TL2 = TL2_Save; TH2 = TH2_Save; TF2 = 0; //標志位清0TR2 = 1; //開始計數#if TIM_USE_STCIPH &= ~0x20; //設置中斷優先級IPH |= (2 & Priority) << 4; //設置中斷優先級#endifPT2 = (1 & Priority); //設置中斷優先級ET2 = 1; //打開定時器2中斷允許break;}EA = 1; //打開總中斷 }TIM.h
#ifndef TIM_H_ #define TIM_H_#include "stdint.h"//使用STC單片機的4級優先級 #define TIM_USE_STC 1#if TIM_USE_STC//STC單片機的4級優先級#define STC_TIM_Priority_Lowest 0#define STC_TIM_Priority_Lower 1#define STC_TIM_Priority_Higher 2#define STC_TIM_Priority_Highest 3#endif//傳統51單片機的2級優先級 #define TIM_Priority_Low 0 #define TIM_Priority_High 1#define TIMER_0 0 #define TIMER_1 1 #define TIMER_2 2#define TIMER_MODE_0 0 #define TIMER_MODE_1 1 #define TIMER_MODE_2 2 #define TIMER_MODE_3 3#define GATE_DISABLE 0 #define GATE_ENABLE 1#define CLK_Internal 0 #define CLK_External 1void Timer_Init(uint8_t Timer_ID, uint8_t Timer_Mode, bit Gate, bit Clock_Source, uint32_t CLK_Freq, uint16_t Period_us, uint8_t Priority); void Timer_Set_Period(uint8_t Timer_ID, uint8_t Timer_Mode, uint32_t CLK_Freq, uint16_t Period_us);#endif定時器0中斷、定時器1中斷、定時器2中斷示例
???????分別設置定時器0為13位計數、定時器1為16位計數、定時器2為16位計數模式,周期均設為1000us,中斷優先級各不相同,定時器0中斷0.5s翻轉一次P20,定時器1中斷1s翻轉一次P21,定時器2中斷2s翻轉一次P22。
main.c
#include <REGX52.H> #include "intrins.h" #include "stdint.h" #include "TIM.h"void main(void) { Timer_Init(TIMER_0, TIMER_MODE_0, GATE_DISABLE, CLK_Internal, 11059200L, 1000, STC_TIM_Priority_Lowest);Timer_Init(TIMER_1, TIMER_MODE_1, GATE_DISABLE, CLK_Internal, 11059200L, 1000, STC_TIM_Priority_Lower);Timer_Init(TIMER_2, TIMER_MODE_0, GATE_DISABLE, CLK_Internal, 11059200L, 1000, STC_TIM_Priority_Higher);while(1){} }修改TIM.c中的中斷服務函數
void TIM0_Callback() interrupt 1 //定時器0中斷函數 {static uint16_t TIM0_Counter = 0;TL0 = TL0_Save;TH0 = TH0_Save; ++TIM0_Counter;if(TIM0_Counter == 500){TIM0_Counter = 0;P2_0 = !P2_0;} }void TIM1_Callback() interrupt 3 //定時器1中斷函數 {static uint16_t TIM1_Counter = 0;TL1 = TL1_Save;TH1 = TH1_Save; ++TIM1_Counter;if(TIM1_Counter == 1000){TIM1_Counter = 0;P2_1 = !P2_1;} }void TIM2_Callback() interrupt 5 //定時器2中斷函數 {static uint16_t TIM2_Counter = 0;TL2 = TL2_Save;TH2 = TH2_Save; ++TIM2_Counter;if(TIM2_Counter == 2000){TIM2_Counter = 0;P2_2 = !P2_2;}if(TF2 == 1){TF2 = 0;}if(EXF2 == 1){EXF2 = 0;} }現象
定時器2可編程時鐘輸出示例
???????將定時器2輸出引腳P1.0配置成周期為1000us的脈沖。
main.c
#include <REGX52.H> #include "intrins.h" #include "stdint.h" #include "TIM.h"void main(void) { Timer_Init(TIMER_2, TIMER_MODE_3, GATE_DISABLE, CLK_Internal, 11059200L, 1000, STC_TIM_Priority_Lowest);while(1){} }現象
P1.0上可測出周期為1000us的脈沖
總結
以上是生活随笔為你收集整理的【51单片机快速入门指南】3.2:定时器/计数器的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 当下流行的分布式文件系统大阅兵
- 下一篇: html分享到微博,前端实现分享内容到微