要學習51單片機中斷的朋友,擁有這一篇博文就夠了,深入淺出,里面包含了暫存器,外部中斷、定時器中斷、中斷嵌套等的講解,還有代碼實戰,快一萬字,寫得不容易,還請大家點贊支持一下,后續持續更新
- (一)暫存器
- 1.什么是暫存器
- 2.暫存器怎么用
- (二)中斷
- 1.中斷允許暫存器IE
- EX0
- ET0
- EX1
- ET1
- ES
- EA
- 使用方法
- 2.中斷優先級暫存器IP
- PS——串行口中斷優先級控制位
- PT1——定時器/計數器1中斷優先級控制位
- PX1——外部中斷1中斷優先級控制位
- PT0——定時器/計數器0中斷優先級控制位
- PX0——外部中斷0中斷優先級控制位
- 中斷優先級(高到低)
- 3.TCON暫存器
- TF1:片內定時器/計數器T1的溢位中斷請求標志位,
- TF0:片內定時器/計數器T0的溢位中斷請求標志位,
- IE1:外部中斷請求1的中斷請求標志位,
- IE0: 外部中斷請求0的中斷請求標志位,
- IT1:選擇外部中斷請求1為負跳變觸發方式還是電平觸發方式,
- IT0:選擇外部中斷請求0為負跳變觸發還是電平觸發方式,
- 4.SCON暫存器
- TI:串行口發送中斷請求標志位,
- RI:串行口接收中斷請求標志位,
- (三)外部中斷
- 1.外部中斷0,按下開關K3,數碼管0變1
- 暫存器配置:
- 完整代碼:
- 2.外部中斷1,按下開關K4,數碼管0變1
- 暫存器配置:
- 完整代碼:
- 3.外部中斷擴展
- 暫存器配置:
- 完整代碼:
- (四)定時器中斷
- 1.定時器0
- 暫存器配置:
- 完整代碼:
- 2.定時器1
- 暫存器配置:
- 完整代碼:
- 3.定時器計數控制數碼管0到60
- 暫存器配置:
- 完整代碼:
- 4.定時器做的時鐘
- 暫存器配置:
- 完整代碼:
- (五)中斷嵌套
- 1.外部中斷嵌套K3,K4
- 暫存器配置:
- 完整代碼:
(一)暫存器
要想學習中斷那么首先就要了解暫存器,在這里我們學習一下什么是暫存器,暫存器怎么用,
1.什么是暫存器
暫存器是特殊的RAM,特殊功能暫存器是控制單片機硬體的開關(例如IE)或者是指示單片機狀態的信號(例如PSW),通過特殊暫存器你就可以方便的控制整個MCU,并且知道當前的MCU的作業狀態,
2.暫存器怎么用
AT89S51單片機中的特殊功能暫存器(SFR)的單元地址映射在片內RAM區的80H~FFH區域中,它共有26個,離散地分布在該區域中,用到哪個暫存器就相應配置哪個暫存器即可,暫存器太多就不一一寫出來了,用到再去找就好,
(二)中斷
單片機的中斷是由單片機片內的中斷系統來實作的,當中斷請求源(簡稱中斷源)發出中斷請求時,如果中斷請求被允許的話,單片機暫時中止當前正在執行的主程式,轉到中斷服務程式處理中斷服務請求,處理完中斷服務請求后,再回到原來被中止的程式之處(斷點),繼續執行被中斷的主程式,
1.中斷允許暫存器IE

