搜索
bottom↓
回复: 154

红外遥控器的解码

[复制链接]

出0入0汤圆

发表于 2011-1-3 17:03:27 | 显示全部楼层 |阅读模式
红外遥控器的解码
实测距离10米时不会错误或需要重复按遥控器 (*^__^*) ……


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


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


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


51开发板配的万能遥控器 (原文件名:20110103428.jpg)

阿莫论坛20周年了!感谢大家的支持与爱护!!

知道什么是神吗?其实神本来也是人,只不过神做了人做不到的事情 所以才成了神。 (头文字D, 杜汶泽)

出0入0汤圆

 楼主| 发表于 2011-1-3 17:11:53 | 显示全部楼层
=====================================H文件========================================================

#ifndef DECODE_H_
#define DECODE_H_


/******************************************************************/
/*                     函 数 声 明                                */
/******************************************************************/
void Timer0init(void);//定时器0初始化
void EX0init(void);   //外部中断初始化
void Decode(void);    //解码子程序
void get_IRkey(void);  //键处理


/******************************************************************/
/*                     宏  定  义  区                             */
/*  由于遥控器和程序存在一定误差,必须允许编码时长有一定的范围    */
/*  以下定义了时长和范围以及本机地址。用于调试                    */
/******************************************************************/
#define IR_addr1 0x0a                                //本机地址1
#define IR_addr2 0x0a                                //本机地址2
#define Guide_timer 39                            //引导码最短时长
#define Continuous_timer 39         //连_发码最短时长
#define IR_L_timer_min 3                        //数据0 最短时长
#define IR_L_timer_max 7                        //数据0 最长时长
#define IR_H_timer_min 8                        //数据1 最短时长
#define IR_H_timer_max 12                        //数据1 最长时长
#define TIMER0_COUNT 0x1f                //定时器定时时间
#define Timeout_cnt 250                            //超时时长

/******************************************************************/
/*                    变  量  保  存  区                          */
/******************************************************************/
static unsigned char Timer0_cnt;                        //定时器计数值
static unsigned char Timer0_cnt_bk;
static bit timeout;                                                        //超时标志
static bit Guide;                                                    //引导码有效
static bit Continuous;                      //连_发码
static unsigned char IR_time[33];                        //保存每两个下降沿之间的时间间隔


/******************************************************************/
/*                       结  构  体  区                           */
/* 保存一次解码后接受到的四字节数据                               */
/******************************************************************/
static struct IR_data                                //红外接收数据寄存
{
unsigned char addr1;                                //地址1(客户码1)
unsigned char addr2;                                //地址2(客户码2)
unsigned char data1;                                //数据1(数据码)
unsigned char data2;                                //数据2(数据码反码)
}IR_data;


#endif


/************ 编解码说明 ***************

引导码+地址吗+地址码+数据码+数据码反码+连_发码+...

引导码:9ms低电平+4.5ms 高电平
连_发码:9ms低电平+2.25ms高电平
数据0:0.56ms低电平+0.56ms高电平
数据1:0.56ms低电平+1.69ms高电平

*****************************************/




=====================================C文件========================================================

/******************************************************************/
/*                   红 外 遥 控 解 码                            */
/* CPU & XTAL :89c52 @ 12Mhz                                     */
/* 支持的红外编码方案: NEC6121                                   */
/* 编码格式:引导信号(或连_发信号)+地址码+地址码+控制码+控制码反码 */
/******************************************************************/


#include "decode.h"
#include "display.c"


/******************************************************************/
/*                   定时器0初始化                                */
/*                   定时值:225us                                */
/*                   方式2 自动重载                               */
/******************************************************************/
void Timer0init(void)//定时器0初始化
{
  //定时值 225us
  TMOD=0x02;//定时器0工作方式2 自动重载
  TH0=TIMER0_COUNT; //重载值
  TL0=TIMER0_COUNT; //初始化值
  ET0=1;    //定时器0中断有效
  TR0=1;    //定时开始
}


/******************************************************************/
/*                   外部中断初始化                               */
/*                   中断端口:外部中断0 P3.2                     */
/*                   触发方式:下降沿                             */
/******************************************************************/
void EX0init(void)
{
EA = 1;    //总中断开
IT0 = 1;   //指定外部中断0下降沿触发,INT0 (P3.2)
EX0 = 1;   //外部中断有效
}


/******************************************************************/
/*                   Timer0中断子程序                             */
/******************************************************************/
void Timer0(void) interrupt 1 using 1
{
Timer0_cnt++;
if(Timer0_cnt>Timeout_cnt)
timeout=1;                                         //超时标志
}


/******************************************************************/
/*                    外部中断0函数                               */
/* 下降沿触发                                                  */
/******************************************************************/
void ex0_isr (void) interrupt 0 using 0
{
static unsigned char m=0;
Timer0_cnt_bk=Timer0_cnt; //备份时间计数值,即前一个下降沿到本下降沿的时间间隔
Timer0_cnt=0x00;                  //清空时间计数值


if(timeout)                   //如果超时
{
TL0=TIMER0_COUNT;  //初始化定时器0
Timer0_cnt=0x00;   //清空时间计数值
timeout=0;                   //清除超时标志
Guide=0;           //清除引导标志
Continuous=0;      //清除连_发标志
m=0;                           //复位数据位
}
else
{
if(Guide|Continuous)                   //如果引导码有效
  {
  IR_time[m++]=Timer0_cnt_bk;         //保存时间间隔
   if(m==32)                                         //接收够32数据后
    {
     m=0;
         Guide=0;                                         //清除引导标志
     Decode();                                         //解码         
    };
  };                                                                
                                                                  
if(Timer0_cnt_bk>Guide_timer)         //如果时间间隔>引导码时长
{
  Guide=1;                                                 //使能引导标志
  m=0;
};
if(Timer0_cnt_bk>Continuous_timer)         //如果时间间隔>引导码时长
{
  Continuous=1;                                                 //使能引导标志

  EX0=0;

  /**此处加入连_发操作代码**/
  display_Continuous();

  EX0=1;
  m=0;  
};

};//end of 超时                                                     

}


/******************************************************************/
/*                       解码子程序                               */
/******************************************************************/

