新聞中心

        EEPW首頁 > 嵌入式系統(tǒng) > 設(shè)計應(yīng)用 > 紅外遙控系統(tǒng)原理及單片機軟件解碼程序

        紅外遙控系統(tǒng)原理及單片機軟件解碼程序

        作者: 時間:2016-11-23 來源:網(wǎng)絡(luò) 收藏
        首先,必須要了解一些基本原理。其實按下遙控器的某一個鍵,遙控器會發(fā)出一連串經(jīng)過調(diào)制后的信號,這個信號經(jīng)過紅外一體化模塊接收后,輸出解調(diào)后的數(shù)字脈沖,每個按鍵對應(yīng)不同的脈沖,故識別出不同的脈沖就能識別出不同的按鍵。

        本文引用地址:http://www.104case.com/article/201611/320460.htm

        上圖就是很常見的車載MP3遙控器,比較小巧,很好用。下面是紅外發(fā)射和接受原理:

        到此讀者可能會有疑惑,那么不同的調(diào)制解調(diào)方法那么出來的脈沖規(guī)則是不一樣的?是的,的確如此。

        遙控發(fā)射器專用芯片很多,根據(jù)編碼格式可以分成兩大類,這里我們以運用比較廣泛,解碼比較容易的一類來加以說明,現(xiàn)以日本NEC的uPD6121G組成發(fā)射電路為例說明編碼原理(一般家庭用的DVD、VCD、音響都使用這種編碼方式)。當發(fā)射器按鍵按下后,即有遙控碼發(fā)出,所按的鍵不同遙控編碼也不同。這種遙控碼具有以下特征:

        采用脈寬調(diào)制的串行碼,以脈寬為0.565ms、間隔0.56ms、周期為1.125ms的組合表示二進制的“0”;以脈寬為0.565ms、間隔1.685ms、周期為2.25ms的組合表示二進制的“1”,其波形如圖所示。

        如圖可見,0與1前端的低電平持續(xù)都是0.56ms,那么就是后面的高電平持續(xù)時間不同,0為0.56ms,1為1.685ms,找到不同之處,編程時就有識別的依據(jù)了!

        上述“0”和“1”組成的32位二進制碼經(jīng)38kHz的載頻進行二次調(diào)制以提高發(fā)射效率,達到降低電源功耗的目的。然后再通過紅外發(fā)射二極管產(chǎn)生紅外線向空間發(fā)射,如圖所示。

        UPD6121G產(chǎn)生的遙控編碼是連續(xù)的32位二進制碼組,其中前16位為用戶識別碼,能區(qū)別不同的電器設(shè)備,防止不同機種遙控碼互相干擾。該芯片的用戶識別碼固定為十六進制01H;后16位為8位操作碼(功能碼)及其反碼。UPD6121G最多額128種不同組合的編碼。

        請看下圖,來自網(wǎng)絡(luò):



        當一個鍵按下超過36ms,振蕩器使芯片激活,將發(fā)射一組108ms的編碼脈沖,這108ms發(fā)射代碼由一個引導碼(9ms),一個結(jié)果碼(4.5ms),低8位地址碼(9ms~18ms),高8位地址碼(9ms~18ms),8位數(shù)據(jù)碼(9ms~18ms)和這8位數(shù)據(jù)的反碼(9ms~18ms)組成。如果鍵按下超過108ms仍未松開,接下來發(fā)射的代碼(連發(fā)碼)將僅由起始碼(9ms)和結(jié)束碼(2.25ms)組成。(實際上人手的動作是很慢的,即使你快速的按下按鍵,可能對于芯片來說還是超過108ms,所以如何處理連發(fā)碼是很關(guān)鍵的)

        遙控器在按鍵按下后,周期性地發(fā)出同一種32位二進制碼,周期約為108ms。一組碼本身的持續(xù)時間隨它包含的二進制“0”和“1”的個數(shù)不同而不同,大約在45~63ms之間,圖為發(fā)射波形圖。

        下面是我寫的代碼,按鍵編碼通過串口發(fā)送到電腦端:

        由于時間關(guān)系,代碼注釋不多。

        其中START_Judge()函數(shù)是判斷9ms低電平,既是判斷有無遙控信號。

        BOOT_REPEATING_CODE_Judge()是判斷是引導碼還是連發(fā)碼,引導碼則進入接受數(shù)據(jù)環(huán)節(jié),連發(fā)碼表明數(shù)據(jù)已經(jīng)接受結(jié)束。

        H_L_LEVEL_Judge()是接受數(shù)據(jù)時判斷高低電平。

        如果亂碼,請參考:

        http://blog.csdn.net/mhjerry/article/details/6601324

        注明:以下代碼為純軟件方式,沒有用到中斷,定時器方式,純CPU查詢,但測試結(jié)果倒也可以,至少比較穩(wěn)定,得到的碼值不管對不對,都是那個值。

        [cpp]view plaincopy
        1. /*------------------------------------------------------------*-
        2. 紅外收發(fā).C
        3. ------------------------------------------------------------
        4. 遙控器測試
        5. -*------------------------------------------------------------*/
        6. #include
        7. //---紅外接收一體化輸出口----------------------------------
        8. sbitIR_Out=P3^2;
        9. bitSTART_Flag=0;
        10. bitBOOT_REPEATING_CODE_Flag=0;
        11. unsignedcharDATA[4]={0};
        12. bdataunsignedcharTEMP_BIT;
        13. sbitB0=TEMP_BIT^0;
        14. sbitB1=TEMP_BIT^1;
        15. sbitB2=TEMP_BIT^2;
        16. sbitB3=TEMP_BIT^3;
        17. sbitB4=TEMP_BIT^4;
        18. sbitB5=TEMP_BIT^5;
        19. sbitB6=TEMP_BIT^6;
        20. sbitB7=TEMP_BIT^7;
        21. //---有無遙控信號判斷函數(shù)----------------------------------
        22. bitSTART_Judge();
        23. //---連發(fā)碼判斷函數(shù)----------------------------------------
        24. bitBOOT_REPEATING_CODE_Judge();
        25. //---"0"和"1"識別------------------------------------------
        26. bitH_L_LEVEL_Judge();
        27. //---串口初始化--------------------------------------------
        28. voidUART_Initial();
        29. voidDELAY_Us(unsignedintUs)
        30. {
        31. unsignedintx;
        32. for(x=0;x<=(Us/200-1);x++);
        33. }
        34. voidDELAY_Ms(unsignedintMs)
        35. {
        36. unsignedintx,y;
        37. for(x=0;x<=(Ms-1);x++)
        38. {
        39. for(y=0;y<=120;y++);
        40. }
        41. }
        42. voidmain()
        43. {
        44. unsignedchari;
        45. UART_Initial();
        46. IR_Out=1;
        47. while(1)
        48. {
        49. START_Flag=START_Judge();
        50. BOOT_REPEATING_CODE_Flag=BOOT_REPEATING_CODE_Judge();
        51. if(START_Flag&&!BOOT_REPEATING_CODE_Flag)
        52. {
        53. for(i=0;i<4;i++)
        54. {
        55. B0=H_L_LEVEL_Judge();
        56. B1=H_L_LEVEL_Judge();
        57. B2=H_L_LEVEL_Judge();
        58. B3=H_L_LEVEL_Judge();
        59. B4=H_L_LEVEL_Judge();
        60. B5=H_L_LEVEL_Judge();
        61. B6=H_L_LEVEL_Judge();
        62. B7=H_L_LEVEL_Judge();
        63. DATA[i]=TEMP_BIT;
        64. }
        65. for(i=0;i<4;i++)
        66. {
        67. SBUF=DATA[i];
        68. while(TI==0);
        69. TI=0;
        70. }
        71. }
        72. }
        73. }
        74. voidUART_Initial()
        75. {
        76. SCON=0x50;//SCON:模式1,8-bitUART,使能接收
        77. TMOD|=0x20;//TMOD:timer1,mode2,8-bitreload
        78. TH1=0xFD;//TH1:reloadvaluefor9600baud@
        79. //11.0592MHz
        80. TR1=1;//TR1:timer1run
        81. EA=0;//關(guān)閉總中斷
        82. ES=0;//關(guān)閉串口中斷
        83. }
        84. bitSTART_Judge()
        85. {
        86. bitTEMP_Flag=1;
        87. unsignedchari=0;
        88. //在正常無遙控信號時,一體化紅外接收頭輸出是高電平,程序一直在循環(huán)。
        89. while(IR_Out==1);
        90. //重復10次,目的是檢測在6876~8352微秒內(nèi)如果出現(xiàn)高電平就退出解碼程序
        91. for(i=0;i<9;i++)
        92. {
        93. DELAY_Us(800);//測試實際延時約為764~928us
        94. if(IR_Out==1)
        95. {
        96. TEMP_Flag=0;
        97. break;
        98. }
        99. }
        100. returnTEMP_Flag;
        101. }
        102. bitBOOT_REPEATING_CODE_Judge()
        103. {
        104. bitTEMP_Flag=1;
        105. while(IR_Out==0);//等待高電平避開9毫秒低電平引導脈沖
        106. DELAY_Ms(1);//測試實際延時約為1.007ms
        107. DELAY_Ms(1);//測試實際延時約為1.007ms
        108. DELAY_Us(200);//0.086ms
        109. DELAY_Us(200);//0.086ms
        110. DELAY_Us(200);//0.086ms
        111. //共計2.272ms
        112. if(IR_Out==0)
        113. {
        114. TEMP_Flag=1;//是連發(fā)碼
        115. }
        116. else
        117. {
        118. TEMP_Flag=0;//不是連發(fā)碼,而是引導碼
        119. }
        120. returnTEMP_Flag;
        121. }
        122. bitH_L_LEVEL_Judge()
        123. {
        124. while(IR_Out==0);//等待地址碼第一位的高電平信號
        125. DELAY_Us(800);//測試實際延時約為764~928us
        126. if(IR_Out==1)
        127. {
        128. DELAY_Ms(1);//測試實際延時約為1.007ms
        129. return1;
        130. }
        131. else
        132. {
        133. return0;
        134. }
        135. }


        編輯如下:

        01 FE 8B 74 --- 01 FE 8D 72 --- 01 FE 8F 70

        01 FE 89 76 --- 01 FE 81 7E --- 01 FE 87 78

        01 FE 0F F0 --- 01 FE 2B D4 --- 01 FE 13 EC

        01 FE 2D D2 --- 01 FE 33 CC --- 01 FE 1B E4

        01 FE 19 E6 --- 01 FE 31 CE --- 01 FE BD 42

        01 FE 11 EE --- 01 FE 39 C6 --- 01 FE B5 4A
        以上為對應(yīng)按鍵的編碼。

        過程中存在問題:

        一是如何有效的識別引導碼和連發(fā)碼,因為這個能直接影響到長時間按鍵,單片機的響應(yīng)與否。這個問題,貌似我以解決,就是長時間按鍵后,單片機識別一次按鍵后,如果還是同一按鍵,就不與理睬。

        還有一個問題就是,如果連續(xù)按下兩次按鍵,該程序能夠識別出,但是如果間隔很短,第二下按鍵的編碼容易出錯,容易變成這樣:

        03 FE 8B 74.。。。就是第一個字節(jié)出現(xiàn)誤差,這個問題現(xiàn)在還未來得及解決。

        還有就是本程序?qū)τ谘訒r函數(shù)的精度要求很高,因為本身處理的脈沖就是MS級別的。所以需要嚴格的測試延時函數(shù)的實際延時時間:

        以上的代碼,可以看出許多問題,軟件延時不準確,大量的“while( IR_Out == 0 ) ;”代碼,抗干擾能力弱,容易進入死循環(huán)。

        下面介紹的這種解碼方法,利用外部中斷觸發(fā)程序,定時器定時(但沒有設(shè)置定時中斷程序,即判斷TF的值確定定時結(jié)束),在代碼過程中,開頭的一個7.93ms延時,足以濾掉不合法的紅外信號。應(yīng)該說效率質(zhì)量更高的。

        代碼注釋很詳細,在此不在細述:

        [cpp]view plaincopy
        1. /*------------------------------------------------------------*-
        2. IR_Decoder.C(v1.00)
        3. ------------------------------------------------------------
        4. 名稱:遙控器紅外解碼,PO口接LED,顯示功能碼以供查看
        5. 編寫:mhjerry
        6. 日期:20011.7
        7. 內(nèi)容:按遙控器上的按鍵,會在PO口LED上顯示
        8. -*------------------------------------------------------------*/
        9. #include"reg52.h"
        10. //此口為紅外信號輸入MCU口
        11. sbitIR_Out=P3^2;
        12. //主程序運行標志位,運行主程序時LED滅,運行中斷程序時LED亮
        13. sbitIR_Flag=P3^1;
        14. //LED顯示口
        15. #defineLED_PortP1
        16. //用于存放按鍵碼值,初始化為00000000這樣接受數(shù)據(jù)時可以只考慮1了
        17. unsignedchardat[4]={0,0,0,0};
        18. /*............................................................*/
        19. voidmain()
        20. {
        21. IR_Out=1;//此口為MCU輸入口,故需要置1
        22. IR_Flag=1;//滅LED燈
        23. TMOD=0x01;//定時器0,方式1
        24. IT0=1;//外部中斷0,下降沿觸發(fā)
        25. EX0=1;//準許外部中斷
        26. EA=1;//CPU準許中斷
        27. while(1)
        28. {
        29. IR_Flag=1;//執(zhí)行主程序時,LED燈滅
        30. }
        31. }
        32. /*------------------------------------------------------------*-
        33. 函數(shù)名稱:Int0()
        34. 函數(shù)輸入:無(容許中斷時,外部觸發(fā))
        35. 函數(shù)輸出:無
        36. 函數(shù)說明:外部中斷0中斷處理
        37. -*------------------------------------------------------------*/
        38. voidInt0()interrupt0
        39. {
        40. unsignedchari,j;
        41. EX0=0;//關(guān)閉外部中斷0
        42. IR_Flag=0;//執(zhí)行中斷程序時,LED燈亮
        43. i=10;//0.793ms延時,運行10次
        44. while(--i)
        45. {
        46. //定時0.793ms,延時0.793ms*10=7.93ms
        47. TH0=0xfc;
        48. TL0=0xe7;
        49. TR0=1;
        50. while(!TF0);
        51. TF0=0;
        52. TR0=0;
        53. //這7.93ms期間只要IR_Out變高電平,就非合法的紅外信號,跳出
        54. if(IR_Out)
        55. {
        56. EX0=1;//準許中斷
        57. return;
        58. }
        59. }
        60. //程序進行到這里,表明是合法的紅外信號(利用9ms判斷)
        61. while(!IR_Out);//等待9ms低電平過去
        62. //程序進行到這里,表明經(jīng)過9ms低電平
        63. TH0=0xf6;
        64. TL0=0xff;
        65. TR0=1;
        66. while(!TF0);
        67. TF0=0;
        68. TR0=0;//延時2.305ms
        69. //IR_Out為低表明是連發(fā)碼,不予理睬,跳出
        70. if(!IR_Out)
        71. {
        72. EX0=1;
        73. return;
        74. }
        75. //程序進行到這里,表明是引導碼,等待4.5ms高電平的過去
        76. while(IR_Out);
        77. //開始接收用戶碼
        78. for(i=0;i<4;i++)
        79. {
        80. for(j=0;j<8;j++)
        81. {
        82. while(!IR_Out);//等待低電平過去
        83. dat[i]>>=1;//把上次的數(shù)據(jù)位右移一位
        84. TH0=0xfc;
        85. TL0=0xe7;
        86. TR0=1;
        87. while(!TF0);
        88. TR0=0;
        89. TF0=0;//延時0.793ms
        90. //若為數(shù)據(jù)"1",則延時后IR_Out為高電平
        91. if(IR_Out)
        92. {
        93. dat[i]|=0x80;//所有數(shù)據(jù)位1放最高位
        94. while(IR_Out);//等待高電平過去
        95. }
        96. }
        97. }
        98. LED_Port=dat[2];
        99. EX0=1;//開中斷
        100. return;
        101. }
        102. /*------------------------------------------------------------*-
        103. ----ENDOFFILE-------------------------------------------
        104. -*------------------------------------------------------------*/



        評論


        技術(shù)專區(qū)

        關(guān)閉
        主站蜘蛛池模板: 三穗县| 滦南县| 镇远县| 商丘市| 包头市| 福建省| 革吉县| 栾城县| 黎川县| 乌海市| 拉萨市| 鄂托克前旗| 宜城市| 宁乡县| 同仁县| 察雅县| 富民县| 德昌县| 泌阳县| 慈溪市| 中阳县| 温宿县| 荥阳市| 奈曼旗| 钟山县| 松滋市| 卫辉市| 赤峰市| 云安县| 化德县| 云梦县| 和静县| 天镇县| 东兰县| 略阳县| 勃利县| 莱州市| 淮阳县| 应城市| 沂水县| 益阳市|