EX0
外部中斷0允許位,EX0=1,允許外部中斷0中斷;EX0=0,禁止外部中斷0中斷,當EX0=1( SETB EX0 )時,同時單片機P3.2引腳上出現中斷信號時,單片機中斷主程式的執行而“飛”往中斷服務子程式,執行完后通過中斷回傳指令RET 動回傳主程式,當EX0=0( CLR EX0)時,即使單片機P3.2引腳上出現中斷信程式也不會從主程式“飛” 出去執行,因為此時單片機的CPU相當于被“堵上了耳朵”,根本接收不到P3.2引腳上的中斷信號,但是這并不表示這個信號不存在,如果單片機的CPU有空查一下TCON中的IE0位,若為1就說明有中斷信號出現過,
ET0
T0溢位中斷允許位,ET0=1,允許T0中斷;ET0=0,禁止T0中斷,
EX1
外部中斷1允許位,EX1=1,允許外部中斷1中斷;EX1=0,禁止外部中斷1中斷,當EX1=1( SETB EX1)時,并且外部P3.3引腳上出現中斷信號時,單片機CPU會中斷主程式而去執行相應的中斷服務子程式;當EX1=0( CLR EX1)時使外部P3.3引腳上即使出現中斷信號,單片機的CPU也不能中斷主程式轉而去行中斷服務子程式,
因此,可以這樣認為,EX0和EX1是決定CPU能否感覺到外部引腳P3.2P3.3上的中斷信號的控制位,
ET1
T1溢位中斷允許位,ET1=1,允許T1中斷;ET1=0,禁止T1中斷,
ES
串行中斷允許位,ES=1,允許串行口中斷;ES=0,禁止串行口中斷,
EA
中斷總允許位,EA=1,CPU開放中斷;EA=0,CPU禁止所有的中斷請求,總允許EA好比一個總開關,EA就相當于每家水管的總閘,如果總閘不開,各個龍頭即使開了也不會有水;反過來,如果總閘開了而各個分閘沒開也不會有水,所當我們想讓P3.2和P3.3引腳上的信號能夠中斷主程式則必須將EA位設定為0(CLR EA),
使用方法
(1)整體賦值:IE=0x81;(開啟全域中斷,打開外部中斷0 ),
(2)單獨賦值:EA=1;EX0=1;(開啟全域中斷,打開外部中斷0 ),
2.中斷優先級暫存器IP

PS——串行口中斷優先級控制位
PS=1,串行口中斷定義為高優先級中斷,
PS=0,串行口中斷定義為低優先級中斷,
PT1——定時器/計數器1中斷優先級控制位
PT1=1,定時器/計數器1中斷定義為高優先級中斷,
PT1=0,定時器/計數器1中斷定義為低優先級中斷,
PX1——外部中斷1中斷優先級控制位
PX1=1,外部中斷1定義為高優先級中斷,
PX1=0,外部中斷1定義為低優先級中斷,
PT0——定時器/計數器0中斷優先級控制位
PT0=1,定時器/計數器0中斷定義為高優先級中斷,
PT0=0,定時器/計數器0中斷定義為低優先級中斷,
PX0——外部中斷0中斷優先級控制位
PX0=1,外部中斷0定義為高優先級中斷,
PX0=0,外部中斷0定義為低優先級中斷,
中斷優先級(高到低)
外部中斷0
T0溢位中斷
外部中斷1
T1溢位中斷
串行口中斷
T2溢位中斷(52)
3.TCON暫存器

TF1:片內定時器/計數器T1的溢位中斷請求標志位,
當啟動T1計數后,定時器/計數器T1從初值開始加1計數,當計數溢位時,由硬體自動為TF1置“1”,向CPU申請中斷,CPU回應TF1中斷時,TF1標志位由硬體自動清零,TF1也可由軟體清零,
TF0:片內定時器/計數器T0的溢位中斷請求標志位,
功能與TF1相同,
IE1:外部中斷請求1的中斷請求標志位,
IE1=0,無中斷請求,
IE1=1,外部中斷1有中斷請求,當CPU回應該中斷,轉向中斷服務程式時,由硬體清“0”IE1,
IE0: 外部中斷請求0的中斷請求標志位,
IE0=0,無中斷請求,
IE0=1,外部中斷0有中斷請求,當CPU回應該中斷,轉向中斷服務程式時,由硬體清“0”IE0,
IT1:選擇外部中斷請求1為負跳變觸發方式還是電平觸發方式,
IT1=0,為電平觸發方式,外部中斷請求輸入信號為低電平有效,并把IE置“1”,轉向中斷服務程式時,則由硬體自動把IE1清零,
IT1=1,為負跳變觸發方式,外部中斷請求輸入信號電平為從高到低的負跳變有效,,并把IE置“1”,轉向中斷服務程式時,則由硬體自動把IE1清零,
IT0:選擇外部中斷請求0為負跳變觸發還是電平觸發方式,
與IT1相似,
4.SCON暫存器