void Decode(void)
{
unsigned char m,n,s=0x00;
static unsigned char *p;  //指向结构体IR_data.XX的指针
EX0 = 0;   //外部中断无效

p=&IR_data.addr1;

for(n=0;n<4;n++)
{
for(m=8;m>0;m--)
  {                                                                                  
  if((IR_time>IR_L_timer_min)&(IR_time<IR_L_timer_max))//数据“0” 0.56ms低电平+0.56ms高电平                  
   {
   *p>>=1;
   *p&=0x7f;
   }
  else if((IR_time>IR_H_timer_min)&(IR_time<IR_H_timer_max)) //数据“1” 0.56ms低电平+1.69ms高电平   
   {
   *p>>=1;
   *p|=0x80;  
   };
  s++;
  };
  p++;
};
if(IR_data.data2==~IR_data.data1)                   //数据2=数据1反码
{
if((IR_data.addr1==IR_addr1)&(IR_data.addr2==IR_addr2))
get_IRkey();
}
else
{

/**非本机遥控器或数据错误**/
display_error();

};
EX0 = 1;                           //重新开放外部中断
}

/******************************************************************/
/*                    键 处 理 函 数                              */
/* 正确接收数据并解码时被中断程序调用                           */
/* 按键处理函数结束前外部中断不开放                               */
/* 此处保存按键处理函数,键值在于结构体IR_data                    */
/******************************************************************/
void get_IRkey()
{
display_keyValue();    //显示从遥控收到的数据
}



============================================资料==============================================================
源程序ourdev_608886TMXLKE.rar(文件大小:41K) (原文件名:遥控解码 测试.rar)
网上找的教程 作者所有ourdev_608887HO95UR.pdf(文件大小:317K) (原文件名:手把手教你红外解码.pdf)
网上找的教程 作者所有ourdev_608888K13FOP.doc(文件大小:164K) (原文件名:红外解码.doc)

出0入0汤圆

发表于 2011-1-3 17:59:30 | 显示全部楼层

出0入0汤圆

发表于 2011-1-3 18:05:23 | 显示全部楼层
谢谢楼主咯

出0入0汤圆

发表于 2011-1-3 18:29:28 | 显示全部楼层
谢谢分享

出0入0汤圆

发表于 2011-1-3 19:18:46 | 显示全部楼层
试了,发现不显示,

/************ 位变量定义 *********/
sbit RS=P1^3;
sbit RW=P1^1;
sbit  E=P1^0;
sbit BF=P3^3;

出0入0汤圆

 楼主| 发表于 2011-1-3 19:53:29 | 显示全部楼层
回复【5楼】b60885262
-----------------------------------------------------------------------

红外接收头接单片机外部中断0,INT0 (P3.2)
1602数据口接P0 (需要上拉电阻)
晶振用12 MHz

出0入0汤圆

发表于 2011-1-3 20:24:18 | 显示全部楼层
谢谢楼主分享。

出0入0汤圆

发表于 2011-1-3 20:40:54 | 显示全部楼层
mark

出0入0汤圆

发表于 2011-1-3 20:48:16 | 显示全部楼层
支持一下

出150入0汤圆

发表于 2011-1-3 21:38:15 | 显示全部楼层
多谢楼主分享

出0入0汤圆

发表于 2011-1-3 21:49:46 | 显示全部楼层
自动识别载波吗?支持一个

出15入190汤圆

发表于 2011-1-3 23:14:11 | 显示全部楼层
顶一个

出0入0汤圆

发表于 2011-1-4 18:41:55 | 显示全部楼层
mark

出0入0汤圆

发表于 2011-1-4 18:49:50 | 显示全部楼层
mark

出0入0汤圆

发表于 2011-1-4 19:40:06 | 显示全部楼层

出0入0汤圆

发表于 2011-1-5 12:09:45 | 显示全部楼层
谢谢楼主咯

出0入0汤圆

发表于 2011-1-5 12:55:47 | 显示全部楼层
这个不错,谢谢!

出0入0汤圆

发表于 2011-1-5 13:01:13 | 显示全部楼层
谢谢

出0入0汤圆

发表于 2011-1-5 13:54:41 | 显示全部楼层
很好!

出0入0汤圆

发表于 2011-1-5 20:39:46 | 显示全部楼层
mark

出0入0汤圆

发表于 2011-1-14 15:56:54 | 显示全部楼层
回复【1楼】qq335702318 | 昌少
-----------------------------------------------------------------------
楼主你好

#define IR_L_timer_min 3 //数据0 最短时长
#define IR_L_timer_max 7 //数据0 最长时长
#define IR_H_timer_min 8 //数据1 最短时长
#define IR_H_timer_max 12 //数据1 最长时长

关于时长的定义是否太宽松了?
0:  4-6
1:  9-11
这样是否跟精确呢?



(原文件名:Untitled.jpg)

出0入0汤圆

 楼主| 发表于 2011-1-16 21:44:17 | 显示全部楼层
回复【21楼】beijisnow
-----------------------------------------------------------------------
程序里面,关于这个时长的比较是没有使用>=或<=的。因此如果定为0:  4~6;   1:  9~11时实际相当于0: 5;   1: 10;
实际上范围是0:  5±1;       1:  10±1

   .......

     if((IR_time>IR_L_timer_min)&(IR_time<IR_L_timer_max)) //数据“0” 0.56ms低电平+0.56ms高电平
   .......
else if((IR_time>IR_H_timer_min)&(IR_time<IR_H_timer_max)) //数据“1” 0.56ms低电平+1.69ms高电平
   .......

出0入0汤圆

发表于 2011-1-16 23:50:39 | 显示全部楼层
mark

出0入0汤圆

发表于 2011-1-17 09:37:08 | 显示全部楼层
用的什么片子?

出0入0汤圆

 楼主| 发表于 2011-1-18 13:14:25 | 显示全部楼层
回复【24楼】tyqhaha
-----------------------------------------------------------------------

51单片机啊

出0入0汤圆

发表于 2011-1-18 14:46:04 | 显示全部楼层
楼主帮忙看看我改写的Sony SIRC解码  看是否有问题呀。

SONY SIRC参考:
http://davidallmon.com/sirc/sirc.php
http://www.8051projects.net/out.php?link=http://sbprojects.com/knowledge/ir/sirc.htm


