前言
随着科技的发展,红外遥控器逐渐被WIFI、蓝牙等所取代。但是并不意味着红外遥控就无用武之地。万物皆有相通之处,学习红外遥控可以有助于后期学习WIFI、蓝牙等通信。
一、红外遥控的背景知识
1、人机交互
- 当面操作的:按键、旋钮、触摸系列的设备;
- 遥控操作的:红外遥控、433M/2.4G无线通信、蓝牙-WIFI-Zigbee-LoRa-4G-5G等无线通信。
2、红外遥控的相关知识
- 红外的基本知识
遥控器由红外接收及发射电路、信号调理电路、中央控制器、程序及数据存储器、键盘及状态指示电路组成。利用红外线进行通信,一般有红外发射和红外接收两部分电路。
- 红外发射和接收
1)红外发射:红外发光二级管是发射的关键部件。它实际上是一种特殊的发光二次管。由于其内部材料与普通发光二次管不同,当两端增加相应的工作电压时,它会发出红外而不是可见光。
2)红外接收:红外接收电路通常由制造商集成在一个元件中,成为一个集成的红外接收头。内部电路包括红外监测二极管、放大器、限副器、滤波器、积分电路、比较器等。红外监测二极管监测红外信号,然后将信号发送到放大器和限幅器,将脉冲范围调整到一定水平,无论红外发射器和接收器之间的距离如何。
3)38KHz载波和数字信号、调制。
4)红外遥控器通信协议:NEC协议。
5)红外接收头内部本身是有个反相的,意思就是:平时发送方无发送信号时接收到的是1,发送方有发送载波时接收头IRD引脚输出的是0,这对我们写代码有影响,后面在看协议时序图时刚好是反的,这样可以提高接收灵敏度。
二、原理图电路分析
接收端原理图
J11与51单片机的P3.2连接,使用外部中断来解析协议
三、NEC协议讲解
1、逻辑1与逻辑0的表示
- 逻辑1为2.25ms,脉冲时间560us,脉冲频率38KHz;
- 逻辑0为1.12ms,脉冲时间560us,脉冲频率38KHz;
2、NEC协议格式
-
单次按
NEC协议中,首次是9ms的高电平脉冲,其后是4.5ms的低电平(起始信号),接下来就是8bit的地址码(从低有效位开始发),而后是8bit的地址码的反码(主要是用于校验是否出错)。然后是8bit 的命令码(也是从低有效位开始发),而后也是8bit 的命令码的反码。
-
长按
发完一个指令码的序列,但当你长时间按住遥控按钮,在这这种情况下,使用NEC协议的红外遥控器将会发射一个以110ms为周期的重复码。也就是说,每一次用户按下遥控器按钮,遥控器在发送一次指令码后,就不会再发送指令码了,而是发送一段重复码。
重复码由9ms高电平和2.25ms的低电平以及560us的高电平组成
注意:红外接收器为了提高接受灵敏度。输入高电平,其输出的是相反的低电平。
3、NEC协议的关键点
- 学会看协议格式:载波和信号;
- 1和0分别是如何表示的;
- 数据是一帧一帧的整帧传递的;
- 红外收发是个串行协议;
- 写代码时时序中的 <时间> 仍然是关键点。
四、代码实现
1、变量定义
sbit IRED = P3^2; //接收引脚接外部中断0
unsigned char gired_data[4]; //存储4个字节接收码(地址码+地址反码+控制码+控制反码)
unsigned char ired_flag = 0; //接收数据完毕
2、延时函数
void delay_10us(unsigned int ten_us) //延时函数,ten_us=1时,大约延时10us
{
while(ten_us--);
}
3、初始化函数
void Ired_Init(void)
{
IT0 = 1; //下降沿触发
EX0 = 1; //打开中断0允许
EA = 1; //打开总中断
IRED = 1; //初始化端口
}
4、中断服务函数,在中断里面解码数据
void Ired() interrupt 0 //外部中断0服务函数
{
unsigned char ired_high_time = 0;
unsigned int time_cnt = 0;
unsigned char i = 0,j = 0;
if(IRED == 0)
{
time_cnt = 1000;
while((!IRED)&&(time_cnt)) //等待引导信号9ms低电平结束,若超过10ms强制退出
{
delay_10us(1); //延时约10us
time_cnt--;
if(time_cnt == 0)return;
}
if(IRED) //引导信号9ms低电平已过,进入4.5ms高电平
{
time_cnt = 500;
while(IRED&&time_cnt) //等待引导信号4.5ms高电平结束,若超过5ms强制退出
{
delay_10us(1);
time_cnt--;
if(time_cnt == 0) return;
}
for(i = 0; i < 4; i++) //循环4次,读取4个字节数据
{
for(j = 0 ; j < 8; j++) //循环8次读取每位数据即一个字节
{
time_cnt = 600;
while((IRED == 0)&&time_cnt)//等待数据1或0前面的0.56ms结束,若超过6ms强制退出
{
delay_10us(1);
time_cnt--;
if(time_cnt == 0) return;
}
time_cnt = 20;
while(IRED) //等待数据1或0后面的高电平结束,若超过2ms强制退出
{
delay_10us(10); //约0.1ms
ired_high_time++;
if(ired_high_time > 20) return;
}
gired_data[i] >>= 1; //先读取的为低位,然后是高位
if(ired_high_time >= 8) //如果高电平时间大于0.8ms,数据则为1,否则为0
gired_data[i] |= 0x80;
ired_high_time = 0; //重新清零,等待下一次计算时间
}
}
}
if(gired_data[2] != ~gired_data[3]) //校验控制码与反码,错误则返回
{
for(i = 0;i < 4; i++)
gired_data[i] = 0; //数组清零
return;
}
else
ired_flag = 1; //接收正确数据标志位
}
}
总结
本节主要介绍了NEC协议,以及代码实现的过程,内容比较简单。需要注意的有以下两点:
- 解析数据’0‘和’1‘时,特别注意时间长度;
- 红外发送的时脉冲时,接收到的是低电平,发送的是低电平时接收的是高电平;