IRLINK(红外遥控器)

工具

1.Proteus 8 仿真器

2.keil 5 编辑器

原理图

讲解

简介

红外遥控:是利用红外线进行通信的设备,由红外LED调制后的信号发出,由专用的红外接头进行解调;

通信方式:单工、异步;

红外LED波长:940nm;

通信协议标准:NEC标准;

通信双方需要完成的内容:调制与解调(防止干扰);

        对于无线通信来说,通信双方中间空气中可能夹杂着许多其他的红外波(例如太阳的辐射),这样就对有用的信号产生了一定的干扰;为了抗除这种干扰,我们对发送的信号在发送前进行调制,在接收后进行解调,这样就可以很大程度上防止其他的干扰。

        调制的原理就是将发送的信号电平,搭载在频率为38Khz的方波(称为载波)上,经过调制的信号经过发送设备进行发送;接收设备接收到信号后,先将38Khz信号进行解调,再按照协议进行读取;

NEC编码

发送

正常结构(单次信号

整段信号由起始码,地址码,地址反码,命令码,命令反码,结束码组成

起始码:高电平---9ms---低电平---4.5ms

数据0:高电平---560us---低电平---560us

数据1:高电平---560us---低电平---1680us

连发结构(长按某个键发送信号

整段信号由起始码,地址码,地址反码,命令码,命令反码,重复码,结束码组成

除正常信号外,需每隔110ms发送一段重复码(Command只在刚开始发一次)

重复码:高电平---9ms---低电平---2.25ms

注意:发送结束后必须要有结束码(构造下降沿供接收检测)

接收

注意:接收端的波形正好是相反的(根据两个下降沿之间的时间差得到数据0或数据1)

代码

发送端

#include <reg52.h>
#include "Delay.h"	
#include "KEY.h"
#include "LCD1602.h"
 
sbit IR_IO = P1^0;	//红外
sbit Button_IO = P1^7; //单独按键
int Key_Num=0;	//键值
unsigned long int SendTime=0; //下发引导码 命令码 命令反码 数据码 数据反码  所消耗的时间
int  TimeInitNum=-1,FirstLoopNum=1;	//TimeInitNum 定时器0中断关键字  First_Loop 首次重发码关键字
void IR_Guide_Code(void);	  //引导码
void IR_Com_Code(int num);//命令码
void IR_Data_Code(int num);//数据码
void IR_Reverse_code(int num);//反码
void IR_Repeat_Code();//重发码
void IR_End_cod(void);//结束码
void IR_Send_0(void);	  //发送数据0
void IR_Send_1(void);	  //发送数据1
void Action(); //按下按键


/**
  * @brief  定时器初始化 
  * @param  控制时间差
  * @retval 
  */
void timer0Init() 
{
		TMOD=0x01;//定时器0工作方式1,
  	TH0=0;
  	TL0=0;
  	ET0=1;//禁止中断
  	TR0=0;
}
/**
  * @brief  开启定时器
  * @retval 
  */
void start_time(unsigned int us)
{

		//清空定时器初始值
		TH0=us?(65536-us)/256:0;
		TL0=us?(65536-us)%256:0;
		//开启定时器
		TR0=1;
}
/**
  * @brief  定时器0中断服务
  * @retval 
  */
void time0() interrupt 1 
{
	//按下的状态
	if(Button_IO==0)
	{
		//停止定时器
		TR0=0;
		//第一次发重发码
		if(FirstLoopNum)
		{
			IR_Repeat_Code();
		}
		if(TimeInitNum<=0)
		{
			TimeInitNum++;
			FirstLoopNum=0;
			start_time(55000); //定时器最大计时小于110ms 所以设置产生一次中断55毫秒  两次就是110ms
			return;
		}else{
			IR_Repeat_Code();
			start_time(55000); 
			TimeInitNum=0;
			FirstLoopNum=0;
			return;
		}
	}else{
		TH0=0;
		TL0=0;
		TR0=0;
		TimeInitNum=-1;
		FirstLoopNum=1;
		//结束码
		IR_End_cod();
		return;
	}
} 
/**
  * @brief  中断初始化
  * @param  触发方式(下降沿)
  * @retval 
  */
void Int0Init()    
{
    //设置 INT0
    IT0=1;//触发方式(下降沿)
    EX0=0;//INT0 的中断允许。 0关闭  //P3.2被矩阵键盘占用 键盘按下抬起时EX0=1; P3.2矩阵扫描时会存在下降沿 此时中断产生   
    EA=1;//打开总中断
}
 
/**
  * @brief  外部中断 0 的中断函数
  * @param  
  * @retval 
  */
void Int0() interrupt 0 
{
    //执行所需的功能
	  //引导码
		IR_Guide_Code();
		//命令码
		IR_Com_Code(7);
		//数据码
		IR_Data_Code(Key_Num);
		IR_IO=1; //构造结束后的上升沿  使接收端有下降沿
		delay_10us(56);
		IR_IO=0; //使其空闲
		//设置定时器时间
		start_time(110000 - SendTime); //开始定时
		EX0=0; //中断完成后 恢复允许位关闭状态
}
 
/**
  * @brief  引导码
  * @retval 
  */
 
void IR_Guide_Code(void)
{
	IR_IO=1; //拉高 通过与门 方波出入红外
	delay_ms(9);
	IR_IO=0;
	delay_ms(4);
	SendTime=13000;
}
 
/**
  * @brief 命令码
  * @retval 
  */
void IR_Com_Code(int num)
{
	unsigned int i=0;
	for(i;i<8;i++)
	{
		if(num>>i&0x01)
		{
			IR_Send_1();
		}else{
			IR_Send_0();
		}
	}
	IR_Reverse_code(num);
}
/**
  * @brief 数据码
  * @retval 
  */
void IR_Data_Code(int num)
{
	unsigned int i=0;
	for(i;i<8;i++)
	{
		if(num>>i&0x01)
		{
			IR_Send_1();
		}else{
			IR_Send_0();
		}
	}
	IR_Reverse_code(num);
} 
/**
  * @brief 反码
  * @retval 
  */
 
void IR_Reverse_code(int num)
{
	unsigned int i=0;
	for(i;i<8;i++)
	{
		if(~num>>i&0x01)
		{
			IR_Send_1();
		}else{
			IR_Send_0();
		}
	}
}
/**
   * @brief  重发码
   * @retval 
   */
void IR_Repeat_Code()
{
		IR_IO=1;
		delay_ms(9);
		IR_IO=0;
		delay_ms(2);
		IR_IO=1; //构造接收端的下降沿  
		delay_ms(3);
		IR_IO=0; //释放
}
/**
  * @brief  结束码
  * @param  使电平跳跃一次 否则接收时最后一帧数据会丢失
  * @retval 
  */
 
void IR_End_cod(void)
{
	IR_IO=1; //构造接收端的下降沿  
	delay_ms(2);
	IR_IO=0; //释放 
	delay_ms(2);
	IR_IO=1; //构造接收端的下降沿 
	delay_ms(2);
	IR_IO=0; //释放
}
//数据0
void IR_Send_0(void)
{
	IR_IO=1;
	delay_10us(56);
	IR_IO=0;
	delay_10us(56);
	SendTime+=1120;
	
}
//数据1
void IR_Send_1(void)
{
	IR_IO=1;
	delay_10us(56);
	IR_IO=0;
	delay_10us(168);
	SendTime+=2240;
}

/**
	* @brief  单按与长按 发送红外信号
  * @retval 
  */
void Action()
{
	  //引导码
		IR_Guide_Code();
		//命令码
		IR_Com_Code(1);
		//数据码
		IR_Data_Code(Key_Num);
		IR_IO=1; //构造结束后的上升沿  使接收端有下降沿
		delay_10us(56);
		IR_IO=0; //使其空闲
		//设置定时器时间
		start_time(110000 - SendTime); //开始定时
}

main(void) 
{ 
	Int0Init();
	LCD_Init();
	timer0Init();
	IR_IO=0; //初始化时给低电平 保证与门不通
	LCD_ShowNum(1,1,Key_Num,4);
	while(1)
	{
		//矩阵单按
		Key_Num=KEY();
		if(Key_Num>=0)
		{
			LCD_ShowNum(1,1,Key_Num,4);
			//进入中断
			EX0=1;
		}
		//单键单按与长按
		if(Button_IO==0)
		{
			//按键消抖
			delay_ms(10);
			if(Button_IO==0)
			{
				Key_Num=1;  //key值设置为1;
				LCD_ShowNum(1,1,Key_Num,4);
				Action();
				while(Button_IO==0);
			}
		}
	}
}

接收端

#include <reg52.h>  
#include "Delay.h"
#include "intrins.h"
#include "LCD1602.h"
#include "DS18B20.h"
 
sbit INT0_IO=P3^2;
unsigned char INT_flag=0;  //中断
unsigned char getdata_flag=0;  //数据接受完成标志
unsigned int time=0,pstate=0;	//time用来表示 两个下降沿之间的时间差 us  pstate 数据指针
unsigned char IRdata[4]; //数据缓存
unsigned int get_Time(void); 
unsigned int get_address(void);
unsigned int get_data(void);
/**
  * @brief  定时器初始化 
  * @param  用来计算时间差
  * @retval 
  */
void timer0Init() 
{
		TMOD=0x01;//定时器0工作方式1,
  	TH0=0;
  	TL0=0;
  	ET0=0;//禁止中断
  	TR0=0;
}
/**
  * @brief  开启定时器
  * @retval 
  */
void start_time(void)
{
		//清空定时器初始值
		TH0=0;
		TL0=0;
		//开启定时器
		TR0=1;
}
/**
  * @brief  获取定时器计数值
  * @retval 
  */
unsigned int get_Time(void)
{
		//关闭定时器
		TR0=0;
		return TH0<<8|TL0;
}
/**
  * @brief  外部中断0初始化
  * @param   捕捉下降沿
  * @retval 
  */
void Int0Init()    
{
    //设置 INT0
    IT0=1;//触发方式(下降沿)
		IE0=0;//清空标志位
    EX0=1;//INT0 的中断允许。 0关闭    
    EA=1;//打开总中断
}
/**
  * @brief  中断响应函数
  * @retval 
  */
void Int0() interrupt 0 
{
		//中断进入
		if(INT_flag==0) //第一次下降沿触发
		{
			//开始定时
			start_time();
			getdata_flag=0;
			INT_flag=1;
			return;
		}
		if(INT_flag==1) //第二次下降沿触发
		{
			//结束定时  获取记录的时间值
			time=get_Time();
			//符合 引导码的两次下降沿时间差 
			if(13000-500<time&&time<13000+500)
			{
				start_time();
				INT_flag=2;
				return;
			}
				//符合 重发码
			if(11000-500<time&&time<11000+500)
			{
				IRdata[2]++;
				IRdata[3]=~IRdata[2];
				getdata_flag=1;
				INT_flag=0;
				return;
			}
			//符合 结束码
			if(4000-500<time&&time<4000+500)
			{
				//数据接受完成
				getdata_flag=1;
				INT_flag=0;
				return;
			}
		
		}
		//接受数据
		if(INT_flag==2)
		{
			time=get_Time();
			//符合数据 0 两次下降沿时间差
			if(1120-500<time&&time<1120+500)
			{
				IRdata[pstate/8]&=~(0x01<<(pstate%8));	//数据对应位清0
				pstate++;
				if(pstate==32)
				{
					pstate=0;
					INT_flag=0;
					return;
				}
				start_time();
				return;
			}
			//符合数据 1 两次下降沿时间差
			if(2240-500<time&&time<2240+500)
			{
				IRdata[pstate/8]|=0x01<<pstate%8;
				pstate++;
				if(pstate==32)
				{
					pstate=0;
					INT_flag=0;
					return;
				}
				start_time();
				return;
			}
			
		}
} 
/**
  * @brief  获取命令地址码
  * @param  反馈地址
  * @param 
  * @param 
  * @retval 
  */
unsigned int get_address(void)
{
	if(IRdata[0]==~IRdata[1])
	{
		return IRdata[0];
	}
	
}
/**
  * @brief  获取数据
  * @param 	反馈数据 
  * @param  
  * @param 
  * @retval 
  */
unsigned int get_data(void)
{
	if(IRdata[2]==~IRdata[3])
	{
		return IRdata[2];
	}
}
	
 
void main(void)
{
	//初始化定时器
	timer0Init(); 
	//中断初始化
	Int0Init();
  //初始化液晶
	LCD_Init();
	LCD_ShowString(1,1,"Old_man");
	while(1)
	{
		if(getdata_flag)
		{
			LCD_ShowNum(2,1,get_address(),2);
			LCD_ShowNum(2,4,get_data(),2);
			getdata_flag=0;
		}
	}
}

实现

🚀本欧也处于学习阶段,所学所识将以笔记发布。

笔记会根据相关知识的接触而随时更新! 

 如果文章对你有帮助,请留下你宝贵的点赞吧👍

V:Werluo  本欧也很喜欢交朋友的哦! 

 

  • 25
    点赞
  • 30
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

欧的曼

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值