红外遥控
人机界面
当面操作的:按键、旋钮 / 触摸按键、触摸屏
遥控操作的:红外遥控、433M-2.4G无线通信、蓝牙-WIFI-Zigbee-4G-LoRa等无线网络红外遥控是利用红外光进行通信的设备,由红外LED将调制后的信号发出,由专用的红外接收头进行解调输出。
通信方式:单工,异步;
红外LED波长:940nm;
通信协议标准:NEC标准(常用)
接收端原理图:
一体集成式接收头内部已经内置了红外载波解调功能,从IRD引脚出来的就是通信的二进制信号。所以单片机的IO可以直接接IRD引脚来读取红外信号中的通信信息。所以38KHz的载波的调制和解调过程对编程是透明的。
红外接收头内部本身是有个反相的,意思就是:平时发送方无发送信号时接收到的是1,发送方有发送载波时接收头IRD引脚输出的是0,这对我们写代码有影响,后面在看协议时序图时刚好是反的。
原理概述
红外通信由发送端和接收端两部分组成,发送端对数据进行编码,然后调制成一系列的脉冲信号,然后通过带有红外发射管的发射电路发送脉冲信号,即红外信号。接收端完成对脉冲信号的接收、放大、检波、整形,然后解调出编码信号,对其解码获取到发送的数据。具体的如下图所示:
NEC协议
NEC协议逻辑1与逻辑0的表示如下图所示:
– 逻辑1为2.25ms,脉冲时间560us。
– 逻辑0为1.12ms,脉冲时间560us。根据脉冲时间长短来解码。推荐载波占空比为1/3至1/4。NEC协议格式如下图所示:
NEC协议中,首次是9ms的高电平脉冲,其后是4.5ms的低电平,接下来就是8bit的地址码(从低有效位开始发),而后是8bit的地址码的反码(主要是用于校验是否出错)。然后是8bit 的命令码(也是从低有效位开始发),而后也是8bit 的命令码的反码。
以上是一个指令码的序列,但当您长时间按住遥控按钮,在这这种情况下,使用NEC协议的红外遥控器将会发射一个以110ms为周期的重复码。也就是说,每一次用户按下遥控器按钮,遥控器在发送一次指令码后,就不会再发送指令码了,而是发送一段重复码。如下图:
重复码由9ms高电平和2.25ms的低电平以及560us的高电平组成,如下图所示:
需要注意的是:1838红外接收器为了提高接受灵敏度。输入高电平,其输出的是相反的低电平。
代码实现
#include "ir.h" // 全局变量在哪个C文件中用就在哪个C文件中定义 // 不能放在头文件中定义 // 如果在多个C文件中都要用到同一个全局变量,应该在一个主要的C文件中定义 // 然后其他C文件中extern声明即可 sbit IRIN = P3^2; unsigned char IrValue[5]; // IrValue的0-3用来放原始数据,4用来放经过校验确认无误的键值 unsigned char Time; void DelayMs(unsigned int x) //0.14ms误差 0us { unsigned char i; while(x--) { for (i = 0; i<13; i++) {} } } void IrInit(void) { IT0=1;//下降沿触发 EX0=1;//打开中断0允许 EA=1; //打开总中断 IRIN=1;//初始化端口 } void ReadIr() interrupt 0 { unsigned char j,k; unsigned int err; Time = 0; DelayMs(40); // 136us*40 if (IRIN == 0) //确认是否真的接收到正确的信号 { err = 1000; //1000*10us=10ms,超过说明接收到错误的信号 /*当两个条件都为真时循环,如果有一个条件为假的时候跳出循环,免得程序出错的时 侯,程序死在这里*/ while ((IRIN==0) && (err>0)) //等待前面9ms的低电平过去 { DelayMs(1); // 136us err--; } if (IRIN == 1) //如果正确等到9ms低电平 { err = 500; while ((IRIN==1) && (err>0)) //等待4.5ms的起始高电平过去 { DelayMs(1); err--; } for (k=0; k<4; k++) //共有4组数据 { for (j=0; j<8; j++) //接收一组数据 { err = 60; while ((IRIN==0) && (err>0))//等待信号前面的560us低电平过去 { DelayMs(1); err--; } err = 500; while ((IRIN==1) && (err>0)) //计算高电平的时间长度。 { DelayMs(1);//0.14ms Time++; err--; if (Time > 30) { EX0 = 1; return; } } IrValue[k] >>= 1; //k表示第几组数据 if (Time >= 8) //如果高电平出现大于565us,那么是1 { IrValue[k] |= 0x80; } Time = 0; //用完时间要重新赋值 } } } if (IrValue[2] == ~IrValue[3]) { IrValue[4] = IrValue[2]; return; } } }