📄 学习型红外线遥控程序.c
字号:
/*************晶体为11.0592M,波特率9600bps
***************学习型红外线遥控程序*******/
#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系统码
//Sys_FMa系统反码、
//User_Ma用户码
//User_FMa用户反码
unsigned char data Sys_Ma _at_ 0x1A;//分别存放红外线译码后的数据
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; //学习按键,可自定义
sbit Led2=P2^5; //接收成功、学习成功指示
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微秒内如P3.2为1就退出
JNB P3.2, $ ;等待高电平避开9毫秒低电平引导脉冲
MOV R4,#10 ;延时4740微秒
D2: MOV R5,#218
DJNZ R5,$
DJNZ R4,D2
;延时4.74毫秒避开4.5毫秒的结果码
MOV R1,#1AH ;设定1AH为起始RAM区
MOV R2,#4 ;接收从1AH到1DH,用于存放操作码和操作反码
PP:
MOV R3,#8 ;每组数据为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引脚此时的电平状态0或1存入C中
JNC TT ;如果为0就跳转到TT
MOV R4,#2 ;延时1000微秒
D6:MOV R5,#248
DJNZ R5,$
DJNZ R4,D6
;检测到高电平1的话延时1毫秒等待脉冲高电平结束
TT:
MOV A,@R1 ;将R1中地址的给A
RRC A ;将C中的值0或1移入A中的最低位
MOV @R1,A ;
DJNZ R3,SS ;接收满8位换一个内存
INC R1 ;对R1中的值加1,换下一个RAM
DJNZ R2,PP ;接收完所有数据
EXIT:
#pragma endasm */
}
/******************红外线学习程序***************************/
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; //关外部中断0
k=0; //给"K"变量赋初值
t=0; //给"t"变量赋初值
Led1=0; //"学习灯亮"
for(j=0;j<80;j++) //进入"for"循环共80次
{ //"for"循环开始
for(k=0;k<9;k++) //进入"for"循环共9次
{ //"for"循环开始
Delay(); //延时
begin: i=20000; //begin:是goto语句中的标号
while(Study_Key) //学习键按下了吗?
{ //学习键未按下
Addr=Display(k);//取EEPROM的存储地址
if(!IrInput) goto Irda;//有红外线到来跳转到"Irda"解码程序。
if(!(i--)) goto end; //如果时间大于8s就退出while学习程序
} //退出while语句
Delay();//延时
} //"for"循环共9次结束
} //"for"循环共80次结束
goto end; //8秒内无任何操作转到end;标题语句处
Irda: //Irda:是goto语句中的标号
Irda(); //调用"Irda"解码程序
h=Both(Sys_FMa,User_FMa);//将两个单字节数(Sys_FMa,User_FMa)装配成一个双字节数
if((Sys_Ma!=~Sys_FMa)||(User_Ma!=~User_FMa))//~按位取反
{ //校验错误则接收到的为错误码
goto begin;//返回begin:处
}
for(i=0;i<=8;i++)
{ //进入for循环
if(h==Read(Address[i])) //将要写入的数据和EEPROM中的八数据比较,相同就擦除
{ //防止在存储单元中出现相同的数据
Erase(Address[i]); //擦除at93c46的指定单元程序
} //退出if语句
} //退出for循环
Write(Addr,h); //写at93c46指定单元程序
rd=Read(Addr); //at93c46读程序
if(rd==h) //将读出的数据和写入的比较
{
Delay();//延时
Led2=0; //学习成功Led指示
Delay();
Led2=1;
Delay();
Led2=0; //学习成功Led指示
Delay();
Led2=1;
}
end:
P0=0xff; //数码管显示为0
Sys_FMa=User_FMa=0;
EX0=1;//开外中断0
}
/*********************擦/写启动*******************/
void Ewen(void)
{
unsigned char i,InData;//完成写放数据: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; //完成写放数据: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; //完成写放数据: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; //完成写放数据: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; //完成写放数据: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();
}
/*将两个单字节数装配成一个双字节数*/
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};//存放显示数据
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;//学习成功
if(h==Read(Address[0]))
{ //无对应控制码
P1=0xff;//关所有的继电器
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; //学习成功灯灭
}
/*外部中断0服务程序*/
void int0_int(void) interrupt 0
{ //红外接收中断服务函数
unsigned int h;
EX0=0; //关闭中断
Irda(); //红外译码
if((Sys_Ma==~Sys_FMa)&&(User_Ma==~User_FMa))//判断系统码与系统反码、
//用户码与用户反码是否正确
{ //校验正确
h=Both(Sys_FMa,User_FMa);//将系统反码(Sys_FMa),和用户反码(User_FMa)
//两个单字节数装配成一个双字节数
Comput(Sys_FMa); //串口输出系统反码遥控数据,可以用软件对电脑进行遥控
Comput(User_FMa);//串口输出用户反码遥控数据
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循环
for(i=0; i<20000; i++)
{
Led1=1;//"学习灯灭"
if(!Study_Key) Study();//查询"KEY"是否按下,按下进入学习状态
}//for循环结束
for(i=0; i<20000; i++)
{
Led1=0;//"学习灯亮"
if(!Study_Key) Study();//查询"KEY"是否按下,按下进入学习状态
}//for循环结束
}//while循环结束
}//主程序结束
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -