2018年12月4日 星期二

【IR #02】淺談紅外線遙控通訊協定 @Arduino @Matlab @Introduction


網頁最後修改時間:2018/12/04

在這一篇關於 "淺談" 紅外線通訊協定(IR Protocol)的部落格網頁,將延續上一篇的紅外線遙控器的按鍵解碼,以實際的例子說明 NEC 和 Philips RC6 的紅外線編碼格式。

就如同上面的圖片,根據解碼出的 Philips RC6 紅外線遙控訊號原始數據進行階梯圖繪製,這個圖形可方便用來輔助學習與了解 RC6 的編碼格式,並驗證所得資料的正確性;沒有繪製成階梯圖,是很難從所得到的原始數據看出端倪的!

為了讓理論與實際能相互對照,以手邊剛好有的紅外線遙控器(NEC 和 Philip RC6 Mode 0)來說明其通訊協定格式,其他的紅外線通訊協定,可以以這篇網頁所談及的部份去了解它們。

【紅外線遙控訊號的調變】

紅外線遙控訊號,不是單純的發送 ON/OFF 的數位訊號,而是以一個固定頻率的 ON/OFF(PWM)訊號來做傳輸(通訊協定不同,頻率也不同),並依照所定義的所謂 Logic "0"Logic "1" 的方式進行調變發送。

大多數紅外線遙控器使用的通訊協定裡所用的遙控訊號 Logic (邏輯)調變示意圖,如下圖所示。

位元(bit)Logic 訊號發送的過程中,mark 代表持續發送 PWM 訊號(這一堆高頻調變波的地方為載波叢發訊號《Carrier Burst》,下面稱為脈衝)、space 代表關掉 pwm 訊號發送;T1-m、T1-s、T0-m、T0-s 代表訊號發送的時間,但其值不一定相同,而且不一定就是 mark 在前、space 在後,通訊協定各自有它們自己的定義。

紅外線遙控訊號 Logic 調變示意圖
發射之後的紅外線訊號被正確的接收之後,輸出是一個反向持續的 ON / OFF 的數位訊號 (還記得紅外線接收模組是低態動作的嗎 ?)Arduino(或是其他微控制器)根據這些持續時間可以判別出紅外線訊號的 Logic 是 "0" 還是 "1",當完整且正確接收完一個紅外線訊號之後,就能再根據下面介紹的紅外線通訊格式識別出相關資訊。

脈衝的 PWM 訊號輸出頻率依所使用的通訊協定而有所不同,不過這其中未談論到的就是其佔空比(duty cycle)。

要知道,IR LED 不同於一般常用的可見光 R/G/B LED,其順向電流可以從 100mA 變化至遠遠超過 1A,為了要得到能控制到非常遠的距離,順向電流要盡量越高越好,但相對地就會增加電力消耗,因此這兩個因素必須相互權衡。

IR LED 發射時使用了 PWM 訊號驅動,因此可以在通過較高的電流值時也不會損壞,但須注意平均功耗不應超過它的最大值、電流也不可超過它的順向脈衝峰值電流限制。其中一個很重要的參數就是 PWM 佔空比(duty cycle)的選擇(佔空比是在 PWM 訊號中 ON 部分所佔的百分比,一般在紅外線 PWM 訊號常用 33.33% 或 25%;Arduino IRremote 函式庫則是選用 33.33% 作為其 PWM 訊號的佔空比),適當的選擇佔空比,可以在增加電流的同時、又不會讓 IR LED 過熱、且能增加較長的控制距離。

下面開始是關於紅外線通訊協定(NEC 和 Philips RC6)的介紹,兩者都是以實際的例子來做解釋,所得到的資料來自於使用 Arduino IRremote 函式庫裡的範例 "IRecvDumpV2",接線與前一篇相同。

/*-/--*-*/*/*/*/***//-*-*-**-*/*-*-/*/*/*-*-/-////--/**/**--**/--///--//**----**//--**//**----***//*-**//*
有購買商品的使用者,網頁中所用到的檔案與程式碼已放置於雲端硬碟,請自行下載使用!
其餘的使用者,請自行依照提供之連結下載相關資料,程式碼複製貼上使用!
/*-/--*-*/*/*/*/***//-*-*-**-*/*-*-/*/*/*-*-/-////--/**/**--**/--///--//**----**//--**//**----***//*-**//*

