找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 14727|回复: 22
打印 上一主题 下一主题
收起左侧

[求助]请问做红外解码时,如何自动判别32位还是42位???

[复制链接]
跳转到指定楼层
楼主
ID:25357 发表于 2010-8-8 00:02 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
请问做红外解码时,如何自动判别32位还是42位???谢谢。
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享淘帖 顶 踩
回复

使用道具 举报

沙发
ID:1 发表于 2010-8-8 08:20 | 只看该作者
42位是什么格式的?什么芯片产生的波形?
回复

使用道具 举报

板凳
ID:1 发表于 2010-8-8 08:23 | 只看该作者

这个是32位的图,你把42位的图发上来我帮你分析自动判别的方法

回复

使用道具 举报

地板
ID:25357 发表于 2010-8-8 10:12 | 只看该作者



[此贴子已经被作者于2010-8-8 10:15:55编辑过]
回复

使用道具 举报

5#
ID:25357 发表于 2010-8-8 10:31 | 只看该作者

还有一个网上的波形,好像不太对。


[此贴子已经被作者于2010-8-8 10:31:21编辑过]
回复

使用道具 举报

6#
ID:25357 发表于 2010-8-8 15:51 | 只看该作者

这个图前面的引导码怎么看?


[此贴子已经被作者于2010-8-8 15:52:13编辑过]
回复

使用道具 举报

7#
ID:1 发表于 2010-8-8 16:51 | 只看该作者

你这个也是32位的,只是引导码不同而已,nec格式的是9ms高电平4.5ms低电平,而你发的这个高低都是4.5毫秒,其他的数据格式一样

回复

使用道具 举报

8#
ID:25357 发表于 2010-8-9 08:21 | 只看该作者
那如果判断32还42位呢?
回复

使用道具 举报

9#
ID:1 发表于 2010-8-9 15:55 | 只看该作者

你发的都是32位的呢,没有42位的啊,你只要去数数据就知道是多少位了 用户码8位,反码8位,数据码8位,反码8位,,4*8=32位

回复

使用道具 举报

10#
ID:25357 发表于 2010-8-9 23:57 | 只看该作者
4楼没有看到???不是吗????
[此贴子已经被作者于2010-8-9 23:58:02编辑过]
回复

使用道具 举报

11#
ID:1 发表于 2010-8-10 01:58 | 只看该作者

不好意思图发的太多了我没注意到4楼, 引导码+13*2+8*2=42位 没有错

 

这个和普通的 日本NEC的uPD6121G的 唯一区别就是用户码多了5位,应该是PT2461、LC7461格式的,引导码+13位用户码+13位用户反码+8位键数据码+8位键数据反码

 

 

   要判别是32位还是42位,我想可以这么做,先把所有的编码都保存在数组里,然后取开头的1->8位 和9->16位比较,看是否互为反码,如果是就说明这是32位格式的编码,如果不是再比较1->13位和14->26位,你看这样行不行.

[此贴子已经被作者于2010-8-10 2:21:35编辑过]
回复

使用道具 举报

12#
ID:25357 发表于 2010-8-10 08:38 | 只看该作者
貌似可以,但是我想问一下,32位和42位,开头都有用户码和用户反码的吗???
回复

使用道具 举报

13#
ID:25357 发表于 2010-8-10 11:57 | 只看该作者

请问这个程序有问题吗???好像解不了42位的,但是我的42位红外发射也是自己做的,不知道是解码问题,还是发射问题???谢谢。

 

 


#include <reg52.h>
#include <intrins.h>
#define uchar unsigned char 
#define RdCommand 0x01 //定义ISP的操作命令
#define PrgCommand 0x02
#define EraseCommand 0x03 
#define Error 1
#define Ok 0
#define WaitTime 0x01 //定义CPU的等待时间
sfr ISP_DATA=0xe2;  //寄存器申明
sfr ISP_ADDRH=0xe3;
sfr ISP_ADDRL=0xe4;
sfr ISP_CMD=0xe5;
sfr ISP_TRIG=0xe6;
sfr ISP_CONTR=0xe7;
sbit dula=P2^6;  //申明U1锁存器的锁存端
sbit wela=P2^7;  //申明U2锁存器的锁存端

