文章目录
- 一、红外通信简介
- 二、红外遥控组成
- 三、NEC协议简介
- 四、红外接收与NEC解码例程
- 五、参考资料
一、红外通信简介
红外通信是一种无线通信技术,利用红外光传输信息。红外光波长介于可见光和微波之间,通常在780纳米至1毫米的范围内。红外通信在许多领域得到广泛应用,例如消费电子产品(如遥控器)、安防系统、智能家居、医疗设备、工业自动化等。它具有以下几个特点和优点:
- 无线性:红外通信不需要物理连接,通过红外光传输信息,实现无线通信,方便灵活。
- 高安全性:由于红外光的传播范围较短,相对不易受到干扰,通信较为安全。
- 低功耗:红外通信设备通常使用低功耗的电子元件,适合电池供电的设备。
- 成本较低:红外通信设备的制造和维护成本相对较低。
红外通信的一个典型应用是红外遥控器。遥控器将电信号转换成红外光信号发送给待控制的设备,设备通过红外接收器接收到信号后进行解码并执行相应操作。
在红外通信中,不同的通信协议规定了红外信号的编码和解码方式,常见的协议包括NEC、RC5、RC6等。通信双方必须使用相同的协议保证正确的通信。总体而言,红外通信是一种简单实用的无线通信技术,在广泛的应用领域发挥着重要的作用。
本篇文章使用STC12单片机接收红外遥控型号,并进行NEC解码。
二、红外遥控组成
在使用红外遥控器时,当用户按下某个按键时,驱动电路会解读按键信息,然后将对应的指令转换成特定的红外信号。红外发射装置发射出的红外光信号被目标设备的红外接收器接收并解码,完成相应的操作。
需要注意的是,不同的红外遥控器可能使用不同的红外通信协议和编码方式,因此在选择红外遥控器时,需要确保它与所控制的目标设备兼容。
总结来说,红外遥控器由按键、红外发射装置、驱动电路、电源和电路板、封装和外壳等组成,通过发射红外光信号实现与目标设备的通信和控制。
三、NEC协议简介
NEC编码是一种常用的红外通信协议,用于遥控器等设备的红外通信。它是由NEC Corporation(日本电气公司)开发的,被广泛应用于各种消费电子产品中,如电视遥控器、音视频设备、空调遥控器等。
NEC编码使用的是脉宽编码调制(PWM)方式,通过控制红外发射器的脉冲宽度来表示不同的信息。NEC编码的一个典型信号由一个引导码(Header Pulse)、一个逻辑"0"的时间间隔(Logic “0” Pulse)和逻辑"1"的时间间隔(Logic “1” Pulse)组成。
NEC编码的时间间隔定义如下:
- 引导码的脉冲宽度为9ms的高电平脉冲,后跟4.5ms的低电平间隔。
- 逻辑"0"的脉冲宽度为0.56ms的高电平脉冲,后跟0.56ms的低电平间隔。
- 逻辑"1"的脉冲宽度为0.56ms的高电平脉冲,后跟1.69ms的低电平间隔。
- NEC编码的数据格式通常为32位,包括一个8位的地址码(Address)和一个8位的命令码(Command),以及它们的反码。
使用NEC编码时,发送端通过在一系列时间间隔内发送特定的脉冲宽度来表示不同的信息,接收端接收到红外信号后根据脉冲宽度解码并执行相应的操作。NEC编码作为一种简单和可靠的红外通信协议,在许多遥控器和其他红外设备中得到了广泛应用。
四、红外接收与NEC解码例程
#include <STC12C5A60S2.H>
#include <intrins.h>
//定义接口功能
sbit buzzer = P2^3;//蜂鸣器
sbit IR = P3^2;//红外接收器
//时钟选择宏定义
#define MAIN_Fosc 11059200L
//#define MAIN_Fosc 12000000L
//相关接口功能宏定义
#define buzzer_OFF buzzer = 1;//关蜂鸣器
#define buzzer_ON buzzer = 0;//开蜂鸣器
#define EA_ON EA = 1;//开总中断
#define EA_OFF EA = 0;//关总中断
//对已有数据类型重新定义
typedef signed char int8; //8位有符号型
typedef signed int int16; //16位有符号型
typedef unsigned char uint8; //8位无符号型
typedef unsigned char uchar; //8位无符号型
typedef unsigned int uint16; //16位无符号型
typedef unsigned int uint; //16位无符号型
typedef unsigned long uint32; //32位无符号型
typedef unsigned char BYTE; //8位无符号型
typedef unsigned int WORD; //16位无符号型
//变量宏定义
uchar IRtime; //检测红外高电平持续时间(脉宽)
uchar IRcord[4]; //此数组用于储存分离出来的4个字节的数据(用户码2个字节+键值码2个字节)
uchar IRdata[33]; //此数组用于储存红外的33位数据(第一位为引导码用户码16+键值码16)
bit IRpro_ok, IRok; //第一个用于红外接收4个字节完毕。IRok用为检测脉宽完毕
//基于STC12单片机1ms延时函数
//函数说明:内部调用
static void Delay1ms()
{
# if MAIN_Fosc == 11059200L
//晶振11.0592MHz
unsigned char i, j;
_nop_();
i = 11;
j = 190;
do
{
while (--j);
} while (--i);
#elif MAIN_Fosc == 12000000L
//晶振12.000000MHZ
unsigned char i, j;
_nop_();
_nop_();
i = 12;
j = 168;
do
{
while (--j);
} while (--i);
#endif
}
//基于STC12单片机ms延时函数
//函数说明:外部调用
void Delay_ms(uint16 time)
{
int i;
for(i=0; i<time; i++)
{
Delay1ms();
}
}
//串口初始化,晶振11.0592,波特率9600
void UartInit(void)//9600bps@11.0592MHz
{
PCON &= 0x7F; //波特率不倍速
SCON = 0x50; //8位数据,可变波特率
AUXR |= 0x04; //独立波特率发生器时钟为Fosc,即1T
BRT = 0xDC; //设定独立波特率发生器重装值
AUXR |= 0x01; //串口1选择独立波特率发生器为波特率发生器
AUXR |= 0x10; //启动独立波特率发生器
}
/***************************************
*函数名称:void sendArray(uchar *s, uint len)
*函数输入:*s 发送的数组指针,len数组长度
*函数返回:无
*函数说明:向串口发送一段数组
***************************************/
void sendArray(uchar *s, uint len)
{
uint i;
for(i=0; i<len; i++)
{
SBUF = *s++;
while(!TI);
TI = 0;
}
}
//定时器0初始化
void Timer0_Init(void)
{
TMOD = 0x22; //定时器0和定时器1工作方式2,8位自动重装
TH0 = 0x00; //高8位装入0那么定时器溢出一次的时间是256个机器周期
TL0 = 0x00;
ET0 = 1; //定时器0中断
TR0 = 1; //启动定时器0
}
//外部中断0初始化
void externalInterrupt0_Init(void)
{
IT0 = 1; //设置外部中断0为跳沿触发方式,来一个下降沿触发一次
EX0 = 1; //启动外部中断0
}
//提取它的33次脉宽进行数据解码
void IRcordpro(void)
{
uchar i, j, k, cord, value; /*i用于处理4个字节,j用于处理一个字节中每一位,k用于33次脉宽中的哪一位
cord用于取出脉宽的时间判断是否符合1的脉宽时间*/
k = 1; //从第一位脉宽开始取,丢弃引导码脉宽
for(i = 0; i < 4; i++)
{
for(j = 0; j < 8; j++)
{
cord = IRdata[k]; //把脉宽存入cord
if(cord > 5) //如果脉宽大于我11.0592的t0溢出率为约278us*5=1390那么判断为1
value = value | 0x80; /*接收的时候是先接收最低位,
把最低位先放到value的最高位在和0x08按位或一下
这样不会改变valua的其他位的数值只会让他最高位为1*/
if(j < 7)
{
value = value >> 1; //value位左移依次接收8位数据。
}
k++; //每执行一次脉宽位加1
}
IRcord[i] = value; //每处理完一个字节把它放入IRcord数组中。
value = 0; //清零value方便下次在存入数据
}
IRpro_ok = 1; //接收完4个字节后IRpro ok置1表示红外解码完成
}
void main()
{
UartInit(); //串口初始化
Timer0_Init(); //定时器0初始化
externalInterrupt0_Init(); //外部中断0初始化
EA_ON; //开总中断
while(1)
{
if(IRok) //判断脉宽是否检测完毕
{
IRcordpro(); //根据脉宽解码出4个字节的数据
IRok = 0; //重新等待脉宽检测
if(IRpro_ok) //判断是否解码完毕
{
sendArray(&IRcord[0], 4);
IRpro_ok = 0;
}
}
}
}
//定时器0中断处理函数
void timer0(void) interrupt 1
{
IRtime++;
}
//外部中断0处理函数
void int0() interrupt 0
{
static uchar i; // 声明静态变量(在跳出函数后在回来执行的时候不会丢失数值)i用于把33次高电平的持续时间存入IRdata
static bit startflag; //开始储存脉宽标志位
if(startflag) //开始接收脉宽检测
{
if( (IRtime < 53) && (IRtime >= 32) ) /*判断是否是引导码,底电平9000us+高4500us
这个自己可以算我以11.0592来算了NEC协议的引导码低8000-10000+高4000-5000
如果已经接收了引导码那么i不会被置0就会开始依次存入脉宽*/
i = 0; //如果是引导码那么执行i=0把他存到IRdata的第一个位
IRdata[i] = IRtime; //以T0的溢出次数来计算脉宽,把这个时间存到数组里面到后面判断
IRtime = 0; //计数清零,下一个下降沿的时候在存入脉宽
i++; //计数脉宽存入的次数
if(i == 33) //如果存入34次 数组的下标是从0开始i等于33表示执行了34次
{
IRok = 1; //那么表示脉宽检测完毕
i = 0; //把脉宽计数清零准备下次存入
//开蜂鸣器
buzzer_ON;Delay_ms(500);
//关蜂鸣器
buzzer_OFF;Delay_ms(500);
}
}
else
{
IRtime = 0; //引导码开始进入把脉宽计数清零开始计数
startflag = 1; //开始处理标志位置1
}
}
五、参考资料
本文章及例程主要参考清翔电子51单片机入门教程,文章开源供单片机学习交流。