为方便理解所看到的波形是从红外接收管出来的信号,跟协议所说的信号高低(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; }