NEC協(xié)議紅外遙控器

發(fā)布時間:2024-03-12
家電遙控器通信距離往往要求不高,而紅外的成本比其他無線設(shè)備要低的多,所以家電遙控器應(yīng)用中紅外始終占據(jù)著一席之地。遙控器的基帶通信協(xié)議很多,大概有幾十種,常用的就有itt協(xié)議、nec協(xié)議、sharp協(xié)議、philipsrc-5協(xié)議、sonysirc協(xié)議等。用的最多的就是nec協(xié)議了,因此我們kst-51開發(fā)板隨板的遙控器直接采用nec協(xié)議,我們這節(jié)課也以nec協(xié)議標(biāo)準(zhǔn)來講解一下。
nec協(xié)議的數(shù)據(jù)格式包括了引導(dǎo)碼、用戶碼、用戶碼(或者用戶碼反碼)、按鍵鍵碼和鍵碼反碼,最后一個停止位,停止位主要起隔離作用,一般不進(jìn)行判斷,編程時我們也不予理會。其中數(shù)據(jù)編碼總共是4個字節(jié)32位,如圖1所示。第一個字節(jié)是用戶碼,第二個字節(jié)可能也是用戶碼,或者是用戶碼的反碼,具體由生產(chǎn)商決定,第三個字節(jié)就是當(dāng)前按鍵的鍵數(shù)據(jù)碼,而第四個字節(jié)是鍵數(shù)據(jù)碼的反碼,可用于對數(shù)據(jù)的糾錯。
圖1nec協(xié)議數(shù)據(jù)格式
這個nec協(xié)議,表示數(shù)據(jù)的方式不像我們之前學(xué)過的比如uart那樣直觀,而是每一位數(shù)據(jù)本身也需要進(jìn)行編碼,編碼后再進(jìn)行載波調(diào)制。
引導(dǎo)碼:9ms的載波+4.5ms的空閑。
比特值“0”:560us的載波+560us的空閑。
比特值“1”:560us的載波+1.68ms的空閑。
結(jié)合圖1我們就能看明白了,最前面黑乎乎的一段,是引導(dǎo)碼的9ms載波,緊接著是引導(dǎo)碼的4.5ms的空閑,而后邊的數(shù)據(jù)碼,是眾多載波和空閑交叉,它們的長短就由其要傳遞的具體數(shù)據(jù)來決定。我們的hs0038b這個紅外一體化接收頭,當(dāng)收到有載波的信號的時候,會輸出一個低電平,空閑的時候會輸出高電平,我們用邏輯分析儀抓出來一個紅外按鍵通過hs0038解碼后的圖形來了解一下,如圖2所示。
圖2紅外遙控器按鍵編碼
從圖上可以看出,先是9ms載波加4.5ms空閑的起始碼,數(shù)據(jù)碼是低位在前,高位在后,數(shù)據(jù)碼第一個字節(jié)是8組560us的載波加560us的空閑,也就是0x00,第二個字節(jié)是8組560us的載波加1.68ms的空閑,可以看出來是0xff,這兩個字節(jié)就是用戶碼和用戶碼的反碼。按鍵的鍵碼二進(jìn)制是0x0b,反碼就是0xf3,最后跟了一個560us載波停止位。對于我們的遙控器來說,不同的按鍵,就是鍵碼和鍵碼反碼的區(qū)分,用戶碼是一樣的。這樣我們就可以通過單片機(jī)的程序,把當(dāng)前的按鍵的鍵碼給解出來。
我們前邊學(xué)習(xí)中斷的時候,學(xué)到51單片機(jī)有外部中斷0和外部中斷1這兩個外部中斷。我們的紅外接收引腳接到了p3.3引腳上,這個引腳的第二功能就是外部中斷1。在寄存器tcon中的bit3和bit2這兩位,是和外部中斷1相關(guān)的兩位。其中ie1是外部中斷標(biāo)志位,當(dāng)外部中斷發(fā)生后,這一位被自動置1,和定時器中斷標(biāo)志位tf相似,進(jìn)入中斷后會自動清零,也可以軟件清零。bit2位是設(shè)置外部中斷類型的,如果bit2位為0,那么只要p3.3為低電平就可以觸發(fā)中斷,如果bit2位為1,那么p3.3從高電平到低電平的下降沿發(fā)生才可以觸發(fā)中斷。此外,外部中斷1使能位是ex1。那下面我們就把程序?qū)懗鰜?,使用?shù)碼管把遙控器的用戶碼和鍵碼顯示出來。
infrared.c文件主要是用來檢測紅外通信的,當(dāng)發(fā)生外部中斷后,進(jìn)入外部中斷,通過定時器1定時,首先對引導(dǎo)碼判斷,而后對數(shù)據(jù)碼的每個位逐位獲取高低電平的時間,從而得知每一位是0還是1,最終把數(shù)據(jù)碼解出來。
/***********************infrared.c文件程序源代碼*************************/
#include<reg52.h>
sbitir_input=p3^3;//紅外接收引腳
bitirflag=0;//紅外接收標(biāo)志,收到一幀正確數(shù)據(jù)后置1
unsignedcharircode[4];//紅外代碼接收緩沖區(qū)
voidinitinfrared(void)//紅外功能的初始化函數(shù)
{
tmod&=0x0f;//清零t1的控制位
tmod|=0x10;//配置t1為模式1
tr1=0;//停止t1計數(shù)
et1=0;//禁止t1中斷
it1=1;//設(shè)置int1為負(fù)邊沿觸發(fā)
ex1=1;//使能int1中斷
}
unsignedintgethightime(void)//獲取高電平時間
{
th1=0;//清零t1計數(shù)初值
tl1=0;
tr1=1;//啟動t1計數(shù)
while(ir_input)//紅外輸入引腳為1時循環(huán)檢測等待,變?yōu)?時則結(jié)束本循環(huán)
{
if(th1>=0x40)
{//當(dāng)t1計數(shù)值大于0x4000,即高電平持續(xù)時間超過約18ms時,
break;//強(qiáng)制退出循環(huán),是為了避免信號異常時,程序假死在這里。
}
}
tr1=0;//停止t1計數(shù)
return(th1*256+tl1);//返回t1的計數(shù)值
}
unsignedintgetlowtime(void)//獲取低電平時間
{
th1=0;//清零t1計數(shù)初值
tl1=0;
tr1=1;//啟動t1計數(shù)
while(!ir_input)//紅外輸入引腳為0時循環(huán)檢測等待,變?yōu)?時則結(jié)束本循環(huán)
{
if(th1>=0x40)
{//當(dāng)t1計數(shù)值大于0x4000,即低電平持續(xù)時間超過約18ms時,
break;//強(qiáng)制退出循環(huán),是為了避免信號異常時,程序假死在這里。
}
}
tr1=0;//停止t1計數(shù)
return(th1*256+tl1);//返回t1的計數(shù)值
}
voidexint1_isr()interrupt2//int1中斷服務(wù)函數(shù),執(zhí)行紅外接收及解碼
{
unsignedchari,j;
unsignedcharbyt;
unsignedinttime;
//接收并判定引導(dǎo)碼的9ms低電平
time=getlowtime();
if((time<7833)||(time>8755))//時間判定范圍為8.5~9.5ms,
{//超過此范圍則說明為誤碼,直接退出
ie1=0;//退出前清零int1中斷標(biāo)志
return;
}
//接收并判定引導(dǎo)碼的4.5ms高電平
time=gethightime();
if((time<3686)||(time>4608))//時間判定范圍為4.0~5.0ms,
{//超過此范圍則說明為誤碼,直接退出
ie1=0;
return;
}
//接收并判定后續(xù)的4字節(jié)數(shù)據(jù)
for(i=0;i<4;i++)//循環(huán)接收4個字節(jié)
{
for(j=0;j<8;j++)//循環(huán)接收判定每字節(jié)的8個bit
{
//接收判定每bit的560us低電平
time=getlowtime();
if((time<313)||(time>718))//時間判定范圍為340~780us,
{//超過此范圍則說明為誤碼,直接退出
ie1=0;
return;
}
//接收每bit高電平時間,判定該bit的值
time=gethightime();
if((time>313)&&(time<718))//時間判定范圍為340~780us,
{//在此范圍內(nèi)說明該bit值為0
byt>>=1;//因低位在先,所以數(shù)據(jù)左移,高位為0
}
elseif((time>1345)&&(time<1751))//時間判定范圍為1460~1900us,
{//在此范圍內(nèi)說明該bit值為1
byt>>=1;//因低位在先,所以數(shù)據(jù)左移,
byt|=0x80;//高位置1
}
else//不在上述范圍內(nèi)則說明為誤碼,直接退出
{
ie1=0;
return;
}
}
ircode[i]=byt;//接收完一個字節(jié)后保存到緩沖區(qū)
}
irflag=1;//接收完畢后設(shè)置標(biāo)志
ie1=0;//退出前清零int1中斷標(biāo)志
}
大家在閱讀這個文件里的代碼時,會發(fā)現(xiàn)我們在獲取高低電平時間的時候做了超時判斷if(th1>=0x40),這個超時判斷一方面是應(yīng)對空間突發(fā)的紅外干擾信號,如果我們不做超時判斷,程序有可能會一直等待下一個跳變才會停止檢測,造成程序假死。另外一個方面,遙控器的單按按鍵和持續(xù)按住按鍵發(fā)出來的信號是不同的。我們先來對比一下兩種按鍵方式的信號狀態(tài),如圖3和4所示。
圖3紅外單次按鍵時序圖
圖4紅外持續(xù)按鍵時序圖
單次按鍵的結(jié)果3和我們之前的圖2是一樣的,這個不需要再解釋。而持續(xù)按鍵,首先會發(fā)出一個和單次按鍵一樣的波形出來,經(jīng)過大概40ms后,會產(chǎn)生一個9ms載波加2.25ms空閑,再跟一個停止位的波形,而后只要你還在按住按鍵,每經(jīng)過大概96ms就會產(chǎn)生9ms載波加2.25ms空閑加停止位這樣的重復(fù)波形。我們?nèi)藶榘聪掳存I的時候,很難控制按下的時間,因此后邊的很容易出現(xiàn)這種延續(xù)波形,我們加上超時判斷也可以有效的避免進(jìn)入延續(xù)波形的死循環(huán)中去。
/***********************main.c文件程序源代碼*************************/
#include<reg52.h>
sbitaddr3=p1^3;//led選擇地址線3
sbitenled=p1^4;//led總使能引腳
unsignedcharcodeledchar[]={//數(shù)碼管顯示字符轉(zhuǎn)換表
0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,
0x80,0x90,0x88,0x83,0xc6,0xa1,0x86,0x8e
};
unsignedcharledbuff[6]={//數(shù)碼管顯示緩沖區(qū)
0xff,0xff,0xff,0xff,0xff,0xff
};
unsignedchart0rh=0;//t0重載值的高字節(jié)
unsignedchart0rl=0;//t0重載值的低字節(jié)
externbitirflag;
externunsignedcharircode[4];
voidconfigtimer0(unsignedintms);
externvoidinitinfrared(void);
voidmain()
{
p0=0xff;//p0口初始化
addr3=1;//選擇數(shù)碼管
enled=0;//led總使能
initinfrared();//初始化紅外功能
configtimer0(1);//配置t0定時1ms
ea=1;//開總中斷
//pt0=1;//配置t0中斷為高優(yōu)先級
while(1)
{
if(irflag)//接收到紅外數(shù)據(jù)時刷新顯示
{
irflag=0;
ledbuff[5]=ledchar[ircode[0]>>4];//用戶碼顯示
ledbuff[4]=ledchar[ircode[0]&0x0f];
ledbuff[1]=ledchar[ircode[2]>>4];//鍵碼顯示
ledbuff[0]=ledchar[ircode[2]&0x0f];
}
}
}
voidconfigtimer0(unsignedintms)//t0配置函數(shù)
{
unsignedlongtmp;
tmp=11059200/12;//定時器計數(shù)頻率
tmp=(tmp*ms)/1000;//計算所需的計數(shù)值
tmp=65536-tmp;//計算定時器重載值
tmp=tmp+15;//修正中斷響應(yīng)延時造成的誤差
t0rh=(unsignedchar)(tmp>>8);//定時器重載值拆分為高低字節(jié)
t0rl=(unsignedchar)tmp;
tmod&=0xf0;//清零t0的控制位
tmod|=0x01;//配置t0為模式1
th0=t0rh;//加載t0重載值
tl0=t0rl;
et0=1;//使能t0中斷
tr0=1;//啟動t0
}
voidinterrupttimer0()interrupt1//t0中斷服務(wù)函數(shù)
{
staticunsignedchariled=0;
th0=t0rh;//定時器重新加載重載值
tl0=t0rl;
//led數(shù)碼管動態(tài)掃描
p0=0xff;//關(guān)閉所有段選位,顯示消隱
p1=(p1&0xf8)|iled;//位選索引值賦值到p1口低3位
p0=ledbuff[iled];//相應(yīng)顯示緩沖區(qū)的值賦值到p0口
if(iled<5)//位選索引0-5循環(huán),因有6個數(shù)碼管
iled++;
else
iled=0;
}
main.c文件程序的主要功能就是把獲取到的紅外遙控器的用戶碼和鍵碼信息,傳送到數(shù)碼管上顯示出來,并且通過定時器0的1ms中斷進(jìn)行數(shù)碼管的動態(tài)刷新。不知道大家經(jīng)過試驗(yàn)發(fā)現(xiàn)沒有,當(dāng)我們按下遙控器按鍵的時候,數(shù)碼管顯示的數(shù)字會閃爍,這是什么原因呢?單片機(jī)的程序都是順序執(zhí)行的,一旦我們按下遙控器按鍵,我們的程序就會進(jìn)入遙控器解碼段,而這個解碼段的時間比較長,要幾十個毫秒,而我們的數(shù)碼管動態(tài)刷新間隔超過了10ms后就會有閃爍的感覺了,因此這個閃爍主要是由于我們程序執(zhí)行紅外解碼時,延誤了數(shù)碼管動態(tài)刷新造成的。
如何解決?前邊我們講過中斷優(yōu)先級問題,如果設(shè)置了中斷優(yōu)先級,就會產(chǎn)生中斷嵌套。中斷嵌套的原理,我們在前邊講中斷的時候已經(jīng)講過一次了,大家可以回頭再復(fù)習(xí)一下。那么這個程序中,有2個中斷程序,一個是外部中斷程序,一個是定時器中斷程序。如果設(shè)置外部中斷優(yōu)先級比較高的話,由于在外部中斷中要接收紅外信號,耗時幾十毫秒,會耽誤數(shù)碼管的動態(tài)刷新。而在定時器中斷程序中,執(zhí)行時間只有幾十個us,即使進(jìn)入中斷,也不會干擾到紅外信號的正常接收,因此這個地方我們把定時器0的中斷優(yōu)先級設(shè)置為高優(yōu)先級。在主程序main函數(shù)中,大家把這句注釋掉的程序“//pt0=1;”取消注釋,再編譯一下,下載到單片機(jī)里,然后再試試發(fā)送按鍵,是不是沒有任何閃爍了呢?而中斷嵌套的意義也有所體會了吧。
上一個:個人如何租用阿里云服務(wù)器
下一個:孩子不滿兩周半夫妻離婚孩子歸誰

怎么換ip?ip地址是干嘛的
為您揭秘銀杏的傳奇歷史
蘋果手機(jī)有4g信號卻上不了網(wǎng)怎么回事(iphone有4g信號但是上不了網(wǎng))
磁翻板液位計浮筒(浮子)的材質(zhì)種類與選用
注意缺陷多動障礙患兒尿中兒茶酚胺分析
小米9charge turbo(小米9turbo怎么打開)
英國moduloc品牌介紹
企業(yè)網(wǎng)站需要什么樣的云服務(wù)器
SF6密度繼電器校驗(yàn)儀性能特點(diǎn)
亞布力雅旺斯滑雪場滑雪攻略 附交通到達(dá)方式
十八禁 网站在线观看免费视频_2020av天堂网_一 级 黄 色 片免费网站_绝顶高潮合集Videos