久久ER99热精品一区二区-久久精品99国产精品日本-久久精品免费一区二区三区-久久综合九色综合欧美狠狠

新聞中心

EEPW首頁 > 嵌入式系統 > 設計應用 > 關于單片機的計時器與中斷系統

關于單片機的計時器與中斷系統

作者: 時間:2016-11-23 來源:網絡 收藏
關于嵌入式,我就自己的XXX長話短說一下,說來話就長了,學過Java、JavaWebandsoon,也做過一些東西,說實話成就感還是蠻大的,但是,學過之后卻總是感覺這些東西都太淺顯了,用另一總話說來,就是感覺學這些東西,站在巨人的肩膀上,卻看不到巨人。什么東西都是封裝好的,知道怎么用就行了,說實話,確實,學這些東西壓力很小,但是總感覺不是真本事。所以生產實習的時候自己報的是Java,但是老是跑到嵌入式的去聽課,之前也沒聽過嵌入式的課,所以是云里霧里。Java的課也沒聽過幾節,最后做東西的時候根本不知道老師叫做個什么東西。對于Java的圖形化編程我還是比較討厭的,沒什么技術含量還麻煩的要死,到最后XXX說讓我幫幫忙,說實話我是真的不會。生產實習的結果就是最后兩頭都沒撈著好(嵌入式寫了一些驅動,但是他們說跟他們用的接口不一樣,最后發現老師給的有范例,直接按照上面改就行了,搞的我跟傻X一樣,Java直接寫都不想寫,真不知道那段能兩個星期不洗澡的日子是怎么熬過來的)。我自己感覺最后的大體方向就是:底層開發,包括操作系統什么的這一系列開發,當然,扎實的硬件、匯編、語言、算法等基礎是少不了的。為什么寫這些東西呢?因為在家大冬天的這么冷,手都不想伸出來寫代碼,只能學學理論,實際實踐缺少了很多,所以寫下加深印象,也為以后查資料方便(課程設計的時候我的博客真是一大寶庫啊!!!:-),下面是以我的51單片機為例說明的)。
下面進入正題:

1、計時器

下面先看一個圖:


其中可以清楚的看到,TH0和TL0是兩個8位寄存器,這兩個寄存器組合成T0加1計數器,所以計數器為16位計數器。同理,TL1和TH1組合成了T1加1計數器。
再看TMOD寄存器,它是一個8位寄存器,名字叫做工作方式寄存器,顯然它是控制工作方式的,看電路圖上看它有兩條灰色的線條延伸到T0和T1,即它可控制T0和T1的工作方式,也可以清楚的看到,其低四位控制T0的工作方式,高4位控制T1的工作方式。
那么什么叫做工作方式呢?工作方式就是指開或者關,芯片是工作在定時模式還是計數模式,和寄存器的使用情況。總體如下:
GATE是門控位,GATE=0時,TCON中TR0/TR1=1時可啟動。
GATE=1時,TCON中TR0/TR1=1,且外部中斷引腳為高電平時可啟動。

C/T=0:定時模式。C/T=1:計數模式。

M1M0組合使用,其值如下:

0013位定時/計數器
0116位定時/計數器
108位自動重裝定時/計數器
11T0分成兩個定時/計數器,T1停止
關于這四種方式的使用下面再介紹。

再看TCON寄存器,它與TMOD一樣,叫做控制寄存器,它是用于控制外部中斷啟動、申請的一系列工作的。定時器/計數器的工作要依賴于溢出中斷,在中斷處理中處理相關事件T0或者T1寄存器溢出時會申請中斷,然后再處理。比如所以如果想要使用T0計數100,那么就用16位寄存器的溢出值減去初始值,既是計數值,那么就是65536-100=65436(65536-65436=100),所以T0要首先置初始值65436。這里先介紹TCON的高4位。

TF1:T1溢出中斷請求標志位,T1溢出時TF1為1,相應中斷后自動清0,也可使用軟件控制。

TR1:T1運行控制位,TR1為1時,T1工作,TR1為0時,T1停止工作。

TF0:T0溢出中斷請求標志位。同理TF1。

TR0:T0運行控制位,同理TR1。

M1M0控制的四種工作方式如下:
0013位計數,使用了TL0的低5位和TH0的8位組成,TH0溢出置TF0中斷。
0116位計數,使用T0。同00。
10自動重裝初值的8位計數方式。
11T1停止,TH0和TL0分開計數。

計時器使用步驟:
·對TMOD賦值,確定T1、T0的工作方式。
·計算初值,并將其寫入T0或者T1。
·對IE(IE后面再介紹)賦值,開放中斷。
·使TR0或者TR1置位,啟動計數。

二、中斷

中斷估計都知道是干啥的,這些就不啰嗦了,這里先上一幅圖:


看這圖估計都沒心情,下面剖開來看:


其他的先不看,先看這點圖,這是一個中斷源,其中IT0是選擇中斷的方式,IT0=1時為選擇下降沿有效,IT0=0時為低電平有效(有一個非門)。當中斷觸發時就將IE0置1,此時,向CPU申請中斷。那么,IT0和IE0是在什么地方呢?
還記得上面講的TCON嗎?現在把低四位也加進去:
TF1TR1TF0TR0IE1IT1IE0IT0
2、




參照1:INT0。
3、


TF0中斷,上面已經介紹。
4、


TF1中斷,上面已經介紹。
5、(RI或TI中斷)


串行口中斷請求標志,當串行口接收完一幀串行數據時,置位RI或當串行口發送完一幀串行數據時置位TI,向CPU申請中斷。

TCON中斷

其中,TCON中的中斷標志有如下幾個:
TF1TR1TF0TR0IE1IT1IE0IT0
IT0:外部中斷0觸發方式門控位。
·IT0=0為下降沿有效
·IT0=1為負邊沿觸發
IE0:外部中斷0中斷請求標志位。
IT1:外部中斷1觸發方式控制位(同IT0)。
IE1:外部中斷1中斷請求標志位。
TF0:T0溢出中斷。
TF1:T1溢出中斷。

SCON中斷

SCON中的中斷如下:
TIRI
RI:串行口接收中斷標志位。當允許串行口接收數據時,每接收完一個串行幀,由硬件置位RI,同樣,RI必須由軟件清除。
TI:串行口發送中斷標志位。當CPU將一個發送數據寫入串行口發送緩沖器時,就啟動了發送過程,每發送完一個串行幀,由硬件置位TI,CPU響應中斷時,不能自動清除TI,TI必須由軟件清除。

下面再看上圖的下一部分:


這部分叫做中斷允許控制,當一個中斷發生時,必須由中斷允許控制來檢測是否允許,如果允許則轉入中斷處理,否則不處理。
先看右邊的EA,這個是總的中斷允許控制位,CPU想要處理中斷,必須開此中斷允許。
再看左邊:
其中各個中斷允許控制如下:
·EX0:外部中斷0允許位
·ET0:T0中斷允許位
·EX1:外部中斷1允許位
·ET1:T1中斷允許位
·ES:串行口中斷允許位
其中,這幾個位都是由中斷允許寄存器IE控制的,IE寄存器具體如下:
EAESET1EX1ET0EX0

很明了,中斷響應條件如下:
1、有中斷請求
2、中斷源中斷允許位為1
3、CPU開中斷(EA=1)

其中,8051有兩個中斷優先級,可以實現二級中斷嵌套。每個中斷源的中斷優先級都是由中斷優先級寄存器IP中的相應位的狀態來規定的。
IP寄存器如下:


