ir remote control NEC protocol

Posted by: 邱小新 at 下午4:32 in

一般指令時脈圖

  1. 圖一:0 與 1 的時脈圖。

  1. 圖二:傳送一個完整指令的時脈圖。
  1. 根據圖一,每次都會先送出 560us 的紅外線,再停止一段時間,再送出 560us 紅外線........直到資料送完。
  2. 根據圖一,送出一個 bit 1 需時 2.25ms 的時間。
  3. 根據圖一,送出一個 bit 0 需時 1.12ms 的時間。
  4. 根據圖二,會先送出一個 start sync (13.5ms),再依序送出 32bit 的資料,總共耗時 67.42ms。
  5. 一般來說 address 我們稱為 custom code,遙控器上的每一個按鍵送出的 address 都一樣,而只有 command 不一樣,以做區別。

重複指令時脈圖

  1. 圖三:傳送一個重複指令的時脈圖。
  1. 圖四:重複指令放大的時脈圖。
  1. 根據圖四,傳送一個重複指令需時 11.25ms。
  2. 根據圖三,傳送一個完整重複指令需時 110ms,所以後面空白時間為 110-11.25-0.56=98.19ms。
  3. 但是實際拿了三支不同的遙控器來試,結果發現三支的空白時間均不同,分別為 96.18ms、96.78ms、97.26ms。所以切記不要拿空白時間來當 repeat 訊號。

紅外線接收圖

  1. 圖五:紅外線接受器的訊號輸出圖。
  1. 根據圖五可以知道,當收到紅外線時,會產生一個 falling edge-triggered,剛好可以配合 8051 的 external interrupt。
  2. 只要利用二個 falling edge-triggered,就可以算出一個 pulse 所需的時間,進而知道是那一種訊號。
  3. 另外再利用 timer 8-bit auto-reload mode 的功能,可以精確計時。

範例程式

原始碼下載 void start_timer(void) { TR0 = LOW; timer_count = 0; TL0 = TIMER_COUNTER_60us; TR0 = HIGH; } void stop_timer(void) { TR0 = LOW; } int get_timer0(void) { int count; stop_timer(); count = timer_count; start_timer(); return count; } void timer0_isr(void) interrupt (1) { if(timer_count < 1500) { timer_count++; } else { stop_timer(); ir_control = 0; } } void init_timer0(void) { TR0 = LOW; TF0 = LOW; TMOD = (TMOD & TIMER1_MASK) | TIMER0_MODE_8BIT_AUTO; TH0 = TIMER_COUNTER_60us; PT0 = HIGH; ET0 = HIGH; } 發現了一個大 bug,i=ir_pos>>3; 要改成 i=(ir_pos&0x1f)>>3; 才可以,不然當接收到太多錯誤訊號時,會造成 ir_pos 溢位,而修改到其它變數。過了好久才發現這個問題,還是不小心發現的,還要感謝同事的遙控器溢波干擾,讓我看到這個大 bug。 void ext0_isr(void) interrupt (0) { static char ir_pos; int pulse; char i; if (ir_control == 0) { ir_control = IR_START; start_timer(); return; } pulse = get_timer0(); if (IS_IR_START(pulse)) { ir_control |= IR_READ; ir_pos = 0; return; } if (IS_IR_REPEAT(pulse)) { if (ir_control == IR_START) { printf_tiny("\n\rrepeat(%d)", pulse); } return; } i = (ir_pos & 0x1f) >> 3; if (IS_BIT_0(pulse)) { ir_code[i] >>= 1; ir_pos++; } else if (IS_BIT_1(pulse)) { ir_code[i] >>= 1; ir_code[i] |= 0x80; ir_pos++; } else { printf_tiny("\n\rerror(%d)", pulse); ir_control = 0; stop_timer(); return; } if(ir_pos >= 32) { ir_control ^= IR_READ; printf_tiny("\n\rcode = %x,%x,%x,%x", ir_code[0], ir_code[1], ir_code[2], ir_code[3]); ir_control = 0; stop_timer(); } } void ir_init(void) { init_timer0(); ir_control = 0; IT0 = HIGH; EX0 = 1; P3_2= HIGH; }

4 意見

感謝大大提供的SOURCE CODE. 照此CODE看來似乎大大收到的訊號是已經過濾掉載波訊號?? 因我在實做的時候是有用示波器量到接收器會有載波訊號, 不知道要怎樣過濾掉載波訊號 ? 否則不是光是一個Start訊號就會被trigger 342次 ??
9ms/(1/38000) = 342

載波頻率為38KHz

不好意思,我非電子科系出身,所以不太懂硬體,在軟體方面量測是沒有被 trigger 342 的問題,如果有此問題,需要從硬體著手修改成只能 trigger 1 次,不然軟體也無法寫。

匿名大大,所提到的是直接在IR phodediode 上面的信號,
而IR遙控器所使用的通常是模組,例如這個
http://www.crowcroft.net/kitsrus/pic1018scl.pdf
這種模組會過濾載波,讓輸出的信號變成 logic level

版大您好 :
最近公司開發一顆 C8051F320 的MCU, 裡面因沒有內建解碼,
所以我要自己寫decoder, 也是要使用NEC protocol,
我參考您這篇code加到我的 keil C 去編譯,
不過遙控器按下後, 印出來結果都是 error ...我無法解出任何按鍵的編碼
我UART printf是用 12M system clock, 9600 baudrate,
板子的 pin0,0 接一顆IR receiver, 資料是要再從pin0,1 發出,
我提供我的原始碼連結 : https://drive.google.com/file/d/0B8CUYbHWVHJ7RDVKZ2hydm1FZjA/view?usp=sharing

可否在煩請版大幫我看看是錯誤在哪裡呢 @@? 非常感謝

張貼留言