紅外遙控
1 紅外發射原理簡介
通用紅外遙控系統主要由發射和接收兩大部分組成。發射部分包括單片機芯片或紅外遙控發射專用芯片實現編碼和調製,紅外發射電路實現發射;接收部分包括一體化紅外接收頭電路實現接收和解調,單片機芯片實現解碼。紅外遙控發射專用芯片非常多,編碼及調製頻率也不完全一樣。手機實現紅外遙控功能,主要就是發射紅外信號部分,這就需要了解下紅外信號的編碼和調製原理。
紅外遙控器發射的信號由一串「0」和「1」的二進制代碼組成,不同的芯片對「0」和「1」的編碼有所不同,通常有曼徹斯特 (Manchester) 編碼和脈衝寬度編碼 (PWM)。家用電器使用的紅外遙控器絕大部分都是脈衝寬度編碼,如下圖所示:
二進制信號的調製由發送單片機芯片或紅外遙控發射專用芯片來完成,把編碼後的二進制信號調製成頻率爲 38kHz 的間斷脈衝串,相當於用二進制信號的編碼乘以頻率爲38kHz 的脈衝信號得到的間斷脈衝串,即是調製後用於紅外發射二極管發送的信號。通用紅外遙控器裏面常用的紅外遙控發射專用芯片載波頻率爲 38kHz,這是由發射端所使用的 455kHz 陶瓷晶振來決定的。在發射端對晶振進行整數分頻,分頻係數一般取 12 所以 455kHz ÷ 12 ≈ 37.9kHz ≈ 38kHz。
2 NEC編碼協議
在紅外開發中,可能最重要的就是發送二進制信號的編碼協議了,各個廠家所使用的編碼協議不同,所以遙控器也不能相互控制,而即使編碼協議相同,使用的用戶碼不同,也不能被接收端接受。所以類似萬能遙控器這種應用,第一個要解決的問題就是各類家用電器,各類廠家所使用的編碼協議以及所使用的用戶碼等。但各類電器衆多,這種應用是很難兼容全的,有的大廠家會將自家產品的編碼及對應功能鍵的數據序列公佈在網上,方便其他開發者開發,至於其他沒有公佈的,可能就要使用紅外解碼儀來破解它所使用的協議以及各功能鍵對應的數據碼等。
在日常家用電器中,NEC 編碼是比較常見的一種編碼協議, 通用紅外遙控器發出的一串二進制代碼按功能可以分爲分「引導碼、用戶碼 16 位、數據碼 8 位、數據反碼 8 位和結束位」,編碼共佔 32 位,如下圖2所示:
其中引導碼由一個 9ms 的 38kHz 載波起始碼和一個 4.5ms 的無載波低電平結果碼組成。用戶碼由低 8 位和高 8 位組成 (用戶碼高八位和低八位可採用原碼與反碼的方式,可用於糾錯,但也可直接是 16 位的原碼方式),不同的遙控器有不同的用戶碼,避免不同設備產生干擾,用戶碼又稱爲地址碼或系統碼。數據碼採用原碼和反碼方式重複發送,編碼時用於對數據的糾錯,遙控器發射編碼時,低位在前,高位在後。結束位是 0.56ms 的 38kHz 載波。而其中的「0」碼由 0.56ms 的 38kHz 載波和 0.56ms 的無載波低電平組合而成,脈衝寬度爲 1.125ms,「1」碼由 0.56ms 的 38kHz 載波和 1.69ms 的無載波低電平組合而成,脈衝寬度爲 2.25ms,如下圖所示:
3 紅外遙控器解碼
紅外遙控器的解碼儀能夠分析常見家電的紅外遙控信號,下面兩種除外:
1、空調遙控器,空調的控制比較複雜,光光溫度就可能調節十幾次,難以破解。
2、燈光遙控器,燈本身發光發熱,同時也會散發大量紅外線,勢必對外部的紅外信號造成嚴重干擾;所以燈只能採取射頻遙控器。
紅外解碼儀是家電維修人員的必備儀器,常用於檢測遙控器能否正常工作,開發者爲了讓手機實現遙控功能,也要利用解碼儀捕捉每個按鍵對應的紅外信號,紅外信號由三部分組成,分別是:
用戶碼,表示廠商代號,每個廠家都有自己的唯一代號;
數據碼,表示按鍵的編號,不同的數據碼代表不同的按鍵;
電路格式,表示紅外信號的編碼協議,每種協議都有專門的指令格式。
比如說電路61212表示的是NEC6121協議,該協議的紅外信號編碼格式爲:引導碼+用戶碼+數據碼+數據反碼+結束碼,其中引導碼和結束碼都是固定的,數據反碼由數據碼按位取反得來,真正變化的只有用戶碼和數據碼。
4 NEC數據格式:
引導碼、用戶碼、用戶碼(或者用戶碼反碼)、按鍵鍵碼和鍵碼反碼,最後一個停止位。每個一個字節。
引導碼:9ms的載波+4.5ms的空閒。
比特值“0”:560us的載波+560us的空閒。
比特值“1”:560us的載波+1.68ms的空閒。
信號調製
目的:方便進行信號的傳輸
基帶信號:從信號源發出沒有經過調製的原始信號,特點是頻率較低,信號頻率從0開始,頻譜較寬。
調製:就是用待傳送信號去控制某個高頻信號的幅度、相位、頻率等參量變化的過程,即用一個信號去裝載另一個信號。
5 代碼
h文件
收到的按鍵編號在IR_code中
#ifndef __REMOTECONTROL_H__
#define __REMOTECONTROL_H__
#include "STC15Fxxxx.h"
/************* 紅外接收程序變量聲明 **************/
sbit P_IR_RX = P3^6; //定義紅外接收輸入IO口
extern bit B_IR_Press; //安鍵動作發生
extern u8 IR_code; //紅外鍵碼
extern u16 UserCode; //用戶碼
extern u8 mode;
extern u8 mode_pre;
extern u16 cmode;
extern u16 lie;
extern bit Point_L_ShowLine;
extern bit Point_R_ShowLine;
void IR_RX_NEC(void);
#endif
c文件
bit P_IR_RX_temp; //Last sample
bit B_IR_Sync; //已收到同步標誌
bit B_IR_Press; //安鍵動作發生
u8 IR_SampleCnt; //採樣計數
u8 IR_BitCnt; //編碼位數
u8 IR_UserH; //用戶碼(地址)高字節
u8 IR_UserL; //用戶碼(地址)低字節
u8 IR_data; //數據原碼
u8 IR_DataShit; //數據移位
u8 IR_code; //紅外鍵碼
u16 UserCode; //用戶碼
/**********************************************/
//*******************************************************************
//*********************** IR Remote Module **************************
//*********************** By (Coody) 2002-8-24 *********************
//*********************** IR Remote Module **************************
//this programme is used for Receive IR Remote (NEC Code).
//data format: Synchro, AddressH, AddressL, data, /data, (total 32 bit).
//send a frame(85ms), pause 23ms, send synchro of continue frame, pause 94ms
//data rate: 108ms/Frame
//Synchro: low=9ms, high=4.5 / 2.25ms, low=0.5626ms
//Bit0: high=0.5626ms, low=0.5626ms
//Bit1: high=1.6879ms, low=0.5626ms
//frame rate = 108ms ( pause 23 ms or 96 ms)
/******************** 紅外採樣時間宏定義, 用戶不要隨意修改 *******************/
#define IR_SAMPLE_TIME (1000000UL/SysTick) //查詢時間間隔, us, 紅外接收要求在60us~250us之間
#if ((IR_SAMPLE_TIME <= 250) && (IR_SAMPLE_TIME >= 60))
#define D_IR_sample IR_SAMPLE_TIME //定義採樣時間,在60us~250us之間
#endif
#define D_IR_SYNC_MAX (15000/D_IR_sample) //SYNC max time
#define D_IR_SYNC_MIN (9700 /D_IR_sample) //SYNC min time
#define D_IR_SYNC_DIVIDE (12375/D_IR_sample) //decide data 0 or 1
#define D_IR_DATA_MAX (3000 /D_IR_sample) //data max time
#define D_IR_DATA_MIN (600 /D_IR_sample) //data min time
#define D_IR_DATA_DIVIDE (1687 /D_IR_sample) //decide data 0 or 1
#define D_IR_BIT_NUMBER 32 //bit number
//*******************************************************************************************
//**************************** IR RECEIVE MODULE ********************************************
void IR_RX_NEC(void)
{
u8 SampleTime;
IR_SampleCnt++; //Sample + 1
F0 = P_IR_RX_temp; //Save Last sample status
P_IR_RX_temp = P_IR_RX; //Read current status
if(F0 && !P_IR_RX_temp) //Pre-sample is high,and current sample is low, so is fall edge
{
SampleTime = IR_SampleCnt; //get the sample time
IR_SampleCnt = 0; //Clear the sample counter
if(SampleTime > D_IR_SYNC_MAX) B_IR_Sync = 0; //large the Maxim SYNC time, then error
else if(SampleTime >= D_IR_SYNC_MIN) //SYNC
{
if(SampleTime >= D_IR_SYNC_DIVIDE)
{
B_IR_Sync = 1; //has received SYNC
IR_BitCnt = D_IR_BIT_NUMBER; //Load bit number
}
}
else if(B_IR_Sync) //has received SYNC
{
if(SampleTime > D_IR_DATA_MAX) B_IR_Sync=0; //data samlpe time too large
else
{
IR_DataShit >>= 1; //data shift right 1 bit
if(SampleTime >= D_IR_DATA_DIVIDE) IR_DataShit |= 0x80; //devide data 0 or 1
if(--IR_BitCnt == 0) //bit number is over?
{
B_IR_Sync = 0; //Clear SYNC
if(~IR_DataShit == IR_data) //判斷數據正反碼
{
UserCode = ((u16)IR_UserH << 8) + IR_UserL;
IR_code = IR_data;
B_IR_Press = 1; //數據有效
}
}
else if((IR_BitCnt & 7)== 0) //one byte receive
{
IR_UserL = IR_UserH; //Save the User code high byte
IR_UserH = IR_data; //Save the User code low byte
IR_data = IR_DataShit; //Save the IR data byte
}
}
}
}
}
void RemotecontrolSwitch(void)
{
switch(IR_code)
{//從左到右,從上到下依次
case 0x45: break;
case 0x46: break;
case 0x47: break;
case 0x44: break;
case 0x40: break;
case 0x43: break;
case 0x07: break;
case 0x15: break;
case 0x09: break;
case 0x16: break;
case 0x19: break;
case 0x0D: break;
case 0x0C: break;
case 0x18: break;
case 0x5E: break;
case 0x08: break;
case 0x1C: break;
case 0x5A: break;
case 0x42: break;
case 0x52: break;
case 0x4A: break;
default:break;
}
}