#include <reg51.h>
/******************************************************************/
/*                     函 数 声 明                                */
/******************************************************************/
void Timer0init(void);     //定时器0初始化
void EX0init(void);        //外部中断初始化
void Decode(void);         //解码子程序
/******************************************************************/
/*                     宏  定  义  区                             */
/*  由于遥控器和程序存在一定误差,必须允许编码时长有一定的范围    */
/*  以下定义了时长和范围以及本机地址。用于调试                    */
/******************************************************************/
#define Guide_timer 22              //引导码最短时长
#define IR_L_timer_min 10           //数据0 最短时长
#define IR_L_timer_max 14           //数据0 最长时长
#define IR_H_timer_min 16           //数据1 最短时长
#define IR_H_timer_max 20           //数据1 最长时长
#define TIMER0_COUNT 0x9c           //定时器定时时间 100us
#define Timeout_cnt 240             //超时时长
/******************************************************************/
/*                    变  量  保  存  区                          */
/******************************************************************/
static unsigned char Timer0_cnt;            //定时器计数值
static unsigned char Timer0_cnt_bk;
static bit timeout;                         //超时标志
static bit Guide;                           //引导码有效
static unsigned char IR_time[13];           //保存每两个下降沿之间的时间间隔
static unsigned int  IR_12bit;
static unsigned char IR_Command;            //7bit命令  保存一次解码后接受到的数据
static unsigned char IR_Address;             //5bit地址  保存一次解码后接受到的数据
static unsigned char IR_Newkey;
/************ 编解码说明 ***************
引导码:2.4ms低电平+ 0.6ms高电平
数据0:0.6ms低电平+0.6ms高电平
数据1:1.2ms低电平+0.6ms高电平
*****************************************/
/******************************************************************/
/*                   红 外 遥 控 解 码                            */
/* CPU & XTAL :51   @ 12Mhz                                     */
/* 支持的红外编码方案: Sony                                     */
/* 编码格式:引导信号 + 7bit command + 5bit address              */
/******************************************************************/
/******************************************************************/
/*                   定时器0初始化                                */
/*                   定时值:100us                                */
/*                   方式2 自动重载                               */
/******************************************************************/
void Timer0init(void)//定时器0初始化
{
    //定时值 100us
    TMOD=0x02;             //定时器0工作方式2 自动重载
    TH0=TIMER0_COUNT;      //重载值
    TL0=TIMER0_COUNT;      //初始化值
    ET0=1;                 //定时器0中断有效
    TR0=1;                 //定时开始
}
/******************************************************************/
/*                   外部中断初始化                               */
/*                   中断端口:外部中断0 P3.2                     */
/*                   触发方式:下降沿                             */
/******************************************************************/
void EX0init(void)
{
    EA = 1;    //总中断开
    IT0 = 1;   //指定外部中断0下降沿触发,INT0 (P3.2)
    EX0 = 1;   //外部中断有效
}
/******************************************************************/
/*                   Timer0中断子程序                             */
/******************************************************************/
void Timer0(void) interrupt 1 using 1
{
    Timer0_cnt++;
    if(Timer0_cnt>Timeout_cnt)
    {
        timeout=1;    //超时标志
    }
}
/******************************************************************/
/*                    外部中断0函数                               */
/* 下降沿触发                                                     */
/******************************************************************/
void ex0_isr (void) interrupt 0 using 0
{
    static unsigned char m=0;
    Timer0_cnt_bk=Timer0_cnt; //备份时间计数值,即前一个下降沿到本下降沿的时间间隔
    Timer0_cnt=0x00;          //清空时间计数值
    if(timeout)               //如果超时
    {
        TL0=TIMER0_COUNT;    //初始化定时器0
        Timer0_cnt=0x00;     //清空时间计数值
        timeout=0;           //清除超时标志
        Guide=0;             //清除引导标志
        m=0;                 //复位数据位
    }
    else
    {
        if(Guide)                           //如果引导码有效
        {
            IR_time[m++]=Timer0_cnt_bk;    //保存时间间隔
            if(m==12)                      //接收够12bit数据后
            {
                m=0;
                Guide=0;                    //清除引导标志
                Decode();                   //解码
            };
        };
        if(Timer0_cnt_bk>Guide_timer)    //如果时间间隔>引导码时长
        {
            Guide=1;                       //使能引导标志
            m=0;
        };
    };
}
/******************************************************************/
/*                       解码子程序                               */
/******************************************************************/
void Decode(void)
{
    unsigned char bitcounter,timecounter=0x00;
    EX0 = 0;   //外部中断无效
    for(bitcounter=12; bitcounter>0; bitcounter--)
    {
        {
            if((IR_time[timecounter]>IR_L_timer_min)&(IR_time[timecounter]<IR_L_timer_max))//数据"0" 0.6ms低电平+0.6ms高电平
            {
                IR_12bit>>=1;
                IR_12bit&=0x7f;
            }
            else if((IR_time[timecounter]>IR_H_timer_min)&(IR_time[timecounter]<IR_H_timer_max)) //数据"1" 1.2ms低电平+0.6ms高电平
            {
                IR_12bit>>=1;
                IR_12bit|=0x80;
            }
            timecounter++;
        }
    }
    IR_12bit>>=4;                               //再右移4位 使command低位对齐
    IR_Command=(char)IR_12bit&0x7f;    //保留低7位
    IR_12bit>>=7;                               //再右移7位 使address低位对齐
    IR_Address=(char)IR_12bit&0x1f;    //保留低5位
    if(IR_Address==0x01)          //地址码=1
    {
        IR_Newkey=1;
    }
    EX0 = 1;              //重新开放外部中断
}
/******************************************************************/
/*                    键 处 理 函 数                              */
/* 正确接收数据并解码时被中断程序调用                             */
/* 按键处理函数结束前外部中断不开放                               */
/* 此处保存按键处理函数,键值在于结构体IR_data                    */
/******************************************************************/
void main()
{
    Timer0init();//定时器0初始化
    EX0init();   //外部中断初始化
    while(1)
    {
        ;
    }
}

出0入0汤圆

发表于 2011-1-18 15:05:28 | 显示全部楼层
发现bug  改了一下

void Decode(void)
{
    unsigned char bitcounter,timecounter=0x00;
    EX0 = 0;   //外部中断无效
    for(bitcounter=12; bitcounter>0; bitcounter--)
    {
        {
            if((IR_time[timecounter]>IR_L_timer_min)&(IR_time[timecounter]<IR_L_timer_max))      //数据"0" 0.6ms低电平+0.6ms高电平
            {
                IR_12bit>>=1;
                IR_12bit&=0xf7ff;  //16位int数的第12位置0
            }
            else if((IR_time[timecounter]>IR_H_timer_min)&(IR_time[timecounter]<IR_H_timer_max)) //数据"1" 1.2ms低电平+0.6ms高电平
            {
                IR_12bit>>=1;
                IR_12bit|=0x800;  //16位int数的第12位置1
            }
            timecounter++;
        }
    }
    IR_Command=(char)IR_12bit&0x7f;    //保留低7位
    IR_12bit>>=7;                      //再右移7位 使address低位对齐
    IR_Address=(char)IR_12bit&0x1f;    //保留低5位
    if(IR_Address==0x01)               //地址码=1
    {
        IR_Newkey=1;
    }
    EX0 = 1;              //重新开放外部中断
}

出0入0汤圆

发表于 2011-1-18 15:41:11 | 显示全部楼层
学下了

出0入0汤圆

发表于 2011-1-22 13:31:59 | 显示全部楼层
谢谢楼主,下载了,调试通过!