*********************************************************************************
紅外線發射/接收入門學習套件可至露天賣場訂購:
*********************************************************************************

【NEC 紅外線通訊協定】

套件中的紅外線遙控器使用的是 NEC 的紅外線通訊協定,而且像是市面上的 LED 燈帶、機上盒等 ...... 的遙控器也大多都是,所以使用相當廣泛!若手邊有非特定廠牌的紅外線遙控器,也可以拿來試試抓取一下訊號。

** 這一節所談論的不涉及延伸的 NEC 紅外線通訊協定

/*--*//**---/*///**---*-*////***--*/*///***----*///--*/*///**--*/*//**--**/*//
* 特點:
  • 載波頻率(Carrier Frequency)38kHz;
  • 8-bit 地址、8-bit 指令;
  • 為了可靠性,通訊協定裡的地址與指令各發送兩次;
  • 脈衝間隔調變(PDM, Pulse Distance Modulation)方式;
    脈衝寬度(mark, T1-m = T0-m)不變,但脈衝間隔(space, T1-s ≠ T0-s)改變
/*--*//**---/*///**---*-*////***--*/*///***----*///--*/*///**--*/*//**--**/*//
* NEC 紅外線遙控訊號邏輯調變方式:

NEC 紅外線遙控訊號使用的載波頻率 38kHz,一個 PWM 週期花費 26.316 µs(ON=8.772 µs, OFF=17.544 µs;佔空比 33.33%)。Logic 脈衝寬度為 562 µs,意謂在此脈衝寬度下產生約 21 個 PWM 訊號。

由下圖可以看出,NEC 的 IR Logic 調變使用 PDM 方式:其脈衝寬度都是 562 µs,Logic "1" 脈衝間隔為 1687.5 µs、Logic "0" 脈衝間隔為 562.5 µs,所以稱為脈衝間隔調變。
NEC IR 遙控訊號邏輯調變方式
這些就是 NEC 紅外線通訊協定格式中,傳送數據時的基本位元邏輯產生的方式,至於其他的部分請看下一小節的說明

/*--*//**---/*///**---*-*////***--*/*///***----*///--*/*///**--*/*//**--**/*//
* NEC 紅外線通訊協定格式:

看下圖,每一次按下按鍵時,首先發送一個 9ms 的自動增益控制(AGC, Automatic Gain Control)突發脈衝訊號(它被用來設置早期 IR 接收器的增益),後面接著一個 4.5ms 的 space 訊號,再送出地址和指令(到這裡總花費時間 67.5ms),最後以一個 562.5 µs 的 mark 作結束(圖的最後有畫出,但是沒特別標上字)。

地址和指令重複傳送兩次,位元組的低位元(LSB)先送;第一次正常傳送,第二次將位元組取反後傳送,地址和指令一正一反傳送一次各是花費 27ms。

地址:0b1010 1010
指令:0b0011 0011
NEC 紅外線通訊協定格式
對於按鍵一直按下的情況,將會先輸出上面的格式一次後,以每隔 110ms 的方式重複輸出下面的訊號;Arduino IRremoe 函式庫抓到的解碼值會是 0xFFFFFFFF。
NEC 紅外線通訊協定格式(Repeat)
下面以一個實際的例子來做說明。

/*--*//**---/*///**---*-*////***--*/*///***----*///--*/*///**--*/*//**--**/*//
* NEC 紅外線遙控器按鍵值解碼原始數據與解碼值:

打開 Arduino IDE 的 Serial Monitor,拿出套件中的遙控器,隨便選擇一個按鍵值按下一秒後放掉,應該就會看到類似下面的輸出訊息。

