一、前言
1.1 功能介绍
随着科技的进步和人们生活水平的提高,红外遥控器已经成为了日常生活中不可或缺的电子设备之一,广泛应用于电视、空调、音响等多种家电产品中。 传统的红外遥控器通常只能实现预设的有限功能,无法满足用户对设备更加智能化、个性化的控制需求。
STC90C51作为一款功能强大的8位微控制器,具备高性能、低功耗和丰富的I/O端口资源,非常适合用于实现红外遥控信号的解码和控制。本项目利用STC90C51微控制器,结合定时器和外部中断机制,实现NEC红外线协议的解码,从而实现对红外遥控器的控制功能。
NEC红外线协议是一种常见的红外遥控通信协议,具有传输速度快、编码简单、可靠性高等特点。通过解码NEC红外线协议,可以获取遥控器发送的按键信息,进而实现对设备的远程控制。在本项目中,我们将利用STC90C51的定时器功能,设置合适的定时参数,以检测红外信号的脉冲宽度和间隔。同时,利用外部中断机制,实时监测红外接收管的状态变化,捕捉红外信号的起始和结束时刻。
通过解码NEC红外线协议,我们可以获取遥控器发送的按键编码,并将其转换为对应的控制指令。在本项目中,我们将以开关控制为例,实现对目标设备的远程控制。具体而言,当遥控器发送“开”或“关”的按键编码时,STC90C51将解码该编码,并发送相应的控制指令给目标设备,以实现设备的开关控制。
本项目的开发背景不仅体现了现代家居和电子设备对远程控制技术的需求,也展示了STC90C51微控制器在嵌入式系统设计和开发中的强大功能。通过实现NEC红外线协议的解码和控制,本项目将为用户带来更加便捷、智能的远程控制体验,推动智能家居和物联网技术的发展。
1.2 NEC协议介绍
NEC协议是一种红外线通信协议,广泛应用于家电遥控器和其他红外线设备之间的通信。该协议具有简单、易于实现和广泛兼容的特点,使得不同品牌和型号的红外设备能够互相通信和控制。
NEC协议的工作原理基于38kHz的红外线载波频率,通过发送特定格式的数据包来传输信息。每个数据包由连续的脉冲和间隔组成,其中脉冲表示逻辑1,间隔表示逻辑0。数据包的结构包括同步码(Sync Header)、地址码、地址码的反码、命令码以及命令码的反码。
同步码是数据包开始的标识,通常是一个持续约9ms的高电平脉冲(Mark),用于同步接收器和发送器之间的通信。地址码和命令码是每个按键特定的标识,用于识别按下的是哪个按键。地址码和地址码的反码用于验证遥控器发送的数据是否正确,而命令码和命令码的反码则用于执行相应的操作。
在NEC协议中,数据以二进制格式进行传输,确保了信息的准确性和高效性。此外,NEC协议还定义了一个重复码,当用户长按遥控器上的某个按键时,遥控器会发送该按键的重复码,以避免连续发送相同的命令。
NEC协议是一种基于红外线通信的协议,通过发送特定格式的数据包来实现不同设备之间的通信和控制。它具有简单、易于实现和广泛兼容的特点,被广泛应用于家电遥控器等红外设备中。
二、代码实现
2.1 main.c
#include <reg51.h>
#include "delay.h"
#include "key.h"
#include "type.h"
#include "led.h"
#include "uart.h"
#include "timer.h"
#include "exti.h"
#include "infrared.h"
int main()
{
UART_Init(); //初始化串口波特率为4800
Infrared_Init(); //初始化红外功能
while(1)
{
if(Infrared_RX_Flag) //接收到红外数据
{
Infrared_RX_Flag=0; //清楚标志
printf("user1:%d,user2:%d\r\n",(int)Infrared_RX_Buff[0],(int)((u8)(~Infrared_RX_Buff[1])));
printf("key1:%d,key2:%d\r\n",(int)Infrared_RX_Buff[2],(int)((u8)(~Infrared_RX_Buff[3])));
}
}
}
2.2 INFRARED.c
#include "Infrared.h"
u8 Infrared_RX_Flag=0; //红外接收标志,收到一帧正确数据后置1
u8 Infrared_RX_Buff[4];//红外代码接收缓冲区
/*
函数功能: 开始红外线解码之前的相关初始化
实验板的晶振频率是12MHZ
51单片机标准架构下一个机器周期是12个时钟周期,如果晶振频率是12MHZ,那一个机器周期的时间就是12/12微秒。
也就是说定时器的计数器+1的时间就是12/12=1us。
*/
void Infrared_Init(void)
{
Infrared_GPIO=1;//红外接收引脚默认保持高电平输出
TMOD&=0xF0; //清除配置
TMOD|=0x01; //配置定时器0,工作在16位计数模式
TR0=0; //停止定时器0计数
ET0=0; //禁止定时器0中断
IT0=1; //开启外部中断0,下降沿触发
EX0=1; //允许外部中断0中断
}
/*
函数功能: 检测高电平持续的时间
*/
u16 Infrared_GetTimeH(void)
{
TH0=0; //定时器0重装值为0
TL0=0; //定时器0重装值为0
TR0=1; //启动定时器0开始计数
while(Infrared_GPIO)//等待高电平结束
{
if(TH0>0x40)//防止超时
{
break;
}
}
TR0=0;//停止定时器0计数
return TH0<<8|TL0;//T0计数值合成为16位整数返回
}
/*
检测低电平持续的时间
*/
u16 Infrared_GetTimeL(void)
{
TH0=0;//定时器0的高8位重装值
TL0=0;//定时器0的低8位重装值
TR0=1;//开启定时器0
while(Infrared_GPIO==0)//等待低电平结束
{
if(TH0>0x40)//防止超时
{
break;
}
}
TR0=0;//停止定时器0计数
return TH0<<8|TL0;//T0计数值合成为16位整数返回
}
/*
外部中断0中断服务函数
*/
void EXTI0_IRQHandler() interrupt 0
{
u8 i, j;
u16 time;
u8 byte;
time=Infrared_GetTimeL(); //获取出现低电平的时间
if((time<7800)||(time>9300))//判断低电平时间是否符合9ms范围
{ //超过此范围则说明为误码,直接退出
IE0=0; //清除外部中断0中断标志
return;
}
time=Infrared_GetTimeH(); //获取出现高电平的时间
if((time<3500)||(time>4700))//高电平是否符合4.5ms范围
{ //超过此范围则说明为误码,直接退出
IE0=0; //清除外部中断0中断标志
return;
}
//接收32位数据位
for(i=0;i<4;i++)
{
for(j=0;j<8;j++)
{
time=Infrared_GetTimeL(); //获取低电平持续时间,标准的间隔时间为560us范围
if((time<300)||(time>700)) //判断范围是否合理
{
IE0=0;//清除外部中断0中断标志
return;
}
//1和0是靠高电平持续的长短来区分的
time=Infrared_GetTimeH(); //获取高电平持续时间
if(time>300&&time<700) //0的标准时间为560us
{
byte>>=1;
}
else if(time>1400&&time<1800) //1的标准时间是1680us
{
byte>>=1;
byte|=0x80;
}
else //不在上面的判断范围内说明是错误码,直接退出
{
IE0=0;//清除外部中断0中标
return;
}
}
Infrared_RX_Buff[i]=byte;//接收完一个字节后保存到缓冲区
}
Infrared_RX_Flag=1;//接收完毕后设置标志
IE0=0;//退出前清除外部中断0中断标志
}
2.3 INFRARED.h
#ifndef _INFRAREAD_H
#define _INFRAREAD_H
#include <reg51.h>
#include "type.h"
sbit Infrared_GPIO=P3^2;//红外接收引脚--外部中断0
void Infrared_Init();//红外线接收初始化
u16 Time_H();//检测高电平
u16 Time_L();//检测低电平
extern u8 Infrared_RX_Flag; //红外接收标志,收到一帧正确数据后置1
extern u8 Infrared_RX_Buff[4]; //红外代码接收缓冲区
#endif