ĐIỀU KHIỂN TỪ XA IR VỚI 8051
Bộ điều khiển từ xa và bộ thu IR tuân theo các giao thức tiêu chuẩn để gửi và nhận dữ liệu. Một số giao thức tiêu chuẩn là NEC, JVC, SIRC (Điều khiển từ xa hồng ngoại của Sony), v.v. Chúng ta sẽ chỉ thảo luận về giao thức NEC. Sau khi hiểu định dạng khung của IR Remote, Chúng tôi sẽ giao tiếp bộ thu IR với 8051 và giải mã phím được nhấn.
NEC Protocol
Giao thức NEC IR mã hóa các khóa bằng định dạng khung 32bit như hình dưới đây.
NEC Frame Format | |||
Address | Complement of Address | Command | Complement of Command |
LSB-MSB(0-7) | LSB-MSB(8-15) | LSB-MSB(16-23) | LSB-MSB(24-31) |
Mỗi bit được truyền bằng cách sử dụng khoảng cách xung như trong hình.
Logic '0': Một xung 562,5µs theo sau bởi một không gian 562,5µs, với tổng thời gian phát là 1,125ms
Logic '0': Một xung 562,5µs theo sau bởi một không gian 1,6875ms, với tổng thời gian phát là 2,25ms
Khi nhấn một phím trên bộ điều khiển từ xa, thông báo được truyền đi bao gồm những điều sau đây, theo thứ tự:
- A 9ms leading pulse burst (16 times the pulse burst length used for a logical data bit)
- A 4.5ms space
- The 8-bit address for the receiving device
- The 8-bit logical inverse of the address
- The 8-bit command
- The 8-bit logical inverse of the command
- A final 562.5µs pulse burst to signify the end of message transmission.
Bốn byte bit dữ liệu là mỗi bit ít quan trọng nhất được gửi đầu tiên. Hình ảnh dưới đây minh họa định dạng của khung truyền NEC IR, cho địa chỉ 00h (00000000b) và lệnh ADh (10101101b).
Tổng cộng 67,5ms được yêu cầu để truyền một khung bản tin. Nó cần 27ms để truyền 16 bit địa chỉ (địa chỉ + nghịch đảo) và 16 bit lệnh (lệnh + nghịch đảo).
IR Key Codes
Bảng dưới đây cung cấp danh sách đầy đủ các Mã cho NEC IR Remote.
Key | Encoded Value |
CH- | 0xFFA25D |
CH | 0xFF629D |
CH+ | 0xFFE21D |
PREV | 0xFF22DD |
NEXT | 0xFF02FD |
PLAY/PAUSE | 0xFFC23D |
VOL- | 0xFFE01F |
VOL+ | 0xFFA857 |
EQ | 0xFF906F |
0 | 0xFF6897 |
100+ | 0xFF9867 |
200+ | 0xFFB04F |
1 | 0xFF30CF |
2 | 0xFF18E7 |
3 | 0xFF7A85 |
4 | 0xFF10EF |
5 | 0xFF38C7 |
6 | 0xFF5AA5 |
7 | 0xFF42BD |
8 | 0xFF4AB5 |
9 | 0xFF52AD |
Sample Code
Dưới đây là mã mẫu để giải mã phím được nhấn trên điều khiển từ xa IR và gửi trên UART. Chúng ta cần một ngắt ngoài để phát hiện các xung và bộ đếm thời gian để đo các độ rộng xung này.
- INT0 (P2.2) sẽ được cấu hình như ngắt cạnh rơi để phát hiện các xung.
- Timer0 (Mode1) sẽ được cấu hình để tạo ngắt định kỳ 1ms.
Hai chuyển tiếp đầu tiên sẽ bị bỏ qua vì chúng sẽ đánh dấu SOF (Bắt đầu của khung). Sau khi thông tin 32-bit liên tục này sẽ được ghi lại trong một biến. Nếu độ rộng xung lớn hơn 2ms thì nó sẽ được coi là LOGIC-1 khác là LOGIC-0. Nếu độ rộng xung lớn hơn 50ms thì nó sẽ được coi là SOF (Bắt đầu của khung).
Tính toán độ trễ 1ms:
Tần số đồng hồ = 11.0592 Mhz
Chu kỳ máy = 12
Độ trễ = 1ms
$$ TimerValue = 65536 - ((Độ trễ * ClockFreq) / Chu kỳ máy) = 65536 - ((1ms * 11.0592Mhz) / 12) = 65536 - 921 = 0xFC67 $$
CODE CHƯƠNG TRÌNH.
/************************* NEC IR Remote Codes ************************** 0xFFA25D: CH- 0xFF629D: CH 0xFFE21D: CH+ 0xFF22DD: PREV 0xFF02FD: NEXT 0xFFC23D: PLAY/PAUSE 0xFFE01F: VOL- 0xFFA857: VOL+ 0xFF906F: EQ 0xFF6897: 0 0xFF9867: 100+ 0xFFB04F: 200+ 0xFF30CF: 1 0xFF18E7: 2 0xFF7A85: 3 0xFF10EF: 4 0xFF38C7: 5 0xFF5AA5: 6 0xFF42BD: 7 0xFF4AB5: 8 0xFF52AD: 9 **************************/ #include <reg51.h> #include "lcd.h" #include "stdutils.h" uint32_t bitPattern=0,newKey=0; uint8_t timerValue; uint8_t msCount=0; char pulseCount=0; void timer0_isr() interrupt 1 { if(msCount<50) msCount++; TH0 = 0xFC; // Reload the timer value for 1ms Delay TL0 = 0x67; } void externalIntr0_ISR() interrupt 0 { timerValue = msCount; msCount = 0; TH0 = 0xFC; // Reload the timer value for 1ms Delay TL0 = 0x67; pulseCount++; if((timerValue>=50)) // If the pulse width is greater than 50ms, this will mark the SOF { pulseCount = -2; // First 2 counts needs to be skipped hence pulse count is set to -2 bitPattern = 0; } else if((pulseCount>=0) && (pulseCount<32)) //Accumulate the bit values between 0-31. { if(timerValue>=2) //pulse width greater than 2ms is considered as LOGIC1 { bitPattern |=(uint32_t)1<<(31-pulseCount); } else { } } else if(pulseCount>=32) //This will mark the End of frame as 32 pulses are received { newKey = bitPattern; // Copy the newKey(patter) and set the pulse count to 0; pulseCount = 0; } } void main() { /*Connect RS->P0.0, RW->P0.1, EN->P0.2 and data bus to P0.4 to P0.7*/ LCD_SetUp(P0_0,P0_1,P0_2,P_NC,P_NC,P_NC,P_NC,P0_4,P0_5,P0_6,P0_7); LCD_Init(2,16); TMOD |= 0x01; // Timer0 MODE1(16-bit timer) TH0 = 0xFC; //Timer value for 1ms at 11.0592Mhz clock TL0 = 0x67; TR0 = 1; // Start the Timer ET0 = 1; // Enable the Timer0 Interrupt IT0 = 1; // Configure INT0 falling edge interrupt EX0 = 1; // Enable the INT0 External Interrupt EA = 1; // Enable the Global Interrupt bit LCD_DisplayString("Init Done"); while(1) { if(newKey!=0) //Wait till newKey press is detected { LCD_Clear(); //Clear the LCD and Display the new Key Code LCD_Printf("newKey:%X",newKey); newKey = 0; //CLear the newKey value for next cycle } } }
DÙNG THƯ VIỆN.
#include <reg51.h> #include "stdutils.h" #include "nec_ir.h" sbit RELAY_PIN = P3^4; void main() { uint32_t key; RELAY_PIN = 0; // Turn OFF the relay during Init IR_RemoteInit(); // Initialtile the INTO and Timer0 for decoding the IR pulses while(1) { key = IR_RemoteGetKey(); // Read the key press, it returns key code if key press is detected, else it returns 0 switch(key) { case IR_CODE_1: RELAY_PIN = 1; break; /* Turn On Relay(Bulb) if 1 is pressed*/ case IR_CODE_0: RELAY_PIN = 0; break; /* Turn OFF Relay(Bulb) if 0 is pressed*/ default: break; } } }