個人的總結 不完善,如有錯誤,歡迎指正,謝謝!!!
1.紅外光按波長範圍分為近紅外、中紅外、遠紅外、極紅外4類。
2.紅外線遙控是利用近紅外光傳送遙控指令的,波長為0.76um~1.5um。
3.用近紅外作為遙控光源,是因為目前紅外發射器件與紅外接收器件的發光與受光峰值波長一般為0.8um~0.94um,這樣可以獲得較高的傳輸效率及較高的可靠性。
1.紅外遙控系統主要由紅外遙控發射裝置、紅外接收設備、遙控微處理機等組成。
2.紅外遙控發射裝置,其主要元件為紅外發光二極體。單只紅外發光二極管的發射功率約 100mW。
3.接收電路的紅外接收管是一種光敏二極體,使用時要給紅外接收二極體加反向偏壓,它才能正常工作而獲得高的靈敏度。
1.常用的紅外線信號傳輸協議有 ITT 協議、 NEC 協議、 Nokia NRC 協議、 Sharp 協議、 Philips RC-5 協議、Philips RC-6協議,
Philips RECS-80協議,以及 Sony SIRC 協議等。
2.協議組成 :一般由引導碼 ,用戶碼,資料碼,重複碼或資料碼的反碼和結束碼構成。
3.載波:常用的有33K,36K,36.6K,38K,40K,56K,無載波
4.占空比:常用的有1/3,1/2,不常用1/4
5.調製方式:脈寬調製,相位調製,脈衝位置調製
在東亞地區比較常用的紅外線傳輸協議是NEC協議,故我們主要介紹NEC協議即6122協議。
紅外線遙控的解碼程序
#include <reg52.h>
#define u8 unsigned char
#define u16 unsigned int
u8 irtime = 0;
u8 startflag = 0;
u8 irdata[33] = {0};
u8 bitnum = 0;
u8 irreceive = 0;
u8 ircore[4] = {0};
u8 irpros = 0;
u8 display[8] = {0};
u8 code smg_du[] = {0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x6f,0x77,0x39,0x5e,0x79,0x71,0x00};
u8 code smg_we[] = {0x08,0x18,0x28,0x38,0x48,0x58,0x68,0x78};
//************************************************
//延時函數 在12MHZ的晶振下
//大約延時 50us
//***********************************************
void delay_time(u16 t)
{
u8 j;
for(;t > 0;t --)
for(j = 19;j > 0;j --);
}
//************************************************
//延時函數 在12MHZ的晶振下
//大約延時 50ms
//***********************************************
void delay_time(u16 t)
{
u8 j;
for(;t > 0;t --)
for(j = 6245;j > 0;j --);
}
//************************************************
//外部中斷 0
//***********************************************
void int0init(void )
{
IT0 = 1;
EX0 = 1;
EA = 1;
}
//************************************************
//開啟中斷定時器0 工作在 2 模式下
//***********************************************
void timer0init(void)
{
TMOD = 0x02;
TH = 0;
TL = 0;
ET0 = 1;
EA = 1;
TR = 1;
}
void irwork()//每個字節用2個數碼管顯示出來
{
diaplay[0] = ircode[0]/16;
diaplay[1] = ircode[0]%16;
diaplay[2] = ircode[1]/16;
diaplay[3] = ircode[1]%16;
diaplay[4] = ircode[2]/16;
diaplay[5] = ircode[2]%16;
diaplay[6] = ircode[3]/16;
diaplay[7] = ircode[3]%16;
}
void displayir() //顯示程序
{
u8 i = 0;
for(i = 0;i < 8;i++)
{
P1 = smg_du[disp[i]];
P2 = smg_we[i];
delay_50us(20);
}
}
void irpros() //處理紅外線按鍵的信息
{
u8 k = 1, v = 0;
u8 value = 0;
u8 j = 0;
for(j = 0 ; j < 4; j++)
{
for(i = 0 ; i < 8; i++)
{
value = value >> 0;
if(irdata[k] > 6) //判斷每一位到底是 0 還是 1 0的時間大約是4.4ms 1的時間大約是 8.8ms
{
value = value |0x80;//查看每一個位是否為 1
}
k++;
}
ircode[j] = value; //將四個字節的紅外線代碼存到數組中
}
irpros = 1;
}
void main()
{
timer0init(); //定時器初始化
int0init(); //外部中斷初始化
while(1)
{
if(irreceive)
{
irpros();
irreceive = 0;
}
if(irpros)
{
irwork();
irpros = 0;
}
display();
}
}
void timer0 interrupt 1 //定時器 0 工作在 2 模式下
{
irtime++; //255
}
void int0init interrupt 0 //外部中斷 0
{
if(startflag)
{
if(irtime > 32) //大約是引導碼得時間
{
bitnum = 0;
}
irdata[bitnmu] = irtime; //開始提取引導碼第一個位
irtime = 0;
bitnum++;
if(bitnum == 33) //引導碼 客戶碼 數據碼 數據反碼 總共33 個位
{
bitnum = 0;
irreceive = 1; //紅外線接受完畢
}
}
else
{
sartflag = 1; //接受到紅外線的標志
irtime = 0;
}
}
紅外發送方:
#include <reg52.h>
static bit OP; // 紅外發射管的亮滅
static unsigned int count; // 延時計數器
static unsigned int endcount; // 終止延時計數
static unsigned int temp; // 按鍵
static unsigned char flag; // 紅外發送標志
static unsigned char num;
sbit ir_in=P3^4;
char iraddr1; //十六位地址的第一個字節
char iraddr2; //十六位地址的第二個字節
unsigned char code table[]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8, //紅外數據傳輸
0x80,0x90,0x88,0x83,0xc6,0xa1,0x86,0x8e}; // 共陽數碼管 0~~f
void SendIRdata(char p_irdata);
void delay(unsigned int);
void keyscan();
/****************** 主函數**************************/
void main(void)
{
num=0;
P2=0x3f;
count = 0;
flag = 0;
OP = 0;
ir_in= 0;
EA = 1; //允許CPU中斷
TMOD = 0x11; //設定時器0和1為16位模式1
ET0 = 1; //定時器0中斷允許
TH0 = 0xFF;
TL0 = 0xE6; //設定時值0為38K 也就是每隔26us中斷一次
TR0 = 1; //開始計數
iraddr1=3; //00000011
iraddr2=252; //11111100
do{
keyscan();
}while(1);
}
/*********************** 定時器0中斷處理 **********************/
void timeint(void) interrupt 1
{
TH0=0xFF;
TL0=0xE6; //設定時值為38K 也就是每隔26us中斷一次
count++;
if (flag==1)
{
OP=~OP;
}
else
{
OP = 0;
}
ir_in= 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++)
{
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(unsigned int z)
{
unsigned char x,y;
for(x=z;x>0;x--)
for(y=110;y>0;y --);
}
/*********************4 ×4鍵盤掃描按下按鍵發射數據************************/
void keyscan()
{
P1=0xfe;
temp=P1;
temp=temp&0xf0;
while(temp!=0xf0)
{
temp=P1;
switch(temp)
{
case 0xee:num=1;
break;
case 0xde:num=2;
break;
case 0xbe:num=3;
break;
case 0x7e:num=4;
break;
}
while(temp!=0xf0)
{
temp=P1;
temp=temp&0xf0;
}
P2=table[num-1];
SendIRdata(table[num -1]);
}
P1=0xfd;
temp=P1;
temp=temp&0xf0;
while(temp!=0xf0)
{
temp=P1;
switch(temp)
{
case 0xed:num=5;
break;
case 0xdd:num=6;
break;
case 0xbd:num=7;
break;
case 0x7d:num=8;
// 紅外數據傳輸
break;
}
while(temp!=0xf0)
{
temp=P1;
temp=temp&0xf0;
}
P2=table[num-1];
SendIRdata(table[num -1]);
}
P1=0xfb;
temp=P1;
temp=temp&0xf0;
while(temp!=0xf0)
{
temp=P1;
switch(temp)
{
case 0xeb:num=9;
break;
case 0xdb:num=10;
break;
case 0xbb:num=11;
break;
case 0x7b:num=12;
break;
}
while(temp!=0xf0)
{
temp=P1;
temp=temp&0xf0;
}
P2=table[num-1];
SendIRdata(table[num -1]);
}
P1=0xf7;
temp=P1;
temp=temp&0xf0;
while(temp!=0xf0)
{
temp=P1;
switch(temp)
{
case 0xe7:num=13;
break;
case 0xd7:num=14;
break;
case 0xb7:num=15;
break;
case 0x77:num=16;
break;
}
while(temp!=0xf0)
{
temp=P1;
temp=temp&0xf0;
}
//紅外數據傳輸
P2=table[num-1];
SendIRdata(table[num -1]);
}
}
紅外的接受方:
#include"reg52.h"
#define uchar unsigned char
#define uint unsigned int
uchar dis_num,num,num1,num2,num3;
sbit led=P1^0;
unsigned char code table[]={
0xc0,0xf9,0xa4,0xb0,
0x99,0x92,0x82,0xf8,
0x80,0x90,0x88,0x83,
0xc6,0xa1,0x86,0x8e}; // 共陽數碼管 0~~f
sbit prem =P3^2; //定義遙控頭的接收腳
uchar ram[4]={0,0,0,0}; // 存放接受到的4個數據 地址碼16位+按鍵碼8位+按鍵碼取反的8位
void delaytime(uint time) //延遲90uS
{
uchar a,b;
for(a=time;a>0;a--)
{
for(b=40;b>0;b--);
}
}
void rem()interrupt 0 //中斷函數
{
uchar ramc=0; //定義接收了4個字節的變量
uchar count=0; //定義現在接收第幾位變量
uint i=0; //此處變量用來在下面配合連續監測9MS 內是否有高電平
prem=1;
for(i=0;i<1100;i++) //以下FOR語句執行時間為8MS左右
{
if(prem) //進入遙控接收程序首先進入引導碼的前半部判斷,即:是否有9MS左右的低電平
return; //引導碼錯誤則退出
}
while(prem!=1); //等待引導碼的后半部 4.5 MS 高電平開始的到來。
delaytime(50); //延時大于4.5MS時間,跨過引導碼的后半部分,來到真正遙控數據32位中
//第一位數據的0.56MS開始脈沖
for(ramc=0;ramc<4;ramc++) // 循環4次接收4個字節
{
for(count=0;count<8;count++) //循環8次接收8位(一個字節)
{
while(prem!=1); //開始判斷現在接收到的數據是0或者1 ,首先在這行本句話時,
//保已經進入數據的0.56MS 低電平階段
//等待本次接受數據的高電平的到來。
delaytime(9); //高電平到來后,數據0 高電平最多延續0.56MS,而數據1,高電平可
// 紅外數據傳輸
//延續1.66MS大于0.8MS 后我們可以再判斷遙控接收腳的電平,
if(prem) //如果這時高電平仍然在繼續那么接收到的數據是1的編碼
{
ram[ramc]=(ram[ramc]<<1)+1; // 將目前接收到的數據位1放到對應的字節中
delaytime(11); //如果本次接受到的數據是1,那么要繼續延遲1MS,這樣才能跨入
//下個位編碼的低電平中(即是開始的0.56MS中)
}
else //否則目前接收到的是數據0的編碼
ram[ramc]=ram[ramc]<<1; // 將目前接收到的數據位0放到對應的字節中
} //本次接收結束,進行下次位接收,此接收動作進行32次,正好完成4個字節的接收
}
if(ram[2]!=(~(ram[3]&0x7f))) //本次接收碼的判斷
{
for(i=0;i<4;i++) //沒有此對應關系則表明接收失敗,清除接受到的數據
ram[i]=0;
return ;
}
dis_num=ram[2]; //將接收到的按鍵數據賦給顯示變量
}
main()
{
IT0=1; // 設定INT0為邊沿觸發
EX0=1; //打開外部中斷0
EA=1; // 全局中斷開關打開
while(1)
{
switch(dis_num)
{
case 0x81: num=0; break;
case 0xcf: num=1; break;
case 0x92: num=2; break;
case 0x86: num=3; break;
case 0xcc: num=4; break;
case 0xa4: num=5; break;
case 0xa0: num=6; break;
case 0x8f: num=7; break;
case 0x80: num=8; break;
case 0x84: num=9; break;
case 0x88: num=10;break;
case 0xe0: num=11;break;
case 0xb1: num=12;break;
case 0xc2: num=13;break;
case 0xb0: num=14;break;
case 0xb8: num=15;break;
}
P2=table[num];
P1=0x01;
delaytime(5);
}
}
|