C51中斷(void timer1(void) interrupt 3 using 3)
interrupt 表示中斷優(yōu)先級,using表示所用工作寄存器組。
interruptxusingy
跟在interrupt后面的xx值得是中斷號,就是說這個函數(shù)對應(yīng)第幾個中斷端口,一般在51中
0外部中斷0
1定時器0
2外部中斷1
3定時器1
4串行中斷
其它的根據(jù)相應(yīng)得單片機(jī)有自己的含義,實(shí)際上c在編譯的時候就是把你這個函數(shù)的入口地址放到這個對應(yīng)中斷的跳轉(zhuǎn)地址
usingy這個y是說這個中斷函數(shù)使用的那個寄存器組就是51里面一般有4個r0--r7寄存器,如果你的終端函數(shù)和別的程序用的不是同一個寄存器組則進(jìn)入中斷的時候就不會將寄存器組壓入堆棧返回時也不會彈出來節(jié)省代碼和時間
外部中斷INT0
void intsvr0(void) interrupt 0 using 1
定時/計數(shù)器T0
void timer0(void) interrupt 1 using 1
外部中斷INT1
void intsvr1(void) interrupt 2 using 1
定時/計數(shù)器T1
void timer1(void) interrupt 3 using 1
串口中斷
void serial0(void) interrupt4 using 1
單片機(jī)的C語言
HNBCC培訓(xùn)
一,中斷的概念
中斷:當(dāng)計算機(jī)執(zhí)行正常程序時,系統(tǒng)中出現(xiàn)某些急需處理的異常情況和特殊請求.
中斷的執(zhí)行:當(dāng)CPU正在執(zhí)行某一程序時,若有中斷響應(yīng),則CPU轉(zhuǎn)而執(zhí)行中斷服務(wù)程序,當(dāng)中斷服務(wù)程序執(zhí)行完畢后,CPU自動返回原來的程序繼續(xù)執(zhí)行.
中斷服務(wù)程序的語句寫法與函數(shù)的寫法完全相同,所以,中斷服務(wù)程序也是函數(shù),只在函數(shù)頭部有不同(后續(xù)).
中斷服務(wù)程序的執(zhí)行與函數(shù)的執(zhí)行不同:函數(shù)的執(zhí)行是有固定位置的,是通過函數(shù)的調(diào)用來完成的;而中斷服務(wù)程序的執(zhí)行是不固定位置的,只要有中斷響應(yīng),在一定條件下都會去響應(yīng)中斷,即執(zhí)行中斷服務(wù)程序.
二,中斷源
中斷源:任何引起計算機(jī)中斷的事件,一般一臺機(jī)器允許有許多個中斷源.
8051系列單片機(jī)至少有5個可能的中斷(8052有6個,其它系列成員最多可達(dá)15個).下面以5個中斷源為例.
8051單片機(jī)的五個中斷源是:
外部中斷請求0,由INT0(P3.2)輸入;
外部中斷請求1,由INT1(P3.3)輸入;
片內(nèi)定時器/計數(shù)器0溢出中斷請求;
片內(nèi)定時器/計數(shù)器1溢出中斷請求;
片內(nèi)串行口發(fā)送/接收中斷請求.
三,與中斷有關(guān)的寄存器
1,定時/計數(shù)器控制寄存器TCON
TF1 TR1 TF0 TR0 IE1 IT1 IE0 IT0
D7 D6 D5 D4 D3 D2 D1 D0
. IT0,IT1:外部中斷0,1觸發(fā)方式選擇位,由軟件設(shè)置;
1→下降沿觸發(fā)方式,INT0/INT1管腳上高到低的負(fù)跳變可引起中斷;
0→電平觸發(fā)方式, INT0/INT1管腳上低電平可引起中斷.
. IE0,IE1:外部中斷0,1請求標(biāo)志位;
當(dāng)外部中斷0,l依據(jù)觸發(fā)方式滿足條件,產(chǎn)生中斷請求時由硬件置位 (IE0/IE1=1);當(dāng)CPU響應(yīng)中斷時由硬件清除(IE0/IE1= 0).
. TR0,TR1: 啟動定時/計數(shù)器0,1.
. TF0,TF1:定時器/計數(shù)器0,1(T/C0,T/C1)溢出中斷請求標(biāo)志;
當(dāng)T/C0,1計數(shù)溢出時由硬件置位(TF0/TF1=l);
當(dāng)CPU響應(yīng)中斷由硬件清除(TFO/TF1=0).
三,與中斷有關(guān)的寄存器
2,串行口控制寄存器SCON
TI RI
D7 D6 D5 D4 D3 D2 D1 D0
. RI:串行口接收中斷請求標(biāo)志位;
當(dāng)串行口接收完一幀數(shù)據(jù)后請求中斷,由硬件置位(RI=1)
RI必須由軟件清"0".
. TI:串行口發(fā)送中斷請求標(biāo)志位.
當(dāng)串行口發(fā)送完一幀數(shù)據(jù)后請求中斷,由硬件置位(TI=1)
TI必須由軟件清"0".
三,與中斷有關(guān)的寄存器
3,中斷允許寄存器IE
EA ET2 ES ET1 EX1 ET0 EX0
D7 D6 D5 D4 D3 D2 D1 D0
. EX0,EX1:外部中斷0,1的中斷允許位;
l→外部中斷0,1開中斷;0→外部中斷0,1關(guān)中斷.
. ET0,ET1:定時器/計數(shù)器0,1(T/C0,T/C1)溢出中斷允許位;
1→T/C0,T/Cl開中斷;0→T/C0,T/Cl關(guān)中斷.
. ES:串行口中斷允許位;
1→串行口開中斷;0→串行口關(guān)中斷.
. ET2:定時器/計數(shù)器2(T/C2)溢出中斷允許位;
1→T/C2開中斷;0→T/C2關(guān)中斷.
. EA:CPU開/關(guān)中斷控制位.
1→CPU開中斷.0→CPU關(guān)中斷.
8051復(fù)位時,IE被清"0",此時CPU關(guān)中斷,各中斷源的中斷也都屏蔽
三,與中斷有關(guān)的寄存器
4,中斷優(yōu)先級寄存器IP
PS PT1 PX1 PT0 PX0
D7 D6 D5 D4 D3 D2 D1 D0
. PX0,PX1:外部中斷0,1中斷優(yōu)先級控制位;
1→高優(yōu)先級;0→低優(yōu)先級.
. PT0,PT1:定時器/計數(shù)器0,1中斷優(yōu)先級控制位;
1→高優(yōu)先級;0→低優(yōu)先級.
. PS:串行口中斷優(yōu)先級控制位;
1→高優(yōu)先級;0→低優(yōu)先級.
8051復(fù)位時,IP被清"0",5個中斷源都在同一優(yōu)先級,其內(nèi)部優(yōu)先級的順序從高到低為: 外部中斷0(IE0)
定時器/計數(shù)器0(TF0)
外部中斷1(IE1)
定時器/計數(shù)器1(TF1)
串行口中斷(RI+TI)
四,中斷響應(yīng)
8051的CPU在每個機(jī)器周期采樣各中斷源的中斷請求標(biāo)志位,如果沒有下述阻止條件,將在下一個機(jī)器周期響應(yīng)被激活了的最高級中斷請求:
1.CPU正在處理同級或更高級的中斷;
2.現(xiàn)行機(jī)器周期不是所執(zhí)行指令的最后一個機(jī)器周期;
3.正在執(zhí)行的是RETI或是訪問IE或IP的指令.
CPU在中斷響應(yīng)后完成如下的操作:
1.硬件清除相應(yīng)的中斷請求標(biāo)志;
2.執(zhí)行一條硬件子程序,保護(hù)斷點(diǎn),并轉(zhuǎn)向中斷服務(wù)程序人口
3.結(jié)束中斷時執(zhí)行RETI指令,恢復(fù)斷點(diǎn),返回主程序.
8051的CPU在響應(yīng)中斷請求時,由硬件自動形成轉(zhuǎn)向與該中斷源對應(yīng)的服務(wù)程序入口地址,這種方法為硬件向量中斷法.
五,中斷服務(wù)程序的入口地址
編號 中斷源 人口地址
0 外部中斷0 0003H
1 定時器/計數(shù)器0 000BH
2 外部中斷1 0013H
3 定時器/計數(shù)器1 001BH
4 串行口中斷 0023H
各中斷服務(wù)程序入口地址僅間隔8個字節(jié),編譯器在這些地址放入無條件轉(zhuǎn)移指令跳轉(zhuǎn)到服務(wù)程序的實(shí)際地址.
六,中斷服務(wù)程序的語法規(guī)則
中斷服務(wù)程序的語法規(guī)則如下:
函數(shù)的返回值 函數(shù)名([參數(shù)]) interrupt n [using m]
{
函數(shù)體;
}
對中斷程序而言,函數(shù)的返回值和參數(shù)一般為void.
interrupt n 中n的取值為0~31的常數(shù),不允許用表達(dá)式,表示中斷向量的編號.
using m 中m的取值為0~3的常數(shù),不允許用表達(dá)式,表示內(nèi)部RAM中的工作寄存器.
七,中斷說明
中斷不允許用于外部函數(shù),它對函數(shù)目標(biāo)代碼影響如下z
·當(dāng)調(diào)用函數(shù)時,SFR中的ACC,B,DPH,DPL和PSW(當(dāng)需要時)入錢;
.如果不使用寄存器組切換,甚至中斷函數(shù)所需的所有工作寄存器都入錢;
.函數(shù)退出前,所有的寄存器內(nèi)容出錢;
·函數(shù)由8051的指令"RETI"終止.
中斷服務(wù)程序使用的任何程序也使用同一寄存器組.
八,中斷例子
#include 〈reg51.h〉
unsigned char status;
bit flag;
void service_int() interrupt 2 using 2
{ flag=1;
status=P1;
}
void main(void)
{
IP=0x04; IE=0x84;
for(;;){
if(flag){
switch(status){
case 0: break;
case 1: break;
case 2: break;
case 3: break;
default: ;}
flag=0;
}
}
}
圖見書中P148
習(xí)題
試設(shè)計滿足下列要求的電路圖:
1 單片機(jī)采用89C51,時鐘11.0592MHz;
2 有4個指示燈表示狀態(tài);
3 外接12位A/D芯片AD574;
4 有4 * 4的鍵盤;
5 有字符型LCD(畫成插座形式,12Pin插座,管腳接法見書P253);
6 有串行接口與計算機(jī)連接;
7 設(shè)置8位二進(jìn)制的地址,地址范圍可表示為0~255;
8 外接EEPROM.
定時器/計數(shù)器(T/C)
8051系列單片機(jī)至少有兩個16位內(nèi)部定時器/計數(shù)器,8052有三個定時器/計數(shù)器,其中有兩個是基本定時器/計數(shù)器是定時器/計數(shù)器.它們既可以編程為定時器使用,也可以編程為計數(shù)器使用.
若是計數(shù)內(nèi)部晶振驅(qū)動時鐘,它是定時器;若是計數(shù),8051的輸入管腳的脈沖信號,它是計數(shù)器.
當(dāng)T/C工作在定時器時,對振蕩源12分頻的脈沖計數(shù),即每個機(jī)器周期計數(shù)值加1,計數(shù)率=1/12f osc.例當(dāng)晶振為12MHz時,計數(shù)率=1000kHz,即每1μs計數(shù)值加1.
當(dāng)T/C工作在計數(shù)器時,計數(shù)脈沖來自外部脈沖輸入管腳T0(P3.4)或T1(P3.5),當(dāng)T0或T1腳上負(fù)跳變時計數(shù)值加1.識別管腳上的負(fù)跳變需兩個機(jī)器周期,即24個振蕩周期.所以T0或T1腳輸入的可計數(shù)外部脈沖的最高頻率為1/24fosc,當(dāng)晶振為12MHZ時,最高計數(shù)率為500kHz,高于此頻率將計數(shù)出錯.
一,與T/C有關(guān)的SFR
1,計數(shù)寄存器Th和TL
T/C是16位的,計數(shù)寄存器由TH高8位和TL低8位構(gòu)成.
在特殊功能寄存器(SFR) 中,
對應(yīng)T/C0為TH0和TL0;
對應(yīng)T/C1為TH1和TL1.
定時器/計數(shù)器的初始值通過TH1/TH0和TL1/TL0設(shè)置.
2,定時器/計數(shù)器控制寄存器TCON
前面已介紹.
二,與T/C有關(guān)的SFR
3,T/C的方式控制寄存器TMOD
. C/T:計數(shù)器或定時器選擇位;
1→為計數(shù)器;0→為定時器.
. GATE :門控信號;
1 → T/C的啟動受到雙重控制,即要求TR0/TR1和INT0/INT1同時為高;
0 → T/C的啟動僅受TR0或TR1控制.
GATE C/T M1 M0 GATE C/T M1 M0
D7 D6 D5 D4 D3 D2 D1 D0
T/C1
T/C0
三,四種工作方式
M1 M0 方式 功 能
0 0 0 13位定時器/計數(shù)器,TL是低5位,TH是高8位
0 1 1 16位定時器/計數(shù)器
1 0 2 常數(shù)自動重裝的8位定時器/計數(shù)器
1 1 3 僅用于T/C0,是兩個8位定時器/計數(shù)器
利用定時器編寫時鐘程序.
四,T/C工作方式的說明
1. 方式0:
當(dāng)TMOD中MlM0=00時,T/C工作在方式0;
方式0為13位的T/C,由TH的高8位,TL的低5位的計數(shù)值,滿計數(shù)值213,但啟動前可以預(yù)置計數(shù)初值.
若T/C開中斷(ET=1)且CPU開中斷(EA=1)時,則定時器/計數(shù)器溢出時,CPU轉(zhuǎn)向中斷服務(wù)程序時,且TF白動清0.
2. 方式1:
當(dāng)TMOD中MlM0=01時,T/C工作在方式1;
方式1與方式0基本相同.唯一區(qū)別在于計數(shù)寄存器的位數(shù)是16位的,由TH和TL寄存器各提供8位,滿計數(shù)值為216.
四,T/C工作方式的說明
3. 方式2:
當(dāng)TMOD中MlM0=10時,T/C工作在方式2;
方式2是8位的可自動重載的T/C,滿計數(shù)值為28;
在方式0和方式1中,當(dāng)計數(shù)滿后,若要進(jìn)行下一次定時/計數(shù),須用軟件向TH和TL重裝預(yù)置計數(shù)初值;
方式2中TH和TL被當(dāng)作兩個8位計數(shù)器,計數(shù)過程中,TH寄存8位初值并保持不變,由TL進(jìn)行8位計數(shù).計數(shù)溢出時,除產(chǎn)生溢出中斷請求外,還自動將TH中初值重裝到TL,即重裝載.
4. 方式3:
方式3只適合于T/C0.當(dāng)T/CO工作在方式3時,TH0和TL0成為兩個獨(dú)立的8位計數(shù)器.
五,定時器/計數(shù)器的初始化
在使用8051的定時器/計數(shù)器前,應(yīng)對它進(jìn)行編程初始化,主要是對TCON和TMOD編程;計算和裝載T/C的計數(shù)初值.一般完成以下幾個步驟:
(1)確定T/C的工作方式——編程TMOD寄存器;
(2)計算T/C中的計數(shù)初值,并裝載到TH和TL;
(3)T/C在中斷方式工作時,須開CPU中斷和源中斷——編程IE寄存器;
(4)啟動定時器/計數(shù)器——編程TCON中TR1或TR0位.
六,定時器/計數(shù)器的初值計算
在定時器方式下,T/C是對機(jī)器周期脈沖計數(shù)的,若fosc=12MHz,一個機(jī)器周期為12/fosc=1μs,則:
方式0 13位定時器最大定時間隔=213 × 1μs=8.192ms;
方式1 16位定時器最大定時間隔=216 × 1μs=65.536ms;
方式2 8位定時器最大定時間隔=28×1μs=256μs.
若使T/C工作在定時器方式1,要求定時1ms,求計數(shù)初值.設(shè)計數(shù)初值為x,則有:
(216-x)×1μs=1000μs
或x=216一1000
因此,TH,TL可置-1000;
即:TH= -1000/256;TL= -1000%256.
對一般fosc有下列公式(設(shè)定時時間為timeμs):
(216-x)×12/fosc= time μs
例1,設(shè)單片機(jī)的fosc=12MHz,要求在P1.0腳上輸出周期為2ms的方波
采用查詢方式.
#include 〈reg51.h〉
sbit P1_0=P1^0;
void main(void〉
{ TMOD=0x01; TR0=1;
for(;;)
{TH0= -1000/256;
TL0= -1000%256;
do {} while(!TF0);
P1_0=!P1_0;
TF0=0;
}
}
采用中斷方式.
#include 〈reg51.h>
sbit P1_0=P1^0;
void timer0(void) interrupt 1using 1 {P1_0=!P1_0; TH0= -1000/256;
TL0= -1000%256;}
void main(void)
{TMOD=0x01; P1_0=0;
TH0= -1000/256;
TL0= -1000%256;
EA=1;ET0=1;TR0=1;
do {} while(1);
}
例2,設(shè)單片機(jī)的fosc=6MHz,要求在P1.7腳上的指示燈亮一秒滅一秒.
void main(void)
{P1_7=0; P1_0=1;
TMOD=0x61;
TH0= -50000/256;
TL0= -50000%256;
TH1= -5; TL1= -5;
IP=0x08;
EA=l; ET0=1;
ET1=l; TR0=l;
TR1=1;
for (;;){}
}
#include
sbit P1_0=P1^0;
sbit P1_7=P1^7;
void timer0( ) interrupt 1 using 1
{P1_0=!P1_0;
TH0= -50000/256;
TL0= -50000%256;
}
void timer1( ) interrupt3 using 2
{P1_7=!P1_7;}
例3,設(shè)單片機(jī)的fosc=10MHz,要求在P1.0腳上輸出周期為2.5μs,占空比20%.
#include
#define uchar unsigned char
uchar time;
uchar period=250;
uchar high=50;
void timer0( ) interrupt l using 1
{TH0= -8333/256;
TL0= -8333%256;
if(++time==high)P1=0;
else if(time==period)
{time=0; P1=1;}
}
void main(void)
{
TMOD=0x01;
TH0= -8333/256;
TL0= -8333%256;
EA=l;
ET0=1;
TR0=1;
do {)while(1);
}
#include
#define uchar unsigned char
#define uint unsigned int
uchar time,status,percent,period;
bit one_round;
uint oldcount,target=500;
void pulse(void) interrupt 1using l
{TH0= -833/256;
TL0= -833%256; ET0=l;
if(++time==percent)P1=0;
else if (time ==100)
{time=0;P2=l;}
void tachmeter(void) interrupt 2 using 2
{union {uint word;
struct{uchar hi;uchar lo;}byte; }newcount;
newcount_byte.hi=TH1;
newcount_byte.lo=TLl;
period=newcount.word--oldcounts;
oldcount=newcount.word;
one -round=1;
void main(void)
{IP=0x04;
TMOD=0x01;
TCON=0x54;
TH1=0;TL1=0;
IE=0x86;
for(;;)
{if(one_round)
{if(period
{if(percent0)
--percent;
}
}
}
串行口
8051系列單片機(jī)有一個標(biāo)準(zhǔn)的串行通信接口,發(fā)送數(shù)據(jù)時由TXD端口送出,接收數(shù)據(jù)時由RXD端口輸入.
內(nèi)置兩個緩沖器SBUF,一個接受緩沖器,另一個是接收緩沖器,可實(shí)行全雙工的串行通信.
近距離可直接用TTL電平,若與計算機(jī)通信,則需要將電平轉(zhuǎn)換成RS232電平形式,若需長距離通信可以采用RS485電平形式,通信的數(shù)據(jù)必須通過軟件的編寫來完成.
一,與串行口有關(guān)的SFR
1,串行口控制寄存器SCON
SM0 SM1 SM2 REN TB8 RB8 TI RI
D7 D6 D5 D4 D3 D2 D1 D0
. SM0,SM1:串行口工作方式控制位(見書P158).
. SM2:多機(jī)通信控制位(方式2,3);
1→只有接收到第9位(RB8)為1,RI才置位;
0→接收到字符RI就置位.
. REN :串行口接收允許位;
1→允許串行口接收;0→禁止串行口接收.
. TB8:方式2和方式3時,為發(fā)送的第9位數(shù)據(jù),也可以作奇偶
校驗(yàn)位.
. RB8:方式2和方式3時,為接收到的第9位數(shù)據(jù);方式1時,
為接收到的停止位.
. TI:發(fā)送中斷標(biāo)志;由硬件置位,必須由軟件清0.
. RI:接收中斷標(biāo)志;由硬件置位,必須由軟件清0.
一,與串行口有關(guān)的SFR
2,電源控制寄存器PCON
SMOD
D7 D6 D5 D4 D3 D2 D1 D0
PCON的第7位SMOD是與串行口的波特率設(shè)置有關(guān)的選擇位.
. SMOD:串行口波特率加倍位.
1→方式1,3波特率=定時器1溢出率/16;方式2波特率為fosc/32;
0→方式1,3波特率=定時器1溢出率/32;方式2波特率為fosc/64.
二,串行口的工作方式
1. 方式0
方式0為移位寄存器輸入/輸出方式,串行數(shù)據(jù)通過RXD輸入/輸出 ,TXD則用于輸出移位時鐘脈沖.
方式0時,收發(fā)的數(shù)據(jù)為8位,低位在前.波特率固定為fosc/12,其中fosc為單片機(jī)外接晶振頻率.
發(fā)送是以寫SBUF寄存器的指令開始的,8位輸出結(jié)束時TI被置位.
方式0接收是在REN=1和RI=0同時滿足時開始的.接收的數(shù)據(jù)裝入SBUF中,結(jié)束時RI被置位.
移位寄存器方式的也可用于兩個單片機(jī)之間的通信.和通常9600波特相比,lMHz通信能力對短距離通信很吸引人.
二,串行口的工作方式
2. 方式1
方式1是10位異步通信方式,1位起始位(0),8位數(shù)據(jù)位和1位停止位(1).其中的起始 位和停止位在發(fā)送時是自動插入的.
任何一條以SBUF為目的寄存器的指令都啟動一次發(fā)送,發(fā)送的條件是TI=0,發(fā)送完置TI為1;
方式l接收的前提條件是SCON中的REN為l,同時下列兩個條件都滿足,本次接收有效,將其裝入SBUF和RB8位.否則放棄接收結(jié)果.兩個條件是:(1)RI=0;(2)SM2=0或
接收到的停止位為1;
方式1的波特率是可變的,波特率可由以下計算公式計算得到: 方式1波特率=2SMOD.(定時器1的溢出率)/32
其中的SMOD為PCON的最高位.定時器1的方式0,1,2,都可以使用,其溢出率為定時時間的倒數(shù)值.
二,串行口的工作方式
3. 方式2和方式3
這兩種方式都是11位異步接收/發(fā)送方式,它們的操作過程完全一樣,所不同的是波特率:
方式2波特率=2SMOD.(fosc/64);
方式3波特率同方式1(定時器l作波特率發(fā)生器).
方式2和方式3的發(fā)送起始于任何一條"寫SBUF"指令,當(dāng)?shù)?位數(shù)據(jù)(TB8)輸出之后,置位TI.
方式2和方式3的接收前提條件也是REN為1.在第9位數(shù)據(jù)接收到后,如果下列條件同時滿足(1)RI=0;(2)SM2=0或接收到的第9位為1,則將已接收的數(shù)據(jù)裝入SBUF和RB8,并置位RI,如果條件不滿足,則接收無效.
三,串行口的初始化
在使用串行口之前,應(yīng)對它進(jìn)行編程初始化,主要是設(shè)置產(chǎn)生波特率的定時器1,串行口控制和中斷控制寄存器.具體步驟如下:
(1) 確定定時器1的工作方式——編程TMOD寄存器;
(2) 計算定時器1的初值——裝載TH1,TL1,具體TH1和
TL1的值可查表得到;
(3) 啟動定時器1——編程TCON中的TR1位,即置TR1為1;
(4) 確定串行口的控制——編程SCON;
(5) 串行口在中斷方式工作時,須開CPU和源中斷——編程IE寄存器.
四,串行口舉例1
#include 〈reg51.h>
#define uchar unsigned char
#define uint unsigned int
uchar idata trdata[10]=
{'M','C','S','-','5','1', 0x0d,
0x0a,0x00};
void main(void)
{ uchar i; uint j;
TMOD=0x20;
TL1=0xfd;TH1=0xfd;
SCON=0xd8;PCON=0x00;
TR1=1;
while(1)
{i=0;
while(trdata[i]!=0x00)
{SBUF=trdata[i];
while(TI==0);
TI=0; i++;
}
for (j=0;j
void main(void〉
{unsigned char a;
TMOD=Ox20;
TL1=0xfd;TH1=0xfd;
SCON=Oxd8;PCON=0x00;
TR1=1;
while (1)
{while (RI==0); RI=0;
a=SBUF; SBUF=a;
while (TI==O); TI=0;
}
}
#include 〈reg51.h〉
#define uchar unsigned char
uchar xdata r_buf[32];
uchar xdata t_buf[32];
uchar r_in,r_out,t_in,t_out;
bit r_full,t_empty,t_done;
code uchar m[]={"this is a test
programrn"};
serial( ) interrupt 4 using 1
{ifRI&&~r_full)
{ r_buf[r_in]=SBUF; RI=0;
r_in=++r_in&0xlf;
if(r_in==r_out) r_full=1;}
else if (TI &&~t_empty)
{SBUF=t_buf[t_out]; TI=0;
t_out=++t_out&0x1f;
if{t_out==t_in)t_empty=l;
else if(TI){TI=0;
t_done =1;
}
}
void loadmsg(uchar code *msg)
{ while((*msg!=0)&&((((t_in+1)^ t_out)&0xlf)!=0))
{ t_buf[t_in]= *msg; msg++;
t_in=++t_in&0x1f;
if(t-done){TI=1;
t_empty=t_done =0 ;}
}
}
void process(uchar ch){return;}
void processmsg(void)
{while(((r_out+1)^r_in)!=0)
{process(r_buf[r_out]);
r_out=++r_out&0x1f;}
}
void main()
{TMOD=0x20;TH1=0xfd;TCON=0x40;
SCON=0x50;IE=0x90;
t_empty=t_done =1;r_full=0;
r_out=t_in=t_out=l;r_in=1;
for(;;){loadmsg(&m);
processmsg();}
}