?? 學(xué)習(xí)型紅外線遙控程序.c
字號:
/*************晶體為11.0592M,波特率9600bps
***************學(xué)習(xí)型紅外線遙控程序*******/
#include <AT89X51.H>
void Ewen(void);
void Ewds(void);
void Delay(void);
void Irda(void);
void Study(void);
void Output(unsigned int h);
void Comput(unsigned char outdata);
void Erase(unsigned char Address);
unsigned int Read(unsigned char Address);
unsigned char Display(unsigned char inAddress);
void Write(unsigned char Address,unsigned int InData);
unsigned int Both(unsigned char data1,unsigned char data2);
//Sys_Ma系統(tǒng)碼
//Sys_FMa系統(tǒng)反碼、
//User_Ma用戶碼
//User_FMa用戶反碼
unsigned char data Sys_Ma _at_ 0x1A;//分別存放紅外線譯碼后的數(shù)據(jù)
unsigned char data Sys_FMa _at_ 0x1B;
unsigned char data User_Ma _at_ 0x1C;
unsigned char data User_FMa _at_ 0x1D;
sbit IrInput=P3^2; //紅外線輸入引腳,可自定義
sbit Study_Key=P3^6; //學(xué)習(xí)按鍵,可自定義
sbit Led2=P2^5; //接收成功、學(xué)習(xí)成功指示
sbit Led1=P2^6; //空閑指示
sbit Dout=P2^3; //at93c16--DO
sbit Din=P2^2; //at93c16--DI
sbit sk=P2^1; //at93c16--SK
sbit cs=P2^0; //at93c16--CS
/*******************紅外線查詢子程序*******************/
void Irda(void)
{
/* #pragma asm
MOV R6,#10
SB:
MOV R4,#19 ;延時880微秒
D1:
MOV R5,#19
DJNZ R5,$
DJNZ R4,D1
JB P3.2,EXIT ;延時882微秒后判斷P3.2腳是為1
DJNZ R6, SB ;在8820微秒內(nèi)如P3.2為1就退出
JNB P3.2, $ ;等待高電平避開9毫秒低電平引導(dǎo)脈沖
MOV R4,#10 ;延時4740微秒
D2: MOV R5,#218
DJNZ R5,$
DJNZ R4,D2
;延時4.74毫秒避開4.5毫秒的結(jié)果碼
MOV R1,#1AH ;設(shè)定1AH為起始RAM區(qū)
MOV R2,#4 ;接收從1AH到1DH,用于存放操作碼和操作反碼
PP:
MOV R3,#8 ;每組數(shù)據(jù)為8位
SS:
JNB P3.2,$ ;等待地址碼第一位的高電平信號
MOV R4,#19 ;延時880微秒
D5:
MOV R5,#19
DJNZ R5,$
DJNZ R4,D5
;高電平開始后882微秒判斷信號的高低電平
MOV C,P3.2 ;將P3.2引腳此時的電平狀態(tài)0或1存入C中
JNC TT ;如果為0就跳轉(zhuǎn)到TT
MOV R4,#2 ;延時1000微秒
D6:MOV R5,#248
DJNZ R5,$
DJNZ R4,D6
;檢測到高電平1的話延時1毫秒等待脈沖高電平結(jié)束
TT:
MOV A,@R1 ;將R1中地址的給A
RRC A ;將C中的值0或1移入A中的最低位
MOV @R1,A ;
DJNZ R3,SS ;接收滿8位換一個內(nèi)存
INC R1 ;對R1中的值加1,換下一個RAM
DJNZ R2,PP ;接收完所有數(shù)據(jù)
EXIT:
#pragma endasm */
}
/******************紅外線學(xué)習(xí)程序***************************/
void Study(void)
{
unsigned char Address[9]={0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08};
//
unsigned int j,h,rd,i;
unsigned char k,t,Addr;
EX0=0; //關(guān)外部中斷0
k=0; //給"K"變量賦初值
t=0; //給"t"變量賦初值
Led1=0; //"學(xué)習(xí)燈亮"
for(j=0;j<80;j++) //進入"for"循環(huán)共80次
{ //"for"循環(huán)開始
for(k=0;k<9;k++) //進入"for"循環(huán)共9次
{ //"for"循環(huán)開始
Delay(); //延時
begin: i=20000; //begin:是goto語句中的標號
while(Study_Key) //學(xué)習(xí)鍵按下了嗎?
{ //學(xué)習(xí)鍵未按下
Addr=Display(k);//取EEPROM的存儲地址
if(!IrInput) goto Irda;//有紅外線到來跳轉(zhuǎn)到"Irda"解碼程序。
if(!(i--)) goto end; //如果時間大于8s就退出while學(xué)習(xí)程序
} //退出while語句
Delay();//延時
} //"for"循環(huán)共9次結(jié)束
} //"for"循環(huán)共80次結(jié)束
goto end; //8秒內(nèi)無任何操作轉(zhuǎn)到end;標題語句處
Irda: //Irda:是goto語句中的標號
Irda(); //調(diào)用"Irda"解碼程序
h=Both(Sys_FMa,User_FMa);//將兩個單字節(jié)數(shù)(Sys_FMa,User_FMa)裝配成一個雙字節(jié)數(shù)
if((Sys_Ma!=~Sys_FMa)||(User_Ma!=~User_FMa))//~按位取反
{ //校驗錯誤則接收到的為錯誤碼
goto begin;//返回begin:處
}
for(i=0;i<=8;i++)
{ //進入for循環(huán)
if(h==Read(Address[i])) //將要寫入的數(shù)據(jù)和EEPROM中的八數(shù)據(jù)比較,相同就擦除
{ //防止在存儲單元中出現(xiàn)相同的數(shù)據(jù)
Erase(Address[i]); //擦除at93c46的指定單元程序
} //退出if語句
} //退出for循環(huán)
Write(Addr,h); //寫at93c46指定單元程序
rd=Read(Addr); //at93c46讀程序
if(rd==h) //將讀出的數(shù)據(jù)和寫入的比較
{
Delay();//延時
Led2=0; //學(xué)習(xí)成功Led指示
Delay();
Led2=1;
Delay();
Led2=0; //學(xué)習(xí)成功Led指示
Delay();
Led2=1;
}
end:
P0=0xff; //數(shù)碼管顯示為0
Sys_FMa=User_FMa=0;
EX0=1;//開外中斷0
}
/*********************擦/寫啟動*******************/
void Ewen(void)
{
unsigned char i,InData;//完成寫放數(shù)據(jù):10011XXXX
cs=0;
sk=0;
cs=1;
InData=0x98;
for(i=9;i!=0;i--)
{
Din=InData&0x80;
sk=1;
sk=0;
InData<<=1;
}
cs=0;
}
/*********************擦/寫屏蔽*******************/
void Ewds(void)
{
unsigned char i,InData; //完成寫放數(shù)據(jù):10000XXXX
cs=0;
sk=0;
cs=1;
InData=0x80;
for(i=9;i!=0;i--)
{
Din=InData&0x80;
sk=1;
sk=0;
InData<<=1;
}
cs=0;
}
/*********************at93c46讀程序*******************/
unsigned int Read(unsigned char Address)
{
unsigned char i;
unsigned int result;
sk=0;
Din=1;
cs=0;
cs=1;
sk=1;
sk=0;
Address=Address&0x3f|0x80; //完成寫放數(shù)據(jù):110---加---五位地址
for(i=8;i!=0;i--)
{
Din=Address&0x80;
sk=1;
sk=0;
Address<<=1;
}
Dout=1;
for(i=16;i!=0;i--)
{
sk=1;
result=(result<<1)|Dout;
sk=0;
}
cs=0;
return(result);
}
/*********************at93c46寫指定單元程序*******************/
void Write(unsigned char Address,unsigned int InData)
{
unsigned char i;
Ewen();
sk=0;
Din=1;
cs=0;
cs=1;
sk=1;
sk=0;
Address=Address&0x3f|0x40; //完成寫放數(shù)據(jù):101---加---五位地址
for(i=8;i!=0;i--)
{
Din=Address&0x80;
sk=1;
sk=0;
Address<<=1;
}
for(i=16;i!=0;i--)
{
Din=InData&0x8000;
sk=1;
sk=0;
InData<<=1;
}
cs=0;
Dout=1;
cs=1;
sk=1;
while(Dout==0) //忙
{
sk=0;
sk=1;
}
sk=0;
cs=0;
Ewds();
}
/*********************at93c46擦除指定單元程序*******************/
void Erase(unsigned char Address)
{
unsigned char i;
Ewen();
sk=0;
Din=1;
cs=0;
cs=1;
sk=1;
sk=0;
Address|=0xc0;
for(i=8;i!=0;i--)
{
Din=Address&0x80; //完成寫放數(shù)據(jù):111---加---五位地址
sk=1;
sk=0;
Address<<=1;
}
cs=0;
Dout=1;
cs=1;
sk=1;
while(Dout==0)
{
sk=0;
sk=1;
}
sk=0;
cs=0;
Ewds();
}
/*將兩個單字節(jié)數(shù)裝配成一個雙字節(jié)數(shù)*/
unsigned int Both(unsigned char data1,unsigned char data2)
{
unsigned int dat;
dat|=data1;
dat<<=8;
dat|=data2;
return(dat);
}
/*顯示輸出和取EEPROM地址*/
unsigned char Display(unsigned char inAddress)
{
unsigned char Address[9]={0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08};//存放EEPROM的存儲地址
unsigned char disp[9]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80};//存放顯示數(shù)據(jù)
unsigned char Addr1,i;
for(i=0;i<=8;i++)
{
if(inAddress==i)
{
Addr1=Address[inAddress];//取EEPROM地址
P0=disp[inAddress]; //顯示輸出
break;
}
else P0=disp[0];
}
return(Addr1);
}
/*顯示輸出和控制輸出*/
void Output(unsigned int h)
{
unsigned char Address[9]={0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08};
unsigned char disp[9]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80};
Led2=0;//學(xué)習(xí)成功
if(h==Read(Address[0]))
{ //無對應(yīng)控制碼
P1=0xff;//關(guān)所有的繼電器
P0=disp[0];goto end;//顯示0
}
if(h==Read(Address[1]))
{
P1_0=~P1_0;//操作1號繼電器
P0=disp[1];goto end;//顯示1
}
if(h==Read(Address[2]))
{
P1_1=~P1_1;//操作2號繼電器
P0=disp[2];goto end;//顯示2
}
if(h==Read(Address[3]))
{
P1_2=~P1_2;//操作2號繼電器
P0=disp[3];goto end;//顯示3
}
if(h==Read(Address[4]))
{
P1_3=~P1_3;//操作3號繼電器
P0=disp[4];goto end;//顯示4
}
if(h==Read(Address[5]))
{
P1_4=~P1_4;//操作4號繼電器
P0=disp[5];goto end;//顯示5
}
if(h==Read(Address[6]))
{
P1_5=~P1_5;//操作5號繼電器
P0=disp[6];goto end;//顯示6
}
if(h==Read(Address[7]))
{
P1_6=~P1_6;//操作6號繼電器
P0=disp[7];goto end;//顯示7
}
if(h==Read(Address[8]))
{
P1_7=~P1_7;//操作7號繼電器
P0=disp[8];goto end;//顯示8
}
end:Delay();//延時
Led2=1; //學(xué)習(xí)成功燈滅
}
/*外部中斷0服務(wù)程序*/
void int0_int(void) interrupt 0
{ //紅外接收中斷服務(wù)函數(shù)
unsigned int h;
EX0=0; //關(guān)閉中斷
Irda(); //紅外譯碼
if((Sys_Ma==~Sys_FMa)&&(User_Ma==~User_FMa))//判斷系統(tǒng)碼與系統(tǒng)反碼、
//用戶碼與用戶反碼是否正確
{ //校驗正確
h=Both(Sys_FMa,User_FMa);//將系統(tǒng)反碼(Sys_FMa),和用戶反碼(User_FMa)
//兩個單字節(jié)數(shù)裝配成一個雙字節(jié)數(shù)
Comput(Sys_FMa); //串口輸出系統(tǒng)反碼遙控數(shù)據(jù),可以用軟件對電腦進行遙控
Comput(User_FMa);//串口輸出用戶反碼遙控數(shù)據(jù)
Output(h); /*顯示輸出和控制輸出,接收成功*/
Sys_FMa=User_FMa=0;//防止下一次誤判斷
}//退出if語句
EX0 = 1;//開中斷
}//退出中斷
/***********************串口輸出**********************/
void Comput(unsigned char outdata)
{
SBUF = outdata;
while(!TI);
TI = 0;
}
/*****************延時程序**********************/
void Delay()
{
unsigned int i,j;
for(i=0;i<2;i++)
for(j=0;j<30000;j++);
}
/*********************主程序***************************/
void main(void)
{
unsigned int i;
SCON = 0x50; //串口方式1,允許接收
TMOD = 0x20; //定時器1定時方式2
TH1 = 0xFD; //波特率9600
TL1 = 0xFD;
IT0 = 1; //INT0下降沿有效
EX0 = 1; //開INT0中斷;
TR1 = 1; //啟動定時器
P2_7=0; //初始化引腳
P1=0xff;
EA = 1; //允許CPU中斷
while(1)
{ //進入while循環(huán)
for(i=0; i<20000; i++)
{
Led1=1;//"學(xué)習(xí)燈滅"
if(!Study_Key) Study();//查詢"KEY"是否按下,按下進入學(xué)習(xí)狀態(tài)
}//for循環(huán)結(jié)束
for(i=0; i<20000; i++)
{
Led1=0;//"學(xué)習(xí)燈亮"
if(!Study_Key) Study();//查詢"KEY"是否按下,按下進入學(xué)習(xí)狀態(tài)
}//for循環(huán)結(jié)束
}//while循環(huán)結(jié)束
}//主程序結(jié)束
?? 快捷鍵說明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -