红外遥控器的解码

2020-01-22 12:01发布

红外遥控器的解码
实测距离10米时不会错误或需要重复按遥控器 (*^__^*) ……


接收头 (原文件名:接收头.jpg.jpg)


正确解码 (原文件名:20110103426.jpg)
第一行显示的是:地址码+地址码+操作码+操作码反码  接受数据正确时第二行显示OK  旁边的数字是连_发次数


错误解码 (原文件名:20110103427.jpg)
第一行显示的是:地址码+地址码+操作码+操作码反码  接受数据错误时第二行显示error  旁边的数字是连_发次数


51开发板配的万能遥控器 (原文件名:20110103428.jpg)
友情提示: 此问题已得到解决,问题已经关闭,关闭后问题禁止继续编辑,回答。
该问题目前已经被作者或者管理员关闭, 无法添加新回复
97条回答
ye955
1楼-- · 2020-01-28 20:50
其实只有笨人才会用外中断做红外遥控接收!!!!因为单片机的外中断端口一般都不多,所以真正产品上不是这样做的!我的方法是利用内部定时器做个125us中断,来查询端口电平从而实现遥控接收。

/*红外遥控接收板*/
/*程序:伍耀斌   13715528667     版本号:2010-8-31*
资源分配:AT89C2051 p3.1用作指示灯驱动(低电平触发)
          p1.1~1.6用作继电器(高电平触发)
                  P1.7用作遥控接收
          */


#include <AT89X52.h>

#define uchar unsigned char   //定义为无符号字付   ~~typedef unsigned char uchar;
#define uint unsigned int    //~~typedef unsigned int uint;

// 定义说明:
//RAM区定义  全部大写
//数值定义   全部小写
//地址标号   首字母大写,其余小写

//uchar code BitTab[]={0xfe,0xfd,0xfb,0xf7,0xef,0xdf};  //11111110,11111101,11111011,11110111,11101111,11011111
//uchar code DispTab[]={0xC0,0xF9,0xA4,0xB0,0x99,0x92,0x82,0xF8,0x80,0x90,0xFF};
//{0xC0,0xF9,0xA4,0xB0,0x99,0x92,0x82,0xF8,0x80,0x90,0xFF};  新板,段位没有加2003
//{0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F,0x00};  旧板,段位没有加2003
//uchar DispBuf[4];   //四位扫描


//unsigned char codes[8]={0x08,0x0c,0x04,0x06,0x02,0x03,0x01,0x09};// 顺时针
                           //{0x0b,0x09,0x0d,0x0c,0x0e,0x06,0x07,0x03}}; //9,18,36,45,54,63,72,81度 逆时针{0x08,0x0c,0x04,0x06,0x02,0x03,0x01,0x09}

static uchar ONE;     //存放个位数据
static uchar TWO;     //存放十位数据
static uchar THREE;   //存放百位数据
static uchar FOUR;    //存放千位数据
static uchar FIVE;
static uchar SIX;
static uchar SEVEN;
static uchar EIGHT;



static uint  TS;      //定义为静态变量 Ts=5msX200=1000ms=1S
//static uchar  TS;
static uchar SEC;     //秒变量
static uchar MIN;     //分变量
static uchar HOUR;    //小时变量
static uchar KEY;     //放键值(做系这里的目的是为了以后可以随时调用)
static uchar SET;     

static uchar CODE;   //码变量


static uchar counts;
static uchar TSS;
static uchar TP;
static uchar SPstait;


static uchar codeTime;
static uchar HeadCode_Reced;

static uchar HeadCode;
static uchar IrFallEdge;

static uchar Ir_Dealed;
static uchar Irprot_LastState;
static uchar Receive_OK;
static uchar codeCnt;


static uchar vData1;
static uchar vData2;
static uchar vData3;
static uchar vData4;
static uchar vData;


//============================================================
void Time (void);    //时间处理
void Light(void);    //灯控制子程序
void Sp (void);    //蜂鸣器子程序

//============================================================

void main(void)
{
TMOD=0x01;    //定时器1用0模式,定时器0用1模式00000001
TH0=(65536-125)/256;    //取整数
TL0=(65536-125)%256;    //取余数

TH1=(8192-1500)/32;     //用正常的8M为2000,但用瑞德的8M经补偿后为
TL1=(8192-1500)%32;
//IE=0x8A;
TR0=1;      //开定时器
TR1=1;   
EA=1;       //开总中断
ET0=1;      //开定时器1中断
ET1=1;
//--------付初值区-----------
TS=0;
TSS=0;
SEC=0;

MIN=0;
HOUR=0;

CODE=0;
  P3_1=1;
  P3_2=1;
  P3_0=0;
  P1_1=0;
  P1_2=0;
  P1_3=0;
  P1_4=0;
  P1_5=0;
  P1_6=0;
  P1_7=1;


//P3=0;  //由于驱动电路是高电平触发,所发未开机前需对端口付0

vData1=vData2=vData3=vData4=0;


//---------------------------


while(1)   //嚟度放以后要添加的服务子程序
{
  Time ();     //时间处理程序
  Light();
  Sp();
}
}
//=================================================================
/*内中断0 用于计时*/
void Timer0(void) interrupt 1 //开定时器0中断,工作于方式0,中断号为1
{
TH0=(65536-70)/256;     //125ms出中断一次.用瑞德的8M经补偿后为70
TL0=(65536-70)%256;

    TS++;
        TP++;

        //P3_1=~P3_1;

    if(TS==80)    //Ts=125us*80=10ms
      {TS=0;
           TSS++;   
       }         
//====================================================================================
        codeTime++;
    if(codeTime>=80)
    {
     codeTime=80;
     HeadCode_Reced=0;//80*125us=10ms时间未接收到低电平信号则清头码接收标志位
     Ir_Dealed=0;
         
    }

//-------------------------------------------------
    P1_7=1;     //先给该口付1
   
    if(P1_7==1)
    {
     Irprot_LastState=1;//置接收端口为1状态标志
     }
//---------------------------------------------------------------------
    else    //该口出现了低电平证明有可能是收到红外信号
    {
       if(Irprot_LastState)    //出现低电平后如证实之前出现高电平,证明确实是有红外信号
       {
         Irprot_LastState=0;//  将接收状态清0
                 
           if(HeadCode_Reced)//查询是否已接收过头码。有就进入解码,无就进入头码(4.5ms计时)
           {
              // vData4<<=1;
                          // if(vData3&0x80){vData4|=0x01;}
                          // vData3<<=1;
                          // if(vData2&0x80){vData3|=0x01;}
                          // vData2<<=1;
                          // if(vData1&0x80){vData2|=0x01;}
                          // vData1<<=1;
                          

                       
                      if(codeTime>15&&codeTime<21)//若头码已接收过,则判断当前接收的是1码或0码   //FTM2->8-<16-11(125*11=1.375,示波器读出0为0.8ms1为1.6ms)
               {                                                                         //HFJ->15-<21--11(125*15=1.875,示波器读出0为1.2ms1为2.4ms)
                vData|=0x01;  //两个下降沿之间的时间大于125us*11=1.375ms,条件满足则接收的为1码
               }
              else if(codeTime>6&&codeTime<12)    //HFJ->6-<12
                                                             //FTN2->3-<8
               {
                vData&=0xFE; ;  //两个下降沿之间的时间小于125us*12=15ms条件不满足则接收的为0码
               }
                          else
               {
                            vData1=vData2=vData3=vData4=0;
                HeadCode_Reced=0;
                           }

//==================================================
                                switch(codeCnt)
                           {case 7: vData1=vData; vData=0;
                            case 15: vData2=vData; vData=0;
                                case 23: vData3=vData; vData=0;
                                case 31: vData4=vData; vData=0;
                                }
                            

                            vData<<=1;
//=======================================================
//-------------------------------------------------------------------------
              codeCnt++;
              if(codeCnt>=32)    //一共接收32个信号位
               {
                 codeCnt=0;
                 if(!Ir_Dealed)
                   {
                    Receive_OK=1;

                               }
               }

             codeTime=0;  //接收完,将时间清0
                         //vData1=vData2=vData3=vData4=0;
          }
                  
                  

         else    //头码总计时   
         {
           if(codeTime>=80&&codeTime<120)    //30   46(FTM2--3.750~5.750计的是低电平+高电平的总时间,即两个下降沿时间.示波器读出是4.9ms)      
            {                               // 80   120(HFJ--10~15ms 计的是低电平+高电平的总时间,即两个下降沿时间.示波器读出是13.6ms)
              HeadCode_Reced=1;
            }
            else
             {
               HeadCode_Reced=0;
              }
            codeCnt=0;      //如果是第一次进入则将码计时时间codeTime与码位codeCnt清0
            codeTime=0;
         }
      }
     }
       
}

//======================================================================
/*内中断1 用于扫描显示*/
void Timer1(void) interrupt 3  //2m扫描显示程序。开定时器1中断,工作于方式0  "void 函数名() interrupt 中断号 using 工作组"
{//uchar tmp;                 //     中断号命名:外中断0为0、内部时钟中断0为1、外中断1为2、内部时钟中断1为3
//static uchar COUNT;    //原为这个,现换下面的
TH1=(8192-1500)/32;     //用正常的8M为2000,但用瑞德的8M经补偿后为
TL1=(8192-1500)%32;
   
}

//================================================================
/*时间处理子程序*/
void Time (void)
{if(TSS==100)    //TSS=10msX100=1000ms=1S  修定为91
      {TSS=0;
           SEC++;  

           //P3_0=~P3_0;

       }   
   
    if(SEC==60)
          {SEC=0;
           MIN++;  
          }
       
        if(MIN==60)
      {MIN=1;
           HOUR++;
          }
   

    if(HOUR==13)
      {HOUR=1;
      }
       
}



//===========================================================================
//灯控制
void Light (void)
{  
        if(vData1==0x08&&vData4==0x17)
        {P3_1=1; P1_6=0;P1_5=0;P1_4=0;P1_3=0;P1_2=0;}

        else if(vData1==0x08&&vData4==0x1F)
        //{P3_1=0;P1_5=1;}
        {P1_7=0;P3_0=1;}
        else if(vData1==0x08&&vData4==0x9F)
        //{P3_1=1; P1_5=0;}
        {P1_7=1;P3_0=0;}

        else if(vData1==0x08&&vData4==0xC7)
        {P3_1=0;P1_4=1;}
        else if(vData1==0x08&&vData4==0x57)
        {P3_1=1;P1_4=0;}

        else if(vData1==0x08&&vData4==0x3F)
        {P3_1=0;P1_6=1;}
        else if(vData1==0x08&&vData4==0x5F)
        {P3_1=1;P1_6=0;}
       
        }

void Sp (void)
{ if(SPstait==1)
  {if(TP==2)    //Ts=125us*80=10ms
      {TS=0;
           P3_2=~P3_2;   
       }
           }   
}
ye955
2楼-- · 2020-01-28 22:35
其实只有笨人才会用外中断做红外遥控接收!!!!因为单片机的外中断端口一般都不多,所以真正产品上不是这样做的!我的方法是利用内部定时器做个125us中断,来查询端口电平从而实现遥控接收。

/*红外遥控接收板*/
/*程序:伍耀斌   13715528667     版本号:2010-8-31*
资源分配:AT89C2051 p3.1用作指示灯驱动(低电平触发)
          p1.1~1.6用作继电器(高电平触发)
                  P1.7用作遥控接收
          */


#include <AT89X52.h>

#define uchar unsigned char   //定义为无符号字付   ~~typedef unsigned char uchar;
#define uint unsigned int    //~~typedef unsigned int uint;

// 定义说明:
//RAM区定义  全部大写
//数值定义   全部小写
//地址标号   首字母大写,其余小写

//uchar code BitTab[]={0xfe,0xfd,0xfb,0xf7,0xef,0xdf};  //11111110,11111101,11111011,11110111,11101111,11011111
//uchar code DispTab[]={0xC0,0xF9,0xA4,0xB0,0x99,0x92,0x82,0xF8,0x80,0x90,0xFF};
//{0xC0,0xF9,0xA4,0xB0,0x99,0x92,0x82,0xF8,0x80,0x90,0xFF};  新板,段位没有加2003
//{0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F,0x00};  旧板,段位没有加2003
//uchar DispBuf[4];   //四位扫描


//unsigned char codes[8]={0x08,0x0c,0x04,0x06,0x02,0x03,0x01,0x09};// 顺时针
                           //{0x0b,0x09,0x0d,0x0c,0x0e,0x06,0x07,0x03}}; //9,18,36,45,54,63,72,81度 逆时针{0x08,0x0c,0x04,0x06,0x02,0x03,0x01,0x09}

static uchar ONE;     //存放个位数据
static uchar TWO;     //存放十位数据
static uchar THREE;   //存放百位数据
static uchar FOUR;    //存放千位数据
static uchar FIVE;
static uchar SIX;
static uchar SEVEN;
static uchar EIGHT;



static uint  TS;      //定义为静态变量 Ts=5msX200=1000ms=1S
//static uchar  TS;
static uchar SEC;     //秒变量
static uchar MIN;     //分变量
static uchar HOUR;    //小时变量
static uchar KEY;     //放键值(做系这里的目的是为了以后可以随时调用)
static uchar SET;     

static uchar CODE;   //码变量


static uchar counts;
static uchar TSS;
static uchar TP;
static uchar SPstait;


static uchar codeTime;
static uchar HeadCode_Reced;

static uchar HeadCode;
static uchar IrFallEdge;

static uchar Ir_Dealed;
static uchar Irprot_LastState;
static uchar Receive_OK;
static uchar codeCnt;


static uchar vData1;
static uchar vData2;
static uchar vData3;
static uchar vData4;
static uchar vData;


//============================================================
void Time (void);    //时间处理
void Light(void);    //灯控制子程序
void Sp (void);    //蜂鸣器子程序

//============================================================

void main(void)
{
TMOD=0x01;    //定时器1用0模式,定时器0用1模式00000001
TH0=(65536-125)/256;    //取整数
TL0=(65536-125)%256;    //取余数

TH1=(8192-1500)/32;     //用正常的8M为2000,但用瑞德的8M经补偿后为
TL1=(8192-1500)%32;
//IE=0x8A;
TR0=1;      //开定时器
TR1=1;   
EA=1;       //开总中断
ET0=1;      //开定时器1中断
ET1=1;
//--------付初值区-----------
TS=0;
TSS=0;
SEC=0;

MIN=0;
HOUR=0;

CODE=0;
  P3_1=1;
  P3_2=1;
  P3_0=0;
  P1_1=0;
  P1_2=0;
  P1_3=0;
  P1_4=0;
  P1_5=0;
  P1_6=0;
  P1_7=1;


//P3=0;  //由于驱动电路是高电平触发,所发未开机前需对端口付0

vData1=vData2=vData3=vData4=0;


//---------------------------


while(1)   //嚟度放以后要添加的服务子程序
{
  Time ();     //时间处理程序
  Light();
  Sp();
}
}
//=================================================================
/*内中断0 用于计时*/
void Timer0(void) interrupt 1 //开定时器0中断,工作于方式0,中断号为1
{
TH0=(65536-70)/256;     //125ms出中断一次.用瑞德的8M经补偿后为70
TL0=(65536-70)%256;

    TS++;
        TP++;

        //P3_1=~P3_1;

    if(TS==80)    //Ts=125us*80=10ms
      {TS=0;
           TSS++;   
       }         
//====================================================================================
        codeTime++;
    if(codeTime>=80)
    {
     codeTime=80;
     HeadCode_Reced=0;//80*125us=10ms时间未接收到低电平信号则清头码接收标志位
     Ir_Dealed=0;
         
    }

//-------------------------------------------------
    P1_7=1;     //先给该口付1
   
    if(P1_7==1)
    {
     Irprot_LastState=1;//置接收端口为1状态标志
     }
//---------------------------------------------------------------------
    else    //该口出现了低电平证明有可能是收到红外信号
    {
       if(Irprot_LastState)    //出现低电平后如证实之前出现高电平,证明确实是有红外信号
       {
         Irprot_LastState=0;//  将接收状态清0
                 
           if(HeadCode_Reced)//查询是否已接收过头码。有就进入解码,无就进入头码(4.5ms计时)
           {
              // vData4<<=1;
                          // if(vData3&0x80){vData4|=0x01;}
                          // vData3<<=1;
                          // if(vData2&0x80){vData3|=0x01;}
                          // vData2<<=1;
                          // if(vData1&0x80){vData2|=0x01;}
                          // vData1<<=1;
                          

                       
                      if(codeTime>15&&codeTime<21)//若头码已接收过,则判断当前接收的是1码或0码   //FTM2->8-<16-11(125*11=1.375,示波器读出0为0.8ms1为1.6ms)
               {                                                                         //HFJ->15-<21--11(125*15=1.875,示波器读出0为1.2ms1为2.4ms)
                vData|=0x01;  //两个下降沿之间的时间大于125us*11=1.375ms,条件满足则接收的为1码
               }
              else if(codeTime>6&&codeTime<12)    //HFJ->6-<12
                                                             //FTN2->3-<8
               {
                vData&=0xFE; ;  //两个下降沿之间的时间小于125us*12=15ms条件不满足则接收的为0码
               }
                          else
               {
                            vData1=vData2=vData3=vData4=0;
                HeadCode_Reced=0;
                           }

//==================================================
                                switch(codeCnt)
                           {case 7: vData1=vData; vData=0;
                            case 15: vData2=vData; vData=0;
                                case 23: vData3=vData; vData=0;
                                case 31: vData4=vData; vData=0;
                                }
                            

                            vData<<=1;
//=======================================================
//-------------------------------------------------------------------------
              codeCnt++;
              if(codeCnt>=32)    //一共接收32个信号位
               {
                 codeCnt=0;
                 if(!Ir_Dealed)
                   {
                    Receive_OK=1;

                               }
               }

             codeTime=0;  //接收完,将时间清0
                         //vData1=vData2=vData3=vData4=0;
          }
                  
                  

         else    //头码总计时   
         {
           if(codeTime>=80&&codeTime<120)    //30   46(FTM2--3.750~5.750计的是低电平+高电平的总时间,即两个下降沿时间.示波器读出是4.9ms)      
            {                               // 80   120(HFJ--10~15ms 计的是低电平+高电平的总时间,即两个下降沿时间.示波器读出是13.6ms)
              HeadCode_Reced=1;
            }
            else
             {
               HeadCode_Reced=0;
              }
            codeCnt=0;      //如果是第一次进入则将码计时时间codeTime与码位codeCnt清0
            codeTime=0;
         }
      }
     }
       
}

