1、红外线简介
人的眼睛能看到的可见光按波长从长到短排列,依次为红、橙、黄、绿、青、
蓝、紫。其中红光的波长范围为 0.62~0.76μm;紫光的波长范围为 0.38~0.46
μm。比紫光波长还短的光叫紫外线,比红光波长还长的光叫红外线。红外线遥
控就是利用波长为 0.76~1.5μm 之间的近红外线来传送控制信号的。
2、
红外遥控的原理
红外遥控是一种无线、非接触控制技术,具有抗干扰能力强,信息传输可靠,
功耗低,成本低,易实现等显著优点,被诸多电子设备特别是家用电器广泛采用,
并越来越多的应用到计算机系统中。
由于红外线遥控不具有像无线电遥控那样穿过障碍物去控制被控对象的能
力,所以,在设计红外线遥控器时,不必要像无线电遥控器那样,每套(发射器
和接收器)要有不同的遥控频率或编码(否则,就会隔墙控制或干扰邻居的家用电
器),所以同类产品的红外线遥控器,可以有相同的遥控频率或编码,而不会出 现
遥控信号“串门”的情况。这对于大批量生产以及在家用电器上普及红外线遥
控提供了极大的方便。由于红外线为不可见光,因此对环境影响很小,再由红外
光波动波长远小于无线电波的波长,所以红外线遥控不会影响其他家用电器,也
不会影响临近的无线电设备。
红外遥控通信系统一般由红外发射装置和红外接收设备两大部分组成。
(1)、红外发射装置
红外发射装置,也就是通常我们说的红外遥控器是由键盘电路、红外编码电
路、电源电路和红外发射电路组成。红外发射电路的主要元件为红外发光二极管。
它实际上是一只特殊的发光二极管;由于其内部材料不同于普通发光二极管,因
而在其两端施加一定电压时,它便发出的是红外线而不是可见光。目前大量的使
用的红外发光二极管发出的红外线波长为 940nm 左右,外形与普通发光二极管
相同。红外发光二极管有透明的,还有不透明的,在我们的红外遥控器上可以看
到这个红外发光二极管。红外遥控器和红外发光二极管如下图所示:

通常红外遥控为了提高抗干扰性能和降低电源消耗,红外遥控器常用载波的
方式传送二进制编码,常用的载波频率为 38kHz,这是由发射端所使用的 455kHz
晶振来决定的。在发射端要对晶振进行整数分频,分频系数一般取 12,所以
455kHz÷12≈37.9kHz≈38kHz。也有一些遥控系统采用 36kHz、 40 kHz、 56 kHz
等,一般由发射端晶振的振荡频率来决定。所以,通常的红外遥控器是将遥控信
号(二进制脉冲码)调制在 38KHz 的载波上,经缓冲放大后送至红外发光二极
管,转化为红外信号发射出去的。
二进制脉冲码的形式有多种,其中最为常用的是 NEC Protocol 的 PWM 码
(脉冲宽度调制)和 Philips RC-5 Protocol 的 PPM 码(脉冲位置调制码,脉冲
串之间的时间间隔来实现信号调制)。如果要开发红外接收设备,一定要知道红
外遥控器的编码方式和载波频率,我们才可以选取一体化红外接收头和制定解码
方案。我们配套的红外遥控器使用的是 NEC 协议,其特征如下:
1、8 位地址和 8 位指令长度;
2、地址和命令 2 次传输(确保可靠性)
3、PWM 脉冲位置调制,以发射红外载波的占空比代表“0”和“1”;
4、载波频率为 38Khz;
5、位时间为 1.125ms 或 2.25ms;
NEC 码的位定义:一个脉冲对应 560us 的连续载波,一个逻辑 1 传输需要
2.25ms(560us 脉冲+1680us 低电平),一个逻辑 0 的传输需要 1.125ms(560us
脉冲+560us 低电平)。而红外接收头在收到脉冲的时候为低电平,在没有脉冲
的时候为高电平,这样,我们在接收头端收到的信号为:逻辑 1 应该是 560us 低
+1680us 高,逻辑 0 应该是 560us 低+560us 高。所以可以通过计算高电平时间判断接收到的数据是 0 还是 1。NEC 码位定义时序图如下图所示:

NEC 遥控指令的数据格式为:引导码、地址码、地址反码、控制码、控制反
码。引导码由一个 9ms 的低电平和一个 4.5ms 的高电平组成,地址码、地址反
码、控制码、控制反码均是 8 位数据格式。按照低位在前,高位在后的顺序发
送。采用反码是为了增加传输的可靠性(可用于校验)。数据格式如下:

