51單片機的中斷和定時器、計數器

中斷使得高低速設備能夠協調工做(低速設備完成工做後經過中斷的方式通知高速設備一次處理一批數據),中斷還能夠根據不一樣的優先級實現嵌套執行。web

定時器本質上是個 16 位的自增計數器,當發生溢出時,若是開啓了溢出中斷,單片機會自動向 CPU 報告這個溢出中斷,處理相應的中斷任務。svg

寄存器

TCON 定時器控制寄存器

TCON 的低 4 位用做外部中斷,高 4 位用做定時控制。地址是 88H。spa

TCON 定時器控制寄存器各個位的意義以下:code

所在位 bit 7 6 5 4 3 2 1 0
名稱 TF1 TR1 TF0 TR0 IE1 IT1 IE0 IT0
  • IT0:外部中斷0觸發方式。1爲低電平觸發,0爲降低沿觸發。
  • IE0:外部中斷0請求標誌位。IE0=1 時表示有中斷請求,0則沒有。
  • IT1:外部中斷1觸發方式。1爲低電平,0爲降低沿信號。
  • IE1:外部中斷1請求標誌位。IE0=1 時表示有中斷請求,0則沒有。
  • TR0:定時器/計數器0啓動中止控制位。1爲啓動,0爲中止。
  • TF0:定時器/計數器0溢出標誌位。1表示發生溢出,若是開啓了中斷,則會觸發中斷。
  • TR1:定時器/計數器1啓動中止控制位。1爲啓動,0爲中止。
  • TF1:定時器/計數器1溢出標誌位。1表示發生溢出,若是開啓了中斷,則會觸發中斷。

IE 中斷容許控制寄存器

CPU 對中斷源的開啓或屏蔽的控制,是經過 IE 寄存器來設置的,IE 既可按字節地址尋址(其字節地址爲 A8H),又可按位尋址。某個中斷對應的位設爲 1 則表示容許中斷,不然禁止。xml

IE 寄存器各個位的意義

IE 中斷容許控制寄存器各個位的意義以下:blog

所在位 bit 7 6 5 4 3 2 1 0
名稱 EA - ET2 ES ET1 EX1 ET0 EX0
  • EX0:外部中斷 0 中斷容許位
  • ET0:定時器/計數器 0 中斷容許位
  • EX1:外部中斷 1 中斷容許位
  • ET1:定時器/計數器 1 中斷容許位
  • ES:串口中斷容許位
  • ET2:定時器/計數器 2 中斷容許位(進行52系列)
  • EA:中斷總開關

定時器工做在中斷方式時,當定時器的值計滿溢出時,會觸發定時器溢出中斷。token

C 語言示例

只要想使用中斷,就必須開啓 EA 總中斷。例如,若是想使用定時器/計數器0,須要添加下面一段 Keil C51 代碼來開啓 EA 和 ET0:事件

EA = 1; // 開啓總中斷
ET0 = 1; // 開啓定時器/計數器0 中斷

或者使用字節操做:圖片

IE |= 0x82; // 設置 IE 寄存器爲 10000010,即開啓總中斷和定時器/計數器0中斷

彙編語言示例

若是使用匯編語言,開啓外部中斷 0 的彙編代碼,字節操做爲:string

MOV IE,#81H
;MOV 0A8H,#81H; 這裏也能夠直接使用 IE 寄存器的地址 A8H

或者使用匯編語言的位操做:

SETB EA
SETB EX0

TMOD 定時器工做模式寄存器

TMOD 用於控制定時器的工做模式,低4位用於 T0,高4位用於 T1。各個位的意義以下:

所在位 bit 7 6 5 4 3 2 1 0
名稱 GATE C/T M1 M0 GATE C/T M1 M0
  • M0 與 M1:共 4 中組合,對應定時器的 4 中工做模式
    • M1 = 0,M0 = 0:模式0,13 位,最大計數範圍 8192。TL 的低 5 位和 TH 的高 8 位組成 13 位計數器,用於兼容 48 系列通常不用。
    • M1 = 0,M0 = 1:模式1,16 位,最大計數範圍 65536
    • M1 = 1,M0 = 0:模式2,8 位,最大計數範圍 256。高 8 位放預置數,只有低 8 位參與計數。計數溢出後能夠自動從新裝填預置數,定時精度高。能夠用於波特率發生器等精確計時場合。
    • M1 = 1,M0 = 1:模式3,8 位,最大計數範圍 256。此時 T0 被拆成 2 個獨立的定時/計數器。其中 TL0 能夠用做 8 位的定時/計數器,TH0 只能用於定時器。TH0 的控制及溢出標誌借用 T1 的。通常僅當 T1 工做在模式 2 時,纔會讓 T0 工做在模式 3。
  • C/T:設置爲 0 則做爲定時器使用,設置爲 1 則成爲計數器
  • GATE:計數脈衝與定時/計數器之間的開關。
    • GATE = 0 時,開關僅由 TR0 控制,TR0 = 1 時計數脈衝能夠經過,不然沒法經過
    • GATE = 1 時,開關由 TR0 和 INT0 同時控制,僅在 TR0 = 1 且 INT0 高電平時,計數脈衝才能夠經過

