1
. 實驗三 定時器中斷實驗(Periodic Interrupt Timer)1 實驗目的掌握定時器相關寄存器的配置,以及定時時間的計算等
2 實驗內容定期器中斷及查詢方式控制P1.0口輸出方波,用實驗箱上的示波器觀察波形,不同定時值對其影響。
3 實驗器材STC89C51RC或實驗箱。
4 實驗步驟a.定時常數的確定
定時器/計數器的輸入脈沖周期與機器周期一樣, 為振蕩頻率的1/12。本實驗中時鐘頻率為6.0 MHZ,現要采用中斷方法來實現0.5秒延時,要在定時器1中設置一個時間常數,使其每隔0.1秒產生一次中斷,CPU響應中斷后將R0中計數值減一,令R0=05H,即可實現0.5秒延時。
時間常數可按下述方法確定:
機器周期=12÷晶振頻率=12/(6×106)=2us
設計數初值為X,則(2e+16-X)×2×106=0.1,可求得X=15535
化為十六進制則X=3CAFH,故初始值為TH1=3CH,TL1=AFH
b.初始化程序
包括定時器初始化和中斷系統初始化,主要是對IE、TCON、TMOD的相應位進行正確的設置,并將時間常數送入定時器中。由于只有定時器中斷,IP便不必設置。
c.設計中斷服務程序和主程序
中斷服務程序除了要完成計數減一工作外,還要將時間常數重新送入定時器中,為下一次中斷做準備。
3 程序下載調試
4 附注:定時器常用方式1和方式2(在實驗五 單片機串口的應用中用到),方式2 為自動重裝計數初值的8位定時器,主要用于串行通信中波特率的產生和短時精確定時(因為不必軟件重裝初值所以更精確)。
5 附注實驗例程:#include
#define unchar unsigned char
#define unint unsigned int
sbit fangbo = P1^0;
void main()
{
TMOD = 0x01; //定時器0工作方式1
TH0 = 0x3c;
TL0 = 0xb0; //裝入定時器初值定時50ms
ET0 = 1; //定時器0中斷允許
EA = 1; //總中斷允許
TR0 = 1; //定時器0開始計時
while(1); //等待
}
void time0() interrupt 1 //定時器0中斷服務函數
{
TH0 = 0x3c;
TL0 = 0xb0; //重裝計數器值
fangbo=~fangbo; //P1.0取反,產生方波
}
對應匯編代碼:
FANGBO EQU P1.0
ORG 0000H
LJMP MAIN
ORG 000BH
LJMP TIME
ORG 0010H
MAIN: MOV TMOD,#01H
MOV TH0,#03CH
MOV TL0,#0B0H
SETB ET0
SETB EA
SETB TR0
SJMP $ ;等待
TIME: MOV TH0,#03CH
MOV TL0,#0B0H
CPL FANGBO
RETI
END
查詢方式C代碼:
#include
#define unchar unsigned char
#define unint unsigned int
sbit fangbo = P1^0;
void main()
{
TMOD = 0x01; //定時器0工作方式1
TH0 = 0x3c;
TL0 = 0xb0; //裝入定時器初值定時50ms
ET0 = 1; //定時器0中斷允許
EA =0; //總中斷允許
TR0 = 1; //定時器0開始計時
while(1) //死循環
{
while(!TF0); //查詢中斷標志并等待
TF0 = 0; //清除標志
TH0 = 0x3c;
TL0 = 0xb0; //重裝初值
fangbo=~fangbo; //P1.0取反,產生方波
}
}
對應匯編代碼:
FANGBO EQU P1.0
ORG 0000H
LJMP MAIN
ORG 0010H
MAIN: MOV TMOD,#01H
MOV TH0,#03CH
MOV TL0,#0B0H
SETB ET0
SETB TR0
TIME: JNB TF0,$
MOV TH0,#03CH
MOV TL0,#0B0H
CLR TF0
CPL FANGBO
SJMP TIME
END
附實驗仿真電路:
注:實驗箱中有模擬示波器,可通過電腦觀察波形。
. 實驗四 外部中斷的應用一 實驗目的通過此次實驗學習51單片機外部中斷的使用,并結合輸入輸出方式熟練掌握外部中斷的應用
二 實驗內容采用按鍵以中斷方式控制一個LED燈的亮滅。
三 實驗器材STC89C52RC 單片機、LED燈,獨立按鍵或實驗箱。
三 實驗步驟- 程序的編寫,采用中斷方式判斷鍵是否按下,并確定是否點亮二極管。
- 程序下載調試(可先進行仿真)。
四 附注中斷方式可以提高CPU的效率,當發生中斷事件時處理器可快速響應中斷,沒有中斷事件時處理器正常工作,不必時刻查詢中斷事件的發生與否,提高代碼效率。
本例中,若采用電平觸發方式,則Key為低電平時Led亮,否則Led息滅;若采用邊沿觸發方式,則Key的每個下降沿,即Key由高變為低時,Led的狀態改變一次。
五 實驗附注例程#include
#define unchar unsigned char
#define unint unsigned int
sbit Led = P1^0;
sbit Key = P3^2; //外部中斷0引角
void main()
{
IT0 = 0; //外部中斷0采用電平觸發方式;邊沿觸發為1下降沿有效
EA = 1; //中斷允許
EX0 = 1; //開外部中斷0
while(1);
}
void int0() interrupt 0
{
Led = 0; //Led 亮
while(Key == 0); //等待鍵釋放
Led = 1; // Led 滅
}
/*
void int0() interrupt 0 //邊沿觸發方式中斷函數。每次Key下降沿改變Led狀態
{
Led = ~Led; //改變Led狀態
}
*/
對應匯編代碼:
KEY EQU P3.2
LED EQU P1.0
ORG 0000H
LJMP MAIN
ORG 0003H
LJMP INIT
ORG 0010
MAIN: CLR IT0 ;電平觸發方式,邊沿觸發為SETB IT0
SETB EA
SETB EX0
SJMP $
INIT: CLR LED
JNB KEY,$
SETB LED
RETI
;INIT: CPL LED ;邊沿觸發方式中斷程序
END
附實驗仿真電路:
附圖1
附圖2 P0口上拉電阻
. 實驗五 單片機串口的應用1 實驗目的通過此次實驗學習單片機串口的應用,掌握串口相關寄存器的配置,并學會用串口做簡單的雙機通信。
2 實驗內容通過串口實現雙機通信,用Key控制發光二極管。
3 實驗器材STC89C52RC單片機、LED燈或實驗箱。
4 實驗步驟5 附注51單片機串行口的SBUF有兩個:接收SBUF和發送SBUF,二者在物理結構上是獨立的,單片機用它們來接收和發送數據。串行通訊的波特率隨串行口工作方式選擇的不同而不同,它除了與系統的振蕩頻率f,電源控制寄存器PCON的SMOD位有關外,還與定時器T1的設置有關。
1、在工作方式0時,波特率固定不變,僅與系統振蕩頻率有關,其大小為f/12。
2、在工作方式2時,波特率也只固定為兩種情況:
當SMOD=1時, 波特率=f/32
當SMOD=0時, 波特率=f/64
3、在工作方式1和3時,波特率是可變的:
當SMOD=1時, 波特率=定時器T1的溢出率/16
當SMOD=0時, 波特率=定時器T1的溢出率/32
其中,定時器T1的溢出率=f/(12*(256-N)),N為T1的定時時間常數。
在實際應用中,往往是給定通訊波特率,而后去確定時間常數。例如:f=6.144MHZ,波特率等于1200,SMOD=0時,則1200=6144000/(12*32*(256-N)),計算得N=F2H。
本例程中設置串行口工作于方式1,SMOD=0,波特率為1200。
6 附注例程中斷方式C代碼:
#include
#define unchar unsigned char
#define unint unsigned int
sbit Key = P1^1;
sbit Led = P1^0;
void uartsend(unchar dat);
void Uartsend(unchar k) //串口發送子函數
{
SBUF = k; //發送數據
while(!TI); //待待發送結束
}
void main()
{
unchar tmp;
TMOD = 0x20; //定時器1工作方式2
TH1 = 0xfa;
TL1 = 0xfa; //裝入定時器初值11.0592M晶振,波特率4800
PCON = 0; //波特率不倍增
ET1 = 0; //定時器1中斷允許
EA = 1; //總中斷允許
ES = 1; //串口中斷允許
TR1 = 1; //定時器0開始計時
SCON = 0x50; //串口工作方工1,準備接收
while(1) //死循環
{
if(Key) //判斷是否有鍵按下
{
Uartsend(0xaa); //用串口發送0xaa
while(Key); //等待鍵釋放
}
else
{
Uartsend(0x55);
while(!Key);
}
}
}
void uart() interrupt 4
{
unchar temp;
if(RI) //判斷是否為接收中斷
{
temp = SBUF; //讀數據
switch(temp) //判斷數據
{
case 0x55:Led = 1;break;
case 0xaa:Led = 0;break;
default:break;
}
RI = 0; //清除中斷標志
}
TI = 0; //清除中斷標志
}
對應匯編代碼:
KEY EQU P1.1
LED EQU P1.0
ORG 0000H
LJMP MAIN
ORG 0023H
LJMP UART
ORG 0100H
MAIN: MOV TMOD,#020H
MOV TH1,#0FAH
MOV TL1,#0FAH
MOV PCON,#00H
CLR ET1
SETB EA
SETB ES
SETB TR1
MOV SCON,#050H
KEYLED: JNB KEY,OFFL
MOV SBUF,#0AAH
KEY0: JB KEY,$
OFFL: MOV SBUF,#055H
KEY1: JNB KEY,$
SJMP KEYLED
UART: JNB RI,RRET
CLR RI
MOV R7,SBUF
CJNE R7,#0AAH,OFFLED
CLR LED
SJMP RRET
OFFLED: SETB LED
RRET: CLR TI
RETI
END
查詢方式C代碼:
#include
#define unchar unsigned char
#define unint unsigned int
sbit Key = P1^1;
sbit Led = P1^0;
void uartsend(unchar dat) //串口發送子函數
{
SBUF = dat; //發送數據
while(!TI); //待待發送結束
TI = 0; //清除中斷標志
}
void uartrec() //串口接收數據子函數
{
unchar temp;
if(RI)
{
temp = SBUF; //讀數據
switch(temp) //判斷數據
{
case 0x55:Led = 1;break;
case 0xaa:Led = 0;break;
default:break;
}
RI = 0; //清除中斷標志
}
}
void main()
{
TMOD = 0x20; //定時器1工作方式2
TH1 = 0xfa;
TL1 = 0xfa; //裝入定時器初值11.0592M晶振,波特率4800
PCON = 0; //波特率不倍增
ET1 = 0; //定時器0中斷允許
EA = 0; //總中斷關閉
ES = 1; //串口中斷允許
TR1 = 1; //定時器0開始計時
SCON = 0x50; //串口工作方工1,準備接收
while(1)
{
if(Key) //判斷鍵是否按下
{
uartsend(0xaa);
while(Key)uartrec(); //等鍵釋放并接收數據
}
uartsend(0x55);
while(!Key)uartrec();
}
}
對應匯編代碼:
KEY EQU P1.1
LED EQU P1.0
ORG 0000H
LJMP MAIN
ORG 0100H
MAIN: MOV TMOD,#020H
MOV TH1,#0FAH
MOV TL1,#0FAH
MOV PCON,#00H
CLR ET1
CLR EA
SETB ES
SETB TR1
MOV SCON,#050H
KEYLED: JNB KEY,OFFL
MOV SBUF,#0AAH
JNB TI,$
CLR TI
SJMP KEY1
OFFL: MOV SBUF,#055H
JNB TI,$
CLR TI
KEY0: JB KEY,KEYLED
LCALL UARTRI
SJMP KEY0
KEY1: JNB KEY,OFFL
LCALL UARTRI
SJMP KEY1
UARTRI: JNB RI,RETT
CLR RI
MOV R7,SBUF
CJNE R7,#0AAH,OFFLED
CLR LED
RETT: RET
OFFLED: SETB LED
SJMP RETT
END
附實驗仿真電路:
注:MCU1的TX接MCU2的RX,MCU1的RX接MCU2的TX。