爲方便理解所看到的波形是從紅外接收管出來的信號,跟協議所說的信號高低(0或1)剛好相反
NEC協議是衆多紅外遙控協議的其中一種,除NEC外,還有RC5、RC6等其它的。市面上買到的非學習型萬能電視遙控器大多集成一種或多種編碼是NEC型的,我買的二個遙控器中就有三種以上編碼是NEC的。
NEC編碼的一幀(通常按一下遙控器按鈕所發送的數據)由引導碼、地址碼及數據碼組成,,如下圖所示,把地址碼及數據碼取反的作用是加強數據的正確性。
引導碼及數據的定義如下圖所示,當一直按住一個按鈕的時候,會隔110ms左右發一次引導碼(重複),並不帶任何數據
以下是用示波器採集到的一直按住某個按鈕時的波形:
按一下按鈕的波形:
一、遙控器解碼說明
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; }