51单片机—红外遥控

- 什么是红外遥控

红外遥控系统主要由红外发射装置和红外接收装置构成。
红外发射装置主要由键盘电路、红外编码芯片、电源和红外发射电路组成(比如遥控器),如图:
在这里插入图片描述
红外接收装置主要由红外接收电路、红外解码芯片、电源和应用电路组成,在单片机开发板上有红外接收电路,而且单片机充当解码芯片。

- 红外信号是怎么传输的

人的眼睛能看到的可见光按波长从长到短排列依次为:红、橙、黄、绿、青、蓝、紫。其中红光的波长范围为0.62~0.72微米,红外遥控就是利用波长为0.76至1.5微米之间的近红外线来传送控制信号的。
红外信号的发射由红外发射电路中的红外发光二极管完成,通常情况下为了提高抗干扰能力与降低电源消耗,遥控器将遥控信号(二进制脉冲码)调制在载波(载波是传送信息的物理基础和承载工具)上经放大后发送至红外二极管,再由二极管转换为红外信号发送出去。
遥控器上不同的按键有着不一样的键值,按下相对应的键,红外二极管就会发送对应的信号,接收装置接收到信号后会对信号进行信号解调后会得到相应按键的键值,再根据不同的键值执行相应的操作。

- NEC协议

就像串口通信一样,红外通信也有其自己的通信协议,我们一般遵循NEC协议。
NEC规定红外二极管每次发送的信号的数据格式如下:
在这里插入图片描述
发送的数据主要由引导码、用户码1、用户码2、数据码、数据反码组成。引导码相当于暗号,当接收装置接收到正确的引导码后就开始读取数据,俩组用户码是为了区别其他的红外发射器发射的信号,数据码中的内容就对应着相应的键值,数据反码是为了在接收信号后检验信号的正确性。(引导码是“9ms高电平+4.5ms低电平”)
这样我们虽然清楚了信号的发送形式,但是怎么表达数据发送中的高低位(“0"和"1”)呢?这又涉及到NEC的位定义了,规定:“0.56ms高电平+0.565ms低电平”代表“1”;“0.56ms高电平+1.69ms低电平”代表“0”,就是说“0”与“1”的不同就是他们低电平所持续的时间不同。(PS:发送数据时从最低位开始发送)
在这里插入图片描述
不知道读者注意到黑体字标出的发送没,为什么要刻意强调是发送时的呢?因为单片机接收到的数据格式与发送时的恰恰相反,就是说接收时的引导码是“9ms低电平+4.5ms高电平”;“0”是“0.56ms低电平+0.565ms高电平”;“1”是“0.56ms低电平+1.69ms高电平”。这一点我们要格外注意,因为后续我们在解码程序中是以接收到的数据为准的!!!
在这里插入图片描述

- 程序分析

敲代码之前首先要对程序有一个清楚的认识,即明白要做哪几个模块?这些模块之间要怎么联系起来?在下做的一个程序是把从红外发射器中接收到数据经过处理后显示在数码管上,这样看来我的程序就需要如下几个模块:
1.初始化模块:包括初始化红外接收引脚(把P3.2外部中断引脚作为红外接收引脚)、打开外部中断允许位;
2.延时模块:延时模块主要用来分析高低电平持续的时间,从而判断对应的位是“0”还是“1”;
3.解码模块:利用外部中断函数interrupt 0进行数据解码,其任务是检验并接收正确的数据信号,对用户码和数据码进行分析,即通过检测高低电平持续的时间来判断相应的位是“0”还是“1”。然后得出相对应的键值,把键值对应的数反馈到程序中;
4.显示模块:其主要任务是接收解码模块反馈的数值,并将数值显示在数码管上;
5.主函数模块:整合前几个模块。
程序如下:

#include"reg52.h"
#define uint unsigned int 
#define uchar unsigned char
sbit a=P2^2;//a、b、c是控制位选的三个引脚
sbit b=P2^3;
sbit c=P2^4;
sbit IR=P3^2;//将红外接收引脚和外部中断0引脚定义在一起,
这样一旦接收到信号就进入中断函数进行解码
uint jz=0,time;//jz存的是键值相对应的数值
uchar irdata[4],duan[17]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,
0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71,0X76};
//duan[17]存的是数码管段选显示0~F的数据;irdata[4]存的是一组用户码和数据码、数据反码

void dy(uint n)	  //延时一次约为0.01ms 用来判断脉冲时间
{while(n--);}

void xs(uint x)   //数码管显示
{
a=0;b=0;c=0;//因为我遥控器上的数只有0~9,所以就位选时控制一个数码管就行
P0=duan[x];//显示数字

}

void init()		 //初始化
{
IT0=1;//确定中断0(红外接收)的触发方式为下降沿触发
EX0=1;//打开外部中断0和总中断的允许位
EA=1;
IR=1;			 //相当于打开外部中断0  此处意义为红外接收器打开
}

void hhh() interrupt 0   //执行中断:进行读取信号  最后产生键值
{
uint i,j,k;
dy(700);//能进入中断函数就代表IR已经为0,此处的延时是为了判断延时的大体时间
if(IR==0)
{
k=1000;
while(IR==0&&(k>0))//检测引导码中9ms低电平
{
dy(1);
k--;
}
if(IR==1)//判断高电平
{
k=500;
while(IR==1&&(k>0))//检测引导码中4.5ms高电平
{
dy(1);
k--;
}
for(i=0;i<4;i++)	//开始读取用户码和数据和数据反码,
因为用户码和数据码、数据反码共有4组,所以外层有四组循环
{
	for(j=0;j<8;j++)//每组数据有八位,故内层循环有八组,每次循环读一位
	{
	 if(IR==0)
	 {
	 k=70;
	 while(IR==0&&(k>0))//检测0.56ms的低电平
	 {
	 k--;
	 dy(1);
	 }
	 }
	 if(IR==1)//进入高电平时间,这一块比较核心,它判断了高电平持续时间的长短
	 {
	 time=0;
	 k=500;
	 while(IR==1&&k>0)//开始检测高电平
	 {
	 dy(10);
	 time++;//time是以0.1ms为单位,因为dy(10);
	 k--;
	 }
	 if(time>30) return ;
	 irdata[i]>>=1;	//移位运算,空出最高为为下一次采集做准备
	 if(time>=8)//如果高电平持续时间超过0.85ms代表位是“1”
	 irdata[i]|=0x80;//或运算,给最高为置1
	 time=0;//重置
	 }
	}
}
}
if(irdata[2]!=~irdata[3])//irdata[2]与irdata[3]分别是数据码和数据反码 ,此操作是检验数据准确性
return;
}
switch(irdata[2])//反馈键值所对应的数值
{
case 0x16:jz=0;break;
case 0x0c:jz=1;break;
case 0x18:jz=2;break;
case 0x5e:jz=3;break;
case 0x08:jz=4;break;
case 0x1c:jz=5;break;
case 0x5a:jz=6;break;
case 0x42:jz=7;break;
case 0x52:jz=8;break;
case 0x4a:jz=9;break;
case 0x45:jz=10;break;
default:break;
}

}
 
void main()
{
init();//初始化
while(1) 
xs(jz);//显示数值
}
  • 86
    点赞
  • 475
    收藏
    觉得还不错? 一键收藏
  • 16
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 16
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值