IP 中斷優先級控制寄存器

所在位 bit 7 6 5 4 3 2 1 0
名稱 - - PT2 PS PT1 PX1 PT0 PX0

SCON 串行口控制寄存器

所在位 bit 7 6 5 4 3 2 1 0
名稱 SM0 SM1 SM2 REN TB8 RB8 TI RI
  • SM0 和 SM1:串行口方式選擇
SM0 SM1 方式 說明 波特率
0 0 0 8位數據發送 fosc/12
0 1 1 10位數據發送,包括起始位,中止位 可變
1 0 2 11位數據發送,包括起始位,中止位 ,校驗位 fosc/64
1 1 3 同方式2
  • SM2:多機通訊使能位。在方式2或方式3中,若SM2=1,則只有當接收到的第9位數據(RB8)爲1時,才能將接收到的數據送入SBUF,並使接收中斷標誌RI置位向CPU申請中斷,不然數據丟失;若SM2=0,則不論接收到的第9位數據爲1仍是爲0,都將會把前8位數據裝入SBUF中,並使接收中斷標誌RI置位向CPU申請中斷。在方式1,如SM2=1,則只有收到有效的中止位時纔會使RI置位。在方式0時,SM2必須爲0。
  • REN:串口數據接收容許位,1容許,0禁止
  • TB8:在方式2和方式3中,這位發送的是第9位。在多機通訊中,常以該位的狀態來表示主機發送的是地址仍是數據。一般規定:TB8爲「0」表示主機發送的是數據,爲「1」表示發送的是地址。
  • RB8:在方式2和方式3中,這位發送的是第9位。它和SM二、TB8一塊兒用於通訊控制。
  • TI:發送中斷標誌位 ,用完時要用軟件清0
  • RI:接受中斷標誌位,用完時要用軟件清0

中斷

中斷源

51單片機有5箇中斷源,5箇中斷源分別是:

  • 外部中斷0,從 P3.2 端口複用
  • 外部中斷1,從 P3.3 端口複用
  • 定時/計數器0溢出中斷
  • 定時/計數器1溢出中斷
  • 串口發送或接收中斷

中斷能夠根據優先級實現嵌套,51 系列能夠實現 2 級嵌套(對應優先級寄存器 IP),52 系列能夠實現 4 級嵌套(對應優先級寄存器 IP 和 IPH)。

中斷對應信息

中斷名稱 中斷標誌位 中斷號 默認優先級 中斷入口地址
外部中斷0 IE0 0 0003H
定時/計數器0溢出中斷 TF0 2 000BH
外部中斷1 IE1 1 0013H
定時/計數器1溢出中斷 TF1 3 001BH
串口發送或接收中斷 RI/TI 4 0023H

中斷處理流程

  1. 中止主程序運行
  2. 保護斷點,把程序計數器 PC 的值壓入堆棧
  3. 尋找中斷入口,每一箇中斷都有不一樣的程序入口
  4. 執行中斷處理程序
  5. 中斷返回,繼續執行主程序

中斷的使用

任何中斷的使用都要知足 3 個條件:

  • 開啓總開關:EA EX = 1
  • 開啓指定中斷的開關,例如要使用外部中斷0,則必須設置:EX0=1
  • 發生中斷事件

中斷系統有一個總的開關 EA(IE 寄存器中),若是想使用中斷,必須打開總開關。

每一箇中斷都有一個單獨的開關,這些單獨的開關跟總開關 EA 同樣,都在 IE 寄存器中。

定時器中斷使用

初始值的計算

假設我要每計數 24 次觸發一次溢出中斷,定時器工做在模式 1,則計數初始值爲 65536 - 24 = 65512。

Keil C51 代碼

外部中斷示例代碼

下面代碼使用了外部中斷0,上電後 P1 端口 0 號引腳的 LED 會一直閃爍,首次觸發外部中斷時,P1 端口全部 LED 點亮,再次觸發外部中斷時,0號引腳的 LED 再次開始閃爍,以此循環:

#include <reg52.h>

int flag = 1;
void delay() {
	unsigned int a = 50000;
	while(a--);
}

void main() {
	EA = 1;// 開啓中斷總開關
	IT0 = 1;// 設置外部中斷0觸發方式,降低沿觸發
	EX0 = 1;// 開啓外部中斷0
	while(1) {
		while(flag & 0x01 == 1) {
			P1 = 0xfe;
			delay();
			P1 = 0xff;
			delay();
		}
		P1 = 0x00;
	}
}

void externelInterrupt() interrupt 0 {
	flag++;
}

電路圖:
在這裏插入圖片描述

串口示例代碼

/*9600@11.0592M*/
#include <reg52.h>
void InitUART(void) {
	TMOD = 0x20;
	SCON = 0x50;
	TH1 = 0xFD;
	TL1 = TH1;
	PCON = 0x00;
	EA = 1;
	ES = 1;
	TR1 = 1;
}
void SendOneByte(unsigned char c) {
	SBUF = c;
	while(!TI);
	TI = 0;
}
void main(void) {
	InitUART();
}
void UARTInterrupt(void) interrupt 4 {
	if(RI) {
		RI = 0;
	} else
		TI = 0;
}
相關文章
相關標籤/搜索