uchar code table[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,
                        0x07,0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71};

uchar f;

#define Imax 14000    //此处为晶振为11.0592时的取值, 
#define Imin 8000    //如用其它频率的晶振时,
#define Inum1 1450    //要改变相应的取值。
#define Inum2 700 
#define Inum3 3000 

uchar Im[6]={0x00,0x00,0x00,0x00,0x00,0x00};
uchar Im1[2]={0x00,0x00};
uchar Im2[3]={0x00,0x00,0x00};
uchar show[6]={0,0,0,0,0,0};
//uchar Eim[4]={0,0,0,0};
unsigned long m,Tc;
unsigned char IrOK;
uchar IR;//分辨32位还是42位


void delay(uchar i)
{
  uchar j,k; 
  for(j=i;j>0;j--)
    for(k=125;k>0;k--);
}

void display()
{
   dula=0;
   P0=table[show[0]];
   dula=1;
   dula=0;
   
   wela=0;
   P0=0xfe;
   wela=1;
   wela=0;
   delay(5);
   
   P0=table[show[1]];
   dula=1;
   dula=0;
   
   P0=0xfd;
   wela=1;
   wela=0;
   delay(5);


   
}

  /* ================ 打开 ISP,IAP 功能 ================= */
void ISP_IAP_enable(void)
{
 EA = 0;       /* 关中断   */
 ISP_CONTR = ISP_CONTR & 0x18;       /* 0001,1000 */
 ISP_CONTR = ISP_CONTR | WaitTime; /* 写入硬件延时 */
 ISP_CONTR = ISP_CONTR | 0x80;       /* ISPEN=1  */
}
/* =============== 关闭 ISP,IAP 功能 ================== */
void ISP_IAP_disable(void)
{
 ISP_CONTR = ISP_CONTR & 0x7f; /* ISPEN = 0 */
 ISP_TRIG = 0x00;
 EA   =   1;   /* 开中断 */
}
/* ================ 公用的触发代码 ==================== */
void ISPgoon(void)
{
 ISP_IAP_enable();   /* 打开 ISP,IAP 功能 */
 ISP_TRIG = 0x46;  /* 触发ISP_IAP命令字节1 */
 ISP_TRIG = 0xb9;  /* 触发ISP_IAP命令字节2 */
 _nop_();
}
/* ==================== 字节读 ======================== */
unsigned char byte_read(unsigned int byte_addr)
{
 ISP_ADDRH = (unsigned char)(byte_addr >> 8);/* 地址赋值 */
 ISP_ADDRL = (unsigned char)(byte_addr & 0x00ff);
 ISP_CMD   = ISP_CMD & 0xf8;   /* 清除低3位  */
 ISP_CMD   = ISP_CMD | RdCommand; /* 写入读命令 */
 ISPgoon();       /* 触发执行  */
 ISP_IAP_disable();    /* 关闭ISP,IAP功能 */
 return (ISP_DATA);    /* 返回读到的数据 */
}
/* ================== 扇区擦除 ======================== */
void SectorErase(unsigned int sector_addr)
{
 unsigned int iSectorAddr;
 iSectorAddr = (sector_addr & 0xfe00); /* 取扇区地址 */
 ISP_ADDRH = (unsigned char)(iSectorAddr >> 8);
 ISP_ADDRL = 0x00;
 ISP_CMD = ISP_CMD & 0xf8;   /* 清空低3位  */
 ISP_CMD = ISP_CMD | EraseCommand; /* 擦除命令3  */
 ISPgoon();       /* 触发执行  */
 ISP_IAP_disable();    /* 关闭ISP,IAP功能 */
}
/* ==================== 字节写 ======================== */
void byte_write(unsigned int byte_addr, unsigned char original_data)
{
 ISP_ADDRH = (unsigned char)(byte_addr >> 8);  /* 取地址  */
 ISP_ADDRL = (unsigned char)(byte_addr & 0x00ff);
 ISP_CMD  = ISP_CMD & 0xf8;    /* 清低3位 */
 ISP_CMD  = ISP_CMD | PrgCommand;  /* 写命令2 */
 ISP_DATA = original_data;   /* 写入数据准备 */
 ISPgoon();       /* 触发执行  */
 ISP_IAP_disable();     /* 关闭IAP功能 */
}

 