出0入0汤圆

发表于 2011-1-22 13:53:21 | 显示全部楼层
mark!!!

出0入0汤圆

发表于 2011-1-22 14:03:55 | 显示全部楼层
MARK

出0入0汤圆

发表于 2011-1-22 14:04:04 | 显示全部楼层
MARK

出0入0汤圆

发表于 2011-1-22 14:04:18 | 显示全部楼层
MARK

出0入0汤圆

发表于 2011-1-22 15:06:28 | 显示全部楼层
mark

出0入0汤圆

发表于 2011-1-24 12:36:37 | 显示全部楼层
mark

出0入0汤圆

发表于 2011-1-24 14:28:19 | 显示全部楼层
回复【1楼】qq335702318 | 昌少
-----------------------------------------------------------------------

mark一下

出0入0汤圆

发表于 2011-1-24 15:36:57 | 显示全部楼层
MARK

出0入0汤圆

发表于 2011-1-26 13:23:28 | 显示全部楼层
我将解码子程序中的
if((IR_data.addr1==IR_addr1)&(IR_data.addr2==IR_addr2))
去掉,发现可以识别家里的电视机、DVD和MP3的遥控器。同时发现不同的遥控器使用不同的代码(最基本的0~9,On/Off等也不相同,不知道有没有国标)。由此想到,可以利用它再编写一个判断语句,对不同的设备做不同的应答。学习楼主程序的一个小小的收获。再次感谢楼主。

出0入0汤圆

发表于 2011-1-26 13:27:33 | 显示全部楼层
另外,外部中断服务程序里的

