这个是32位的图,你把42位的图发上来我帮你分析自动判别的方法
还有一个网上的波形,好像不太对。
这个图前面的引导码怎么看?
你这个也是32位的,只是引导码不同而已,nec格式的是9ms高电平4.5ms低电平,而你发的这个高低都是4.5毫秒,其他的数据格式一样
你发的都是32位的呢,没有42位的啊,你只要去数数据就知道是多少位了 用户码8位,反码8位,数据码8位,反码8位,,4*8=32位
不好意思图发的太多了我没注意到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位,你看这样行不行.
请问这个程序有问题吗???好像解不了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(); } } }
你这个程序能解32位的吗,测试成功了没有?
告诉你个办法测试你的42位发射器,你可以用51hei单片机开发板制作一个红外波形分析器
http://www.51hei.com/bbs/dpj-4524-1.html
来看发射出来的波形是否正确,
只有在你的发射波形正确的前提下你再进行解码试验,不然那是毫无意义的.
我也看不出这个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++) { } } }
程序应该没有问题我看了,你发送了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
谢谢你的提醒,我把 if(irdata-(irdata/2)*2) //判断二进制数个位为1还是0 改为 if(irdata&0x01) 了。但是,测试了一个,还是接收不到42位的。
那应该是你的解码程序有问题了 仔细调试下 看问题出来哪里
看见大家在讨论 32 位和 42 位的问题,也说几句:
1.如果你接收的是有标准格式的数据码(不是什么硬性标准,仅仅是市场拥有量有一定规模的),当然需要会出现这种 32 位或 42 位 或 更多其它数值位数的问题(实际上并不是仅仅只有这 2 种位数哦!).测试时可以借助一些工具(红外线码接收分析,本论坛就有简单可靠),或者无限制长度进行接收.弄清楚位数,查找数据码与引导头的区别.有些品种一直按着遥控器会重复发送数据.
2.如果是非标准的代码,方法也如上面差不多.但是变数更多,不要主观认为引导头必须=9ms,没有这个规定!也不要认为发射频率就是 38KHZ,也有 36KHZ 到 43KHZ 之间的.不要认为就是多少位,实际多少位都可以的,任意人家安排的----有点破解密码的味道!
3.红外线除了我们通常说的遥控器之外,也有用来通信的,作为传送数据使用----本来就是传送数据嘛!遥控器的特色是以可以代表一个特定的按键为主,传送数据的用途时,就没有这种限制了.-----开发人员怎么考虑,怎么安排,完完全全你是不知道的.----例如:做一个 5 位数值显示的温度表,加上校验码,引导头等等,你说会是多少位?
再例如:与 PC 机的 RS232 通信,没有位数限制.发多少就送多少,就接收多少,它再也不用位数来判断是否发送完成了.
4.代码的 0 与 1 .串行数据没有其它办法,它只有使用时间长短来代表 0 与 1.这个时间,不同厂家使用完全可以不按照通常"标准"遥控器来做的.只要它自己可以配套就行了!-------也有抗干扰好处呢!引导头,结束标志,都可以脱离标准方式的.-----如果打算彻底弄明白,需要花费许多时间与精力.
今天就写这些.------仅供参考!
欢迎光临 (http://www.51hei.com/bbs/) | Powered by Discuz! X3.1 |