工具
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(int num);
void command_code(int num);
void reverse_code(int num);
void end_cod(void);
/**
* @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
{
//执行所需的功能
//引导码
red_start();
//命令码
command_code(7);
//数据码
send_bit(keynum);
//结束码
end_cod();
EX0=0; //中断完成后 恢复允许位关闭状态
}
/**
* @brief 引导码
* @retval
*/
void red_start(void)
{
red_IO=1; //拉高 通过与门 方波出入红外
delay_ms(9);
red_IO=0;
delay_ms(4);
}
/**
* @brief 命令码
* @retval
*/
void command_code(int num)
{
unsigned int i=0;
for(i;i<8;i++)
{
if(num>>i&0x01)
{
send_1();
}else{
send_0();
}
}
reverse_code(num);
}
/**
* @brief 反码
* @retval
*/
void reverse_code(int num)
{
unsigned int i=0;
for(i;i<8;i++)
{
if(~num>>i&0x01)
{
send_1();
}else{
send_0();
}
}
}
/**
* @brief 结束码
* @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(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_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(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)
{
//数据接受完成
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 本欧也很喜欢交朋友的哦!