if(timeout)    //如果超时
{
TL0=TIMER0_COUNT;  //初始化定时器0

初始化定时器0这一句可以去掉,因为TMOD=0x02。

出0入0汤圆

 楼主| 发表于 2011-1-26 19:21:24 | 显示全部楼层
回复【39楼】hmzwm
-----------------------------------------------------------------------

谢谢 你的意思是自动重载方式无需初始化定时器0?

出0入0汤圆

发表于 2011-1-26 21:02:02 | 显示全部楼层
回复【40楼】qq335702318 | 昌少
-----------------------------------------------------------------------

不是啊...

贴上我参考您的程序,改写的一个版本。


/*        
        CPU-XTL :89S52-12MHz
        红外编码方案: NEC upd6121,upd6122;PT2222; SC6121; HS6221,HS6222
        编码格式:引导信号(或连_发信号)+地址码1+地址码2+数据码+数据码反码
        引导码:9ms低电平+4.5ms 高电平
        连_发码:9ms低电平+2.25ms高电平
        数据0:0.56ms低电平+0.56ms高电平
        数据1:0.56ms低电平+1.69ms高电平                  
        2011.1.24        OK
*/
#include<LCD1602.h>                  //包含延时函数Delay.h

/* 宏定义*/
/* 由于遥控器和程序存在一定误差,须允许编码时长有一定的范围便于调试*/
/******************************************************************/
//#define IR_ADDR1 0x00                                //本机地址1
//#define IR_ADDR2 0xFF                                //本机地址2
#define GTime 39                                    //引导码最短时长          39*225us=8775us=8.775ms[9ms]
#define CTime 100                                 //连_发码最短时长        39-> 100
#define D0MinTime 3                                        //数据0 最短时长        平均5*225us=1125us=1.125ms
#define D0MaxTime 7                                        //数据0 最长时长        0.56ms+0.56ms=1.120ms
#define D1MinTime 8                                        //数据1 最短时长        平均10*225us=2250us=2.25ms
#define D1MaxTime 12                                //数据1 最长时长        0.56ms+1.69ms=2.25ms
#define TIMER0_COUNT 0x1f                //定时器定时时间        12MHz-225us           0x1f=31
#define TimeOut_cnt 250                            //超时时长                        250*225us=56250us=56.25ms

/*全局公共变量*/
static unsigned char T0_CNT;                //定时器计数值
static unsigned char T0_CNT_bk;                //计数备份
static bit TimeOut;                                        //超时标志
static bit Guide;                                        //引导码有效
static bit Continuous;                                //连_发码
static unsigned char IR_Time[33];        //保存每两个下降沿之间的时间间隔  

/*结构体*/                   /* 保存一次解码后接收到的四字节数据*/
static struct IR_data                                //红外接收的数据结构
{         unsigned char addr1;                        //地址1(客户码1)
        unsigned char addr2;                        //地址2(客户码2)
        unsigned char data1;                        //数据1(数据码)
        unsigned char data2;                        //数据2(数据码反码)
}IR_DATA;         
//unsigned char IR_KeyValue;                         //红外遥控器键值
/*LCD显示用ASCII字符表*/
unsigned char code ASCII_Tab[16]={'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};
/* 看门狗2011.1.21*/
sfr WatchDogTimer = 0xC1;
sbit BEEP=P1^0;      /* BEEP */
static unsigned char nKey;                //正确解码的次数,用于键值处理2011.1.25
/******************************************************************/
/* 函数声明*/
void Timer0_Init(void);                        //定时器0初始化
void EX1_Init(void);                           //外部中断1初始化
void Decode(void);                            //解码子程序

void get_IRkey(void);                          //键处理
void display_keyValue(void);          //显示从遥控器接收到的数据
void display_Continuous(void);        //显示连_发次数
void SysInit(void);                //系统初始化
/******************************************************************/
/*函数定义*/
/*定时器0初始化: 定时值:225us 12MHz(11.0592MHz) ;方式2 自动重载 重载值31(0X1F)*/
void Timer0_Init(void)//定时器0初始化
{         TMOD=0x02;//定时器0工作方式2 自动重载
        TH0=TIMER0_COUNT; //重载值
        TL0=TIMER0_COUNT; //初始化值
        ET0=1;    //定时器0中断有效
        TR0=1;    //定时开始
}
/******************************************************************/
/*Timer0中断子程序*/
void Timer0_Int(void) interrupt 1 using 1
{        T0_CNT++;
        if(T0_CNT>TimeOut_cnt)        TimeOut=1;           //超时标志                                                 
}
/******************************************************************/
/*外部中断1初始化:外部中断1 P3.3,触发方式:下降沿*/
void EX1_Init(void)
{        EA = 1;    //总中断开
        IT1 = 1;   //指定外部中断1下降沿触发,INT1 (P3.3)
        EX1 = 1;   //开外部中断1
}
/******************************************************************/
/* 外部中断1函数,下降沿触发*/
void EX1_Int(void) interrupt 2 using 0
{        static unsigned char m=0;
       
        T0_CNT_bk=T0_CNT;                //备份时间计数值,即前一个下降沿到本下降沿的时间间隔
        T0_CNT=0x00;                          //清空时间计数值
         
        if(TimeOut)                                   //如果超时
        {//        TL0=TIMER0_COUNT;          //初始化定时器0           -0x1f(31)
                TimeOut=0;                   //清除超时标志
                m=0;                           //复位数据位
                T0_CNT=0x00;                   //清空时间计数值
                Guide=0;           //清除引导标志
                Continuous=0;      //清除连_发标志
        }
        else                                  //正常按键时长58.5ms~76.5ms
        {        if(Guide|Continuous)                           //如果引导码有效
                {        IR_Time[m++]=T0_CNT_bk;                 //保存时间间隔
                        if(m==32)                                         //接收够32数据后
                        {        m=0;
                                Guide=0;                                         //清除引导标志
                                /*进行解码操作*/
                                Decode();                                         //解码
                                nKey++;          //正确解码的次数,用于键值处理2011.1.25
                        }
                }                                                                
                                                                           
                if(T0_CNT_bk>GTime)         //如果时间间隔>引导码时长
                {        Guide=1;        m=0;        };//使能引导标志
                if(T0_CNT_bk>CTime)         //如果时间间隔>连_发码时长
                {        Continuous=1;                                                 //使能连_发标志
                        EX1=0;                   //关外部中断1
                        /**此处加入连_发操作代码**/
                        display_Continuous();

                        EX1=1;                //开外部中断1
                        m=0;  
                }
        }//end of 超时
}  

/******************************************************************/
/*解码核心程序*/
void Decode(void)
{        unsigned char i=0x00,j,k;
        static unsigned char *p;  //指向结构体IR_DATA.XX的指针
       
        EX1 = 0;   //关外部中断1
        /*/////////////////////////进行解码处理////////////////////////*/
        p=&IR_DATA.addr1;
        for(k=0;k<4;k++)
        {        for(j=0;j<8;j++)
                  {        if((IR_Time>D0MinTime)&(IR_Time<D0MaxTime))
                           {        *p>>=1;        *p&=0x7f;}//右移1位,        //与0111 1111置0. 数据“0” 0.56ms低电平+0.56ms高电平                  
                          else if((IR_Time>D1MinTime)&(IR_Time<D1MaxTime))
                           {        *p>>=1;        *p|=0x80;}//右移1位,//或1000 0000置1. 数据“1” 0.56ms低电平+1.69ms高电平   
                          i++;
                  }
                  p++;
        }
        if(IR_DATA.data2==~IR_DATA.data1){        get_IRkey();        }   /*提取按键值*///数据2=数据1反码
        else {         WriteStrTo1602(2,1,"Error!");        };        /**非本机遥控器或数据错误**/
        /*/////////////////////////解码处理完毕////////////////////////*/
        EX1 = 1;   //重新开放外部中断1
}
/******************************************************************/
/*中断程序调用——红外遥控键处理函数。键值功能为用户自定义*/
void get_IRkey()
{        display_keyValue();          //显示从遥控收到的数据
}   
/*                不同的遥控器各键值代码有不同的定义 eg.:
//0~9数字键
0-0x0D                1-0x0C                2-0x18                3-0x5E                4-0x08
5-0x1C                6- 0x5A                7-0x42                8-0x52                9-0x4A
//功能键
|<<         0x07        >|| 0x09        >>| 0x15        VOL- 0x16
VOL+ 0x19        CH+ 0x40        EQ  0x43        CH- 0x44
ON/FF 0x45        RETURN 0x46        MODE 0x47
*/
/******************************************************************/
/*按键处理函数,输入:接收到的数据码——结构体IR_DATA*/
void display_keyValue(void)
{        WriteCharTo1602(1,1,ASCII_Tab[IR_DATA.addr1/0x10]);       
        WriteCharTo1602(1,2,ASCII_Tab[IR_DATA.addr1%0x10]);
        WriteCharTo1602(1,4,ASCII_Tab[IR_DATA.addr2/0x10]);
        WriteCharTo1602(1,5,ASCII_Tab[IR_DATA.addr2%0x10]);
        WriteCharTo1602(1,7,':');
        WriteCharTo1602(1,9,ASCII_Tab[IR_DATA.data1/0x10]);
        WriteCharTo1602(1,10,ASCII_Tab[IR_DATA.data1%0x10]);
        WriteCharTo1602(1,12,ASCII_Tab[IR_DATA.data2/0x10]);
        WriteCharTo1602(1,13,ASCII_Tab[IR_DATA.data2%0x10]);
        WriteStrTo1602(1,15,"OK");

        WriteStrTo1602(2,1,"U=");
        WriteCharTo1602(2,3,ASCII_Tab[IR_DATA.addr1/0x10]);       
        WriteCharTo1602(2,4,ASCII_Tab[IR_DATA.addr1%0x10]);
        WriteCharTo1602(2,6,ASCII_Tab[IR_DATA.addr2/0x10]);
        WriteCharTo1602(2,7,ASCII_Tab[IR_DATA.addr2%0x10]);

        WriteStrTo1602(2,13,"K=");
        WriteCharTo1602(2,15,ASCII_Tab[IR_DATA.data1/0x10]);
        WriteCharTo1602(2,16,ASCII_Tab[IR_DATA.data1%0x10]);

        BEEP=0;
        DelayNms(5);
        BEEP=1;
}
/******************************************************************/
/*显示连_发函数*/
void display_Continuous(void)
{        static unsigned char n;
       
        WriteCharTo1602(2,10,ASCII_Tab[n/0x10]);
        WriteCharTo1602(2,11,ASCII_Tab[n%0x10]);
        n++;

        BEEP=0;
        DelayNms(50);
        BEEP=1;
}
/***************************************
* 名称 : SysInit()
* 功能 : 单片机初始化,设置定时器,中断,看门狗等初值
* 输入 : 无
* 输出 : 无
****************************************/
void SysInit(void)
{        /****************看门狗初始化************************/
        WatchDogTimer = 0x3C;                  /*晶振在12M或11.0592M时,溢出时间为1s左右2011.1.21*/
        /* 0011,1100 EN_WDT = 1,CLR_WDT = 1,IDLE_WDT = 1,PS2=1,PS1=0,PS0=0 */
        /****************LCD1602显示器初始化*****************/
    Initiate1602();
          WriteStrTo1602(1,1,"IR Decode System");/*LOGO*/
          WriteStrTo1602(2,1,"(c)");
          WriteStrTo1602(2,8,"2011-1-24");
        DelayNms(1500);
        WriteCmdTo1602(0x01);/* 清屏 */       
        /****************外部中断1初始化**********************/
        EX1_Init();
        /****************定时器0初始化************************/
        Timer0_Init();
        /****************波特率初始化************************/
  
        /****************其他硬件相关初始化******************/

}
/***************************************
* 名称 : main()
* 功能 : 主函数
* 输入 : 无
* 输出 : 无
****************************************/
//主函数
void main(void)
{        SysInit();

        while(1)
        {        /*看门狗——喂狗2011.1.21*/
                WriteCharTo1602(2,10,nKey+'0');
                DelayNms(1000);
                WatchDogTimer = 0x3C; //喂狗
        }
}

出0入0汤圆

发表于 2011-1-26 21:09:25 | 显示全部楼层
在下面的外部中断1服务子程序中那个“如果超时”下面的那句话,我去掉后调试通过,程序运行正常。

******************************************************************/
/* 外部中断1函数,下降沿触发*/
void EX1_Int(void) interrupt 2 using 0
{ static unsigned char m=0;

T0_CNT_bk=T0_CNT; //备份时间计数值,即前一个下降沿到本下降沿的时间间隔
T0_CNT=0x00;    //清空时间计数值
  
if(TimeOut)     //如果超时
{// TL0=TIMER0_COUNT;   //初始化定时器0    -0x1f(31)
TimeOut=0;    //清除超时标志
m=0;    //复位数据位
T0_CNT=0x00;    //清空时间计数值
Guide=0;           //清除引导标志
Continuous=0;      //清除连_发标志
}
...

出0入0汤圆

发表于 2011-1-26 21:14:13 | 显示全部楼层
借楼主的宝地,顺便把其他几个文件也贴上来,供和我一样的菜鸟们参考。

//LCD1602.H

#ifndef __LCD1602_H
#define __LCD1602_H

#include<reg52.h>
#include<Delay.h>        /* 延时函数 */
  
#undef LCD_Data_Port                                /*消除重复定义*/
#define LCD_Data_Port P0                 /* 向LCD输出数据的I/O口为P0口,需要根据硬件设置 */

/************ 位变量定义(需结合实际硬件电路,调整)*********/
/* 注意:下面的LCD引脚和硬件设计相关 2010.12.7 */
sbit E= P2^7;      /* 1602使能引脚 */
sbit RW=P2^6;      /* 1602读写引脚 */
sbit RS=P2^5;      /* 1602数据/命令选择引脚 */
/* 8个5*8自定义汉字字符 */
unsigned char code ChineseData[]=
{  0x1f,0x02,0x04,0x1f,0x04,0x04,0x14,0x08,/* 代码 0x00*/
        0x04,0x1f,0x04,0x0e,0x04,0x1f,0x04,0x04,/* 代码 0x01*/
        0x00,0x04,0x02,0x1F,0x02,0x04,0x00,0x00,/* 代码 0x02*/
        0x0A,0x17,0x10,0x15,0x15,0x15,0x12,0x17,/* 代码 0x03*/
    0x04,0x04,0x1F,0x15,0x15,0x1F,0x04,0x04,/* 代码 0x04*/
        0x08,0x1F,0x0E,0x15,0x04,0x1F,0x04,0x15,/* 代码 0x05*/
        0x1F,0x0D,0x0D,0x1E,0x0D,0x0E,0x0D,0x16,/* 代码 0x06*/
        0x1F,0x11,0x1F,0x00,0x1F,0x04,0x03,0x1F,/* 代码 0x07*/
};
/************ 函数声明 2011.1.24************/
extern void WriteCmdTo1602(unsigned char cmd);                /* 1602命令函数,可供其他函数调用 */
           void WriteDataTo1602(unsigned char ShuJu);        /* 1602写数据函数,只用于本库函数*/
extern void WriteCharTo1602(unsigned char row,unsigned char column,char ZiFu);        /* 在指定位置写字符,可供其他函数调用  */
extern void WriteStrTo1602(unsigned char row,unsigned char column,unsigned char *p);        /* 向1602写字符串,可供其他函数调用  */
           void WriteCGRAM(void);                /* 向1602写入8个自建的字符库,只用于本库函数 */
extern void Initiate1602(void);                /* 1602初始化,可供其他函数调用  */

/* LCD1602模块的标准处理函数群2010.12.7*/
/****************************************
* 名称 : WriteCmdTo1602(unsigned char cmd)
* 功能 : 1602写命令函数
* 输入 : 输入的命令值
* 输出 : 无
****************************************/
void WriteCmdTo1602(unsigned char cmd)
{   LCD_Data_Port = cmd;
    RS = 0;                /* 指令 */
    RW = 0;                /* 写 */
    E = 0;                /* 关LCD1602 */
    DelayNus(100);
    E = 1;                /* 开LCD1602 */
    DelayNus(100);
}
/***************************************
* 名称 : WriteDataTo1602(unsigned char ShuJu)
* 功能 : 1602写数据函数
* 输入 : 需要写入1602的数据
* 输出 : 无
****************************************/
void WriteDataTo1602(unsigned char ShuJu)
{   LCD_Data_Port = ShuJu;
    RS = 1;                /* 数据 */
    RW = 0;                /* 写 */
    E = 0;                /* 关LCD1602 */
    DelayNus(100);
    E = 1;                /* 开LCD1602 */
    DelayNus(100);
}
/***************************************
* 名称 : WriteCharTo1602(unsigned char  row,unsigned char  column,char ZiFu)
* 功能 : 在指定位置写字符.eg: WriteCharTo1602(1,2,'Z'); 在第1行第2个字符处显示"Z"
* 输入 : 行,列,需要输入1602的字符数据
* 输出 : 无
****************************************/
void WriteCharTo1602(unsigned char row,unsigned char column,char ZiFu)
{   unsigned char A;
    if((column>0)&(column<=16))        /* 不能超出1602的显示范围 */
    {   if(row <= 1) A = 0x80;        /* 第一行 */
        else A = 0xC0;                        /* 第二行 */
        A += column - 1;
        WriteCmdTo1602(A);
        WriteDataTo1602(ZiFu);
    }
}
/***************************************
* 名称 : WriteStrTo1602(unsigned char row,unsigned char column,unsigned char *p)
* 功能 : 向1602写字符串.eg:WriteStrTo1602(1,2,"ZWM"); 在第1行第2个字符开始显示"ZWM"
* 输入 : 行,列,需要输入1602的字符串数据
* 输出 : 无
****************************************/
void WriteStrTo1602(unsigned char row,unsigned char column,unsigned char *p)
{   unsigned char A;
    if((column>0)&(column<=16))        /* 不能超出1602的显示范围 */
    {   if(row <= 1) A = 0x80;        /* 第一行 */
        else A = 0xC0;                        /* 第二行 */
        A += column - 1;
        WriteCmdTo1602(A);
        while(*p != '\0')
        {   WriteDataTo1602(*p);
                p++;
            }
    }
}         
/***************************************
* 名称 : WriteCGRAM()
* 功能 : 向1602的CGRAM里写入8个自定义5*8汉字字符、图形点阵
* 输入 : 无
* 输出 : 无
****************************************/
void WriteCGRAM(void)
{        unsigned char i,j;
    for(i=0x00;i<0x08;i++)
    {   WriteCmdTo1602(0x40+i*8);/*8个自定义字符地址0x40,0x48,0x50,0x58,0x60,0x68,0x70,0x78*/
        for(j=0x00;j<0x08;j++) {  WriteDataTo1602(ChineseData[i*8+j]);  }/*写入汉字字符的数据*/
    }
}
/************************************
* 名称 : Initiate1602()
* 功能 : 1602初始化
* 输入 : 无
* 输出 : 无
*************************************/
void Initiate1602(void)
{   /* 常规的初始化过程 */
    WriteCmdTo1602(0x01);/* 清屏 */
    WriteCmdTo1602(0x38);/* 八位数据,分两行显示,字符点阵5*7,1/16占空比 */
        WriteCmdTo1602(0x38);
        WriteCmdTo1602(0x38);
        WriteCmdTo1602(0x08);/* 关闭显示 */
    WriteCmdTo1602(0x01);/* 清屏 */
    WriteCmdTo1602(0x06);/* 光标移动设置,读/写一个字符后地址指针加1 &光标加1 */
    WriteCmdTo1602(0x0c);/* 开显示,不显示光标,不闪烁 */
    WriteCGRAM();                                 /* 写入8个自定义汉字 */
}

#endif          /* __LCD1602_H */


//Delay.h
#ifndef __DELAY_H
#define __DELAY_H
#include <intrins.h>                 //使用了其中的_nop_ ()函数

/* 函数声明 *///对这些常用的延时函数加extern 声明,可供其它文件调用2011.1.24
extern void Delay1us(void);
extern void Delay1ms(void);
extern void DelayNms(unsigned int n);/* 延时n(ms)子程序 */
extern void DelayNus(unsigned int n);

/* 函数定义 */
/***********************************************************************/
void Delay1us(void)                 //1us延时函数
{        _nop_ ();                                                 //XTL=12MHz时候1NOP=1us
}
/***********************************************************************/
void DelayNus(unsigned int n)       //N us延时函数
{        unsigned int i=0;

        for (i=0;i<n;i++)          {        Delay1us();        }
}
/***********************************************************************/  
void Delay1ms(void)                 //1ms延时函数
{        unsigned int i;

        for (i=0;i<250;i++){        ;        }
}
/***********************************************************************/
void DelayNms(unsigned int n)           //N ms延时函数
{        unsigned int i=0;

        for (i=0;i<n;i++)         {        Delay1ms();          };
}
/***********************************************************************/  
#endif         /*__DELAY_H*/

出150入0汤圆

发表于 2011-1-26 21:49:10 | 显示全部楼层
好帖子

出0入0汤圆

发表于 2011-1-26 21:51:01 | 显示全部楼层

(原文件名:调整大小 ALIM2269.JPG)


(原文件名:调整大小 ALIM2270.JPG)

出0入0汤圆

发表于 2011-2-10 13:36:25 | 显示全部楼层
顶一个

出0入0汤圆

发表于 2011-3-15 10:33:48 | 显示全部楼层
一般都是32位解码器
有没有可以解出64位的红外遥控解码器啊

出0入0汤圆

发表于 2011-4-23 01:38:27 | 显示全部楼层
mark

出0入0汤圆

发表于 2011-4-23 13:27:59 | 显示全部楼层
回复【楼主位】qq335702318 | 昌少
-----------------------------------------------------------------------

测试了一下OK,还得到楼主的指导,谢谢

出0入0汤圆

发表于 2011-4-23 14:01:20 | 显示全部楼层
mark

出0入0汤圆

发表于 2011-4-23 14:43:41 | 显示全部楼层
mark

出0入0汤圆

发表于 2011-4-23 15:09:35 | 显示全部楼层
留个记号有空再看!

出0入0汤圆

发表于 2011-4-23 17:35:50 | 显示全部楼层
记号

出0入0汤圆

发表于 2011-4-23 18:24:15 | 显示全部楼层
mark

出0入0汤圆

发表于 2011-4-23 18:49:39 | 显示全部楼层
这个不错,谢谢!

出0入0汤圆

发表于 2011-4-23 19:29:32 | 显示全部楼层
mark

出0入0汤圆

发表于 2011-5-6 16:53:22 | 显示全部楼层
顶一下

出0入112汤圆

发表于 2011-5-6 17:40:13 | 显示全部楼层
强!

出0入0汤圆

发表于 2011-5-6 22:43:35 | 显示全部楼层

出0入0汤圆

发表于 2011-5-7 11:05:06 | 显示全部楼层

出0入0汤圆

发表于 2011-5-7 12:33:57 | 显示全部楼层
其实只有笨人才会用外中断做红外遥控接收!!!!因为单片机的外中断端口一般都不多,所以真正产品上不是这样做的!我的方法是利用内部定时器做个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.8ms\1为1.6ms)
               {                                                                         //HFJ->15-<21--11(125*15=1.875,示波器读出0为1.2ms\1为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;   
       }
           }   
}