欄位解釋如下:
  • Encoding:代表紅外線遙控所使用的通訊協定為何?經辨識出來的是 NEC;
  • Code:接收的紅外線訊號解碼值,由 Timing 陣列中的原始數據計算後得到;
  • Timing[67]:接收的紅外線訊號解碼的原始數據。其值表示的是時間(µs)、67 表示的是原始數據的數目;
  • unsigned int rawData[67]:這裡是定義上面的原始數據為一個陣列,用來作為 sendRaw() 函式的引數,以此控制被解碼的紅外線裝置;
  • unsigned int data = 0xFDA857:將 Code 整理成一個可用於程式的變數定義;
Timing 下面所列出的原始數據是帶正負號的,跟 rawData[] 裡的不同,主要是用來方便識別此處的數字所代表的是屬於 mark(+) 還是 space(-)訊號,67 的由來則是  2 + (8 + 8 + 8 + 8) * 2 + 1 = 67。

NEC 紅外線遙控器按鍵解碼輸出訊息
把上面輸出的 Code 的 16 進位值替代入到上一篇的程式碼後編譯上傳,再按下同一個按鍵,就會看到類似下面的輸出。依照這種方式就可以得到遙控器上面的所有按鍵解碼值。
接收紅外線遙控訊號並顯示在 OLED 上
仔細的將 Timing 陣列裡面的值對照到格式中,很容易就能瞭解紅外線通訊協定格式構成的原理,以及 Code(解碼值)的 16 進位值是如何而來的!

【Philips RC6 紅外線通訊協定】

Philips RC6 對比於 NEC 的紅外線通訊協定比較複雜一點:

  • 邏輯採用的是雙相位編碼調變方式;
  • 同一個按鍵有兩種解碼值;
  • 按鍵持續按下時,輸出的是當前鍵值;
  • Arduino IRremote 函式庫解碼所得原始數據數量與格式應有數量不同;

** 請注意,畢竟所使用的紅外線接收模組的載波率是 38kHz,所以並不能保證所有的紅外線接收模組都能容易的接收解碼出像這一節所給出的 Philips RC6(36kHz)輸出資料。

/*--*//**---/*///**---*-*////***--*/*///***----*///--*/*///**--*/*//**--**/*//
* 特點:
  • 載波頻率(Carrier Frequency)36kHz,duty cycle 介於 25% ~ 50%;
  • 雙相位編碼調變(Bi-Phase Code《又稱為曼徹斯特編碼 (Machester coding)》)方式;
  • 脈衝寬度(mark, T1-m = T0-m)等於脈衝間隔(space, T1-s = T0-s),但邏輯調變前後順序不同;

/*--*//**---/*///**---*-*////***--*/*///***----*///--*/*///**--*/*//**--**/*//
* Philips RC6 的時間單位(Timing Unit)t

Philip RC6 紅外線通訊協定格式裡,主要的時間單位是 t,是載波週期的 16 倍((1/36000) * 16 = 444.4 µs),通訊協定格式中的邏輯調變以此作為時間單位。

/*--*//**---/*///**---*-*////***--*/*///***----*///--*/*///**--*/*//**--**/*//
* Philips RC6 紅外線通訊協定格式(Philips RC6 Mode 0):

介紹 Philips RC6 邏輯調變之前,先來看看它的通訊格式。

如同小節一開始所說的,對於使用 Philips RC6 紅外線通訊協定的遙控器而言,每一個按鍵都有兩種解碼值,但是主要的變化就是在格式的第三部分(第五個邏輯處)將數據邏輯 "0""1" 的 markspace 的時間加倍(每按下一次進行邏輯變換),其餘維持一樣。

如下圖,是一實際 Philips DVD Player(RC6)開關的紅外線解碼訊號格式,也是下一小節用來解釋按鍵解碼原始數據和解碼值的參考依據。

格式的每一個部分,它擴號裡面的數字表示所佔的位元(bit)數量,其中:
  • Start (1+1):起頭位元,有兩個:一長(6t+2t)一短(t + t);
  • Field (3):又稱為操作模式(Operating Mode),Philips DVD Player 使用的是其 Mode 0,所以三個位元都是邏輯 "0",採用數據邏輯調變(t + t);
  • Toggle (1):按鍵切換的位元,只有一個,採用按鍵切換邏輯調變(2t + 2t);
  • Address (8):地址,有八個位元,採用數據邏輯調變(t + t),高位元先送;
  • Command (8):指令,有八個位元,採用數據邏輯調變(t + t),高位元先送;
