一、簡介
隨著科技進(jìn)步,手機(jī)逐漸融入了我們的生活。通過在手機(jī)中內(nèi)置紅外發(fā)射器,手機(jī)可以模擬各種遙控器的操作,實(shí)現(xiàn)對不同家電設(shè)備的控制。在電視精靈的Android版本中,也支持了紅外遙控器功能,實(shí)現(xiàn)對移動(dòng)高清機(jī)頂盒的遙控操作,提升了用戶手機(jī)控制大屏的體驗(yàn)。紅外遙控器的具體樣式,如下圖1所示,基本涵蓋了用戶日常操作指令。
紅外遙控是一種古老而實(shí)用的技術(shù),它是利用紅外線的特性來傳遞信息。紅外線是一種不可見光,具有較強(qiáng)的穿透力和方向性。在紅外遙控中,發(fā)射器會(huì)將控制指令編碼成特定的紅外信號,并通過發(fā)射二極管將其發(fā)射出去。當(dāng)這些紅外信號到達(dá)接收設(shè)備時(shí),接收設(shè)備中的紅外接收器會(huì)將其接收并解碼,從而執(zhí)行相應(yīng)的操作。接下來,本文將詳細(xì)介紹一下紅外系統(tǒng)的實(shí)現(xiàn)原理,并以電視精靈紅外遙控為例,介紹如何在Android系統(tǒng)上開發(fā)紅外遙控功能。
二、紅外遙控原理
2.1 紅外系統(tǒng)
紅外遙控系統(tǒng)通常由紅外發(fā)射器和紅外接收器組成。紅外發(fā)射器將控制信號轉(zhuǎn)換為紅外光信號發(fā)射出去,而紅外接收器則接收這些紅外光信號,并將其轉(zhuǎn)換回電信號,從而實(shí)現(xiàn)對設(shè)備的控制。紅外遙控系統(tǒng)發(fā)送和接收的主要組成部分,如下圖所示。
發(fā)送端:
指令輸入:用戶通過遙控器上的按鍵輸入控制指令。
編碼:將指令編碼為紅外信號格式。
調(diào)制:使用特定的調(diào)制方式,將編碼后的信號與載波進(jìn)行調(diào)制。
紅外發(fā)射:通過紅外發(fā)射二極管將調(diào)制后的紅外信號發(fā)射出去。
接收端:
紅外接收:紅外接收二極管接收紅外信號。
解調(diào):對接收的信號進(jìn)行解調(diào),還原出編碼信息。
解碼:將解碼后的信息轉(zhuǎn)換為具體的控制指令。
指令執(zhí)行:根據(jù)接收到的控制指令,執(zhí)行相應(yīng)的操作,如控制家電設(shè)備的開關(guān)、調(diào)節(jié)等。
2.2 紅外編碼
紅外遙控器發(fā)射的信號由一串“0”和“1”的二進(jìn)制代碼組成,不同的芯片對“0”和“1”的編碼有所不同,通常有曼徹斯特 (Manchester) 編碼和脈沖寬度編碼 (PWM)。
2.2.1 曼徹斯特編碼(Manchester Encoding)
原理:曼徹斯特編碼是一種雙相編碼,通過電平的高低轉(zhuǎn)換來表示“0”或“1”。每位中間的電平轉(zhuǎn)換既表示了數(shù)據(jù)代碼,也作為定時(shí)信號使用。
-
特點(diǎn):
每位數(shù)據(jù)都有一個(gè)電平跳變,位中間的跳變既作時(shí)鐘信號,又作數(shù)據(jù)信號。
數(shù)據(jù)傳輸速率是調(diào)制速率的1/2,因?yàn)槊總€(gè)碼元都被調(diào)制成兩個(gè)電平。
編碼效率約為50%,因?yàn)槊總€(gè)時(shí)鐘位都必須有一次變化。
2.2.2 脈沖寬度編碼(PWM, Pulse Width Modulation)
原理:脈沖寬度編碼以發(fā)射紅外載波的占空比代表“0”和“1”。一般通過固定發(fā)射紅外載波的時(shí)間,通過改變不發(fā)射載波的時(shí)間來改變占空比。
-
特點(diǎn):
節(jié)省能量,因?yàn)榘l(fā)射紅外載波的時(shí)間固定。
解碼方便,通常包含引導(dǎo)碼以輔助解碼。
不同芯片或制造商的PWM編碼可能有所不同。
2.2.3 脈沖寬度編碼舉例
家用電器使用的紅外遙控器絕大部分都是脈沖寬度編碼,例如常用的電視遙控器使用NEC upd6121芯片,其“0”為載波發(fā)射0.56ms,不發(fā)射0.56ms;其“1”為載波發(fā)射0.56ms,不發(fā)射1.68ms。如下圖所示:
2.3 紅外調(diào)制
在紅外通信中,將編碼后的二進(jìn)制信號調(diào)制成特定頻率(如38kHz)的間斷脈沖串是一個(gè)常見的做法。這種調(diào)制方式通常被稱為脈沖調(diào)制或載波調(diào)制。在這個(gè)過程中,原始的二進(jìn)制信號(由“0”和“1”組成)被用來控制一個(gè)高頻載波信號(如38kHz的脈沖信號)的開關(guān)狀態(tài)。
具體實(shí)現(xiàn)時(shí),二進(jìn)制信號中的“1”和“0”,分別由不同38kHz載波和低電平組成。如“0”為由 0.56ms 的 38kHz 載波和 0.56ms 的無載波低電平組合而成;“1”由 0.56ms 的 38kHz 載波和 1.69ms 的無載波低電平組合而成。這樣,原始的二進(jìn)制信號就被轉(zhuǎn)換成了一個(gè)間斷的脈沖串,其中每個(gè)脈沖都對應(yīng)于原始信號中的一個(gè)位。
如下圖所示,以下是一個(gè)簡化的描述,說明如何使用高低電平來控制紅外信號的調(diào)制:
原始二進(jìn)制信號:例如,我們有二進(jìn)制信號“0010”。
載波頻率:選擇38kHz作為載波頻率。
-
調(diào)制過程:
當(dāng)二進(jìn)制信號為“1”時(shí),生成一個(gè)由0.56ms 的 38kHz 載波和 1.69ms 的無載波低電平脈沖
當(dāng)二進(jìn)制信號為“0”時(shí),生成一個(gè)由0.56ms 的 38kHz 載波和 0.56ms 的無載波低電平脈沖。
2.4 紅外解調(diào)
解調(diào)是調(diào)制的逆過程,是通過紅外接收管進(jìn)行接收的。其基本工作過程為:當(dāng)接收到調(diào)制信號時(shí),輸出高電平,否則輸出為低電平。
2.5 紅外解碼
解碼是將解調(diào)輸出的脈沖,還原為二進(jìn)制的“0”和“1”,得到二進(jìn)制的“0”,“1”序列,進(jìn)而通過編碼協(xié)議分析傳輸內(nèi)容所含的用戶碼和數(shù)據(jù)碼。
三、開發(fā)實(shí)踐
3.1 Android紅外開發(fā)
截止目前,iphone手機(jī)內(nèi)部沒有配置紅外發(fā)射硬件,因此在iphone手機(jī)上是不支持紅外指令發(fā)射的。文中后續(xù)的開發(fā)介紹,以Android系統(tǒng)為基礎(chǔ)。
3.1.1 權(quán)限申請
在App工程的AndroidManifest.xml中補(bǔ)充紅外權(quán)限配置。
<!--紅外遙控-->
<uses-permission android:name="android.permission.TRANSMIT_IR" />
<!-- 是否僅在支持紅外的設(shè)備上運(yùn)行 -->
<uses-feature android:name="android.hardware.ConsumerIrManager" android:required="false" />
3.1.2 API調(diào)用
紅外遙控功能從Android4.4之后才開始支持,對應(yīng)的管理類名叫ConsumerIrManager,常用的三個(gè)方法分別是:
- 檢測設(shè)備是否支持紅外發(fā)射器
/**
* 返回true表示支持紅外發(fā)射,返回false表示不支持紅外發(fā)射
*/
public boolean hasIrEmitter()
- 獲得紅外發(fā)射器可用的載波頻率范圍
/**
* 返回CarrierFrequencyRange類型數(shù)組,表示紅外發(fā)射器可用的載波頻率范圍
*/
public CarrierFrequencyRange[] getCarrierFrequencies()
- 發(fā)射紅外信號
/**
* @param carrierFrequency 信號頻率,單位赫茲(Hz),家用電器的紅外頻率通常使用38000Hz
* @param pattern 整型數(shù)組形式的信號格式
*/
public void transmit(int carrierFrequency, int[] pattern)
3.1.3 碼值編碼
紅外編碼由“引導(dǎo)碼 + 用戶編碼(高八位)+ 用戶編碼(低八位)+ 鍵數(shù)據(jù)碼 + 鍵數(shù)據(jù)反碼 + 結(jié)束碼”組成,然后按照一定的編碼規(guī)則,合成數(shù)組的形式。以NEC6122協(xié)議舉例,引導(dǎo)碼固定為(9000 + 4500),結(jié)束碼固定為(560,20000)。不同遙控器差別主要在于用戶碼和數(shù)據(jù)碼,同一個(gè)遙控器的用戶碼是一樣的,不同按鍵有不同的碼值,碼值可以轉(zhuǎn)換出對應(yīng)的數(shù)據(jù)碼和數(shù)據(jù)反碼。
上述表格中列了NEC協(xié)議的幾個(gè)指令,下面以按鍵數(shù)字2進(jìn)行舉例。
數(shù)字按鍵2的十六進(jìn)制表示:
用戶碼:0x08E6
碼值:0x41
轉(zhuǎn)換為二進(jìn)制:
-
用戶碼
高八位:00001000(表示08)
低八位:11100110(表示E6)
-
數(shù)據(jù)碼
原碼:01000001(表示41)
反碼:10111110(41的反碼)
由于手機(jī)與遙控器的信號編碼有區(qū)別,需要逆序編碼。
逆序編碼:
-
用戶碼
高八位: 00010000
低八位: 01100111
-
數(shù)據(jù)碼
原碼:10000010
反碼:01111101
編碼轉(zhuǎn)換完成,通過transmit方法進(jìn)行發(fā)送。但是參數(shù)要傳遞整型數(shù)組形式的信號,并不是二進(jìn)制數(shù)而是電平信號數(shù)據(jù)。電平是電路中某一點(diǎn)電壓的高低狀態(tài),在數(shù)字電路中常用高電平表示“1”,用低電平表示“0”。根據(jù)上文可以看出,遙控器發(fā)射紅外信號之時(shí),通過“560us高電平+1690us低電平”代表“1”,通過“560us高電平+565us低電平”代表“0”。于是編寫Android代碼的時(shí)候,使用“560,1690”表示二進(jìn)制的1,使用“560,565”表示二進(jìn)制的0,具體數(shù)組值如下所示:
int[] patternForKey2 = {9000,4500, // 開頭兩個(gè)數(shù)字表示引導(dǎo)碼
// 下面兩行表示用戶碼: 00010000 01100111
560,565, 560,565, 560,565, 560,1690, 560,565, 560,565, 560,565, 560,565,560,565, 560,1690, 560,1690, 560,565, 560,565, 560,1690, 560,1690, 560,1690,
// 下面一行表示數(shù)據(jù)碼:10000010
560,1690, 560,565, 560,565, 560,565, 560,565, 560,565, 560,1690, 560,565,
// 下面一行表示數(shù)據(jù)反碼:01111101
560,565, 560,1690, 560,1690, 560,1690, 560,1690, 560,1690, 560,565, 560,1690,
560,20000}; // 末尾兩個(gè)數(shù)字表示結(jié)束碼
3.1.4 指令發(fā)送
當(dāng)我們做好指令和數(shù)組值的映射,并選定信號頻率。在需要發(fā)射紅外信號處調(diào)用如下:
/**
* 按下按鍵發(fā)射紅外信號
*/
public void transmit() {
ConsumerIrManagerApi.transmit(38000, patternForKey2);
}
3.2 電視精靈紅外遙控實(shí)現(xiàn)
紅外遙控功能,已經(jīng)在電視精靈的Android版本中落地。為了保證用戶體驗(yàn)和功能的有效性,在開發(fā)過程中,我們考慮并解決了以下兩個(gè)問題:
電視精靈需要控制多種不同款的機(jī)頂盒,不同類型機(jī)頂盒,可能支持的紅外碼是不一樣的。
用戶快速點(diǎn)擊多個(gè)指令,如何確保指令不丟失?
針對如上兩個(gè)問題,對應(yīng)解決方案分別是:
根據(jù)綁定設(shè)備類型,動(dòng)態(tài)獲取紅外碼值。
提供指令隊(duì)列,防止指令丟失。
3.2.1 紅外碼值動(dòng)態(tài)獲取
紅外遙控為了兼容不同設(shè)備,采用了紅外碼值動(dòng)態(tài)下發(fā)的方式。主要流程如下圖所示:
應(yīng)用啟動(dòng)判斷當(dāng)前是否綁定設(shè)備,并發(fā)起紅外配置獲取請求,如果有設(shè)備則帶上設(shè)備相關(guān)信息。
紅外配置獲取成功,則使用云端配置信息初始化紅外遙控。
紅外配置獲取失敗,則使用本地兜底數(shù)據(jù)初始化紅外遙控。
3.2.2 指令隊(duì)列控制
當(dāng)用戶快速點(diǎn)擊紅外遙控時(shí),可能會(huì)導(dǎo)致部分指令丟失。為了確保每個(gè)指令在手機(jī)端都能得到處理,我們基于線程池框架,實(shí)現(xiàn)紅外操作指令的控制隊(duì)列,具體實(shí)現(xiàn)如下所示。
- 定義發(fā)碼線程池
private static ExecutorService executorService = Executors.newSingleThreadExecutor();
- 單線程發(fā)碼保證先后順序,確保每次只有一個(gè)指令在執(zhí)行
/**
* 發(fā)射紅外信號
* @param carrierFrequency 紅外頻率
* @param pattern 紅外碼
*/
public void transmit(int carrierFrequency, int[] pattern) {
executorService.submit(new Runnable() {
@Override
public void run() {
if(consumerIrManager != null){
consumerIrManager.transmit(carrierFrequency, pattern);
}
}
});
}
四、總結(jié)
紅外遙控是一項(xiàng)非常實(shí)用的技術(shù),它讓我們能夠輕松地操控各種家電設(shè)備。紅外遙控具有操作簡單、成本相對較低等優(yōu)點(diǎn),在家庭和日常生活中得到了廣泛應(yīng)用。但它也存在一些不足之處,比如信號容易被阻擋、對角度有一定要求,且不同設(shè)備之間可能存在兼容性問題。盡管如此,紅外遙控依然是我們生活中不可或缺的一部分,它為我們帶來了便利,也見證了科技的發(fā)展與進(jìn)步。