- 硬件:STC89C52RC
- 開發工具:Keil uVision4
前言:8051是一款很經典的、歷史悠久的單片機,作爲一款入門級的單片機8051受到很多初學者的歡迎。89c52是8051系列的成員之一,擁有8K字節程序存儲空間,512字節隨機數據存儲空間;I/O口控制端口、中斷功能、定時器及串行接口。下面詳細講述外部中斷功能的使用。
外部中斷:單片機提供的系統緊急事件的輸入控制。事件觸發的方式包括輸入信號的下降沿觸發、低電平觸發。當觸發中斷後,單片機會跳到某一個固定的地址去執行中斷服務程序。
外部中斷信號由INT0、INT1引腳傳送進來,如圖所示:
有關中斷處理的相關控制寄存器如下:
- 計時計數器控制寄存器 TCON
- 中斷允許控制寄存器 IE
- 中斷優先權寄存器 IP
寄存器並不算多,配置起來也不復雜。先對各個寄存器進行說明:
TCON寄存器:
“T”開頭的是計數/定時器相關位,“I”開頭的是外部中斷相關位,我們需要看的是後者:
IE寄存器:
IP寄存器:
CPU接到中斷信號發生時會停止當前的工作跳轉到中斷服務程序。那麼當CPU同時接到多箇中斷信號時,該怎麼選擇?當CPU正在中斷函數時又接受到另一箇中斷信號,該怎麼處理?
關於中斷的優先級有一下原則:
1、CPU同時接收到幾個中斷時,首先響應優先級最高的中斷請求,低優先的進入隊列等待;
2、正在進行的中斷過程不能被新的同級或低優先級的中斷請求所中斷;
3、正在進行的低優先級中斷服務,能被高優先級中斷請求中斷;
那麼,IP寄存器的某一中斷配置爲1就成爲高優先級。每一箇中斷在IP裏面只佔一位配置位(IP.x=0或OP.x=1),也就是說系統裏只存在兩種優先級,要麼是高優先級,要麼是低優先級。
如果,任何中斷都不配置IP寄存器的優先級,也等同於系統上電時,默認的優先級順序如下:
外部中斷0 > 定時/計數器0 > 外部中斷1 > 定時/計數器1 > 串行中斷
關於外部中斷的寄存器已經瞭解清楚了,接下來看代碼設計:
外部中斷0(下降沿觸發)
/*-----------------------------------------------
功能:外部中斷0邊沿觸發
現象:首先將P3.2口通過上拉電阻接到電源,保證在空閒時P3.2處於高電平;
當外部中斷信號輸出口P3.2接到GND時,產生了一個下降沿信號,接到P0.0
口的LED燈反轉;若此後P3.2持續接到GND,LED只反轉一次,這與電平觸發
有區別。
------------------------------------------------*/
#include<reg52.h>
sbit LED=P0^0; //定義LED端口
void DelayMs(unsigned char t) //大致延時1mS
{
unsigned short T=500;
while(t--)
{
while(--T);
}
}
void INT0_init(void) //外部中斷0初始化
{
LED=1; //LED口初始值
EA=1; //全局中斷開
EX0=1; //外部中斷0開
IT0=1; //邊沿觸發
}
main()
{
INT0_init();
while(1){
//主循環
}
}
//中斷服務程序 interrupt 0 指明是外部中斷0的中斷函數
/*
interrupt 0 指明是外部中斷0;
interrupt 1 指明是定時器中斷0;
interrupt 2 指明是外部中斷1;
interrupt 3 指明是定時器中斷1;
interrupt 4 指明是串行口中斷;
*/
void ISR_Key(void) interrupt 0 using 1
{
if(!INT0){
DelayMs(10); //防抖動
if(!INT0){
LED=!LED; //按下觸發一次,LED取反一次
}
}
}
外部中斷0(電平觸發)
/*-----------------------------------------------
功能:外部中斷0電平觸發
現象:首先將P3.2口通過上拉電阻接到電源,保證在空閒時P3.2處於高電平;
當外部中斷信號輸出口P3.2接到GND時,產生了一個低電平信號,接到P0.0
口的LED燈反轉;若此後P3.2持續接到GND,LED會反覆反轉,這與邊沿觸
發有區別。
------------------------------------------------*/
#include<reg52.h>
sbit LED=P0^0; //定義LED端口
void DelayMs(unsigned char t) //大致延時1mS
{
unsigned short T=500;
while(t--)
{
while(--T);
}
}
void INT0_init(void) //外部中斷0初始化
{
LED=1; //LED口初始值
EA=1; //全局中斷開
EX0=1; //外部中斷0開
IT0=0; //電平觸發
}
main()
{
INT0_init();
while(1){
//主循環
}
}
//中斷服務程序 interrupt 0 指明是外部中斷0的中斷函數
/*
interrupt 0 指明是外部中斷0;
interrupt 1 指明是定時器中斷0;
interrupt 2 指明是外部中斷1;
interrupt 3 指明是定時器中斷1;
interrupt 4 指明是串行口中斷;
*/
void ISR_Key(void) interrupt 0 using 1
{
if(!INT0){
DelayMs(20); //防抖動
if(!INT0){
LED=!LED; //按下觸發一次,LED取反一次
}
}
}
外部中斷1(下降沿觸發)
/*-----------------------------------------------
功能:外部中斷1邊沿觸發
現象:首先將P3.3口通過上拉電阻接到電源,保證在空閒時P3.3處於高電平;
當外部中斷信號輸出口P3.3接到GND時,產生了一個下降沿信號,接到P0.0
口的LED燈反轉;若此後P3.3持續接到GND,LED只反轉一次,這與電平觸發
有區別。
------------------------------------------------*/
#include<reg52.h>
sbit LED=P0^0; //定義LED端口
void DelayMs(unsigned char t) //大致延時1mS
{
unsigned short T=500;
while(t--)
{
while(--T);
}
}
void INT1_init(void) //外部中斷0初始化
{
LED=1; //LED口初始值
EA=1; //全局中斷開
EX1=1; //外部中斷1開
IT1=1; //邊沿觸發
}
main()
{
INT1_init();
while(1){
//主循環
}
}
/*
interrupt 0 指明是外部中斷0;
interrupt 1 指明是定時器中斷0;
interrupt 2 指明是外部中斷1;
interrupt 3 指明是定時器中斷1;
interrupt 4 指明是串行口中斷;
*/
void ISR_Key(void) interrupt 2 using 1
{
if(!INT1){
DelayMs(10); //防抖動
if(!INT1){
LED=!LED; //按下觸發一次,LED取反一次
}
}
}
#endif
外部中斷1(電平觸發)
/*-----------------------------------------------
功能:外部中斷1電平觸發
現象:首先將P3.3口通過上拉電阻接到電源,保證在空閒時P3.3處於高電平;
當外部中斷信號輸出口P3.3接到GND時,產生了一個低電平信號,接到P0.0
口的LED燈反轉;若此後P3.3持續接到GND,LED會反覆反轉,這與邊沿觸
發有區別。
------------------------------------------------*/
#include<reg52.h>
sbit LED=P0^0; //定義LED端口
void DelayMs(unsigned char t) //大致延時1mS
{
unsigned short T=500;
while(t--)
{
while(--T);
}
}
void INT1_init(void) //外部中斷1初始化
{
LED=1; //LED口初始值
EA=1; //全局中斷開
EX1=1; //外部中斷1開
IT1=0; //電平觸發
}
main()
{
INT1_init();
while(1){
//主循環
}
}
/*
interrupt 0 指明是外部中斷0;
interrupt 1 指明是定時器中斷0;
interrupt 2 指明是外部中斷1;
interrupt 3 指明是定時器中斷1;
interrupt 4 指明是串行口中斷;
*/
void ISR_Key(void) interrupt 2 using 1
{
if(!INT1){
DelayMs(10); //防抖動
if(!INT1){
LED=!LED; //按下觸發一次,LED取反一次
}
}
}
以上四種模式,代碼都是大同小異,比較一下就知道哪些是關鍵點了。
注意點:
- 上面的程序已經是測試過沒有問題的,如果出現led不反轉,那麼檢測一下電路,有一些集成了很多元件的開發板裏面電路複雜,幾個外圍元件可能共用一個IO口,容易被幹擾,以至於達不到想要的效果。最好還是買一個最小系統的單片機,所有IO獨立出來。
- 在選擇“電平觸發”模式下,因爲低電平的持續時間比較長(雖然只是按一下,對於單片機來說已經持續很長),會出現反覆進入中斷,導致LED不會反轉,解決方法就是在進入第一次中斷後,先把該中斷關閉掉並且用while循環,直到中斷信號引腳退出低電平狀態再打開中斷並退出while循環,這麼做缺點就是會阻塞在中斷裏面,可能導致主函數裏面的程序不能及時運行。
- 上面的代碼比較簡單,需要根據實驗出現的問題進一步優化。
- 外部中斷還可以應用到檢測波形的週期、佔空比、頻率以及紅外接收處理,有興趣可以試一下。
僅供參考,錯誤之處以及不足之處還望多多指教。