出0入0汤圆

发表于 2011-5-7 12:34:39 | 显示全部楼层
其实只有笨人才会用外中断做红外遥控接收!!!!因为单片机的外中断端口一般都不多,所以真正产品上不是这样做的!我的方法是利用内部定时器做个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.8ms\1为1.6ms)
               {                                                                         //HFJ->15-<21--11(125*15=1.875,示波器读出0为1.2ms\1为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;   
       }
           }   
}

出0入0汤圆

发表于 2011-5-7 13:24:03 | 显示全部楼层
回复【62楼】ye955  
-----------------------------------------------------------------------

真正产品上不是这样做的??你见过多少真正产品?不是所以产品外部中断口都很紧张的,不要动不动就说别人笨。你那个timer 125us中断多频繁还不是一样占用大量资源,具体情况具体分析

出0入0汤圆

发表于 2011-5-7 14:02:01 | 显示全部楼层
回复【63楼】kaimpf
-----------------------------------------------------------------------

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

出0入0汤圆

发表于 2011-5-8 14:40:17 | 显示全部楼层
学习 mark

出0入0汤圆

发表于 2011-5-8 16:19:44 | 显示全部楼层
MARK

出0入0汤圆

发表于 2011-5-8 16:20:14 | 显示全部楼层
mark

