201405110040紅外線遙控器整合使用智慧手持裝置控制

我並不是故意把標題下得像是專題報告一樣.........只是不知如何一言以蔽之

這次的專案是某回到同事家,身為科技宅男新貴的他

在觀看數位多媒體的選擇上當然會有電視、MOD、藍光DVD、多媒體播放器

對聲音要求一點,當然要用擴大機、音低頻揚音器,弄個家庭劇院才成啊!

可是這時就會聽到他老婆抱怨:「我永遠搞不清楚要怎麼開.......」

同事就很不耐煩地過來:

『先開電視,看是在那個source,切到你要的,再拿對應遙控器開嘛!』
『聲音就是這支啊!DVD要選擴大機裡的這個source嘛!』
『不想看,要用這支先關擴大機、再用這支關DVD、最後關電視,不會很複雜啊!』

..................................................................................................

回家後,我就趕緊來弄一套遙控器整合計劃,要不然我深怕以後會變成討人厭的老公(抖)

現在大家都用智慧型手機,在家手機是連wifi,所以把手持裝置變成遙控器是最好的選擇!

另外還要做出"一鍵通"功能,按一個鍵發送很多道指令去控不同裝置

因此此篇要學習的有:

1.紅外線的接收&發送

2.新增紅外線通訊協定

3.UDP發送控制指令

此專案的檔案下載連結→請按此

 

《紅外線的接收&發送》

關於arduino的紅外線接收和發送,網路上有許多朋友分享做法,因此這裡簡單介紹

arduino官網下載的函式庫中並沒有紅外線遙控的函式庫

大部份都是下載Ken Shirriff所提供的IRRemote函式庫,裡面包含接收解碼&發送

連過去,見頁面右下角"Download ZIP",可下載使用

接收器和LED發射零件都很便宜,台幣10來塊左右

只是要注意的是,接收器種類有很多,最常用的是38kHz的,另外也有56kHz

大多數為38kHz左右,至於RCA通訊協定和DISH網路電視則是使用56kHz

接收器有3根pin,接收面朝上,由左至右大多為Vout、GND、5V

其中GND和5V腳位根據廠商不同,位置會互相調換

紅外線發射器的接法如下,根據板子的不同,腳位也有所變換

詳細的內容可以看IRremoteInt.h這個定義檔

 

《新增紅外線通訊協定》

第一階段並不難,而且有很多參考資料,所以在這裡分享較進階的玩法

我要控制的設備並不多,Vizio 42"電視、MOD、Denon擴大機,只有3種設備

Vizio和MOD的遙控器都是NEC Protocol,很快地就把每個鍵給解碼出來

(有需要的話,請自行連結至相簿中下載Vizio和MOD遙控器的碼)

       (左至右:Vizio, MOD, Denon)

Denon擴大機就是喜歡和別人不一樣!走自己的protocol.....

雖然IRremote函式庫中有sendRaw()的功能,但就是忍不住想把Denon加進去!

在新增前先了解一下遙控器的原理,我用一個我自認為很簡單的比喻來說明........

小明和小華為了偷作弊不被老師發現,所以發明了自己的摩斯密碼!規則如下

每隔1秒敲一下,連續敲了三下後表示準備要溝通了

三下敲完後會停2秒,代表接下來我要說答案了

若第6秒敲下去,代表A;第7秒才敲代表B;第8秒敲代表C;第9秒代表D

第10秒一定要敲,代表這回的溝通結束了

因此小明若要跟小華說答案是B的話,他敲桌子的時間會是



紅外線遙控器其實就和小明小華的摩斯密碼相似,各家定義自己的通訊協定

只要按照定義好的規則去送,接收端收到無誤後,會做什麼動作就看設定

關於紅外線遙控更詳細的說明、還有常見的各家大廠的通訊協定,可至 SB-Projects:IR

在這邊我就以最常見的NEC protocol為範例做說明,如何新增至函式庫

先查詢NEC的定義,使用38kHz,指令格式由Head、Address、Command、Stop組成

送邏輯"1" (High)時,高電位持續560us、之後低電位持續1690us

送邏輯"0" (Low)時,高電位持續560us、之後低電位持續560us

Address和Command都佔8 bits,且都要反向

到這裡先打住,先跳到arduino接收器得到的結果

