
這個是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://m.raoushi.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://m.raoushi.com/bbs/) | Powered by Discuz! X3.1 |