目錄
一、中斷基礎知識介紹
1、中斷基礎
2、寄存器
3、中斷口的設定
二、外部中斷的使用
1、中斷使用流程
2、中斷代碼
三、内部中斷的使用
1、相關知識介紹
2、中斷使用流程
3、相關代碼
中斷其實并不是那麼吓人哦,一定要搞清楚各寄存器、中斷口、中斷源等示意圖,後來你會發現其實就是根據你一開始的選擇不斷設定而已!
一、中斷基礎知識介紹
你知道中斷是什麼嗎?它有哪些類型呢?
1、中斷基礎
中斷系統:計算機執行某程式時,發生了緊急事件或有特殊請求,處理完畢後再重新執行程式的過程
中斷類型: 中斷分為外部中斷及内部中斷,外部中斷可以由低電平或下降沿兩種方式實作,而 内部中斷則分為計數器模式和定時器模式。
中斷流程: 中斷請求->中斷響應->中斷處理->中斷傳回
**中斷源示意圖**:
小tip:後面中斷相關代碼都要根據該圖設定,不是随意設定的,該圖的掌握對中斷而言至關重要哦!
2、寄存器
寄存器的使用與設定,是中斷不可缺少的重要環節,它可用于控制中斷開關、設定中斷方式等等。
(1)IE寄存器
(2)TCON寄存器
小知識穿插(有關資料的輸入/輸出傳送方式):
- 無條件傳送方式 : 一方對另一方總是準備好的
- 查詢傳送方式 : 傳送前一方先查詢另一方狀态,若已準備好就傳送,否則就繼續查詢/等待
- 中斷傳送方式: 一方通過申請中斷的方式與另一方進行資料傳送
3、中斷口的設定
一定要根據自己選擇的中斷方式與觸發方式(或工作模式)結合圖示選擇中斷入口,不可以自己随意設定!
二、外部中斷的使用
不管是内部中斷還是外部中斷,上述内容中的寄存器與中斷源示意圖都需要熟練掌握哦,後面的程式均要結合其進行代碼編寫!
1、中斷使用流程
- 允許中斷(IE寄存器) 打開IE中斷總開關 打開相應的中斷開關(外部中斷0或1)
- 配置中斷方式(TCON寄存器) 選擇中斷方式為低電平還是下降沿
- 編寫中斷服務函數(寫對應的中斷入口)和主函數
2、中斷代碼
下降沿觸發相關代碼
#include <reg52.h>
#define uchar unsigned char
#define uint unsigned int
sbit flag = P3^3; //對應P3^3的第二功能(外部中斷1輸入)
sbit key = P3^1; //中斷1必須要使用P3^3,中斷2必須使用P3^2
void delay(uint z)
{
uint x,y;
for(x=z;x>0;x--)
for(y=114;y>0;y--);
}
void int1init()
{
EA=1; //打開EA總開關
EX1=1; //允許外部中斷1中斷
ET1=1; //外部中斷1下降沿觸發
}
void int1() interrupt 2
{
//該單片機中斷口有問題,進了中斷不會出來,隻能加上該循環,正常情況可以不用
while(!key)
{
P2=~P2; //P2的狀态按位取反
}
}
void main()
{
int1init(); //調用初始化函數進行初始化
while(1)
{
if(key==0)
{
delay(20);
if(key==0)
{
flag=1;
flag=0;
while(!key); //松手檢測
}
}
}
}
三、内部中斷的使用
1、相關知識介紹
51單片機有兩個16位定時器/計數器: 定時器0(T0 引腳為P3^4) 定時器1(T1引腳為P3^5)
是以,定時器/計數器可以工作在如下不同模式:
**當定時器工作在定時器模式時** 每經過一個機器周期内部的16位計數寄存值加1,當這個寄存器裝滿時溢出
**當定時器工作在計數器模式** T0(P3^4) T1(P3^5) 每來一個脈沖寄存器加1
工作模式寄存器(用于調配上述寄存器工作模式)
2、中斷使用流程
1、允許中斷(IE寄存器) 打開IE中斷總開關 2、啟動定時/計數器(TCON控制器) TR0=1/TR1=1(T0/T1開始計數) 3、設定定時/計時器工作模式 調配定時/計時工作模式 調配8位/16位模 4、查詢定時/計數器是否溢出(讀TCON中TF位)
3、相關代碼
定時器模式
#include "reg52.h"
sbit LA=P2^2;
sbit LB=P2^3;
sbit LC=P2^4;
sbit key1 = P3^0; //按鍵1
sbit key2 = P3^1; //按鍵2
unsigned char smgduan[17]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,
0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71};
void delay(unsigned int z)
{
unsigned int x,y;
for(x=z;x>0;x--)
for(y=120;y>0;y--);
}
void timefrist()
{
EA = 1; //打開總開關
ET0 = 1; //中斷函數0的開關
TR0 = 1; //打開定時器0開關
TMOD = 0x01; //模式一,定時模式
TH0 = 0xED; //這裡改值了,到上限就5ms(改初值)
TL0 = 0xFF;
//開關、模式、賦初值
}
unsigned char miao=0;
void DigDisplay(unsigned char h)
{
unsigned char a=h%10; //個位
unsigned char b=h/10; //十位
static unsigned char wei=0; //靜态變量,就是函數執行完也不會抹去這個變量的值,在次使用函數值可以用(隻有初值時才會初始的,後來不改變)
switch(wei) //這裡重新布局,我們這裡不斷交換顯示,用一次函數就顯示一個,當快速多顯示就動态顯示
{
case 0: LA=1;LB=1;LC=1;P0 = smgduan[b];break; //wei值0與1不斷交換,就動态顯示
case 1: LA=0;LB=1;LC=1;P0 = smgduan[a];break;
}
wei++; //用過之後++
if(wei==2) //我們隻要1與0不斷交換,為2時就重新回0
{
wei = 0;
}
}
void timer0() interrupt 1
{
TH0 = 0xED; //重新定義5ms初始值
TL0 = 0xFF;
DigDisplay(miao); //顯示,不斷5ms顯示就是動态顯示
}
void main()
{
timefrist();
while(1)
{
if(key1==0) //為0,按鍵被按下
{
delay(20);
if(key1==0) //按鍵消抖
{
miao++; //全局miao加1,顯示就會加1了
while(!key1); //松手檢測
}
}
if(key2==0) //同理
{
delay(5);
if(key2==0)
{
miao--;
while(!key2);
}
}
}
}
小tips:定時器模式初值如何設定?
例如 5ms,5ms=5000us,5000/1.085(機器周期)=4608(次),65535-4608=60926; 将其換算為二進制為11101101 11111110,則高八位為0xED(TH0),低八位為0xFE(TL0)
計時模式
#include <reg52.h>
sbit LA=P2^2;
sbit LB=P2^3;
sbit LC=P2^4; //區段碼位選
sbit key1=P3^0; //按鍵1
sbit key2=P3^1; //按鍵2
#define uchar unsigned char
#define uint unsigned int
uint data;
unsigned char code smgduan[17]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x7f,0x07,0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71};
//延時函數
void delay(uchar z)
{
uchar x,y;
for(x=z;x>0;x--)
for(y=114;y>0;y--);
}
void timeint1() //定時器1中斷初始化
{
EA = 1; //打開中斷總開關
TR1 = 1;
TMOD = 0x10; //0001 0000(十六位定時器,TL1、TH1全用)
TH0=0xED;
TL0=0XFE; //設定初值為5ms
}
void display(data)
{
uint m,n;
m=data/10; //該數的十位數
n=data%10; //該數的個位數
static uchar wei = 0; //靜态變量,函數執行完了之後資料不會抹去,下一次執行該函數還可以接着用
switch(wei)
{
case 0: LA=1;LB=1;LC=1; P0=smgduan[m]; break;
case 1: LA=0;LB=1;LC=1; P0=smgduan[n]; break;
}
wei++; //也就是說,每過10ms才會實作一次個位與十位的顯示,但是速度極快,可以看成是動态顯示
if(wei==2)
{
wei=0;
}
}
void timer1() interrupt 0
{
TH0=0xED;
TL0=0XFE; //重新設定初值為5ms
display(data); //顯示數字,不斷5ms即實作動态顯示
}
void main()
{
timeint1();
while(1)
{
if(key1==0) //按鍵1被按下時為零
{
delay(20);
if(key1==0) //防誤觸
{
data++; //按鍵按下,秒數加1
while(!key1) //松手檢測
}
}
if(key2==0) //按鍵2被按下時為0
{
delay(20);
if(key2==0) //防誤觸
{
data--; //按鍵按下,秒數減1
while(!key2) //松手檢測
}
}
}
}