出0入0汤圆

发表于 2011-5-9 11:01:26 | 显示全部楼层
mark

出0入0汤圆

发表于 2011-5-9 18:56:41 | 显示全部楼层
谢谢分享资料

出0入0汤圆

发表于 2011-5-16 14:50:49 | 显示全部楼层
留个记号再慢慢看

出0入0汤圆

发表于 2011-5-16 14:58:48 | 显示全部楼层
xuexi

出0入0汤圆

发表于 2011-5-31 15:19:27 | 显示全部楼层
留个记号再慢慢看

出0入0汤圆

发表于 2011-5-31 15:51:46 | 显示全部楼层
不错!

出0入0汤圆

发表于 2011-5-31 16:15:34 | 显示全部楼层
mark

出0入0汤圆

发表于 2011-5-31 17:31:58 | 显示全部楼层
mark

出0入0汤圆

发表于 2011-5-31 17:39:26 | 显示全部楼层
mark 标记留着慢慢看

出0入0汤圆

发表于 2011-6-1 16:24:20 | 显示全部楼层
MARK

出0入0汤圆

发表于 2011-6-2 09:51:26 | 显示全部楼层
高人多,记下。

出0入0汤圆

发表于 2011-6-2 10:39:54 | 显示全部楼层
good

出0入0汤圆

