單片機筆記
定時器/計數(shù)器
定時器/計數(shù)器的結(jié)構(gòu)
AT89S51內(nèi)部兩個16位定時器/計數(shù)器:T0(P3.4),T1(P3.5),定時器/計數(shù)器T0由特殊寄存器TH0,TL0構(gòu)成,T1由特殊功能寄存器TH1,TL1構(gòu)成
T0,T1都有定時器和計數(shù)器兩種工作模式,兩種模式實質(zhì)都是對脈沖信號進(jìn)行計數(shù),只不過技術(shù)信號來源不同。
-
計數(shù)器模式 是對T0(P3.4)和T1(P3.5)兩個引腳上的外部脈沖進(jìn)行計數(shù)
-
定時器模式是對系統(tǒng)時鐘信號(fosc)經(jīng)12分頻后的內(nèi)部脈沖信號(機器周期Tcy)計數(shù).由于系統(tǒng)時鐘頻率fosc是定值,可根據(jù)數(shù)值計算出定時時間T(定時時間T = n * Tcy).
振蕩周期Tosc = 1/fosc, 機器周期Tcy = 12Tosc = 12/fosc)
例如:fosc = 12Hz, Tcy = 1us
T0,T1屬于加1計數(shù)器,即每記一個脈沖,計數(shù)器加1.(51單片機)
T0,T1具有4種工作方式(方式0,1,2,3)
特殊功能寄存器TMOD用于選擇定時器/計數(shù)器T0,T1的工作模式和工作方式.
特殊功能寄存器TCON用于控制T0,T1的啟動和停止計數(shù),同時包含了T0,T1狀態(tài).
計數(shù)器起始計數(shù)從初值開始,單片機復(fù)位時計數(shù)器初值為0,也可給計數(shù)器裝入一個新的初值(0 ~ 2^16 - 1).
若計數(shù)器溢出會產(chǎn)生中斷,稱溢出中斷,最大計數(shù)值2^16 = 65536, 此時刻發(fā)生溢出中斷, 最大初值2^16 - 1 = 65535
工作方式控制寄存器TMOD
寄存器地址89H, 不可按位操作, 高4位控制T1, 低4位控制T0.
D7 | D6 | D5 | D4 | D3 | D2 | D1 | D0 |
---|---|---|---|---|---|---|---|
GATE | C/T’ | M1 | M0 | GATE | C/T’ | M1 | M0 |
D7-D4 : T1方式字段, D3-D0 : T0方式字段
M1, M0工作方式選擇位
M1 | M0 | 工作方式 |
---|---|---|
0 | 0 | 方式0, 13位定時器/計數(shù)器 |
0 | 1 | 方式1, 16位定時器/計數(shù)器 |
1 | 0 | 方式2, 8位的常數(shù)自動重新裝載的定時器/計數(shù)器 |
1 | 1 | 方式3, 僅適用于T0, 此時T0分成2個8位計數(shù)器, T1停止計數(shù) |
方式0為兼容早期8048的13位定時器/計數(shù)器
GATE - 門控位
- GATE = 0, 定時器是否計數(shù), 由啟動控制位TRx(x = 0, 1)來控制. (TRx = 1 時啟動)
- GATE = 1, 定時器是否計數(shù), 由外部中斷引腳INTx’上的電平與運行控制位TRx共同控制.(1 == INTx’ & 1 == TRx 為真時啟動)
C/T’ - 計數(shù)器模式和定時器模式選擇位
**C : Counter, T : Timer **
- C/T’ = 0, 定時器模式, 對系統(tǒng)時鐘12分頻后的脈沖(fosc/12)進(jìn)行計數(shù).
- C/T’ = 1, 計數(shù)器模式, 對計數(shù)器外部輸入引腳T0(P3.4)或T1(P3.5)的外部脈沖(負(fù)跳變, 即對下降沿計數(shù))計數(shù).
定時器/計數(shù)器控制寄存器TCON
TCON字節(jié)地址88H, 位地址為88H~8FH.
D7 | D6 | D5 | D4 | D3 | D2 | D1 | D0 |
---|---|---|---|---|---|---|---|
TF1 | TR1 | TF0 | TR0 | IE1 | IT1 | IE0 | IT0 |
TF1, TF0 - 計數(shù)溢出標(biāo)志位
當(dāng)計數(shù)器計數(shù)溢出時, 該位置1. 使用查詢方式時, 此位可提供CPU查詢, 但應(yīng)注意查詢后, 用軟件及時該位清0. 使用中斷方式時, 作為中斷請求標(biāo)志位, 進(jìn)入終端服務(wù)程序后由硬件自動清0.
TR1, TR0 - 計數(shù)運行控制位
- TR1/TR0位 = 1, 啟動計數(shù)器計數(shù)的必要條件.
- TR1/TR0位 = 0, 停止計數(shù)器計數(shù).
該位可由軟件置1和清0
定時器/計數(shù)器的4種工作方式
方式1(M1 = 0, M0 = 1)
方式1和方式0差別僅存在于計數(shù)器的位數(shù)不同, 方式1為16位計數(shù)器, 由THx高8位和TLx低8位構(gòu)成(x = 0,1), 方式0為13位計數(shù)器, 有關(guān)控制狀態(tài)位含義(GATE, C/T’, TFx, TRx)與方式0相同.
方式0(M1 = 0, M0 = 0)
該方式為13位定時/計數(shù)器的計數(shù)最大值位2^13 = 8196
方式2
方式0和方式1最大特點是計數(shù)溢出后, 計數(shù)器為全0. 因此在循環(huán)定時或循環(huán)計數(shù)應(yīng)用時就存在用指令反復(fù)裝入計數(shù)初值的問題, 這會影響定時精度(指令本身執(zhí)行也需要時間), 方式2就是為解決此問題而設(shè)置的.
當(dāng)M1, M0 = 1, 0時, 工作方式2. 8位自動重裝載方式
低8位用來計數(shù)/定時, 高8位用來保存初值, 硬件自動完成裝入初值的操作
最大計數(shù)/定時范圍2^8 = 256
方式3
方式3是為增加一個附加的8位定時器/計數(shù)器而設(shè)置的, 從而使AT89S51具有3個定時器/計數(shù)器. 方式3只適用于T0, T1不能工作在方式3
T0在方式3下, 分為了兩個8位定時器/計數(shù)器
對外部輸入的計數(shù)信號的要求
計數(shù)器模式時, 計數(shù)脈沖來自外部輸入引腳T0或T1. 當(dāng)輸入信號產(chǎn)生負(fù)跳變時, 計數(shù)值增1.
由于確認(rèn)一次負(fù)跳變要花2個機器周期, 即24個振蕩周期, 因此外部輸入的計數(shù)脈沖的最高頻率為系統(tǒng)振蕩器頻率的1/24
對外輸入信號占空比沒有限制, 但為確保某一給定電平在變化前能被采樣1次, 該電平至少保持1個機器周期.
方式1應(yīng)用 : P1口控制8只LED每0.5s閃亮一次
分析
設(shè)置晶振頻率12MHz, 則機器周期為1us, 一次溢出中斷時間的總耗時計算65536 * 1us = 65…ms
題目要求0.5s即500ms, 500ms > 65ms,故需軟件計數(shù), 500ms約溢出中斷次數(shù)為100次
可用軟件編寫計時器對中斷次數(shù)進(jìn)行計數(shù)
設(shè)置TMOD寄存器
- TMOD寄存器的M1 = 0, M0 = 1則T0工作在方式1
- 設(shè)置C/T’ = 0, 為定時器模式
- GATE為0, 對T0的運行控制僅由TR0來控制
- 定時器T1不使用, 各相關(guān)位均設(shè)為0
D7 | D6 | D5 | D4 | D3 | D2 | D1 | D0 |
---|---|---|---|---|---|---|---|
GATE | C/T’ | M1 | M0 | GATE | C/T’ | M1 | M0 |
0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 |
TMOD初始化值則為0x01
計算定時器T0的計數(shù)初值
設(shè)定時時間5ms(即5,000us), 設(shè)T0計數(shù)初值為X, 假設(shè)晶振頻率為11.0592MHz, 則定時時間為:
定時時間 = (2^16 - X) * Tcy = (2^16 - X) * 12/晶振頻率
則 5000 = (2^16 - X) * 12 / 11.0592, 得X = 60,928
轉(zhuǎn)換成16進(jìn)制為0xee00, 其中0xee裝入TH0, 0x00裝入TL0.
X --> 65536(產(chǎn)生溢出)
個數(shù)n = 65536 - X
定時時間T = n * Tcy == 5ms == 5,000us
機器周期Tcy = 12 / 11.0592 us
設(shè)置IE寄存器
本例采用定時器T0中斷, 因此需將IE寄存器中的EA,ET0位置1
啟動T0
將定時器控制寄存器TCON中的TR0置1, 則啟動定時器T0
源碼
/*
* 功能實現(xiàn): 使用方式1定時中斷控制LED閃亮
* 編寫環(huán)境: Keil5
* 硬件仿真: Proteus 8 Professional
* 日期: 2022-11-05
*/
#include <reg51.h>
char i = 100; // 用于軟件計數(shù)
int main(void)
{
TMOD = 0x01; // 定時器T0為方式1
TH0 = 0xee; // 設(shè)置定時器初值
TL0 = 0x00;
P1 = 0x00; // P1口8個LED點亮
EA = 1; // 總中斷開
ET0 = 1; // T0中斷開
TR0 = 1; // 啟動T0
while(1) // 循環(huán)等待
{
;
}
return 0;
}
void timer0() interrupt 1 // T0中斷程序
{
TH0 = 0xee; //重新賦初值
TL0 = 0x00;
// 軟件計數(shù), 100次溢出中斷后, LED狀態(tài)進(jìn)行轉(zhuǎn)換
i--; // 循環(huán)次數(shù)減1
if (i <= 0)
{
P1 = ~P1; // P1口按位取反, LED狀態(tài)轉(zhuǎn)換
i = 100; // 重置循環(huán)次數(shù)
}
return;
}
計數(shù)器應(yīng)用
如圖,T1采用計數(shù)模式,方式1中斷,計數(shù)輸入引腳T1(P3.5)上外接按鈕開關(guān),作為計數(shù)信號輸入。按4次按鈕開關(guān)后,P1口的8只LED閃爍不停。
設(shè)置TMOD寄存器
- T1工作在方式1,應(yīng)使TMOD的M1,M0 = 0,1
- 設(shè)置C/T’=1,為計數(shù)器模式
- 對T0運行控制僅由TR0來控制啟動,應(yīng)使GATE0=0.
- 定時器T0不使用,各相關(guān)位均設(shè)0.
所以, TMOD寄存器應(yīng)初始化為0x50.
計算定時器T1的計數(shù)初值
由于每按1次按鈕開關(guān),計數(shù)1次,按4次后,P1口的8只LED閃爍不停. 因此計數(shù)器初值為65536 - 4 = 65532, 所以, TH1 = (65536 - 4) / 256, TL1 = (65536 - 4) % 256.
設(shè)置IE寄存器
由于采用T1中斷,因此需將IE寄存器的EA, ET1位置1.
啟動和停止定時器T1
將寄存器TCON中TR1 = 1, 則啟動T1計數(shù).
源碼
#include <reg51.h>
void Delay(unsigned int i);
int main(void)
{
TMOD = 0x50; // 設(shè)置定時器T1位方式1計數(shù)
TH1 = (65536 - 4) / 256; // 向TH1寫入初值的高8位
TL1 = (65536 - 4) % 256; // 向TL1寫入初值的低8位
EA = 1; // 總中斷允許
ET1 = 1; // 定時器T1中斷允許
TR1 = 1; // 啟動定時器T1
while (1)
{
;
}
return 0;
}
void Delay(unsigned int i)
{
unsigned int j;
for ( ; i > 0; i--)
{
for (j = 0; j < 125; j++)
{
;
}
}
return;
}
void T1_int(void) interrupt 3 // T0中斷時interrupt為0, T1中斷時interrupt為3
{
while (1) // 一般中斷函數(shù)不會設(shè)置為死循環(huán)
{
// 單次的計數(shù)中斷所以不需要重新賦初值
P1 = 0xff; // 8位LED全滅
Delay(500); // 延時500ms
P1 = 0; // 8位LED全亮
Delay(500); // 延時500ms
}
return;
}
習(xí)題
習(xí)題7-1
采用T0方式1的定時中斷方式, 控制AT89C51的P1.1引腳輸出100Hz的方波.
分析
f = 100Hz, T = 10ms, 定時時間為10/2 = 5ms(單高電平或低電平的時間) < 65ms, 所以定時時間T = 5ms
假設(shè)時鐘頻率fosc = 12MHz, 工作在方式1時最大時間為65536ms
TMOD = 0x01
5ms = 5000us = (2^16 - X) * 12 / 12, 解得X = 60,536
轉(zhuǎn)換為16進(jìn)制, 則初值X = 0xEC78, TH0 = 0xEC, TL0 = 0x78
因操作為P1.1需提前定義,如下
sbit Pulse = P1^1;
// LED狀態(tài)轉(zhuǎn)換
Pulse = !Pulse;
源碼
/*
* 功能實現(xiàn): 采用T0方式1的定時中斷方式, 控制AT89C51的P1.1引腳輸出100Hz的方波.
* 編寫環(huán)境: Neovim + Keil5
* 硬件仿真: Proteus 8 Professional
* 日期: 2022-11-05
*/
#include <reg51.h>
sbit Pulse = P1^1; // 定義P1.1口為Pulse
int main(void)
{
TMOD = 0x01; // 定時器T0為方式1
TH0 = 0xEC; // 設(shè)置定時器初值
TL0 = 0x78;
/*
* 計算過程:
* f = 100Hz, T = 10ms, 定時時間為10/2 = 5ms(單高電平或低電平的時間) < 65ms, 所以定時時間T = 5ms
* 假設(shè)時鐘頻率fosc = 12MHz, 工作在方式1時最大時間為65536ms
* 5ms = 5000us = (2^16 - X) * 12 / 12, 解得X = 60,536
* 轉(zhuǎn)換為16進(jìn)制, 則初值X = 0xEC78, TH0 = 0xEC, TL0 = 0x78
* TH0 = (65536-5000)/256, TL0 = (65536-5000)%256
*/
Pluse = 0; // P1.1輸出低電平
EA = 1; // 總中斷開
ET0 = 1; // T0中斷開
TR0 = 1; // 啟動T0
while(1) // 循環(huán)等待
{
;
}
return 0;
}
void timer0() interrupt 1 // T0中斷程序
{
TH0 = 0xEC; //重新賦初值, 循環(huán)計時的時候需要重新賦初值
TL0 = 0x78;
P1 = ~P1; // P1口按位取反, LED狀態(tài)轉(zhuǎn)換
Pluse = !Pluse; // P1.1口按位取反, 高低電平轉(zhuǎn)換
return;
}
習(xí)題7-2
采用T0方式1的定時中斷方式, 控制AT89C51的P1.1引腳輸出100Hz, 占空比為20%的脈沖.
分析
高電平時間1/5 * T, T = 1/100 = 10ms; 所以高電平持續(xù)時間為2ms, 低電平持續(xù)時間為8ms.
定時器定時2ms, 設(shè)計軟件計數(shù)器在中斷一次后計4次中斷(即8ms
)后置低電平
TMOD = 0x01;
/*
* 2ms = 1us * 2000, 故n = 2000
* TH0 = (2^16 - n) / 256
*/
TH0 = (65536 - 2000) / 256;
TL0 = (65536 - 2000) % 256;
源碼
/*
* 功能實現(xiàn): 采用T0方式1的定時中斷方式, 控制AT89C51的P1.1引腳輸出100Hz, 占空比為20%的脈沖
* 編寫環(huán)境: Neovim + Keil5
* 日期: 2022-11-15
*/
#include <reg51.h>
sbit Pulse = P1^1; // 定義P1.1口為Pulse
unsigned char count = 0;
int main(void)
{
TMOD = 0x01; // 定時器T0為方式1
TH0 = (65536 - 2000) / 256; // 設(shè)置定時器初值
TL0 = (65536 - 2000) % 256;
Pluse = 0; // P1.1輸出低電平
EA = 1; // 總中斷開
ET0 = 1; // T0中斷開
TR0 = 1; // 啟動T0
while(1) // 循環(huán)等待
{
;
}
return 0;
}
void timer0() interrupt 1 // T0中斷程序
{
TH0 = (65536 - 2000) / 256; //重新賦初值
TL0 = (65536 - 2000) % 256;
count++;
if (1 == count) // 2ms過后, 高電平持續(xù)時間結(jié)束, 需將P1.1變?yōu)榈碗娖?/span>
{
Pluse = 0;
}
else if (5 == count) // (5-1) * 2ms過后, 低電平持續(xù)時間結(jié)束, 需將P1.1變?yōu)楦唠娖?/span>
{
Pluse = 1;
count = 0; // 一個脈沖周期結(jié)束, 將count清零
}
return;
}
課后題7-5
Proteus虛擬仿真. 使用T0, 采用方式2定時中斷, 在P1.0引腳上輸出周期為400us, 占空比為25%的矩形脈沖, 要求在P1.0引腳上接有虛擬示波器, 觀察P1.0引腳輸出的矩形脈沖波形.
分析
TMOD = 0000 0010
- D0 = 0
- D1 = 1 D1D0 = 10 為方式2
- D3(C/T’) = 1, Counter計數(shù)器模式, 對計數(shù)器外部輸入引薦T0(P3.4)或T1(P3.5)的外部脈沖(負(fù)跳變)計數(shù)
- D3(GATE) = 0, 定時器是否計數(shù), 由啟動控制位TR0/TR1來控制(置1時啟動)
高電平持續(xù)時間為1/4 * 400us = 100us, 低電平持續(xù)時間為300us
中斷定時為100us, 設(shè)計軟件計數(shù)器, 中斷次數(shù)為1時跳變?yōu)榈碗娖? 中斷次數(shù)為(4 - 1)時, 跳變?yōu)楦唠娖? 循環(huán)往復(fù)
12MHz時:
n = 100us / 1us = 100
TL0 = 2^8 - 100, TL1 = 2^8 - 100
方式2為8位, 且TH0用于儲存初值, 故TL0和TH0二者數(shù)值相同, 不存在將十六進(jìn)制數(shù)分位的問題文章來源:http://www.zghlxwxcb.cn/news/detail-739235.html
文章來源地址http://www.zghlxwxcb.cn/news/detail-739235.html
源碼
/*
* 功能實現(xiàn): 使用T0, 采用方式2定時中斷, 在P1.0引腳上輸出周期為400us, 占空比為25%的矩形脈沖
* 編寫環(huán)境: Neovim + Keil5
* 硬件仿真: Proteus 8 Professional
* 日期: 2022-11-15
*/
#include <reg51.h>
sbit Pluse = P1^0; // 定義P1.0口為Pulse
unsigned char count = 0;
int main(void)
{
TMOD = 0x01; // 定時器T0為方式1
TH0 = 256 - 100; // 設(shè)置定時器初值
TL0 = 256 - 100;
Pluse = 0; // P1.1輸出低電平
EA = 1; // 總中斷開
ET0 = 1; // T0中斷開
TR0 = 1; // 啟動T0
while(1) // 循環(huán)等待
{
;
}
return 0;
}
void timer0() interrupt 1 // T0中斷程序
{
TH0 = 256 - 100; // 重新賦值
TL0 = 256 - 100;
count++;
if (1 == count) // 100us過后, 高電平持續(xù)時間結(jié)束, 需將P1.1變?yōu)榈碗娖?/span>
{
Pluse = 0;
}
else if (4 == count) // (4-1) * 100us過后, 低電平持續(xù)時間結(jié)束, 需將P1.1變?yōu)楦唠娖?/span>
{
Pluse = 1;
count = 0; // 一個脈沖周期結(jié)束, 將count清零
}
return;
}
到了這里,關(guān)于51單片機筆記:定時器/計數(shù)器的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!