TI:串行口發送中斷請求標志位,
當CPU將1位元組的資料寫入串行口的發送緩沖器SBUF時,就啟動一幀串行資料的發送,每發送完一幀串行資料后,硬體把TI中斷請求標志位自動置“1”,CPU回應串行口發送中斷時,并不能清除TI標志位,TI標志位必須在中斷服務程式中用指令對其清零,
RI:串行口接收中斷請求標志位,
在串行口接收完一個串行資料幀,硬體自動使RI中斷請求標志位置“1”,CPU在回應串行口接收中斷時,RI標志位并不清零,必須在中斷服務程式中用指令對RI清零,
(三)外部中斷
51單片機的外部中斷int0對應的引腳為p3.2,外部中斷int1對應的引腳為p3.3,
1.外部中斷0,按下開關K3,數碼管0變1
暫存器配置:
EA=1;//總中斷允許
EX0=1;//允許外部中斷0
IT0=0;//選擇外部中斷0為電平觸發方式
完整代碼:
#include<reg51.h>
#define uchar unsigned char
sbit key = P3^2;
void delay(unsigned int i)//延時函式
{
unsigned int j;
for(;i>0;i--)
for(j=0;j<333;j++){}
}
void main()//主函式
{
EA=1;//總中斷允許
EX0=1;//允許外部中斷0
IT0=0;//選擇外部中斷0為電平觸發方式
while(1)//回圈
{P0=0x3f;}//P0.0口的Led亮
}
void key_scan() interrupt 0 //外部中斷0的中斷服務函式
{
if(key==0)//判斷是否有按鍵按下
{
delay(10);//延時去抖
if(key==0)
{
P2=0xfe;
P0=0x06;
while(!key);//等待按鍵松開
P2=0xff;
P0=0x3f;
}
}
}
2.外部中斷1,按下開關K4,數碼管0變1
暫存器配置:
EA=1;//總中斷允許
EX1=1;//允許外部中斷0
IT1=0;//選擇外部中斷0為電平觸發方式
完整代碼:
#include<reg51.h>
#define uchar unsigned char
sbit key = P3^3;
void delay(unsigned int i)//延時函式
{
unsigned int j;
for(;i>0;i--)
for(j=0;j<333;j++){}
}
void main()//主函式
{
EA=1;//總中斷允許
EX1=1;//允許外部中斷0
IT1=0;//選擇外部中斷0為電平觸發方式
while(1)//回圈
{P0=0x3f;}//P0.0口的Led亮
}
void key_scan() interrupt 1 //外部中斷1的中斷服務函式
{
if(key==0)//判斷是否有按鍵按下
{
delay(10);//延時去抖
if(key==0)
{
P2=0xfe;
P0=0x06;
while(!key);//等待按鍵松開
P2=0xff;
P0=0x3f;
}
}
}
3.外部中斷擴展
暫存器配置:
IT0 = 1;//跳沿觸發
IT1 = 1;//跳沿觸發
PX1 = 1;//中斷1高于中斷0
IE = 0x85;/*由低到高:EX1(第3位)=1,EX0 (第0位)= 1,EA (第八位)= 1 IE = 10000101*/
完整代碼:
#include<reg52.h>
#include<intrins.h>
#define uchar unsigned char
#define uint unsigned int
uint i;
void delay(uint xms);
void Int();
void Interrupt0();
void Interrupt1();
void main()
{
Int();
P2 = 0xfe;
while(1)
{
for (i = 0;i < 7;i++)
{
P2 = _crol_(P2, 1);//先左移
delay(600);
}
for (i = 0;i < 7;i++)
{
P2 = _cror_(P2, 1);//再右移
delay(600);
}
}
}
void Int()
{
IT0 = 1;//跳沿觸發
IT1 = 1;//跳沿觸發
PX1 = 1;//中斷1高于中斷0
IE = 0x85;/*由低到高:EX1(第3位)=1,EX0 (第0位)= 1,EA (第八位)= 1 IE = 10000101*/
}
void delay(uint xms)//AT89C5211.0592MHz
{
uint x, y;
for (x = xms;x > 0;x--)
for (y = 110;y > 0;y--);
}
void Interrupt1() interrupt 0
{
while (1)
{
P2 = 0x0f;
delay(600);
P2 = 0xf0;
delay(600);
}
}
void Interrupt2() interrupt 2/*外部中斷1的標號是2!*/
{
while (1)
{
P2 = 0xcc;//(11001100)
delay(600);
P2 = 0x33;
delay(600);
}
}
(四)定時器中斷
1.定時器0
暫存器配置:
TMOD = 0x01;
TH0 = (65536 - 45872) / 256; // 設定定時器0為作業方式1(M1M0為01)
TL0 = (65536 - 45872) % 256; // 裝初值11.0592M晶振定時50ms數位45872
EA = 1; // 開總中斷
ET0 = 1; // 開定時器0中斷
TR0 = 1; // 啟動定時器0
完整代碼:
#include<reg51.h>
#include<intrins.h>
#define uchar unsigned char
#define uint unsigned int
sbit led1 = P2^0;
uchar num = 0;
void main()
{
TMOD = 0x01;
TH0 = (65536 - 45872) / 256; // 設定定時器0為作業方式1(M1M0為01)
TL0 = (65536 - 45872) % 256; // 裝初值11.0592M晶振定時50ms數位45872
EA = 1; // 開總中斷
ET0 = 1; // 開定時器0中斷
TR0 = 1; // 啟動定時器0
while(1)
{
;
}
}
void T0_time() interrupt 1
{
TH0 = (65536 - 45872) / 256;
TL0 = (65536 - 45872) % 256;
num++;
if (num == 20)
{
num = 0;
led1 = ~led1;
}
}
2.定時器1
暫存器配置:
TMOD = 0x01;
TH0 = (65536 - 45872) / 256; // 設定定時器1為作業方式1(M1M0為01)
TL0 = (65536 - 45872) % 256; // 裝初值11.0592M晶振定時50ms數位45872
EA = 1; // 開總中斷
ET1 = 1; // 開定時器1中斷
TR1 = 1; // 啟動定時器1
完整代碼:
#include<reg51.h>
#include<intrins.h>
#define uchar unsigned char
#define uint unsigned int
sbit led1 = P2^0;
uchar num = 0;
void main()
{
TMOD = 0x01;
TH0 = (65536 - 45872) / 256; // 設定定時器1為作業方式1(M1M0為01)
TL0 = (65536 - 45872) % 256; // 裝初值11.0592M晶振定時50ms數位45872
EA = 1; // 開總中斷
ET1 = 1; // 開定時器1中斷
TR1 = 1; // 啟動定時器1
while(1)
{
;
}
}
void T1_time() interrupt 3
{
TH0 = (65536 - 45872) / 256;
TL0 = (65536 - 45872) % 256;
num++;
if (num == 20)
{
num = 0;
led1 = ~led1;
}
}
3.定時器計數控制數碼管0到60
暫存器配置:
TMOD=0x11;//寫在一起
//定時器0
//TMOD=0x01;
TH0=(65536-45872)/256;
TL0=(65536-45872)%256;
EA=1;
ET0=1;
TR0=1;
//定時器1
//TMOD=0x10;
TH1=(65536-45872)/256;
TL1=(65536-45872)%256;
EA=1;
ET1=1;
TR1=1;
完整代碼:
#include <reg52.h>
#define uint unsigned int
#define uchar unsigned char
uchar code table[]={
0x3f,0x06,0x5b,0x4f,
0x66,0x6d,0x7d,0x07,
0x7f,0x6f,0x77,0x7c,
0x39,0x5e,0x79,0x71
};//共陰極數碼管編碼
uchar num0,num1;
uint ge ,shi;
sbit LSA=P2^2;//74HC138譯碼器埠
sbit LSB=P2^3;
sbit LSC=P2^4;
void display_time(uint ,uint);
void delay_ms(uint);
void main()
{
TMOD=0x11;//寫在一起
//定時器0
//TMOD=0x01;
TH0=(65536-45872)/256;
TL0=(65536-45872)%256;
EA=1;
ET0=1;
TR0=1;
//定時器1
//TMOD=0x10;
TH1=(65536-45872)/256;
TL1=(65536-45872)%256;
EA=1;
ET1=1;
TR1=1;
while(1)
{
display_time(ge ,shi);//時間一直顯示中
}
}
void T0_time()interrupt 1 //數碼管處理 T0定時器
{
TH0=(65536-45872)/256;//每50ms產生一次中斷
TL0=(65536-45872)%256;//所以每20次中斷,個位+1
num0++;
if(num0==20)
{
num0=0;
ge++;
if(ge==10)
{
shi++; //時間進位
ge=0;
}
if(shi==6)
shi=0; //時間歸零
}
}
void display_time(uint ge ,uint shi)
{
LSA=0;LSB=1;LSC=1;
P0=table[ge];//送入個位數字
delay_ms(5);
LSA=1;LSB=1;LSC=1;
P0=table[shi];//送入十位數字
delay_ms(5);
}
void delay_ms(uint ms)
{
uint i,j;
for(i=ms;i>0;i--)
for(j=110;j>0;j--);
}
4.定時器做的時鐘
暫存器配置:
TMOD=0x01;
TH0=(65536-45872)/256;
TL0=(65536-45872)%256;
EA=1;
ET0=1;
TR0=1;
完整代碼:
#include <reg52.h>
#define uint unsigned int
#define uchar unsigned char
uchar code table[]={
0x3f,0x06,0x5b,0x4f,
0x66,0x6d,0x7d,0x07,
0x7f,0x6f,0x77,0x7c,
0x39,0x5e,0x79,0x71
};//共陰極數碼管編碼
uchar num;
uint hour_ge,hour_shi,minute_ge, minute_shi,second_ge,second_shi;
sbit LSA=P2^2;//74HC138譯碼器埠
sbit LSB=P2^3;
sbit LSC=P2^4;
void display_time(uint,uint,uint,uint,uint,uint);
void delay_ms(uint);
void main()
{
TMOD=0x01;
TH0=(65536-45872)/256;
TL0=(65536-45872)%256;
EA=1;
ET0=1;
TR0=1;
while(1)
{
display_time(hour_shi,hour_ge,minute_shi,minute_ge,second_shi,second_ge);
//時間一直顯示中
}
}
void T0_time()interrupt 1 //數碼管處理 T0定時器
{
TH0=(65536-45872)/256;//每50ms產生一次中斷
TL0=(65536-45872)%256;//所以每20次中斷,個位+1
num++;
if(num==20)
{
num=0;
second_ge++;//秒+1
}
if(second_ge==10)
{
second_ge=0;
second_shi++;
if(second_shi==6)
{
second_shi=0;
minute_ge++;
if(minute_ge==10)
{
minute_ge=0;
minute_shi++;
if(minute_shi==6)
{
minute_shi=0;
hour_ge++;
if(hour_ge==10)
{
hour_ge=0;
hour_shi++;
if(hour_shi==2&&hour_ge==4)
{
hour_shi=0;
hour_ge=0;
}
}
}
}
}
}
}
void display_time(uint hour_shi,uint hour_ge,uint minute_shi,uint minute_ge,uint second_shi,uint second_ge)
{
LSA=0;LSB=0;LSC=0;//第六個數碼管送入second_ge
P0=table[second_ge];
delay_ms(1);
LSA=1;LSB=0;LSC=0;//第五個數碼管送入second_shi
P0=table[second_shi];
delay_ms(1);
LSA=1;LSB=1;LSC=0;//第四個數碼管送入minute_ge
P0=table[minute_ge];
delay_ms(1);
LSA=0;LSB=0;LSC=1;//第三個數碼管送入minute_shi
P0=table[minute_shi];
delay_ms(1);
LSA=0;LSB=1;LSC=1;//第二個數碼管送入hour_ge
P0=table[hour_ge];
delay_ms(1);
LSA=1;LSB=1;LSC=1;//第一個數碼管送入hour_shi
P0=table[hour_shi];
delay_ms(1);
}
void delay_ms(uint ms)
{
uint i,j;
for(i=ms;i>0;i--)
for(j=110;j>0;j--);
}
(五)中斷嵌套
1.外部中斷嵌套K3,K4
暫存器配置:
IT0 = 1;
IT1 = 1;
PX0 = 1;
IE = 0x85;/*由低到高:EX1(第3位)=1,EX0 (第0位)= 1,EA (第八位)= 1 IE = 10000101*/
完整代碼:
#include<reg52.h>
#define uchar unsigned char
#define uint unsigned int
sbit LED1 = P2 ^ 0;
sbit LED2 = P2 ^ 1;
void Int();
void Interrupt1();
void Interrupt2();
void main()
{
Int();
while (1);
}
void Int()
{
IT0 = 1;
IT1 = 1;
PX0 = 1;
IE = 0x85;/*由低到高:EX1(第3位)=1,EX0 (第0位)= 1,EA (第八位)= 1 IE = 10000101*/
}
void Interrupt1() interrupt 0
{
LED1 = ~LED1;
}
void Interrupt2() interrupt 2/*外部中斷1的標號是2!*/
{
LED2 = ~LED2;
}
看到最后相信你也應該識訓到很多,一起進步吧!
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/292129.html
標籤:其他
上一篇:免費開源的智能家居系統,SpringBoot+Vue前后端分離,Arduino設備接入,手把手開發安卓APP,建立QQ智能管家機器人!
下一篇:STC學習:串口通信