发表于 2011-6-2 10:47:55 | 显示全部楼层
牛屁的人多啊

出0入0汤圆

发表于 2011-6-2 10:55:32 | 显示全部楼层

出0入0汤圆

发表于 2011-6-2 11:37:53 | 显示全部楼层
MARK

出0入0汤圆

发表于 2011-6-3 10:43:59 | 显示全部楼层
mark

出0入0汤圆

发表于 2011-6-5 08:11:27 | 显示全部楼层
mark
头像被屏蔽

出0入0汤圆

发表于 2011-6-7 10:55:30 | 显示全部楼层
提示: 作者被禁止或删除 内容自动屏蔽

出0入0汤圆

发表于 2011-6-7 23:52:47 | 显示全部楼层
马克

出0入0汤圆

发表于 2011-6-8 08:25:12 | 显示全部楼层
mark

出0入0汤圆

发表于 2011-6-8 09:18:25 | 显示全部楼层
mark

出0入0汤圆

发表于 2011-6-8 09:51:24 | 显示全部楼层
太厉害了,谢谢楼主。

出0入0汤圆

发表于 2011-6-8 10:25:34 | 显示全部楼层
不错喔!

出0入0汤圆

发表于 2011-6-8 18:00:05 | 显示全部楼层
又来红外解码

出0入0汤圆

发表于 2011-6-8 21:23:15 | 显示全部楼层
xuexi xuexi!xie!

出0入0汤圆

发表于 2011-6-8 21:49:55 | 显示全部楼层
mark,准备学习一下

出0入0汤圆

发表于 2011-6-8 22:03:44 | 显示全部楼层
mark

出0入0汤圆

发表于 2011-6-9 14:40:00 | 显示全部楼层
xuexile

出0入0汤圆

发表于 2011-6-22 10:47:50 | 显示全部楼层
回复【62楼】ye955
-----------------------------------------------------------------------

实际试了一下,还是蛮不错的,就是解出来的码是反的比如0X1F,用这个程序解出来是0XF8,另外这上面没连按的程序,楼主能不能发一下啊?谢谢,楼主请留个QQ,大家交流一下

出0入0汤圆

发表于 2011-6-22 12:18:29 | 显示全部楼层
回复【61楼】ye955
-----------------------------------------------------------------------

井底之蛙,你才见过几种遥控器,就敢说用中断是笨人?
遥控器用的最多的是电视,DVD,空调等,人家用的单片机会缺中断口?如果都用你的方法,就别干别的事了。
另外告诉你,人家90%都不是51单片机。

有用查询方式,但都是用在极简系统,就象你举的例子,风扇、电暖气之类的,那是不得已而为之。你们不用,只能说明你们做的产品档次太低。
-----------------------------------
回复 97 楼
你把解码子程序 Decode里移位顺序反过来
程序没细看,你试试下面程序
void Decode(void)
{
    unsigned char bitcounter,timecounter=0x00;
    EX0 = 0;   //外部中断无效
    for(bitcounter=12; bitcounter>0; bitcounter--)
    {
        {
            if((IR_time[timecounter]>IR_L_timer_min)&(IR_time[timecounter]<IR_L_timer_max))      //数据"0" 0.6ms低电平+0.6ms高电平
            {
                IR_12bit<<=1;        //逆序 //IR_12bit>>=1;
                IR_12bit&=0xfffe;    //逆序 //IR_12bit&=0xf7ff;  //16位int数的第12位置0
            }
            else if((IR_time[timecounter]>IR_H_timer_min)&(IR_time[timecounter]<IR_H_timer_max)) //数据"1" 1.2ms低电平+0.6ms高电平
            {
                IR_12bit<<=1;    //逆序 //IR_12bit>>=1;
                IR_12bit|=0x001; //逆序 //IR_12bit|=0x800;  //16位int数的第12位置1
            }
            timecounter++;
        }
    }

出0入0汤圆

 楼主| 发表于 2011-6-22 14:32:15 | 显示全部楼层
回复【97楼】tzsteel
-----------------------------------------------------------------------

连按部分的程序试验时发现不能正常工作,但手上没示波器 , 所以没有去深究原因。回复【64楼】ye955

出0入0汤圆

发表于 2011-6-22 14:53:02 | 显示全部楼层
先下了资料再看,看了再回贴
回帖提示: 反政府言论将被立即封锁ID 在按“提交”前,请自问一下:我这样表达会给举报吗,会给自己惹麻烦吗? 另外:尽量不要使用Mark、顶等没有意义的回复。不得大量使用大字体和彩色字。【本论坛不允许直接上传手机拍摄图片,浪费大家下载带宽和论坛服务器空间,请压缩后(图片小于1兆)才上传。压缩方法可以在微信里面发给自己(不要勾选“原图),然后下载,就能得到压缩后的图片。注意:要连续压缩2次才能满足要求!!】。另外,手机版只能上传图片,要上传附件需要切换到电脑版(不需要使用电脑,手机上切换到电脑版就行,页面底部)。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

手机版|Archiver|amobbs.com 阿莫电子技术论坛 ( 粤ICP备2022115958号, 版权所有:东莞阿莫电子贸易商行 创办于2004年 (公安交互式论坛备案:44190002001997 ) )

GMT+8, 2024-7-23 12:28

© Since 2004 www.amobbs.com, 原www.ourdev.cn, 原www.ouravr.com

快速回复 返回顶部 返回列表