//外部中断解码程序
void intersvr1(void) interrupt 2 using 1
{

 Tc=TH0*256+TL0;   //提取中断时间间隔时长
 TH0=0; 
    TL0=0;         //定时中断重新置零
 if((Tc>Imin)&&(Tc<Imax))
      { 
  m=0;
        f=1;
  return;
      }       //找到启始码
   if(f==1)
      {
        if(Tc>Inum1&&Tc<Inum3) 
    {
   Im[m/8]=Im[m/8]>>1|0x80; m++; 
       }
      if(Tc>Inum2&&Tc<Inum1) 
        {
         Im[m/8]=Im[m/8]>>1; m++; //取码
  }
 if(m>=16)
 {
    if(Im[0]!=~Im[1])  //判定32位或42位
  {
   if(m==42)
   m=0;
   f=0;
   if((Im[3]<<2|Im[4]>>6)==~(Im[4]<<2|Im[5]>>6))
   {
   IrOK=1;
   IR=42;
   Im2[0]=Im[0];
   Im2[1]=Im[1]>>3;
   Im2[2]=Im[3]<<2|Im[4]>>6 ;
   }
   else
   IrOK=0;
  }
 
   else {
    if(m==32) 
   {
         m=0;  
         f=0;
         if(Im[2]==~Im[3]) 
      {
           IrOK=1;
     IR=32; 
     Im1[0]=Im[0];
     Im1[1]=Im[2];
   }
        else IrOK=0;   //取码完成后判断读码是否正确
     }
  }
 }


   }
 
}


/*演示主程序*/
void main(void)
{
    unsigned int  a;
   
 m=0;
    f=0;
 EA=1;
 
 IT1=1;EX1=1;
 
 TMOD=0x11;  
 TH0=0;TL0=0;
 TR0=1;//ET0=1;

 while(1)
 {
 
       if(IrOK==1) 
    {
      SectorErase(0x2000);//擦除扇区
         if(IR==32)
    {
   byte_write(0x2000,Im1[1]);//重新写入数据  
   byte_write(0x2001,Im1[0]);
       }
      if(IR==42) 
    {
   byte_write(0x2000,Im2[2]);//重新写入数据  
      byte_write(0x2001,Im2[0]);
      byte_write(0x2002,Im2[1]);

   }
    }
       
     Im[2]=byte_read(0x2000); 
           show[1]=Im[2] & 0x0F;     //取键码的低四位
           show[0]=Im[2] >> 4;   

           IrOK=0;      
  
           for(a=100;a>0;a--)
          {
    display();
   }
 
 }
}


回复

使用道具 举报

14#
ID:1 发表于 2010-8-10 17:20 | 只看该作者

你这个程序能解32位的吗,测试成功了没有?

 

告诉你个办法测试你的42位发射器,你可以用51hei单片机开发板制作一个红外波形分析器
http://www.51hei.com/bbs/dpj-4524-1.html

来看发射出来的波形是否正确,

 

只有在你的发射波形正确的前提下你再进行解码试验,不然那是毫无意义的.

回复

使用道具 举报

15#
ID:25357 发表于 2010-8-10 20:31 | 只看该作者
32位的已经测试成功。。。但是我想用rtx51 tiny来写,结果显示不出来。
回复

使用道具 举报

16#
ID:22246 发表于 2010-8-10 23:33 | 只看该作者
你发个基于51hei开发板的 42位的红外 发射程序吧,我没有这样的发射器所以只能用51hei开发板来代替,这样才能调试你的接受程序,至于移植到rtx51 tiny出现问题,这肯定移植过程不小心出了错误,仔细找找.
回复

使用道具 举报

17#
ID:25357 发表于 2010-8-11 00:47 | 只看该作者

我也看不出这个42位发射的程序对 不对。

 


#include <AT89X51.h> 
static bit OP;        //红外发射管的亮灭
static unsigned int count;       //延时计数器
static unsigned int endcount; //终止延时计数
static unsigned char flag;      //红外发送标志
char iraddr1;  
char iraddr2; 
char iraddr3;  
char iraddr4;  

