|
51單片機(jī)中斷系統(tǒng)程序?qū)嵗?(STC89C52RC)
51單片機(jī)有了中斷,在程序設(shè)計(jì)中就可以做到,在做某件事的過(guò)程中,停下來(lái)先去響應(yīng)中斷,做別的事情,做好別的事情再繼續(xù)原來(lái)的事情。中斷優(yōu)先級(jí)是可以給要做的事情排序。
單片機(jī)的學(xué)習(xí)不難,只要掌握學(xué)習(xí)方法,學(xué)起來(lái)并不難。什么是好的學(xué)習(xí)方法呢,一定要掌握二個(gè)要點(diǎn):
1. 要知道寄存器的英文全拼,比如IE = interrupt中斷
不知道全拼,要去猜,去查。這樣就可以理解為什么是這個(gè)名稱,理解了以后就不用記憶了。
2. 每個(gè)知識(shí)點(diǎn)要有形像的出處
比如看到TF0,腦子里馬上要形像地定位到TCON寄存器的某位
看到ET0, 馬上要形像地定位到IE寄存器的第2位
51hei獨(dú)家揭秘: 形像是記憶的最大技巧。當(dāng)人眼看到某個(gè)圖時(shí),是把視覺(jué)信號(hào)轉(zhuǎn)化成電信號(hào),再轉(zhuǎn)化成人能理解的形像。當(dāng)我們回憶形像時(shí),就是在重新檢索原先那個(gè)視覺(jué)信號(hào),并放大。在學(xué)習(xí)過(guò)程中,不斷練習(xí)檢索、放大信號(hào),我們的學(xué)習(xí)能力就會(huì)越來(lái)越強(qiáng)。
寫(xiě)程序代碼時(shí),也要把盡量把每行代碼形像化。
51單片機(jī)內(nèi)中斷源
8051有五個(gè)中斷源,有兩個(gè)優(yōu)先級(jí)。與中斷系統(tǒng)有關(guān)的特殊功能寄存器有IE(中斷允許寄存器)、IP(中斷優(yōu)先級(jí)控制寄存器)、中斷源控制寄存器(如TCON、SCON的有關(guān)位)。51單片機(jī)的中斷系統(tǒng)結(jié)構(gòu)如下圖(注意,IF0應(yīng)為T(mén)F0):
8052有6個(gè)中斷源,它比8051多一個(gè)定時(shí)器/計(jì)數(shù)器T2中斷源。
8051五個(gè)中斷源分別是:
(1)51單片機(jī)外部中斷源
8051有兩個(gè)外部中斷源,分別是INT0和INT1,分別從P3.2和P3.3兩個(gè)引腳引入中斷請(qǐng)求信號(hào),兩個(gè)中斷源的中斷觸發(fā)允許由TCON的低4位控制,TCON的高4位控制運(yùn)行和溢出標(biāo)志。
INT0 也就是Interrupt 0。在這里應(yīng)該看一下你的51單片機(jī)開(kāi)發(fā)板的電路原理圖。離開(kāi)形像的記憶是沒(méi)有意義的。讀到上面這句,你應(yīng)該回憶起原理圖上的連接。任何記憶都轉(zhuǎn)化為形 像,這是學(xué)習(xí)的根本原理,我們通過(guò)學(xué)習(xí)單片機(jī)要學(xué)會(huì)這種學(xué)習(xí)方法,會(huì)讓你一輩子受益無(wú)窮。
TCON的結(jié)構(gòu)如下圖:
(a)定時(shí)器T0的運(yùn)行控制位TR0
TR0由軟件置位或者清0。當(dāng)門(mén)控位GATE=0時(shí),TO計(jì)數(shù)器僅由TR0控制,TR0=1啟動(dòng)計(jì)數(shù),TR0=0時(shí)停止。當(dāng)門(mén)控位GATE=1時(shí),T0計(jì)數(shù)器由INT0和TR0共同控制,當(dāng)INT0=1且TR0=1時(shí)啟動(dòng)T0計(jì)數(shù)器。
(b)定時(shí)器T0溢出標(biāo)志位TF0
當(dāng)T0溢出時(shí)TF0=1,并向CPU申請(qǐng)中斷,CPU響應(yīng)中斷后由硬件將TF0清0,也可以由軟件查詢方式將TF0清0。
c)定時(shí)器T1的運(yùn)行控制位TR1
功能同TR0。
(d)定時(shí)器T1溢出標(biāo)志為T(mén)F1
功能同TF1。
(e)外部中斷源1(INT1、P3.3)中斷請(qǐng)求標(biāo)志IE1
IE1=1時(shí)外部中斷源1正在向CPU請(qǐng)求中斷,當(dāng)CPU響應(yīng)該中斷時(shí)由硬件將IE1清0(下降沿觸發(fā)方式)。
(f)外部中斷源1觸發(fā)方式選擇位IT1
IT1=0時(shí)外部中斷源1選擇電平觸發(fā)方式,當(dāng)輸入低電平時(shí)置位IE1;IT1=1時(shí)外部中斷源1選擇下降沿觸發(fā)方式,當(dāng)中斷源由高電平變低電平時(shí)置位 IE1,向CPU請(qǐng)求中斷。
(g)外部中斷源0(INT0、P3.2)中斷請(qǐng)求標(biāo)志IE0
功能類(lèi)同IE1。
(h)外部中斷源0觸發(fā)方式選擇位IT0
功能類(lèi)同IT1。
CPU在每個(gè)機(jī)器周期采樣INT0和INT1引腳的輸入電平。
i、電平觸發(fā)方式
當(dāng)CPU采樣到低電平時(shí),置位IE0和IE1,采樣到高電平時(shí),將IE0和IE1清零。在電平觸發(fā)方式下,外部中斷源必須一直保持低電平(至少保持1個(gè)以 上的機(jī)器周期)直到CPU響應(yīng)中斷請(qǐng)求,否則中斷請(qǐng)求將丟失,同時(shí)在中斷處理程序結(jié)束之前必須,外部中斷源必須變?yōu)楦唠娖,否則將產(chǎn)生另一次中斷。
ii、下降沿觸發(fā)方式
CPU 每個(gè)機(jī)器周期采樣中斷輸入引腳,如果相續(xù)的兩次采樣,第一次是高電平,第二次是低電平,則置位相應(yīng)的IE,響應(yīng)中斷后,硬件自動(dòng)將IE清0。采樣下降沿觸 發(fā)方式,中斷源的高、低電平都必須保持12個(gè)振蕩周期(即1個(gè)機(jī)器周期)以上,這樣CPU才能有效檢測(cè)到下降沿,并引發(fā)CPU中斷。
(2)51單片機(jī)內(nèi)部中斷源
8051有3個(gè)內(nèi)部中斷源,分別是定時(shí)器T0、T1和串行口中斷。8052增加了一個(gè)T2定時(shí)器中斷。
2、51單片機(jī)中斷使能控制
中斷的允許和禁止由中斷使能控制寄存器IE控制,其字節(jié)地址為0A8H,可以位尋址,其結(jié)構(gòu)如下圖所示:
EX0:外部中斷0中斷允許位;
ET0:定時(shí)器/計(jì)數(shù)器T0中斷允許位;
EX1:外部中斷1中斷允許位;
ET1:定時(shí)器/計(jì)數(shù)器T1中斷允許位;
ES:串行口中斷允許位;
ET2:定時(shí)器/計(jì)數(shù)器T2中斷允許位;(只要8052具有)
EA:CPU中斷總允許位,EA=1時(shí)所有的中斷開(kāi)放,EA=0時(shí)禁止所有的中斷。
3、51單片機(jī)中斷優(yōu)先級(jí)
51有兩個(gè)優(yōu)先級(jí):高、低。通過(guò)IP(中斷優(yōu)先級(jí)寄存器)來(lái)設(shè)置優(yōu)先級(jí),其字節(jié)地址為0B8H,可位尋址,其結(jié)構(gòu)如下圖:
IP中各位值為0時(shí)表示低優(yōu)先級(jí)中斷,為1時(shí)表示高優(yōu)先級(jí)中斷。CPU復(fù)位后IP=0。
高優(yōu)先級(jí)中斷可以中斷低優(yōu)先級(jí)中斷,同優(yōu)先級(jí)中斷不能相互中斷。當(dāng)CPU同時(shí)接到同優(yōu)先級(jí)的幾個(gè)中斷請(qǐng)求時(shí),CPU按照如下硬件順序進(jìn)行中斷響應(yīng):
4、51單片機(jī)中斷請(qǐng)求的撤除
CPU響應(yīng)中斷請(qǐng)求,執(zhí)行中斷服務(wù)程序,但在中斷返回指令(RETI)之前必須撤除中斷信號(hào),否則將可能再次引起中斷而發(fā)生錯(cuò)誤。
中斷請(qǐng)求撤銷(xiāo)的方法有三種:
a、單片機(jī)內(nèi)部硬件自動(dòng)復(fù)位:對(duì)于定時(shí)器/計(jì)數(shù)器T0、T1及采用邊沿觸發(fā)方式的外部中斷請(qǐng)求,CPU在響應(yīng)中斷后,由內(nèi)部硬件自動(dòng)撤銷(xiāo)中斷請(qǐng)求;
b、應(yīng)用軟件清除響應(yīng)標(biāo)志:對(duì)串口發(fā)送/接收中斷請(qǐng)求及定時(shí)器T2的溢出和捕獲中斷請(qǐng)求,CPU響應(yīng)中斷后,內(nèi)部無(wú)硬件自動(dòng)復(fù)位RI、TI、TF2及EXF2,必須在中斷服務(wù)程序中清除這些標(biāo)志,才能撤除中斷;
c、既無(wú)軟件清除也無(wú)硬件撤除:對(duì)于采用電平方式的外部中斷請(qǐng)求,CPU對(duì)引腳上的中斷請(qǐng)求信號(hào)既無(wú)控制能力,也無(wú)應(yīng)答信號(hào),為保障CPU響應(yīng)中斷請(qǐng)求中斷后,執(zhí)行返回指令前撤除中斷請(qǐng)求,必須考慮另外的措施。
5、51單片機(jī)中斷響應(yīng)過(guò)程
51 單片機(jī)在每個(gè)機(jī)器周期的S5P2狀態(tài)順序檢查每個(gè)中斷源的中斷請(qǐng)求標(biāo)志,若有中斷源發(fā)送中斷請(qǐng)求,CPU在下個(gè)機(jī)器周期的S5P2狀態(tài)按優(yōu)先級(jí)順序查詢各 中斷標(biāo)志,并且取高優(yōu)先級(jí)的中斷進(jìn)行響應(yīng)。響應(yīng)中斷后置位相應(yīng)的中斷優(yōu)先級(jí)狀態(tài)觸發(fā)器,標(biāo)明當(dāng)前中斷服務(wù)的優(yōu)先級(jí)別,執(zhí)行硬件調(diào)用程序,將程序計(jì)數(shù)器PC 的內(nèi)容壓入堆棧進(jìn)行保護(hù)。對(duì)于中斷源的中斷入口地址裝入程序計(jì)數(shù)器PC,使程序轉(zhuǎn)入該中斷入口處執(zhí)行中斷服務(wù)程序,直到遇到RETI指令。執(zhí)行RETI指 令,撤銷(xiāo)中斷優(yōu)先級(jí)觸發(fā)器,彈出斷點(diǎn)地址至程序計(jì)數(shù)器PC,繼續(xù)源程序的執(zhí)行過(guò)程。
在接收中斷申請(qǐng)時(shí),如遇到下列情況之一,硬件調(diào)用子程序?qū)⒈环怄i:
a、正在執(zhí)行同級(jí)或高一級(jí)的中斷服務(wù)程序;
b、當(dāng)前指令周期不是該指令的最后一個(gè)周期(或一條指令未執(zhí)行完);
c、當(dāng)前正在執(zhí)行的指令是RETI或?qū)E、IP的讀寫(xiě)操作。
6、中斷入口地址
各中斷源的中斷入口地址為:
STC86C52RC 51單片機(jī)中斷示例程序
#include <reg52.h>
typedef unsigned char uint8;
typedef unsigned int uint16;
typedef unsigned long uint32;
sbit enableG1 = P1^3; sbit enableG2 = P1^4;
sbit selectC = P1^2; sbit selectB = P1^1; sbit selectA = P1^0;
code uint16 num16[16] = { 0xC0, 0xF9, 0xA4, 0xB0,
0x99, 0x92, 0x82, 0xF8,
0x80, 0x90, 0x88, 0x83,
0xC6, 0xA1, 0x86, 0x8E };//共陽(yáng)數(shù)碼管真極表
uint8 num6[6] = {0};//儲(chǔ)存秒,0-5對(duì)應(yīng)于個(gè)位...10萬(wàn)位上各位上的值
void enable138(void); //啟用138譯碼器切換IO口
void refresh_led(void);
void thtl_init(void);
void timer1_init(void);
void et1_init(void);
void main(void)
{
enable138();
timer1_init();
et1_init();
while(1);
}
void interrupt_timer1(void) interrupt 3
{
static uint16 counter = 0;
static uint32 sec = 0;
counter++;
thtl_init();
if(counter == 1000)
{
counter = 0;
sec++;
num6[0] = sec % 10;
num6[1] = sec/10%10;
num6[2] = sec/100%10;
num6[3] = sec/1000%10;
num6[4] = sec/10000%10;
num6[5] = sec/100000%10;
}
refresh_led();//更新num6數(shù)組后再刷新數(shù)碼管
}
void enable138(void) { enableG1 = 1; enableG2 = 0; }
//刷新數(shù)碼管,只顯示有效值
void refresh_led(void)
{
static uint8 i = 0;
switch(i)
{
case 0: selectC = 0; selectB = 0; selectA = 0; P0 = num16[ num6[0] ]; break;
case 1: selectC = 0; selectB = 0; selectA = 1; P0 = num6[5] == 0 && num6[4] == 0 && num6[3] == 0 && num6[2] == 0 && num6[1] == 0 ? 0xFF : num16[ num6[1] ]; break;
case 2: selectC = 0; selectB = 1; selectA = 0; P0 = num6[5] == 0 && num6[4] == 0 && num6[3] == 0 && num6[2] == 0 ? 0xFF : num16[ num6[2] ]; break;
case 3: selectC = 0; selectB = 1; selectA = 1; P0 = num6[5] == 0 && num6[4] == 0 && num6[3] == 0 ? 0xFF : num16[ num6[3] ]; break;
case 4: selectC = 1; selectB = 0; selectA = 0; P0 = num6[5] == 0 && num6[4] == 0 ? 0xFF : num16[ num6[4] ]; break;
case 5: selectC = 1; selectB = 0; selectA = 1; P0 = num6[5] == 0 ? 0xFF : num16[ num6[5] ]; break;
default: break;
}
i = ++i % 6;
}
//設(shè)置計(jì)數(shù)器初數(shù)值,重用的內(nèi)容都應(yīng)該寫(xiě)成獨(dú)立函數(shù)出來(lái)方便維護(hù)
void thtl_init(void)
{
TH1 = (65536 - 922) / 256;
TL1 = (65536 - 922) % 256;
}
void timer1_init(void)
{
TMOD |= 0X10;
TMOD &= 0xDF;
thtl_init();
TR1 = 1;
}
void et1_init(void) { ET1 = 1; EA = 1; }
|
|