Philips DVD Player ON/OFF RC6 紅外線訊號(Toggle "0"
Philips DVD Player ON/OFF RC6 紅外線訊號(Toggle "1"

/*--*//**---/*///**---*-*////***--*/*///***----*///--*/*///**--*/*//**--**/*//
* Philips RC6 紅外線遙控訊號邏輯調變方式:

Philip RC6 的邏輯調變,依據格式不同部分可區分三個部分:起頭、數據和按鍵切換,分述如下:

** 起頭:

紅外線訊號的起頭位元,一長一短,所用的時間不一樣;注意 Start (+1) 其實用的是數據邏輯 "1" 的調變方式。
Philips RC6 紅外線邏輯調變 - 起頭
** 按鍵切換:

不管目的是作為發射或是接收紅外線訊號之用,同一個按鍵會出現兩個解碼值,而唯一區分就是根據這個位元。

若根據解碼值來做辨識的話,就是有無加上了 0x10000 這個數值;例如,Philips DVD Player 開關的解碼值就會在 0x4C7 和 0x104C7 兩者之間做變化,若是持續按下的話就會一值維持同一個值,若手邊有同類型的遙控器的話可以自己試試!

Philips RC6 紅外線邏輯調變 - 按鍵切換
** 數據:

通訊協定格式裡面 Address Command 的部分,使用下面的方式進行邏輯調變。
Philips RC6 紅外線邏輯調變 - 數據
下面以一個實際的例子來做說明,例子裡面的原始數據已通過開關 Philips DVD Player 電源的測試。

/*--*//**---/*///**---*-*////***--*/*///***----*///--*/*///**--*/*//**--**/*//
* Philips RC6 紅外線遙控器按鍵值解碼原始數據與解碼值:

打開 Arduino IDE 的 Serial Monitor,拿出套件中的遙控器,隨便選擇一個按鍵值按下一秒後放掉,應該就會看到類似下面的輸出訊息。

Philips RC6 紅外線遙控器按鍵解碼輸出訊息
如上的數據經過驗證是正確且可使用的!但仔細算一下 Timing 應該包含的原始數據數量(( (1 + 1) + (3) + (1) + (8) + (8) ) * 2 )等於 44,不過實際由 Arduino IRremote 函式庫所得出的卻是 35、37 或 37、39(看影片中的展示),這是為什麼呢?
這就跟函式庫的撰寫有關係了,簡單說:跟邏輯調變的 mark space 前後順序有關係!
NEC 的邏輯調變不管是 "0" 或是 "1" 都是 mark 在前、space 在後;但 Philips RC6 的調變邏輯 "0" 則是 space 在前、mark 在後,當 "0" 緊接著 "1" 或是 "1" 緊接著 "0",就會導致 mark space 的時間加倍,造成上一個 "bit" 的 mark space 被算進到下一個 "bit" 的 mark space 的時間裡,所以 Timing 的陣列長度才會比想像中的短。

不過沒有關係,可以把它畫出來看再進行分析,很容易就能看出其中的差異!

只有把圖形畫出來才能知道實際的格式與接收的數據間有著什麼關係,也才能真正了解格式的意義。畫出來的階梯圖配合前面所說的 t 時間和格式進行劃分切割,可得到下面的結果。

Philips RC6, Timing[37], 0x4C7

Philips RC6, Timing[35], 0x104C7
若你仔細看一下上面的階梯圖最後面一個位元,它的底線是紅色的,我把它補上去的的目的是為了把最後一個位元補完整。這是因為接收紀錄只到此位元的 mark 部分就結束了,沒有紀錄最後的 space 部分。當使用這些原始數據作為紅外線訊號發送(sendRaw())時,最後一個 mark 發出結束後,程式就會直接關掉輸出訊號(也就是 space(0)),所以不會影響其正確性,不過應用上需要了解一下。

但這又沿生出另一個問題:那如果最後一個位元是 0 呢?
Timing 陣列長度會各多加 2。但不管 Timing 陣列長度為何,只要接收的數據是正確的,階梯圖都會符合格式的劃分!
那麼接下來,就把上面談論的這兩種情形,加入到下面的階梯圖繪製小節中,影片中所用到的檔案與文件也一併提供,可自己動手畫畫。

/*--*//**---/*///**---*-*////***--*/*///***----*///--*/*///**--*/*//**--**/*//
*繪製原始數據階梯圖:

雖然似乎可以用 Excel 來畫,不過後來沒這樣做,因為剛好找到一個不需付費使用的數學軟體網站: Octave Online;採用的是可線上編寫類似 Matlab 語法的整合開發環境,也提供 .m 草稿檔的運行,但使用之前需要註冊一下帳號 (可以用 FB、Google等......直接註冊) ,要不無法線上儲存文件,那就無法跟影片做到相同的事囉!

成功登入之後,拖拉需要的三個文件到左方上傳:plotirsignal.m 是草稿檔,其他兩個是 RC6 Toggle "0" 和 Toggle "1" 的原始數據。

原始數據是來自於 IRrecvDumpV2.ino 的輸出 rawdata[] 陣列裡的內容,以逗號區隔的 CSV 檔案。

執行很簡單,只要輸入:
plotirsignal('rc6-raw-data-#.csv') % # 表示 0 或 1
若執行出現錯誤提示,打開 plotirsignal.m 文件看看裡面是否出現額外的文字?刪除不必要的文字就可順利執行!

繪製階梯圖的 .m 檔(如下)可同時用於 Matlab 軟體和 Ovtave 網站,至於兩個 .csv 檔案都是空白檔案可自行建立。

plotirsignal.m 下載

下面影片中,實際演示了由紅外線訊號接收到繪製階梯圖的過程。


** 影片中切換成大階梯圖時忘記切換 Plot: Line # 為下一則圖形,導致大階梯圖都是顯示第一則的圖形,實際使用時請別忘了切換,特此說明!

在影片中,由遙控器的兩個不同按鍵所產生的四組資料 Timing 陣列的長度都不一樣(35 和 37 同一個按鍵;37、39 同一個按鍵),會導致這樣的結果是由於訊號最後一個位元(bit)是 "0" 或是 "1" 導致,輸出的原始數據如下所示:

輸出數據下載

利用上面數據所繪出的四張階梯圖(原尺寸大小),如下所示(點擊看原尺寸圖):
Plot: Line 2, , Timing[37], 0x42C
Plot: Line 3, Timing[35], 0x1042C
Plot: Line 4, Timing[39], 0x47E
Plot: Line 5, Timing[37], 0x1047E

【結論】

紅外線通訊協定或許有很多種,但基本的東西都差不多,有差異、但有資料的話不難理解。

會花這麼多的篇幅與時間來寫這一篇,除了是為了瞭解紅外線通訊協定之外,主要的目的是要能在需要的時候客製化自己的紅外線通訊協定或是將其衍生。

網頁當中也提供了將 Philips RC6 Mode 0 的原始數據繪製成階梯圖的 .m 草稿檔,對於了解紅外線通訊格式很有幫助,以後遇到未知格式且能重複產生相同數據的紅外線訊號時,就可以以這檔案為基礎進行繪製。

了解了紅外線接收和通訊格式之後,接下來要做的就是紅外線發射的部分,至於到底要做什麼,想到了再說吧!


<< 部落格相關文章 >>

2 則留言:

  1. 不好意思可以請教一下 Code(解碼值)的 16 進位值是如何從Timing轉換而來的嗎

    回覆刪除
    回覆
    1. 仔細的將 Timing 陣列裡面的值對照到格式中,很容易就能瞭解紅外線通訊協定格式構成的原理,以及 Code(解碼值)的 16 進位值是如何而來的!

      刪除

留言屬名為"Unknown"或"不明"的用戶,大多這樣的留言都會直接被刪除掉,不會得到任何回覆!

發問問題,請描述清楚你(妳)的問題,別人回答前不會想去 "猜" 問題是什麼?

不知道怎麼發問,請看 [公告] 部落格提問須知 - 如何問問題 !