void SendIRdata(char p_irdata);
void delay();
void main(void) 
{
  count = 0;
  flag = 0;
  OP = 0;
  P2_3 = 0;
  EA = 1; //允许CPU中断 
  TMOD = 0x11; //设定时器0和1为16位模式1 
  ET0 = 1; //定时器0中断允许 

  TH0 = 0xFF; 
  TL0 = 0xE5; //设定时值0为38K 也就是每隔26us中断一次  
  TR0 = 1;//开始计数
  iraddr1=0xb3;
  iraddr2=0x8a;
  iraddr1=0xa9;
  iraddr2=0x02;

  do{
      delay();
      SendIRdata(0x36);// 在此填入发射数据
  }while(1);
} 
//定时器0中断处理 
void timeint(void) interrupt 1 
{ 
  TH0=0xFF; 
  TL0=0xE5; //设定时值为38K 也就是每隔26us中断一次
  count++;
  if (flag==1)
  {
    OP=~OP;
  }
  else
  {
    OP = 0;
  }
  P2_3 = OP;
} 

void SendIRdata(char p_irdata)
{
  int i;
  char irdata=p_irdata;
  //发送9ms的起始码
  endcount=223;
  flag=1;
  count=0;
  do{}while(count<endcount);
  //发送4.5ms的结果码
  endcount=117;
  flag=0;
  count=0;
  do{}while(count<endcount);
  
  irdata=iraddr1;
  for(i=0;i<8;i++)
  {
     //先发送0.56ms的38KHZ红外波(即编码中0.56ms的低电平)
     endcount=10;
     flag=1;
     count=0;
     do{}while(count<endcount);
 
     if(irdata-(irdata/2)*2)  //判断二进制数个位为1还是0
     {
       endcount=41;  //1为宽的高电平
     }
    else
     {
     endcount=15;   //0为窄的高电平
     }
    flag=0;
    count=0;
    do{}while(count<endcount);
    irdata=irdata>>1;
  }

  irdata=iraddr2;
  for(i=0;i<8;i++)
  {
     //先发送0.56ms的38KHZ红外波(即编码中0.56ms的低电平)
     endcount=10;
     flag=1;
     count=0;
     do{}while(count<endcount);
 
     if(irdata-(irdata/2)*2)  //判断二进制数个位为1还是0
     {
       endcount=41;  //1为宽的高电平
     }
    else
     {
     endcount=15;   //0为窄的高电平
     }
    flag=0;
    count=0;
    do{}while(count<endcount);
    irdata=irdata>>1;
  }

  irdata=iraddr3;
  for(i=0;i<8;i++)
  {
     //先发送0.56ms的38KHZ红外波(即编码中0.56ms的低电平)
     endcount=10;
     flag=1;
     count=0;
     do{}while(count<endcount);
 
     if(irdata-(irdata/2)*2)  //判断二进制数个位为1还是0
     {
       endcount=41;  //1为宽的高电平
     }
    else
     {
     endcount=15;   //0为窄的高电平
     }
    flag=0;
    count=0;
    do{}while(count<endcount);
    irdata=irdata>>1;
  }
  //发送26位 的后2位
  irdata=iraddr4;
  for(i=0;i<2;i++)
  {
     endcount=10;
     flag=1;
     count=0;
     do{}while(count<endcount);
     if(irdata-(irdata/2)*2)
     {
        endcount=41;
     }
     else
     {
       endcount=15;
     }
     flag=0;
     count=0;
     do{}while(count<endcount);
     irdata=irdata>>1;
  }
  //发送八位数据
  irdata=p_irdata;
  for(i=0;i<8;i++)
  {
     endcount=10;
     flag=1;
     count=0;
     do{}while(count<endcount);
     if(irdata-(irdata/2)*2)
     {
         endcount=41;
     }
     else
     {
       endcount=15;
     }
     flag=0;
     count=0;
     do{}while(count<endcount);
     irdata=irdata>>1;
  }
  //发送八位数据的反码
  irdata=~p_irdata;
  for(i=0;i<8;i++)
  {
     endcount=10;
     flag=1;
     count=0;
     do{}while(count<endcount);
     if(irdata-(irdata/2)*2)
     {
         endcount=41;
     }
     else
     {
       endcount=15;
     }
     flag=0;
     count=0;
     do{}while(count<endcount);
     irdata=irdata>>1;
  }
  endcount=10;
  flag=1;
  count=0;
  do{}while(count<endcount);
  flag=0;
}
void delay()
{
  int i,j;
  for(i=0;i<400;i++)
  {
    for(j=0;j<100;j++)
    {
    }
  }
}
回复

