NEC紅外線編碼協議

紅外遙控協議-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;
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章