目录
一、引言
??红外线是波长在750nm至1mm之间的电磁波,其频率高于微波而低于可见光,是一种人的眼眼看不到的光线。无线电波和微波已被广泛应用在长距离的无线通信中,但由于红外线的波长较短,对障碍物的衍射能力差,所以更适合应用在需要短距离无线通信场合 点对点的直接线数据传输。为了使各种设备能够通过一个红外接口进行通信,红外数据协议(InfraredDataAssociation,简称IRDA)发布了一个关于红外的统一的软硬件规范,也就是红外数据通讯标准。
??红外通信是利用950nm近红外波段的红外线作为传递信息的媒体,即通信信道。发送端采用脉位调制 (PPM)方式,将二进制数字信号调制成某一频率的脉冲序列,并驱动红外发射管以光脉冲的形式发送出去;接收端将接收到的光脉转换成电信号,再经过放大、滤波等处理后送给解调电路进行解调,还原为二进制数字信号后输出。
??PPM是以帧为单位,帧内每个脉冲间隔表示一个通道的控制量,两帧之间 有一个长一点的低电平,这个信号曾经用于同步,作为帧和帧之间的划分。
??简而言之,红外通信的实质就是对二进制数字信号进行调制与解调,以便利用红外信道进行传输;红外通信接口就是针对红外信道的调制解调器。
二、数据格式
??数据格式包括了引导码、用户码、数据码和数据码反码,编码总占32位。数据反码是数据码反相后的编码,编码时可用于对数据的纠错。注意:第二段的用户码也可以在遥控应用电路中被设置 成第一段用户码的反码
本文使用的STC51单片机使用的红外遥控采用NEC协议 :
1、8 位地址和 8 位指令长度; 2、地址和命令 2 次传输(确保可靠性) 3、PWM 脉冲位置调制,以发射红外载波的占空比代表“0”和“1”; 4、载波频率为 38Khz; 5、位时间为 1.125ms 或 2.25ms 6、一个脉冲对应 560us 的连续载波,一个逻辑 1 传输需要 2.25ms(560us脉冲+1680us 低电平),一个逻辑 0 的传输需要 1.125ms(560us 脉冲+560us 低电平)。
在NEC码中,起始码用于同步,接着是用户码、用户码反码、数据、数据反码。传输时低位在前、高位在后。
三、解码
使用外部中断1(P33引脚)接收信号,收到信号后串口输出,显示对应的十六进制数值。
外部中断步骤:
1.声明一变量来存放高电平时间; 2.如果P3^3口为低电平,超时判断(等待前9ms过去) 如果传输正确(为高电平)接着运行,否则9ms后结束; 3.如果P3^3口为高电平,超时判断(等待4.5ms过去) 开始接受数据(4组8位数据); 4.采用for循环嵌套(大循环4次对应4字节,小循环8次对应每个字节的8位)循环内: ??等待前面560us低电平 计算高电平时间(区分位0和位1)判断如果时间超过3ms退出(位1的总时间为2.25ms); ??对高电平时间判断分辨出位0或者位1,存放在数组中 时间变量清零; 5.判断数据码和数据反码(取反后)如果相等则退出中断。
void ReadIr() interrupt 2
{
u8 j,k;
u16 err;
Time=0;
delay_10us(700);
if(IRIN==0)
{
err=1000;
while((IRIN==0)&&(err>0))
{
delay_10us(1);
err--;
}
if(IRIN==1)
{
err=500;
while((IRIN==1)&&(err>0))
{
delay_10us(1);
err--;
}
for(k=0;k<4;k++)
{
for(j=0;j<8;j++)
{
err=60;
while((IRIN==0)&&(err>0))
{
delay_10us(1);
err--;
}
err=500;
while((IRIN==1)&&(err>0))
{
delay_10us(10);
Time++;
err--;
if(Time>30)
{
return;
}
}
IrValue[k]>>=1;
if(Time>=8)
{
IrValue[k]|=0x80;
}
Time=0;
}
}
}
if(IrValue[2]!=~IrValue[3])
{
return;
}
}
}
读取的红外数据存放在IrValue中,根据NEC的帧格式,第三位是数据码,即IrValue[2]。在主程序中使用串口发送到电脑上。
使用两个变量存放数据值,当新的红外数据发生变化的时候 再使用串口发出去。
while(1)
{
new_value=IrValue[2];
if(new_value!=old_value)
{
old_value=new_value;
SBUF =new_value;
while (!TI);
TI = 0;
SBUF ='\r';
while (!TI);
TI = 0;
SBUF ='\n';
while (!TI);
TI = 0;
}
delay_10us(100);
}
在电脑的串口助手中,选择十六进制方式查看,不要使用字符(char),因为有些编码对应的字符是不能显示的,可能会显示“?”之类的。示例:
1C 0D 0A
18 0D 0A
其中,1C、18是NEC帧中的数据,0D和0A 是回车换行 。
四、应用
可以正确解码,那么下来就要应用了。最常用的有2种,拿空调举例
- 空调遥控板按下“开”,就一直运行着。
- 空调遥控板按一下“温度+”,温度只增加一度,不应该一直增加。
对于第一种情况,可以用这种格式:
if(IrValue[2]==0x18)
{
task();
}
对于第二种情况,可以用:
if(IrValue[2]==0x18)
{
IrValue[2]==0x00;
task();
}
无、完整代码
#include "reg52.h"
#include <string.h>
#include <stdio.h>
typedef unsigned int u16;
typedef unsigned char u8;
sbit IRIN=P3^3;
u8 IrValue[6];
u8 Time;
void delay_10us(u16 i)
{
while(i--);
}
void IrInit()
{
IT1=1;
EX1=1;
EA=1;
IRIN=1;
}
void UsartInit()
{
SCON=0X50;
TMOD=0X20;
PCON=0X80;
TH1=0XF3;
TL1=0XF3;
ES=1;
TR1=1;
}
void main()
{
char old_value,new_value;
IrInit();
UsartInit();
old_value=1;
while(1)
{
new_value=IrValue[2];
if(new_value!=old_value)
{
old_value=new_value;
SBUF =new_value;
while (!TI);
TI = 0;
SBUF ='\r';
while (!TI);
TI = 0;
SBUF ='\n';
while (!TI);
TI = 0;
}
delay_10us(100);
}
}
void ReadIr() interrupt 2
{
u8 j,k;
u16 err;
Time=0;
delay_10us(700);
if(IRIN==0)
{
err=1000;
while((IRIN==0)&&(err>0))
{
delay_10us(1);
err--;
}
if(IRIN==1)
{
err=500;
while((IRIN==1)&&(err>0))
{
delay_10us(1);
err--;
}
for(k=0;k<4;k++)
{
for(j=0;j<8;j++)
{
err=60;
while((IRIN==0)&&(err>0))
{
delay_10us(1);
err--;
}
err=500;
while((IRIN==1)&&(err>0))
{
delay_10us(10);
Time++;
err--;
if(Time>30)
{
return;
}
}
IrValue[k]>>=1;
if(Time>=8)
{
IrValue[k]|=0x80;
}
Time=0;
}
}
}
if(IrValue[2]!=~IrValue[3])
{
return;
}
}
}
|