單片機(jī) 中斷( 定時器/計(jì)數(shù)器詳說 )
方式0應(yīng)用
通過設(shè)置TMOD寄存器中的M1M0位00選擇定時器方式0,方式0的計(jì)數(shù)位數(shù)是13位,對T0來說,TL0寄存器的低5位(高3位未用)和TH0寄存器的8位組成。TL0的低5位溢出時向TH0進(jìn)位,TH0溢出時,置位TCON中的TF0標(biāo)志,向cpu發(fā)出中斷請求。其邏輯圖如下
定時器方式0位13位計(jì)數(shù)器,最多能裝載的個數(shù) 2的13次方=8192個,當(dāng)TL0和TH0的初始值為0時,最多經(jīng)過8192個機(jī)器周期該計(jì)數(shù)器就會溢出一次,向cpu申請中斷。
THX=(8192-N)/32 TLX=(8192-N)%32。機(jī)器周期=12 X (1/時鐘頻率)
單片機(jī)定時器程序的步驟: 對TMOD賦值、計(jì)算初值、中斷方式,對IE賦值,開放中斷、使TR0或TR1置位,啟動定時器
讓發(fā)光二極管以1s亮滅閃爍 代碼:
#include
#define uchar unsigned char
#define uint unsigned int
sbit led1=P1^0; // 假定發(fā)光二極管接P10口
uchar num;
void main()
{
TMOD=0x00; //設(shè)置定時器0的工作方式為0
TH0=(8192-4607)/32; //裝初值
TL0=(8192-4607)%32;
EA=1; //開總中斷
ET0=1; //開定時器0中斷
TR0=1; //啟動定時器0
while(1)
{
if( num==20 )
{
num=0;
led1=~led1;
}
}
}
void T0_time() interrupt 1
{
TH0=( 8192-4607 )/32;
TL0=( 8192-4607 )%32;
num++;
}
方式2應(yīng)用
在定時器的方式0和1中,當(dāng)計(jì)數(shù)溢出后,計(jì)數(shù)器變?yōu)?,因此在循環(huán)定時過程中反復(fù)的裝初值必然會影響到定時的精度。方法2可解決裝初值的問題。通過設(shè)置TMOD寄存器中的M1M0位為10選擇定時器方式2,方式2被稱為8位初值自動重裝的8位定時器/計(jì)數(shù)器,THX被稱為常數(shù)緩沖器,當(dāng)TLX溢出時,在TFX置1時的同時,還自動的將THX中的常數(shù)重新裝入TLX中,使TLX從初值開始重新計(jì)數(shù),這樣避免了人為軟件重裝初值所帶來的時間誤差,從而提高定時精度
代碼,讓發(fā)光二極管以1s亮滅閃爍
#include
#define uint unsigned int
sbit led1=P1^0; //二極管接P1^0口
uint num;
void main()
{
TMOD=0x02;
TH0=6; // TH0、TL0取6和下面的num取3686是為了得到1s的時間。也可取其他的數(shù)字
TL0=6;
EA=1;
ET0=1;
TR0=1;
while( 1 )
{
if( num==3686 )
{
num=0;
led1=~led1;
}
}
}
void T0_time() interrupt 1
{
num++;
}
方式3應(yīng)用
方式3只適用于定時器/計(jì)數(shù)器 T0,當(dāng)設(shè)定定時器T0處于方式3時,定時器T1不計(jì)數(shù)。方式3將T0分成2個獨(dú)立的8位計(jì)數(shù)器TL0和TH0,定時器3的邏輯結(jié)構(gòu)圖
分析上圖可知,定時器被分成2個獨(dú)立的計(jì)數(shù)器。其中TL0為正常的8位計(jì)數(shù)器,計(jì)數(shù)溢出后置位TF0,向cpu發(fā)出中斷申請,之后再重裝初值。TH0也被固定為一個8位計(jì)數(shù)器,它占用定時器T1的中斷請求標(biāo)志TF1和定時器啟動控制位TR1。
代碼 讓第一個二極管1s閃爍、第二個二極管0.5s閃爍
#include
#define uchar unsigned char
#define uint unsigned int
sbit led1=P1^0; //二極管接一個P1^0口另一個接P1^2口
sbit led2=P1^1;
uint num_1,num_2;
void main()
{
TMOD=0x03;
TH0=6; // TH0、TL0取6和下面的num取3686是為了得到1s的時間。也可取其他的數(shù)字
TL0=6;
EA=1;
ET0=1;
ET1=1;
TR1=1;
TR0=1;
while( 1 )
{
if( num>=3686 )
{
num_1=0;
led1=~led1;
}
if( num_2>=1843 )
{
num_2=0;
led2=~led2;
}
}
}
void TL0_time() interrupt 1
{
TL0=6;
num_1++;
}
void TH0_time() interrupt 3
{
TH0=6;
num_2++;
}