⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 学习型红外线遥控程序.c

📁 25811226hongwaigooog.rar
💻 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 + -