首要,有必要要了解一些基本原理。其实按下遥控器的某一个键,遥控器会宣布一连串通过调制后的信号,这个信号通过红外一体化模块接纳后,输出解调后的数字脉冲,每个按键对应不同的脉冲,故辨认出不同的脉冲就能辨认出不同的按键。
上图便是很常见的车载MP3遥控器,比较细巧,很好用。下面是红外发射和承受原理:
到此读者或许会有疑问,那么不同的调制解调办法那么出来的脉冲规则是不一样的?是的,确实如此。
遥控发射器专用芯片许多,根据编码格局能够分红两大类,这儿咱们以运用比较广泛,解码比较简单的一类来加以阐明,现以日本NEC的uPD6121G组成发射电路为例阐明编码原理(一般家庭用的DVD、VCD、音响都运用这种编码办法)。当发射器按键按下后,即有遥控码宣布,所按的键不同遥控编码也不同。这种遥控码具有以下特征:
选用脉宽调制的串行码,以脉宽为0.565ms、距离0.56ms、周期为1.125ms的组合标明二进制的“0”;以脉宽为0.565ms、距离1.685ms、周期为2.25ms的组合标明二进制的“1”,其波形如图所示。
如图可见,0与1前端的低电平继续都是0.56ms,那么便是后边的高电平继续时刻不同,0为0.56ms,1为1.685ms,找到不同之处,编程时就有辨认的根据了!
上述“0”和“1”组成的32位二进制码经38kHz的载频进行二次调制以进步发射功率,到达下降电源功耗的意图。然后再通过红外发射二极管发生红外线向空间发射,如图所示。
UPD6121G发生的遥控编码是接连的32位二进制码组,其间前16位为用户辨认码,能差异不同的电器设备,避免不同机种遥控码相互搅扰。该芯片的用户辨认码固定为十六进制01H;后16位为8位操作码(功用码)及其反码。UPD6121G最多额128种不同组合的编码。
请看下图,来自网络:
当一个键按下超越36ms,振动器使芯片激活,将发射一组108ms的编码脉冲,这108ms发射代码由一个引导码(9ms),一个成果码(4.5ms),低8位地址码(9ms~18ms),高8位地址码(9ms~18ms),8位数据码(9ms~18ms)和这8位数据的反码(9ms~18ms)组成。假如键按下超越108ms仍未松开,接下来发射的代码(连发码)将仅由开端码(9ms)和完毕码(2.25ms)组成。(实践上人手的动作是很慢的,即便你快速的按下按键,或许关于芯片来说仍是超越108ms,所以怎么处理连发码是很要害的)
遥控器在按键按下后,周期性地宣布同一种32位二进制码,周期约为108ms。一组码自身的继续时刻随它包括的二进制“0”和“1”的个数不同而不同,大约在45~63ms之间,图为发射波形图。
下面是我写的代码,按键编码通过串口发送到电脑端:
由于时刻联系,代码注释不多。
其间START_Judge()函数是判别9ms低电平,既是判别有无遥控信号。
BOOT_REPEATING_CODE_Judge()是判别是引导码仍是连发码,引导码则进入承受数据环节,连发码标明数据现已承受完毕。
H_L_LEVEL_Judge()是承受数据时判别凹凸电平。
假如乱码,请参阅:
http://blog.csdn.net/mhjerry/article/details/6601324
注明:以下代码为纯软件办法,没有用到中止,守时器办法,纯CPU查询,但测验成果倒也能够,至少比较稳定,得到的码值不论对不对,都是那个值。
- /*————————————————————*-
- 红外收发.C
- ————————————————————
- 遥控器测验
- -*————————————————————*/
- #include
- //—红外接纳一体化输出口———————————-
- sbitIR_Out=P3^2;
- bitSTART_Flag=0;
- bitBOOT_REPEATING_CODE_Flag=0;
- unsignedcharDATA[4]={0};
- bdataunsignedcharTEMP_BIT;
- sbitB0=TEMP_BIT^0;
- sbitB1=TEMP_BIT^1;
- sbitB2=TEMP_BIT^2;
- sbitB3=TEMP_BIT^3;
- sbitB4=TEMP_BIT^4;
- sbitB5=TEMP_BIT^5;
- sbitB6=TEMP_BIT^6;
- sbitB7=TEMP_BIT^7;
- //—有无遥控信号判别函数———————————-
- bitSTART_Judge();
- //—连发码判别函数—————————————-
- bitBOOT_REPEATING_CODE_Judge();
- //—“0″和”1″辨认——————————————
- bitH_L_LEVEL_Judge();
- //—串口初始化——————————————–
- voidUART_Initial();
- voidDELAY_Us(unsignedintUs)
- {
- unsignedintx;
- for(x=0;x<=(Us/200-1);x++);
- }
- voidDELAY_Ms(unsignedintMs)
- {
- unsignedintx,y;
- for(x=0;x<=(Ms-1);x++)
- {
- for(y=0;y<=120;y++);
- }
- }
- voidmain()
- {
- unsignedchari;
- UART_Initial();
- IR_Out=1;
- while(1)
- {
- START_Flag=START_Judge();
- BOOT_REPEATING_CODE_Flag=BOOT_REPEATING_CODE_Judge();
- if(START_Flag&&!BOOT_REPEATING_CODE_Flag)
- {
- for(i=0;i<4;i++)
- {
- B0=H_L_LEVEL_Judge();
- B1=H_L_LEVEL_Judge();
- B2=H_L_LEVEL_Judge();
- B3=H_L_LEVEL_Judge();
- B4=H_L_LEVEL_Judge();
- B5=H_L_LEVEL_Judge();
- B6=H_L_LEVEL_Judge();
- B7=H_L_LEVEL_Judge();
- DATA[i]=TEMP_BIT;
- }
- for(i=0;i<4;i++)
- {
- SBUF=DATA[i];
- while(TI==0);
- TI=0;
- }
- }
- }
- }
- voidUART_Initial()
- {
- SCON=0x50;//SCON:形式1,8-bitUART,使能接纳
- TMOD|=0x20;//TMOD:timer1,mode2,8-bitreload
- TH1=0xFD;//TH1:reloadvaluefor9600baud@
- //11.0592MHz
- TR1=1;//TR1:timer1run
- EA=0;//封闭总中止
- ES=0;//封闭串口中止
- }
- bitSTART_Judge()
- {
- bitTEMP_Flag=1;
- unsignedchari=0;
- //在正常无遥控信号时,一体化红外接纳头输出是高电平,程序一直在循环。
- while(IR_Out==1);
- //重复10次,意图是检测在6876~8352微秒内假如呈现高电平就退出解码程序
- for(i=0;i<9;i++)
- {
- DELAY_Us(800);//测验实践延时约为764~928us
- if(IR_Out==1)
- {
- TEMP_Flag=0;
- break;
- }
- }
- returnTEMP_Flag;
- }
- bitBOOT_REPEATING_CODE_Judge()
- {
- bitTEMP_Flag=1;
- while(IR_Out==0);//等候高电平避开9毫秒低电平引导脉冲
- DELAY_Ms(1);//测验实践延时约为1.007ms
- DELAY_Ms(1);//测验实践延时约为1.007ms
- DELAY_Us(200);//0.086ms
- DELAY_Us(200);//0.086ms
- DELAY_Us(200);//0.086ms
- //合计2.272ms
- if(IR_Out==0)
- {
- TEMP_Flag=1;//是连发码
- }
- else
- {
- TEMP_Flag=0;//不是连发码,而是引导码
- }
- returnTEMP_Flag;
- }
- bitH_L_LEVEL_Judge()
- {
- while(IR_Out==0);//等候地址码第一位的高电平信号
- DELAY_Us(800);//测验实践延时约为764~928us
- if(IR_Out==1)
- {
- DELAY_Ms(1);//测验实践延时约为1.007ms
- return1;
- }
- else
- {
- return0;
- }
- }
修改如下:
01 FE 8B 74 — 01 FE 8D 72 — 01 FE 8F 70
01 FE 89 76 — 01 FE 81 7E — 01 FE 87 78
01 FE 0F F0 — 01 FE 2B D4 — 01 FE 13 EC
01 FE 2D D2 — 01 FE 33 CC — 01 FE 1B E4
01 FE 19 E6 — 01 FE 31 CE — 01 FE BD 42
01 FE 11 EE — 01 FE 39 C6 — 01 FE B5 4A
以上为对应按键的编码。
过程中存在问题:
一是怎么有用的辨认引导码和连发码,由于这个能直接影响到长时刻按键,单片机的呼应与否。这个问题,形似我以处理,便是长时刻按键后,单片机辨认一次按键后,假如仍是同一按键,就不与答理。
还有一个问题便是,假如接连按下两次按键,该程序能够辨认出,可是假如距离很短,第二下按键的编码简单犯错,简单变成这样:
03 FE 8B 74.。。。便是第一个字节呈现差错,这个问题现在还未来得及处理。
还有便是本程序关于延时函数的精度要求很高,由于自身处理的脉冲便是MS等级的。所以需求严厉的测验延时函数的实践延时时刻:
以上的代码,能够看出许多问题,软件延时不精确,很多的“while( IR_Out == 0 ) ;”代码,抗搅扰才能弱,简单进入死循环。
下面介绍的这种解码办法,使用外部中止触发程序,守时器守时(但没有设置守时中止程序,即判别TF的值确认守时完毕),在代码过程中,最初的一个7.93ms延时,足以滤掉不合法的红外信号。应该说功率质量更高的。
代码注释很具体,在此不在细述:
- /*————————————————————*-
- IR_Decoder.C(v1.00)
- ————————————————————
- 称号:遥控器红外解码,PO口接LED,显现功用码以供检查
- 编写:mhjerry
- 日期:20011.7
- 内容:按遥控器上的按键,会在PO口LED上显现
- -*————————————————————*/
- #include”reg52.h”
- //此口为红外信号输入MCU口
- sbitIR_Out=P3^2;
- //主程序运转标志位,运转主程序时LED灭,运转中止程序时LED亮
- sbitIR_Flag=P3^1;
- //LED显现口
- #defineLED_PortP1
- //用于寄存按键码值,初始化为00000000这样承受数据时能够只考虑1了
- unsignedchardat[4]={0,0,0,0};
- /*……………………………………………………*/
- voidmain()
- {
- IR_Out=1;//此口为MCU输进口,故需求置1
- IR_Flag=1;//灭LED灯
- TMOD=0x01;//守时器0,办法1
- IT0=1;//外部中止0,下降沿触发
- EX0=1;//允许外部中止
- EA=1;//CPU允许中止
- while(1)
- {
- IR_Flag=1;//履行主程序时,LED灯灭
- }
- }
- /*————————————————————*-
- 函数称号:Int0()
- 函数输入:无(容许中止时,外部触发)
- 函数输出:无
- 函数阐明:外部中止0中止处理
- -*————————————————————*/
- voidInt0()interrupt0
- {
- unsignedchari,j;
- EX0=0;//封闭外部中止0
- IR_Flag=0;//履行中止程序时,LED灯亮
- i=10;//0.793ms延时,运转10次
- while(–i)
- {
- //守时0.793ms,延时0.793ms*10=7.93ms
- TH0=0xfc;
- TL0=0xe7;
- TR0=1;
- while(!TF0);
- TF0=0;
- TR0=0;
- //这7.93ms期间只需IR_Out变高电平,就非合法的红外信号,跳出
- if(IR_Out)
- {
- EX0=1;//允许中止
- return;
- }
- }
- //程序进行到这儿,标明是合法的红外信号(使用9ms判别)
- while(!IR_Out);//等候9ms低电平曩昔
- //程序进行到这儿,标明通过9ms低电平
- TH0=0xf6;
- TL0=0xff;
- TR0=1;
- while(!TF0);
- TF0=0;
- TR0=0;//延时2.305ms
- //IR_Out为低标明是连发码,不予答理,跳出
- if(!IR_Out)
- {
- EX0=1;
- return;
- }
- //程序进行到这儿,标明是引导码,等候4.5ms高电平的曩昔
- while(IR_Out);
- //开端接纳用户码
- for(i=0;i<4;i++)
- {
- for(j=0;j<8;j++)
- {
- while(!IR_Out);//等候低电平曩昔
- dat[i]>>=1;//把前次的数据位右移一位
- TH0=0xfc;
- TL0=0xe7;
- TR0=1;
- while(!TF0);
- TR0=0;
- TF0=0;//延时0.793ms
- //若为数据”1″,则延时后IR_Out为高电平
- if(IR_Out)
- {
- dat[i]|=0x80;//一切数据位1放最高位
- while(IR_Out);//等候高电平曩昔
- }
- }
- }
- LED_Port=dat[2];
- EX0=1;//开中止
- return;
- }
- /*————————————————————*-
- —-ENDOFFILE——————————————-
- -*————————————————————*/