NO IMAGE

紅外遙控協議-NEC協議

為方便理解所看到的波形是從紅外接收管出來的訊號,跟協議所說的訊號高低(0或1)剛好相反

NEC協議是眾多紅外遙控協議的其中一種,除NEC外,還有RC5、RC6等其它的。市面上買到的非學習型萬能電視遙控器大多整合一種或多種編碼是NEC型的,我買的二個遙控器中就有三種以上編碼是NEC的。

NEC編碼的一幀(通常按一下遙控器按鈕所傳送的資料)由引導碼、地址碼及資料碼組成,,如下圖所示,把地址碼及資料碼取反的作用是加強資料的正確性。

IR NEC Protocol

引導碼及資料的定義如下圖所示,當一直按住一個按鈕的時候,會隔110ms左右發一次引導碼(重複),並不帶任何資料

引導碼及資料

以下是用示波器採集到的一直按住某個按鈕時的波形:

image

按一下按鈕的波形:

image

一、遙控器解碼說明

1、遙控器的編碼格式常見有兩種,一種是NEC 格式,一種是RC5 格式。遙控器發出的訊號,通過一個紅外的接收頭之後,訊號被送到MCU 的一箇中斷引腳。通過MCU 來識別不同的時序,來實現遙控器按鍵訊號的解碼。

2、遙控器時序圖及資料格式(NEC 格式)

資料格式:

 

   遙控器傳送的資料碼由以下部分組成:引導碼,8位的客戶碼,8位客戶碼的補碼,8位的按鍵值,8位按鍵值的補碼; 

具體的時序:

單次按鍵時的時序:

 注: 一個完整的週期是108 ms 

連續按鍵時的時續:

在單次按鍵的時序之後,緊跟如下時序:(週期也是108ms)

 

二、軟體設計思想及處理函式 

根據遙控器訊號時序的特點,在設計軟體時,需要利用時序,首先找到引導區,再讀取客戶碼(可以一次讀取16位),識別是否為廠家所制定的數值;之後讀取8位的按鍵值,並將讀取到的資料儲存起來

需要定義的在遙控器解碼過程中用到的狀態值:

#define         IR_STATE_IDLE                0x00
#define         IR_STATE_LEAD_ON             0x01
#define         IR_STATE_LEAD_OFF            0x02
#define         IR_STATE_CUSTOM              0x03
#define         IR_STATE_DATA1               0x04
#define         IR_STATE_DATA2               0x05

同時定義一下描述高低電平持續時間的一個常量

複製程式碼
#define      IR_R_Max                         40
#define      IR_R_Min                         30
#define      IR_H_Max                         40
#define      IR_H_Min                         30
#define      IR_L_Max                         20
#define      IR_L_Min                         15
複製程式碼

定義以下變數:

static unsigned char IrState ; 
static unsigned char IrData; 
static unsigned short IrCustom; 

解碼的過程如下:遙控器的解碼是在中斷處理函式中完成的,當MCU 的中斷引腳發生電平變化時,會引發中斷; 

void interrupt NEC_IR(void)

{

————————————-

  NEC遙控器中斷處理 

————————————

}

 

關於RC5 格式的遙控器解碼

RC5 格式的遙控器除了時序和NEC格式的遙控器有一點差別之外,軟體的解碼過程基本類似,不再單獨描述。

 

三、遙控器訊號解碼的流程

 

四、實現的程式碼(基於PIC晶片)

複製程式碼
//----------------------------------------------------------------------------
// Function Name: NEC_IR
// Description:IR interrupt manage
// Params: None
// Returns: None
// Notes: SYS INT service process
//----------------------------------------------------------------------------
void interrupt NEC_IR(void) 
{ 
unsigned char t0; 
//here first things to disable the interupt!
GIE=0;
//IR Intrupt input here.
//preamble=9ms" --|__|--"   4.5ms"_|--|_",others Data high 2.25ms and low 1.25ms;
//Data =" --|__|--"   "_|--|_" high 2.25ms and low 1.25ms.
//Repeat==9ms" --|__|--"   2.25 ms"_|--|_".
if(INTF)
{
t0 = TMR0;
TMR0 = 0;
switch (IrState)
{
case IR_STATE_IDLE:
INTEDG = 1;//Rising edge trigger
IrState = IR_STATE_LEAD_ON;
break;
case IR_STATE_LEAD_ON:
INTEDG = 0;//Falling edge trigger
if((t0 > Pream_L_Min) && (t0 < Pream_L_Max))
{
IrState = IR_STATE_LEAD_OFF;
}
else
{
IrState = IR_STATE_IDLE;
}
break;
case IR_STATE_LEAD_OFF:
if ((t0 > Pream_S_Min) && (t0 < Pream_S_Max))
{
IrState = IR_STATE_CUSTOM;
IrCustom = 0;
BitCounter = 0;
Repeat = 0;
}
else
{
if ((t0 > IR_R_Min) && (t0 < IR_R_Max))
{
if ((Repeat)&&(SystemState == POWER_ON_STATE))
{ 
Repeat = 0;//IR key Repeat
}
}
else
{
Repeat = 0;
}
INTEDG = 0;
IrState = IR_STATE_IDLE;
}
break;
case IR_STATE_CUSTOM:
if ((t0 > IR_L_Min) && (t0 < IR_L_Max))
{
IrCustom >>= 1; 
}
else
{
if ((t0 > IR_H_Min) && (t0 < IR_H_Max))
{
IrCustom = ((IrCustom >> 1) | 0x8000); 
}
else
{
INTEDG = 0;
IrState = IR_STATE_IDLE;
Repeat = 0;
break;
}
}
if (  BitCounter == 16)
{
if (IrCustom != CustomCode)
{
INTEDG = 0;
IrState = IR_STATE_IDLE;
Repeat = 0;
break;
}
IrState = IR_STATE_DATA1;
BitCounter = 0;
IrKeyCode = 0;
}
break;
case IR_STATE_DATA1:
BitCounter  ;
if ((t0 > IR_L_Min) && (t0 < IR_L_Max))
{
IrKeyCode >>= 1; 
}
else
{
if ((t0 > IR_H_Min) && (t0 < IR_H_Max))
{
IrKeyCode = ((IrKeyCode >> 1) | 0x80); 
}
else
{
INTEDG = 0;
IrState = IR_STATE_IDLE;
Repeat = 0;
break;
}
}
if (BitCounter == 8)
{
IrState = IR_STATE_DATA2;
BitCounter = 0;
IrData = 0;
}
break;
case IR_STATE_DATA2:
BitCounter  ;
if ((t0 > IR_L_Min) && (t0 < IR_L_Max))
{
IrData >>= 1; 
}
else
{
if ((t0 > IR_H_Min) && (t0 < IR_H_Max))
{
IrData = ((IrData >> 1) | 0x80); 
}
else
{
INTEDG = 0;
IrState = IR_STATE_IDLE;
Repeat = 0;
break;
}
}
if (BitCounter == 8)
{
INTEDG = 0;
IrState = IR_STATE_IDLE;
IrData = ~IrData;
if (IrKeyCode == IrData)
{
// Check if data is valid
}
else
{
Repeat = 0;
}
}
break;
}
INTF=0; 
}
GIE=1;
}