使用道具 举报

18#
ID:1 发表于 2010-8-11 02:46 | 只看该作者

程序应该没有问题我看了,你发送了26位用户码分了4次发送的,见下的4行
iraddr1=0xb3;
iraddr2=0x8a;
iraddr1=0xa9;
iraddr2=0x02;

化为2进制为
10110011
10001010
10101001
10

再组合为2个13位 得到
0101010110011
1010101001100

这2组互为反码,说明应该是正确的.

 

但是程序也有缺点,下面这个语句又是乘法又是除法,执行起来恐怕时间要花上10us吧,而载波的周期才26us.这里要改进.

 if(irdata-(irdata/2)*2)  //判断二进制数个位为1还是0

[此贴子已经被作者于2010-8-11 2:51:52编辑过]
回复

使用道具 举报

19#
ID:25357 发表于 2010-8-11 08:28 | 只看该作者

谢谢你的提醒,我把   if(irdata-(irdata/2)*2)  //判断二进制数个位为1还是0      改为    if(irdata&0x01) 了。但是,测试了一个,还是接收不到42位的。

回复

使用道具 举报

20#
ID:1 发表于 2010-8-11 14:47 | 只看该作者

那应该是你的解码程序有问题了 仔细调试下 看问题出来哪里

回复

使用道具 举报

21#
ID:27770 发表于 2011-1-12 13:02 | 只看该作者

看见大家在讨论 32 位和 42 位的问题,也说几句:

1.如果你接收的是有标准格式的数据码(不是什么硬性标准,仅仅是市场拥有量有一定规模的),当然需要会出现这种 32 位或 42 位 或 更多其它数值位数的问题(实际上并不是仅仅只有这 2 种位数哦!).测试时可以借助一些工具(红外线码接收分析,本论坛就有简单可靠),或者无限制长度进行接收.弄清楚位数,查找数据码与引导头的区别.有些品种一直按着遥控器会重复发送数据.

2.如果是非标准的代码,方法也如上面差不多.但是变数更多,不要主观认为引导头必须=9ms,没有这个规定!也不要认为发射频率就是 38KHZ,也有 36KHZ 到 43KHZ 之间的.不要认为就是多少位,实际多少位都可以的,任意人家安排的----有点破解密码的味道!

3.红外线除了我们通常说的遥控器之外,也有用来通信的,作为传送数据使用----本来就是传送数据嘛!遥控器的特色是以可以代表一个特定的按键为主,传送数据的用途时,就没有这种限制了.-----开发人员怎么考虑,怎么安排,完完全全你是不知道的.----例如:做一个 5  位数值显示的温度表,加上校验码,引导头等等,你说会是多少位?

再例如:与 PC 机的 RS232 通信,没有位数限制.发多少就送多少,就接收多少,它再也不用位数来判断是否发送完成了.

4.代码的 0 与 1 .串行数据没有其它办法,它只有使用时间长短来代表 0 与 1.这个时间,不同厂家使用完全可以不按照通常"标准"遥控器来做的.只要它自己可以配套就行了!-------也有抗干扰好处呢!引导头,结束标志,都可以脱离标准方式的.-----如果打算彻底弄明白,需要花费许多时间与精力.

今天就写这些.------仅供参考!

回复

使用道具 举报

22#
ID:72947 发表于 2015-2-2 00:17 | 只看该作者
前天解了个万能彩电遥控,就是用户码并不规则,前后并不是反码...
回复

使用道具 举报

23#
ID:73792 发表于 2015-2-23 16:56 | 只看该作者
学习学习。。。。。。
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

手机版|小黑屋|51黑电子论坛 |51黑电子论坛6群 QQ 管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网

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