實驗目的
練習用 IRRemote 函式庫接收紅外線訊號。在這個實驗裏,你將利用 decode_results 結構來判斷並顯示遙控器的紅外線協定種類,如 NEC, Sony SIRC, Philips RC5 和 Philips RC6 等紅外線協定(Infrared Protocol)。
前提
在做這個實驗前,我假設:
- 你已經看過「IRRemote 紅外線遙控教學」一文,而且
- 也已經把 IRRemote 函式庫安裝起來了
材料
- 麵包板 x 1
- Arduino 主板 x 1
- 38 kHz 紅外線接收器(如 TSOP2438,TSOP4438, PNA4602, FM-8038TM2-5DN) x 1
- 單心線 x N
接線
- 照下表把紅外線接收器跟 Arduino 連接起來:
紅外線接收器接腳 Arduino 接腳 GND(-) 接到 GND Vcc(+ 或 V+) 接到 +5V 電源 Vout(或 OUT) 接到 pin 2。你可以接到其它 Digital pin,但程式要配合修改
▲ 有些紅外線接收器 GND 和 Vcc 是相反的,接線時請查閱你的 datasheet
decode_results 結構
從前一篇中,你已經知道 decode_results 是用來存放紅外線訊號解碼結果的結構。decode_results 結構它的定義如下:
下表是 decode_results 結構各個欄位的說明:
decode_results 欄位名稱 | 說明 |
---|---|
decode_type | 協定種類,包括 NEC, SONY, RC5, RC6, DISH 以及 SHARP 等紅外線協定,若解析不出則為 UNKNOWN。 |
value | 解到的編碼數值 |
bits | 編碼的位元數(即資料長度) |
rawbuf | 紅外線訊號原始波形資料 |
rawlen | rawbuf 的記錄總筆數 |
我們已經看過 value 和 bits 欄位。rawbuf, rawlen 是紅外線訊號的原始波形資料與記錄總筆數,這兩個欄位是比較深入的東西,一般而言,這兩個欄位的機會非常少,所以目前你可以先暫時忽略不管。
這次實驗的目的是判斷並顯示紅外線協定的種類,因此程式將會用到 decode_type 欄位。
程式
底下的程式(Example1.2.pde)示範如何用 decode_type 欄位來判斷並顯示紅外線協定種類:
程式碼沒有太大的變動,只是增加一個 showIRProtocol() 函式來顯示紅外線協定的種類而已,相信你一定看得懂。
示範照片
隨手拿起一個電視遙控器按幾個鈕測試:
打開 Serial Monitor 觀察解碼結果:
上述那些紅外線接收器不知上哪兒買, 小弟用紅外線接收LED 也是一樣效果.
回覆刪除我是在光華商場買的,我用的那款是 FM-8038TM2
回覆刪除其它的我沒用過,也許你可以到 mouser 或露天拍賣找一下
ex:
這個, 這個, 還有這個
您好,
回覆刪除我想請問 decode_results *results 這行是什麼意思
另外, results->value 是不是等於 results.value ?
麻煩您了,謝謝
您好,
回覆刪除再請問 volatile unsigned int *rawbuf 這行程式中
開頭的volatile有什麼意思?以及*rawbuf為何要加上"*"
再一個問題,const int irReceiverPin = 2 這行當中,
const是什麼意思?
問了這麼多真不好意思,麻煩您了,謝謝
你是說 void showIRProtocol(decode_results *results) 裏的 decode_results *results 這行是什麼意思嗎?
回覆刪除Mm.. 這行是宣告 decode_results 型別的變數,變數名稱叫做 results,而因為 results 變數前面有一個星號,所以 results 它是一個指標變數。
results->value; // 這個是用指標存取結構欄位 (field) 的寫法
results.value; // 這個則是一般變數存取結構欄位 (field) 的寫法
volatile 這個不好用文字解釋呢,請你先看一下這篇教學:
回覆刪除http://blog.csdn.net/c_bg44/article/details/1538235
簡單來說,volatile 是告訴編譯器不要對某個變數的存取做程式碼最佳化,每當程式存取某個變數時,就老老實實的記憶體裏存取,而非利用 CPU 暫存器,避免產生狀態不一致的情形。
rawbuf 前面加上星號,代表它是一個指標
也就是說,真正用來存放 IR 原始資料的 buffer 是在另一個地方,所以這邊才會使用指標。
const 是常數的意思,所以 const int irReceiverPin = 2 這行便是宣告一個整數常數,整數常數叫做 irReceiverPin,然後它的數值是 2。因為是用 const 宣告成常數,所以之後程式不能改變 irReceiverPin 的內容。
不會啊,對我來說,算是溫故知新啊。:)
Coopermaa你好~~
回覆刪除請問7位數字跟32位元是否有關係呢?
為什麼不是8位數字代表32位元呢?
我的想法是16^8=2^32
但為什麼你顯示的是七位數字呢?
麻煩您回復了 謝謝~
你好,
回覆刪除你是說為什麼 "4FB48B7" 這是 32 位元的數值嗎? 是這樣的, "4FB48B7" 是 16 進位 hex code,每一位數字是 4 個位元,"4FB48B7" 總共有 7 位,所以是 7 * 4 = 28 位元,不過,其實還有第一位數,只是因為第一位是剛好是 0,所以 Serial.println() 沒把 0 顯示出來,事實上還是 32 位元的
謝謝!!! 原來是沒有顯示~~~:))
回覆刪除不好意思我想請問一下
回覆刪除我的遙控器最一開始接收的訊號是:
Protocol: NEC, irCode: 20DF10EF, bits: 32
Protocol: NEC, irCode: FFFFFFFF, bits: 0
Protocol: NEC, irCode: FFFFFFFF, bits: 0
所以我在測試發射紅外線的訊號這邊是打:
if (buttonState == HIGH) {
// 發射紅外線訊號
irsend.sendNEC(0x20DF10EF, 32);
}
但是這樣測試開關卻測試不出來!
那我又打說:
if (buttonState == HIGH) {
// 發射紅外線訊號
irsend.sendNEC(0x20DF10EF, 32);
irsend.sendNEC(0xFFFFFFFF, 0);
}
這樣也無法測試...
我想請問一下,這樣打是錯在哪?!應該怎麼修正比較好?!
if (buttonState == HIGH) {
回覆刪除// 發射紅外線訊號
irsend.sendNEC(0x20DF10EF, 32);
}
這樣寫應該沒錯。你測試的是什麼開關?
也許同一個按鍵可以多解碼幾次,看看解到的碼是不是每次都一樣。
BTW, irCode 為 FFFFFFFF 是 NEC Protocol 的 repeat code,你可以加個判斷式把它過瀘掉,像這樣:
if (irrecv.decode(&results)) { // 解碼成功,收到一組紅外線訊號
if (results.value != -1) {
// 印到 Serial port
...
}
}
恩恩~真的很謝謝你!!!
回覆刪除但是不好意思...想再請問一下
我的是電視遙控器,算是那種通用的電視遙控器
而我測的是開電視開關的那個按鈕
我有重新測試了你說的加上"if (results.value != -1)",但是這樣似乎反而測不出是NEC的遙控器,他的輸出是:
Protocol: Unknown encoding, irCode: EAB7BACD, bits: 32
Protocol: Unknown encoding, irCode: B853798A, bits: 32
Protocol: Unknown encoding, irCode: EDB7BF84, bits: 32
Protocol: Unknown encoding, irCode: 97307A58, bits: 32
反而有四種不一的訊號了...
而...若是設定不要=0的訊號,為什麼我打
if (irrecv.decode(&results) && results.value != 0)
這個出來的結果和原本的沒甚麼改變!
但若是更改為你說的那個
if (results.value != -1)後,反而會沒有0的值?!但是蹦出4個不一樣的值了??!
不好意思...我不大明白,提出了這麼多的疑問...
同一顆 Power 鈕反而解出四種不一樣的訊號? 怪~~
回覆刪除可以貼一下你完整的 code 嗎?
不好意思捏...恕我愚笨...是先用你網站上面的程式碼先測試的...但就有bug了!
回覆刪除所以是這樣的:
#include
const int irReceiverPin = 2;
IRrecv irrecv(irReceiverPin);
decode_results results;
void setup()
{
Serial.begin(9600);
irrecv.enableIRIn(); }
void showIRProtocol(decode_results *results)
{
Serial.print("Protocol: ");
switch(results->decode_type) {
case NEC:
Serial.print("NEC");
break;
case SONY:
Serial.print("SONY");
break;
case RC5:
Serial.print("RC5");
break;
case RC6:
Serial.print("RC6");
break;
default:
Serial.print("Unknown encoding");
}
Serial.print(", irCode: ");
Serial.print(results->value, HEX);
Serial.print(", bits: ");
Serial.println(results->bits);
}
void loop()
{
if (irrecv.decode(&results)) {
if (results.value != -1) {
showIRProtocol(&results);
irrecv.resume();
}
}
}
這個是一開始測試接收紅外線的種類的!!!
但測出來就有不同的四個了!
若是沒有加if (results.value != -1)
則會出現我之前說的那三個而已!!
試把 loop 函式:
回覆刪除void loop()
{
if (irrecv.decode(&results)) {
if (results.value != -1) {
showIRProtocol(&results);
irrecv.resume();
}
}
}
改成這樣:
void loop()
{
if (irrecv.decode(&results)) {
if (results.value != -1) {
showIRProtocol(&results);
}
irrecv.resume(); // 搬到外面來
}
}
也許會撥雲見日喔!^o^
回應Emily:
回覆刪除先前我也使用Cooper的紅外線接收程式接收電視遙控器發射出來的訊號, 也會有亂碼的問題.
經過我多方測試,"只要直接對著紅外線接受器發射紅外線"就可避免亂碼的產生.
我歸納如下,如果是自己做紅外線發射器的話,通常會有兩個原因產生亂碼:
1.紅外線發射電流不足,導致訊號不清晰==>加入電晶體放大電流就可以改善問題
2.各種紅外線LED燈規格不同,能夠通過的peak電流也不同,發射角度也不同,多少都會影響,所以建議配置能通過大電流的紅外線LED燈,並且對著接受器直接發射,減少亂碼的產生.
最後...如果還是配不出電晶體跟找不到適當的紅外線LED, 就直接解焊電視遙控器上面的燈還有電晶體跟周邊電阻,量測這些規格在進而製作自己的版本吧!!
以上...過來人XDDD
建議先把接收端的程式跟電路都弄好,然後用電視遙控器測試ok後,再進行紅外線發射器的製作這樣可以釐清是硬體問題還是程式問題~~ :))
BTW,有個重點~~
回覆刪除先前測試的時候通常設定電晶體跟紅外線LED燈的工作點都不會設置在他們的continuous(連續輸出)範圍
因為continuous範圍的電流限制都太小了
其實紅外線發射也不是一直持續大電流的供應
所以建立在高電流的工作區是沒問題的
也就是說盡量操爆紅外線LED燈跟電晶體
要不然無法發揮他們的效能!!
但還是先建議在continuous的電流限制下先做測試,如果接受狀況不好,在進行加大電流測試八!!
@Sven Wang
回覆刪除有你的分享,蓬蓽生輝,感謝!
這兩天我又回過頭玩了一下紅外線 (相關記錄可參考 http://bit.ly/PKw6MS)
在做紅外線解碼的時候,發現燈光也會影響解碼
我在房間裏測試,好幾次只是手或身體動了一下擋到光線,結果接收器就有反應,解到一個 Unknown 的碼....
不知道是不是燈光顏色的關係,因為我房間燈光比較偏黃光,感覺好像比較容易讓紅外線接收器產生反應
TO Sven Wang, Coopermaa:
回覆刪除恩恩!!! 我明白了!!!
真的很謝謝你們!!! :))
那麼我現在程式碼他的訊號我有照你們說的,而沒有產生亂碼了!
但就是接了線路想發射紅外線,用arduino板子開電視...反而不行,也有可能是因為電流的問題嗎?!
是不是我同樣的加上電晶體就會改善了?!
真的很謝謝你們喔~
你發紅外線發射器接在哪一支腳位?
回覆刪除可以貼一下接線照片嗎?
可以可以!!!
回覆刪除就是...怎麼把照片PO上來啊??!
放到 dropbox/public 資料夾
回覆刪除然後再貼上檔案連結就行啦~~
作者已經移除這則留言。
回覆刪除不好意思...現在才回
回覆刪除https://www.dropbox.com/s/jax54nfbd745mkk/IMAG1092.jpg?m
https://www.dropbox.com/s/qxqcbflaicdpel9/IMAG1093.jpg?m
2張圖都是一樣的!!!
請問這樣你看的到嗎?!
這太考驗我的眼力啦!
回覆刪除發射器是接 pin 3 還是 pin 2?
另外你的程式是只有處理發射功能,還是有發射同時有接收功能呢?