紅外遙控解碼實(shí)驗(yàn)
一. 實(shí)驗(yàn)?zāi)康?br />
1. 了解紅外遙控編碼并用單片機(jī)捕捉信號(hào)及解碼
2. 熟悉LCD1602的驅(qū)動(dòng)
二.紅外遙控器編碼
遙控器編碼分好幾種,常見(jiàn)的32位編碼碼和42位編碼碼,目前我手中遙控器就是42位編碼,如圖1所示,當(dāng)有按鍵時(shí)就會(huì)產(chǎn)一個(gè)9.12ms低電平和4.5ms高電平的起始碼,緊接著是26位系統(tǒng)碼,此系統(tǒng)碼能區(qū)別不同的電器設(shè)備,防止不同機(jī)種遙控碼互相干擾,接下來(lái)是8位數(shù)據(jù)碼和8位數(shù)據(jù)反碼,間隔23ms的高電平后,再發(fā)一個(gè)與啟始碼完全一樣的結(jié)束碼
以脈寬為0.565ms、間隔0.56ms、周期為1.125ms的組合表示二進(jìn)制的“0”;以脈寬為0.565ms、間隔1.685ms、周期為2.25ms的組合表示二進(jìn)制的“1”,其波形如圖2所示。
圖2
再回頭看圖1,大家不難看出,圖1是遙控器按鍵1的一串編碼
三. 硬件連接
接收電咱我們使用一化紅外接紅外接收管1838,不需要任何外接無(wú)件,就能完成從紅外線接收到輸出與TTL電平信號(hào)兼容的所有工作,實(shí)物如圖所示
電路圖如下:
四. 解碼
以上我們了解了紅外遙控的編碼及硬件連接,現(xiàn)在就對(duì)其進(jìn)行解碼,所謂解碼就是能用單片機(jī)把以不同寬度的脈沖區(qū)別開(kāi)來(lái),一種比較好思路就是計(jì)算兩次下降沿間隔時(shí)間,當(dāng)單片機(jī)外部中斷1口有下降沿時(shí)中斷一次,并啟動(dòng)定時(shí)器,定時(shí)器定50us,當(dāng)下次下降沿到來(lái)時(shí)我們計(jì)算定時(shí)器中斷的次數(shù),這樣我們就能很好的區(qū)分不同寬度的脈沖了。
大家可能已經(jīng)迫不急待的要開(kāi)始解碼了,別急,我們先把注意事項(xiàng)先講一下,實(shí)際上,我們紅外接收頭收到的信號(hào)的是有毛刺的,放大后就如下圖,所以在下降沿中斷觸發(fā)后,要做延時(shí)去抖處理
*************************************以下是完整解碼程序********************************
/*********************************************
**項(xiàng)目: 紅外遙控解碼(EE01學(xué)習(xí)板演示程序)
**作者:一線工人
**網(wǎng)站:電子工程師之家
www.eehome.cn
**本程序適合42位碼遙控器,即26位系統(tǒng)碼,16位
數(shù)據(jù)碼,如:57L5,55K2,54B4,KD-29,55K8,5Z26A,
等型號(hào)的遙控器,轉(zhuǎn)貼請(qǐng)保持代碼的完整性
*********************************************/
#include<reg52.h>
#define uint unsigned int
#define uchar unsigned char
sbit ir=P3^3;//紅外端口
sbit dm=P1^4;//數(shù)碼管段碼控制位
sbit wm=P1^5;//數(shù)碼管位碼控制位
sbit led_cs=P1^6;//LED控制位
sbit rs=P3^5;//1602數(shù)據(jù)命令選擇端
sbit en=P3^4;//1602使能信號(hào)
uchar num;
uchar key_code=0;//遙控鍵值
uchar new_code=0;//有無(wú)新按鍵
uint buf_key_code=0;//鍵值暫存
uchar key_bit_count=0;//鍵編碼脈沖計(jì)數(shù)
uint count=0;//定時(shí)中斷次數(shù)計(jì)數(shù)
uint buf_count=0;//定時(shí)中斷計(jì)數(shù)暫存
uchar common_code_count=0;//前導(dǎo)碼脈沖計(jì)數(shù)
uchar ir_status=0;//脈沖接收器所處的狀態(tài),0:無(wú)信號(hào),1:系統(tǒng)碼接收區(qū),2:數(shù)據(jù)編碼接收區(qū)
uchar code table[]="EE01 DEMO:IR";
uchar code table1[]="code:";
uchar code table2[]={'0','1','2','3','4','5','6','7','8','9',};
void delay_10us(unsigned char y)///延時(shí)子程序10us
{
unsigned char x;
for(x=y;x>0;x--);
}
void delay_ms(uint z)//延時(shí)子程序1ms
{
uint x,y;
for(x=z;x>0;x--)
for(y=113;y>0;y--);
}
void init(void)/////初始化
{
ir=1; //紅外端口寫(xiě)1
led_cs=0; //關(guān)閉LED
EA=1; //開(kāi)總中斷
TMOD=0x02; //定時(shí)器0,模式2,8位自動(dòng)裝載模式
TH0=0Xd1; //定時(shí)50us
TL0=0Xd1;
IT1=1; //INT1下降沿觸發(fā)
ET0=1; //允許定時(shí)器中斷
EX1=1; //允許外部中斷
}
/***********************************************
定時(shí)器中斷
***********************************************/
void time0() interrupt 1///定時(shí)器中斷
{
count++;//定時(shí)器中斷次數(shù)累加
}
/**********************************************
外部中斷,紅外解碼程序
**********************************************/
void int1() interrupt 2///外部中斷
{
TR0=1;//開(kāi)定時(shí)器中斷
if(count>12&&count<270)//如果信號(hào)合法,則放入buf_count,count清0,對(duì)下一個(gè)脈沖信號(hào)計(jì)時(shí)
{
buf_count=count;
count=0;
}
delay_10us(10);//延時(shí)100us以消除下降沿跳變抖動(dòng)
if(ir==0)//INT1引腳穩(wěn)定為低電平,則表法確實(shí)是信號(hào),count重新計(jì)時(shí),因上面延時(shí)了50us,故要補(bǔ)償1次TO中斷
{
count=2;
}
if(buf_count>12&&buf_count<270)//若收到的信號(hào)合法,則再進(jìn)行信號(hào)分析
{
if(ir_status==0)//如果之前未收到引導(dǎo)碼
{
if(buf_count>210&&buf_count<270)//判斷是否引導(dǎo)碼13.5ms
{
ir_status=1;//系統(tǒng)標(biāo)記
buf_count=0;//
}
}
else if(ir_status==1)///收到引導(dǎo)碼
{
if(common_code_count>=25)//若收完26個(gè)脈沖
{
ir_status=2;//數(shù)據(jù)解碼標(biāo)記
common_code_count=0;//系統(tǒng)碼計(jì)算清零
buf_count=0;//中斷計(jì)數(shù)暫存清0
}
else if((buf_count>40&&buf_count<70)||(buf_count>12&&buf_count<32))
{
buf_count=0;
common_code_count++;//每收到一個(gè)信號(hào)自加1
}
}
else if(ir_status==2)//進(jìn)入數(shù)據(jù)編碼接收
{
if(key_bit_count<8)//收到數(shù)據(jù)少于8位,則將收到的數(shù)據(jù)寫(xiě)入buf_key_code
{
if(buf_count>40&&buf_count<70)
{
buf_count=0;
buf_key_code>>=1;
buf_key_code|=0x80;//收到1
key_bit_count++;//數(shù)據(jù)脈沖累加
}
else if(buf_count>12&&buf_count<32)//收到0
{
buf_count=0;
buf_key_code>>=1;//收到0
key_bit_count++;
}
}
else //若收完8位數(shù)據(jù)則做以下處理
{
ir_status=0;//接收狀態(tài)返回到空閑
key_code=buf_key_code;
key_bit_count=0;
buf_key_code=0;
buf_count=0;
TR0=0;
new_code=1;
}
}
}
}
/**********************************************
1062驅(qū)動(dòng)程序
**********************************************/
void wirte_cmd(uchar cmd)//寫(xiě)命令
{
rs=0;
P0=cmd;
en=1;
delay_ms(5);
en=0;
}
void wirte_data(uchar dat)//寫(xiě)數(shù)據(jù)
{
rs=1;
P0=dat;
en=1;
delay_ms(5);
en=0;
}
void wirte_string(const unsigned char *s)//在第二行第5個(gè)字開(kāi)始寫(xiě)字符串
{
wirte_cmd(0x80+0x40+0x05);
while(*s)
{
wirte_data(*s);
s++;
}
}
void init_1602()///1602初始化
{
dm=0;
wm=0;
led_cs=0;
wirte_cmd(0x38);
delay_ms(5);
wirte_cmd(0x0c);
delay_ms(5);
wirte_cmd(0x06);
}
/*************************************
主程序
*************************************/
void main()
{
init(); ///初始化
init_1602(); //1602初始化
while(!new_code);//判斷是否有新按鍵,如果有則執(zhí)行下面程序,沒(méi)有則一直循環(huán)
wirte_cmd(0x01);//1602清屏
delay_ms(5);
wirte_cmd(0x80);//在第一行寫(xiě)入EE01 DEMO:IR
for(num=0;num<12;num++)
{
wirte_data(table[num]);
delay_ms(1);
}
wirte_cmd(0x80+0x40);//在第二行寫(xiě)入code:
for(num=0;num<5;num++)
{
wirte_data(table1[num]);
delay_ms(1);
}
if(key_code<10)//如果按鍵小于10則寫(xiě)入相應(yīng)的數(shù)字
{
wirte_data(table2[key_code]);
delay_ms(2);
}
else if(key_code<50)//大于10則寫(xiě)入字符,與遙控器對(duì)應(yīng)
{
switch(key_code)
{
case 21:wirte_string("mute");break;
case 28:wirte_string("power");break;
case 10:wirte_string("-/--");break;
case 14:wirte_cmd(0x80+0x40+0x05);wirte_data(0x7f);wirte_data(0x7e);break;//先寫(xiě)字符位置,然后寫(xiě)字符,
case 25:wirte_string("SLEEP");break;
case 19:wirte_string("P.P");break;
case 15:wirte_string("TV/AV");break;
case 30:wirte_string("VOL-");break;
case 31:wirte_string("VOL+");break;
case 27:wirte_string("P+");break;
case 26:wirte_string("P-");break;
case 16:wirte_string("MENU");break;
case 24:wirte_string("A-MODE");break;
case 13:wirte_string("SYS");break;
case 12:wirte_string("GAME");break;
case 20:wirte_string("DISP");break;
delay_ms(2);
}
new_code=0;
}
}