(圖片來源 http://www.sbprojects.com/knowledge/ir/ )

嚐試去解碼MOD遙控的Power電源鍵,請看下圖中Raw (68)這個地方

IRremote函式庫裡的解碼會將1和0所佔的時間長度標示出來,亦即raw data

去掉開頭那個13044的數值,可得到總共67筆資料

上面的NEC protocol中,address和command共佔 8+8(反向)+8+8(反向) = 32 bits

所以address+command會偵測出 32 * 2 = 64筆raw data

開頭有2筆、結束有1筆,因此加總起來正好是64+2+1=67筆

指令格式正確了,接下來我們看時間長度是否符合

發送的時間長度不可能100%,都會有一個容忍值

看raw data的第2、第3筆,也就是NEC protocol Head的部份

定義上寫Head由High 9ms、Low 4.5ms組成,實際偵測出來8800us、-4450us,符合

邏輯"0"為High 560us、Low 560us,實際偵測出來大多在500~550us之間,也是符合的

邏輯"1"為High 560us、Low 1690us,實際約在1600~1700之間,亦是符合

從上面的結果我們得到遙控器送出來的符合NEC protocol,接下來就是寫進code裡

在IRremoteInt.h中,就需將protocol的數值定義好

其中MARK是指高電位、SPACE是指低電位、HDR為Head、ONE是邏輯"1"、ZERO是邏輯"0"

實作的部份如sendNEC()和decodeNEC()就需要花時間去讀

配合通訊協定就能理解實作的流程

// Pulse parms are *50-100 for the Mark and *50+100 for the space
// First MARK is the one after the long gap pulse parameters in usec
#define NEC_HDR_MARK  9000
#define NEC_HDR_SPACE 4500
#define NEC_BIT_MARK  560
#define NEC_ONE_SPACE 1600
#define NEC_ZERO_SPACE  560
#define NEC_RPT_SPACE 2250
#define NEC_BITS  32

 

根據上述的說明後,上網去找DENON遙控器的protocol,找到了這份

address長度為5 bits、command則是10 bits,沒有Head,但有Stop bit

32kHz,邏輯1和邏輯0可以看下圖說明

同樣指令要發送2次,第2次的資料要反向,且第1次的開頭距離第2次開頭要65ms

先用IR Receive程式,確定了raw data符合Denon protocol後,就可以著手新增了

// IRremoteInt.h
#define DENON_BIT_MARK 225
#define DENON_ONE_SPACE 1900
#define DENON_ZERO_SPACE 775
#define DENON_RPT_LENGTH 65000
#define DENON_TOGGLE_MASK 0x3FFF
#define DENON_BITS 15

// IRremote.h
#define DENON 11
long decodeDenon(decode_results *results);
void sendDenon(unsigned long data, int nbits);

//IRremote.cpp
int IRrecv::decode(decode_results *results) {
  ....//略
#ifdef DEBUG
  Serial.println("Attempting Denon decode");
#endif 
  if (decodeDenon(results)) {
    return DECODED;
  }
}

void IRsend::sendDenon(unsigned long data, int nbits)
{
  enableIROut(32);
  
  unsigned long invertdata = data ^ DENON_TOGGLE_MASK;
  unsigned long time1, time2;
  time1 = micros();
  for (int i = 0; i < nbits; i++) {
    if (data & 0x4000) {
      mark(DENON_BIT_MARK);
      space(DENON_ONE_SPACE);
    }
    else {
      mark(DENON_BIT_MARK);
      space(DENON_ZERO_SPACE);
    }
    data <<= 1;
  }
  mark(DENON_BIT_MARK);
  space(DENON_ZERO_SPACE);
  
  time2 = micros() - time1;
  delayMicroseconds(DENON_RPT_LENGTH-time2);
  
  for (int i = 0; i < nbits; i++) {
    if (invertdata & 0x4000) {
      mark(DENON_BIT_MARK);
      space(DENON_ONE_SPACE);
    }
    else {
      mark(DENON_BIT_MARK);
      space(DENON_ZERO_SPACE);
    }
    invertdata <<= 1;
  }
  mark(DENON_BIT_MARK);
  space(DENON_ZERO_SPACE);
}

long IRrecv::decodeDenon(decode_results *results) {
  long data = 0;
  int offset = 1; // Skip first space	  
  if (irparams.rawlen < 2 * DENON_BITS ) {
    return ERR;
  }
	  
  // Initial mark
  if (!MATCH_MARK(results->rawbuf[offset], DENON_BIT_MARK)) {
    return ERR;
  }
	  
  for (int i = 0; i < DENON_BITS; i++) {
    if (!MATCH_MARK(results->rawbuf[offset], DENON_BIT_MARK)) {
      return ERR;
    }
    offset++;
	    
    if (MATCH_SPACE(results->rawbuf[offset], DENON_ONE_SPACE)) {
      data = (data << 1) | 1;
    } 
    else if (MATCH_SPACE(results->rawbuf[offset], DENON_ZERO_SPACE)) {
      data <<= 1;
    } 
    else {
      return ERR;
    }
    ffset++;
  }
	  
  //Stop bit
  if (!MATCH_MARK(results->rawbuf[offset], DENON_BIT_MARK)){
    return ERR;
  }
	  
  // Success
  results->bits = DENON_BITS;
  results->value = data;
  results->decode_type = DENON;
  return DECODED;
}

decode和send的做法與其它protocol大同小異,只不過在send的地方

宣告了變數記錄第1次發射的時間,用65ms減去後做delay,就是第2次反向發射的時間點

 

當然也不一定要這麼麻煩做新增函式庫的動作,你也可以直接複製得到的raw data

然後使用void IRsend::sendRaw(unsigned int buf[], int len, int hz)這個函式

把raw data的第1個數字去掉,負數值也去掉,宣告成array,如

unsigned int Ary[n] = {0x01, 0x02, ...., 0x0n};

然後再用 sendRaw(Ary, n, hz); 發送就好了,這是最簡單的方法

 

 

《UDP控制》

紅外線搞定後,接下來就是把一連串的動作整合起來,並用手機的APP去控制

UDP的控制先前已有談過,實作起來並不困難

正好之前花了2999買了一個鳥鳥的7" android平板來玩,就把它當作遙控器吧!

我是下載免費版的"UDP TCP Server",可以自行編輯按鍵的名稱和發送指令

考量到我也只會看TV或MOD,所以只需要設定2個訊號鍵

當我在TV下時,按鍵就是發送TV遙控器;在MOD下時,當然就是發送MOD的

因此按鍵的設計如下,共18個鍵:
[TV] [MOD]
[Ch+] [Ch-] [Vol+] [Vol-]
[1] [2] [3]
[4] [5] [6]
[7] [8] [9]
[R] [0] [OK] //R是指返回上一個頻道

當我想看電視時,按下[TV]鍵,就會進行一連串動作:
1.啟動電視
2.等待2秒後啟動擴大機
3.等待18秒切到TV source

至於按下[MOD]鍵,動作則是:
1.啟動MOD
2.等待3秒後啟動電視
3.等待2秒後啟動擴大機
4.等待18秒切到HDMI1 source

現在電視愈做愈smart,功能愈來愈多,開個機沒花個10~20秒初始化都不行....

不過至少只要按下一個鍵,就可以把一連串功能做完

這裡有個經驗分享一下,像MOD,因為我是使用HDMI out,常見一個問題就是

如果你先開了電視,再開MOD,偶爾會有影像沒有聲音,電視重開就會好

為避免這狀況,所以[MOD]鍵的第1個動作會先開MOD,約等3秒讓MOD系統穩定後再開電視

 

到這邊都算簡單,不過當腦婆看膩了TV後,想轉到MOD時....哇!怎麼電視關了!?

是的!操作邏輯沒有考量好,出代誌啦!只好新增2個變數power status和input mode

[TV]鍵邏輯考量:

if (關機狀態) {
  電視開機&設定訊號源為TV
}
else {
  if (訊號源是TV) {
    電視關機
  }
  else {
    表示要從MOD切到TV
  }
}

MOD的邏輯作法也同樣,正好Denon擴大機遙控器電源開/關是不同鍵

增加變數判斷也利於操控Denon擴大機

整合了之後,家裡人的手機也安裝了UDP TCP Server app

接下來就出現............

 

每個人手上都有遙控器進行搶頻道大戰了............................何苦呢我........

 

 

沒有上一則|日誌首頁|沒有下一則
回應
關鍵字
    沒有新回應!