PT2PSPT1PX1PT0PX0
PX0:外部中斷0優先級設定位,當將其設置為1時中斷優先級較高。
可以按照上圖以此類推。
(這里,PT2是80C52的中斷,不介紹)
優先級高的中斷可以打斷優先級低的中斷而先執行,實現中斷嵌套。那么同一優先級之間不能打斷,如果多個同優先級中斷同時申請,則按照自然優先級順序執行中斷,自然優先級如下:
中斷源中斷標志中斷服務程序入口優先級順序
外部中斷0IE00003H
T0TF0000BH
外部中斷1IE10013H
T1TF1001BH
串行口中斷RI或者TI0023H

中斷使用方法如下所示:
函數名interruptxusingy
例如:voidfun()interrupt0using1
那么,這里的x代表的是何種中斷具體如下:
0:代表外部中斷0
1:定時/計數器0
2:外部中斷1
3:定時/計數器1
4:串行口中斷
這里y代表寄存器組,可取0~7,也可以不寫。
例如,外部中斷0可以寫:
interrupt0using1
外部中斷1可寫
interrupt2using1


下面看一個使用定時器和中斷的數字時鐘的例子:

#include

#defineucharunsignedchar

ucharsecond=1; //秒,全局變量
ucharcount=0; //中斷次數
ucharcodetab[10]={0xbf,0x86,0xdb,0xcf,0xe6,0xed,0xfd,0x87,0xff,0xe7};

voidDelay(inta){ //延遲
inti;
while(a--){
for(i=0;i<148;i++);
}
}

//次函數表明使用的是定時器,定時為50ms
voidTime0_Init()
{
TMOD=0x01;
//TMOD為00000001 表明定時器處于定時模式,
//且為16位定時器,GATE=0,配合下面TR0=1,則啟動寄存器
TH0=0x4c;
//設定初值,即設定定時時間
TL0=0x00;
//設定初值,即設定定時時間
IE =0x82;
//0x82二進制為10000010,即RA=1,ET0=1,
//設定允許響應總中斷和T0中斷
TR0=1;
//設置TCON中TR0=1,允許T0工作
}

voidTime0_Int()interrupt1 //中斷處理
{
TH0=0x4c;
//重新設定初值
TL0=0x00;
count++;
if(count==20){
count=0;
second++;
//時間秒數加1
}
}

ucharkeyscan(){//4×4鍵盤掃描檢測
ucharhang[4]={0xfe,0xfd,0xfb,0xf7};
uchartemp;
inti,j;
for(i=0;i<4;i++){
P1=hang[i];
temp=0x10;
for(j=0;j<4;j++){
if(!(temp&P1)){
returni*4+j;
}
temp<<=1;
}
}
return0;
}

ucharshow_hour(ucharh){ //顯示小時
ucharx=h/24;
uchary=h$;
P2=0;
P0=tab[y/10]-0x80;
Delay(1);
P2=1;
P0=tab[y];
returnx;
}

ucharshow_minute(ucharm){ //顯示分鐘
ucharx=m/60;
uchary=m`;
P2=3;
P0=tab[y/10]-0x80;
Delay(1);
P2=4;
P0=tab[y];
returnx;
}

ucharshow_second(uchars){ //顯示秒
ucharx=s/60;
uchary=s`;
P2=6;
P0=tab[y/10]-0x80;
Delay(1);
P2=7;
P0=tab[y];
returnx;
}

voidmain()
{
ucharhour=1,minute=1;
ucharh,m,s;
uchark,mk=0;
Time0_Init();
while(1){
Delay(1);
if(mk==0){
s=show_second(second);
second%=60;
mk++;
}
elseif(mk==1){
minute+=s;
m=show_minute(minute);
minute%=60;
mk++;
}else{
hour+=m;
h=show_hour(hour);
hour%=24;
mk++;
mk=mk%3;
}
k=keyscan();//檢測按鍵
if(12==k||13==k||14==k){
Delay(50);
k=keyscan(); //軟件消抖
if(12==k||13==k||14==k){
if(12==k)hour++;
elseif(13==k)minute++;
elseif(14==k)second++;
}
}
}
}



評論


技術專區

關閉