(2)
红外接收设备
红外接收设备是由红外接收电路、红外解码、电源和应用电路组成。红外遥
控接收器的主要作用是将遥控发射器发来的红外光信好转换成电信号,再放大、
限幅、检波、整形,形成遥控指令脉冲,输出至遥控微处理器。近几年不论是业
余制作还是正式产品,大多都采用成品红外接收头。成品红外接收头的封装大致
有两种:一种采用铁皮屏蔽;一种是塑料封装。均有三只引脚,即电源正( VDD)、
电源负(GND)和数据输出(VOUT)。其外观实物图如下图所示:

正对接收头的凸起处看,从左至右,管脚依次是 1:VOUT,2:GND,3:VDD。
由于红外接收头在没有脉冲的时候为高电平,当收到脉冲的时候为低电平,
所以可以通过外部中断的下降沿触发中断,在中断内通过计算高电平时间来判断
接收到的数据是 0 还是 1。外部中断的相关知识,大家可以参考前面的“外部
中断实验”,如果想要更加深入的了解红外遥控通信,大家可以百度,网上这方
面的资料可谓是铺天盖地。
3、硬件设计
本实验使用到硬件资源如下:
(1)动态数码管
(2)红外接收头和遥控器
动态数码管电路在前面章节都介绍过,这里就不再重复。红外遥控器和接收
头是一体的,内部结构不用去管它。下面来看下开发板上红外接收模块电路,如
下图所示:

从上图中可知,红外接收头的输出管脚接至单片机 P3.2 管脚上,为了保证
红外接收头输出管脚默认为高电平,需外接一个 10K 上拉电阻,可在上图并没有
看到有上拉电阻,在前面介绍最小系统时已知道,单片机 IO 口都增加了 10K 上
拉电阻,所以此处可省略。
4、
软件设计
本章所要实现的功能是:数码管上显示红外解码遥控器键值。
程序框架如下:
(1)编写数码管显示功能
(2)编写红外解码函数
(3)编写主函数
ired.c程序如下:
#include "ired.h"
u8 gired_data[4];//存储4个字节接收码(地址码+地址反码+控制码+控制反码)
/*******************************************************************************
* 函 数 名 : ired_init
* 函数功能 : 红外端口初始化函数,外部中断0配置
* 输 入 : 无
* 输 出 : 无
*******************************************************************************/
void ired_init(void)
{
IT0=1; //下降沿触发
EX0=1; //打开中断0允许
EA=1; //打开总中断
IRED=1; //初始化端口
}
void ired() interrupt 0 //外部中断0服务函数
{
u8 ired_high_time=0;
u16 time_cnt=0;
u8 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; //时间超过10ms,退出
}
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;
}
}
}
smg.c文件如下:
#include "smg.h"
//共阴极数码管显示0~F的段码数据
u8 gsmg_code[17]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,
0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71};
/*******************************************************************************
* 函 数 名 : smg_display
* 函数功能 : 动态数码管显示
* 输 入 : dat:要显示的数据
pos:从左开始第几个位置开始显示,范围1-8
* 输 出 : 无
*******************************************************************************/
void smg_display(u8 dat[],u8 pos)
{
u8 i=0;
u8 pos_temp=pos-1;
for(i=pos_temp;i<8;i++)
{
switch(i)//位选
{
case 0: LSC=1;LSB=1;LSA=1;break;
case 1: LSC=1;LSB=1;LSA=0;break;
case 2: LSC=1;LSB=0;LSA=1;break;
case 3: LSC=1;LSB=0;LSA=0;break;
case 4: LSC=0;LSB=1;LSA=1;break;
case 5: LSC=0;LSB=1;LSA=0;break;
case 6: LSC=0;LSB=0;LSA=1;break;
case 7: LSC=0;LSB=0;LSA=0;break;
}
SMG_A_DP_PORT=dat[i-pos_temp];//传送段选数据
delay_10us(100);//延时一段时间,等待显示稳定
SMG_A_DP_PORT=0x00;//消音
}
}
main.c文件如下:
/**************************************************************************************
#include "public.h"
#include "smg.h"
#include "ired.h"
/*******************************************************************************
* 函 数 名 : main
* 函数功能 : 主函数
* 输 入 : 无
* 输 出 : 无
*******************************************************************************/
void main()
{
u8 ired_buf[3];
ired_init();//红外初始化
while(1)
{
ired_buf[0]=gsmg_code[gired_data[2]/16];//将控制码高4位转换为数码管段码
ired_buf[1]=gsmg_code[gired_data[2]%16];//将控制码低4位转换为数码管段码
ired_buf[2]=0X76;//显示H的段码
smg_display(ired_buf,6);
}
}
普中51单片机遥控器按键编码如下,我们接受的是按键编码,并不是按键上面印刷的数字与符号。