//======================================================================
/*内中断1 用于扫描显示*/
void Timer1(void) interrupt 3  //2m扫描显示程序。开定时器1中断,工作于方式0  "void 函数名() interrupt 中断号 using 工作组"
{//uchar tmp;                 //     中断号命名:外中断0为0、内部时钟中断0为1、外中断1为2、内部时钟中断1为3
//static uchar COUNT;    //原为这个,现换下面的
TH1=(8192-1500)/32;     //用正常的8M为2000,但用瑞德的8M经补偿后为
TL1=(8192-1500)%32;
   
}

//================================================================
/*时间处理子程序*/
void Time (void)
{if(TSS==100)    //TSS=10msX100=1000ms=1S  修定为91
      {TSS=0;
           SEC++;  

           //P3_0=~P3_0;

       }   
   
    if(SEC==60)
          {SEC=0;
           MIN++;  
          }
       
        if(MIN==60)
      {MIN=1;
           HOUR++;
          }
   

    if(HOUR==13)
      {HOUR=1;
      }
       
}



//===========================================================================
//灯控制
void Light (void)
{  
        if(vData1==0x08&&vData4==0x17)
        {P3_1=1; P1_6=0;P1_5=0;P1_4=0;P1_3=0;P1_2=0;}

        else if(vData1==0x08&&vData4==0x1F)
        //{P3_1=0;P1_5=1;}
        {P1_7=0;P3_0=1;}
        else if(vData1==0x08&&vData4==0x9F)
        //{P3_1=1; P1_5=0;}
        {P1_7=1;P3_0=0;}

        else if(vData1==0x08&&vData4==0xC7)
        {P3_1=0;P1_4=1;}
        else if(vData1==0x08&&vData4==0x57)
        {P3_1=1;P1_4=0;}

        else if(vData1==0x08&&vData4==0x3F)
        {P3_1=0;P1_6=1;}
        else if(vData1==0x08&&vData4==0x5F)
        {P3_1=1;P1_6=0;}
       
        }

void Sp (void)
{ if(SPstait==1)
  {if(TP==2)    //Ts=125us*80=10ms
      {TS=0;
           P3_2=~P3_2;   
       }
           }   
}
kaimpf
3楼-- · 2020-01-28 23:21
 精彩回答 2  元偷偷看……
ye955
4楼-- · 2020-01-29 01:52
回复【63楼】kaimpf
-----------------------------------------------------------------------

1、51的芯片一般只有两个外中断!外中断一般是用来做通信等高时序要求的。
2、对于家电类产品(如风扇、电暧器)在布板时对芯片的端口引出的位置有时可能很有要求(如板小,或者走线不便),所以如果只能用外中断来做接收端口是不太可能的。
3、我上述用的中断做法是采用查询方式(请细睇程序),即是在接收信号时不用在主程序中做延时子程序(浪费系统时间)。
4、我是在顺德瑞德电子开发部做电控板设计(主要客户有:美的生活电器、美的环境、九阳、东菱、山瑚风扇),或者你可能随便拆台如“美的”的风扇或者电暧器,看一看就明白。他们多用合泰或松瀚或三星的9454单片机。有时连复位口也用上来做遥控接收。反正我们公司开发部就没有一人会用外中断口来做遥控接收!
wpnx
5楼-- · 2020-01-29 05:57
学习 mark
ERDTxiduoduo
6楼-- · 2020-01-29 10:26
MARK

一周热门 更多>