工具
1.Proteus 8 仿真器
2.keil 5 编辑器
原理图
讲解
简介
红外遥控:是利用红外线进行通信的设备,由红外LED调制后的信号发出,由专用的红外接头进行解调;
通信方式:单工、异步;
红外LED波长:940nm;
通信协议标准:NEC标准;
通信双方需要完成的内容:调制与解调(防止干扰);
对于无线通信来说,通信双方中间空气中可能夹杂着许多其他的红外波(例如太阳的辐射),这样就对有用的信号产生了一定的干扰;为了抗除这种干扰,我们对发送的信号在发送前进行调制,在接收后进行解调,这样就可以很大程度上防止其他的干扰。
调制的原理就是将发送的信号电平,搭载在频率为38Khz的方波(称为载波)上,经过调制的信号经过发送设备进行发送;接收设备接收到信号后,先将38Khz信号进行解调,再按照协议进行读取;
NEC编码
发送
正常结构(单次信号)
整段信号由起始码,地址码,地址反码,命令码,命令反码组成
起始码:高电平---9ms---低电平---4.5ms
数据0:高电平---560us---低电平---560us
数据1:高电平---560us---低电平---1680us
连发结构(长按某个键发送信号)
除正常信号外,需每隔110ms发送一段重复码(命令码只在刚开始发一次)
重复码:高电平---9ms---低电平---2.25ms
注意:发送结束后必须要有结束码(构造下降沿供接收检测)
接收
注意:接收端的波形正好是相反的(根据两个下降沿之间的时间差得到数据0或数据1)
代码
发送端
#include <reg52.h>
#include "Delay.h" //延时函数头文件
#include "KEY.h"
#include "LCD1602.h"sbit red_IO = P1^0;
int keynum=0;
void red_start(void);
void send_0(void);
void send_1(void);
void send_bit(unsigned int num);
void command_code(unsigned int num);
void reverse_code(unsigned int num);
void end_cod(void);
void Int0Init() //中断初始化
{//设置 INT0IT0=1;//触发方式(下降沿)EX0=0;//INT0 的中断允许。 0关闭 //P3.2被矩阵键盘占用 键盘按下抬起时EX0=1; P3.2矩阵扫描时会存在下降沿 此时中断产生 EA=1;//打开总中断
}
//当触发中断后即会进入中断服务函数,外部中断 0 中断服务函数如下:
void Int0() interrupt 0 //外部中断 0 的中断函数
{//执行所需的功能//引导码red_start();//命令码command_code(7);//数据码send_bit(keynum);//结束码end_cod();EX0=0; //中断完成后 恢复允许位关闭状态
}
//引导码
void red_start(void)
{red_IO=1; //拉高 通过与门 方波出入红外delay_ms(9);red_IO=0;delay_ms(4);
}
//命令码
void command_code(unsigned int num)
{unsigned int i=0;for(i;i<8;i++){if(num>>i&0x01){send_1();}else{send_0();}}reverse_code(num);
}
//反码
void reverse_code(unsigned int num)
{unsigned int i=0;for(i;i<8;i++){if(~num>>i&0x01){send_1();}else{send_0();}}
}
/*** @brief 结束码* @param 使电平跳跃一次 否则接收时最后一帧数据会丢失* @param * @param * @retval */
void end_cod(void)
{red_IO=1;delay_10us(56);red_IO=0;
}
//数据0
void send_0(void)
{red_IO=1;delay_10us(56);red_IO=0;delay_10us(56);
}
//数据1
void send_1(void)
{red_IO=1;delay_10us(56);red_IO=0;delay_10us(168);
}
//发送一字节
void send_bit(unsigned int num)
{unsigned int i=0;for(i;i<8;i++){if(num>>i&0x01){send_1();}else{send_0();}}reverse_code(num);
}main(void)
{ Int0Init();LCD_Init();red_IO=0; //初始化时给低电平 保证与门不通LCD_ShowNum(1,1,keynum,4);while(1){keynum=KEY();if(keynum>=0){LCD_ShowNum(1,1,keynum,4);//进入中断EX0=1;}}
}
接收端
#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_byte(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;time=TH0<<8|TL0;return time;
}
/*** @brief 外部中断0初始化* @param 捕捉下降沿* @retval */
void Int0Init()
{//设置 INT0IT0=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(INT_flag==2){time=get_Time();//符合数据 0 两次下降沿时间差if(1120-500<time&&time<1120+500){IRdata[pstate/8]&=~(0x01<<(pstate%8)); //数据对应位清0pstate++;if(pstate==32){//数据接受完成getdata_flag=1;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){//数据接受完成getdata_flag=1;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,9,get_data(),2);getdata_flag=0;}}
}
实现
🚀本欧也处于学习阶段,所学所识将以笔记发布。
笔记会根据相关知识的接触而随时更新!
如果文章对你有帮助,请留下你宝贵的点赞吧👍
V:Werluo 本欧也很喜欢交朋友的哦!