51单片机入门:红外遥控

51单片机入门:红外遥控红外遥控系统是利用红外光进行通信的设备 通常由发射和接收两大部分组成 即 由红外 LED 将调制后的信号发出 再由专门的红外接收头进行解调输出

大家好,欢迎来到IT知识分享网。

红外遥控系统简介

红外遥控系统是利用红外光进行通信的设备,通常由发射和接收两大部分组成,即:由红外LED将调制后的信号发出,再由专门的红外接收头进行解调输出。

红外LED:外表与普通的LED没有什么不同,发射940nm的红外光,人眼看不到。也有850nm的红外LED,可以看见微微的红光。

51单片机入门:红外遥控

通讯方式单工,只能一方发送一方接受,不能反过来;异步,没有单独的时钟线,通信需要双方约定时间。

通信协议标准:NEC标准(我国常用)、RC5、SONY、REC80、SAMSWNG等,主要是欧洲和日本生产厂家所使用的编码格式。

生活中,红外LED被广泛应用,比如在电视、空调和电扇的遥控里都有找到红外LED的身影。这些设备之所以能被控制,是因为内部有与之匹配的红外接收二极管,红外接收二极管的颜色一般是黑色的,当红外接收二极管被红外光照射阻值会变小

51单片机入门:红外遥控


硬件电路

1、红外发送部分

主要由如下两种电路结构所示:

51单片机入门:红外遥控

对于第一个电路,只有当两个三极管开关同时打开时,红外LED才发光。其中第一个接口的38KHz为调制频率,在发送信号时需要一直给这个接口输入一个频率为38KHz的方波;第二个接口就输入我们想要传输的波形。

将两个接口互相联系起来,会发现:在高电平时,红外LED不会发光;在低电平时,红外LED以38KHz频率闪着亮。(这是为了抵抗干扰,在自然界中有很多红外光,例如太阳光,而调制的目的就是为了区分自然光与作为信号的红外光。)

对于第二个电路,没有了38KHz接口,只是一个纯粹的三极管开关(给低电平亮、给高电平不亮),在发送的时候需要程序来实现38KHz调制的功能。

2、红外接收部分

51单片机入门:红外遥控

接收部分有单独的一个红外接收LED(黑色),如果直接用红外接收管,则接受到的信号就会有很多成分(自然光等),因此后面还需要进行电路操作(例如滤除自然光、放大发送的信号、滤除38KHz部分的信号,使其输出信号看上去和IN端输入信号一致)。一体化红外接收管就包含了红外接收LED和这些功能电路。

注意,需要将输出信号OUT接在外部中断上。


基本发送与接收

空闲状态:红外LED不亮,接收头输出高电平。

发送低电平:红外LED以38KHz频率闪烁发光,接收头输出低电平。

发送高电平:红外LED不亮,接收头输出高电平。

51单片机入门:红外遥控

接收装置如何区分空闲状态和发送高电平?

接收装置以第一个下降沿为开始,在此之后的一段时间内其输出波形都是发送装置所发送的波形(此时红外LED不亮为高电平输出),波形结束后又一直输出高电平(此时红外LED不亮为空闲状态)。

注意,此处的高电平和低电平都不代表逻辑1或0,仅仅是指物理现象本身。


NEC编码

NEC编码是一种红外遥控协议,常用于遥控器与设备之间的通信。它是一种常用的编码格式;将遥控发送过来的信号进行一定形式的编码,转换为对应的信息。

51单片机入门:红外遥控

如上所示,这是一帧完整的红外信号(注意是红外信号,即这是从发送装置来看,对应输出信号波形高低电平与之相反),其中黄色区域既不是高电平也不是低电平,而是38KHz的高频脉冲信号

可以看出,一帧完整的红外信号包括:起始位、地址码、地址反码、数据码、数据反码、结束位。

1、起始位:持续低电平(高频脉冲)9ms后持续高电平(不亮)4.5ms,表示要开始传输数据了。

2、地址码:由8位0或1表示,用于确定(选定)设备(比如家里面有很多红外设备,不同的红外设备其地址码是不同的。)其逻辑0或1表示如下:

51单片机入门:红外遥控

逻辑0是由562.5us的高频脉冲和562.5us的不亮表示;逻辑1是由562.5us的高频脉冲和1687.5us的不亮表示。对于上上图,其地址码为:。

3、地址反码:对地址码进行取反,因而地址反码为:00001111。地址反码是为了保证传输的准确性,一旦有一个地址反码和地址码对不上号,这这一帧数据都将作废。

4、数据码:同样由8个0或1组成,对于上上图,其数据码为:1111 1111。其包含的信息为所匹配红外设备需要执行的功能。通过8个0或1的排列组合,有256个不同的结果,也就是说红外遥控器最多有256个按键。

5、数据反码:对数据码进行取反。

6、结束位:持续高频脉冲562.5us,表示数据传输结束。

7、重复码:持续低电平9ms后持续不亮4.5ms,在持续562.5us的高频脉冲,在然后又是持续不亮。每个一帧数据的时间约是110ms。(重复码通常用于调音量时的长按)

51单片机入门:红外遥控


51单片机的外部中断

以STC89C52为例,有4个外部中断(传统51单片机只有两个)。其外部中断有两种触发方式:下降沿触发和低电平触发。

其外部中断0(INT0)和外部中断1(INT1)外部中断号分别为0、2。


代码设计

Timer0.c

#include <REGX52.H> //定时器初始化 void Timer0_Init() { TMOD&=0xF0; //设置定时器模式 TMOD|=0x01; //设置定时器模式 TL0=0x18; //设置定时器初值 TH0=0xFC; //设置定时器初值 TF0=0; //清除TF0标志 TR0=0; //定时器0不计时 } //设置定时器初始值 void Timer0_SetCounter(unsigned int Value) { TH0=Value/256; TL0=Value%256; } //把定时器里变化后的数据拿出来,得到时间差 unsigned int Timer0_GetCounter() { return (TH0<<8)|TL0; } //定时器启动开关 void Timer0_Run(unsigned char Flag) { TR0=Flag; //Flag为1,开始计时;为0,停止计时 }

Int0.c

#include <REGX52.H> //外部中断0初始化 void Int0_Init() { IT0=1; IE0=0; EX0=1; EA=1; PX0=1; //优先级设为高优先级 }

此处需要将外部中断0的中断优先级设置为高优先级,保证在同时触发多个中断时优先执行此中断,使红外信号被及时接收。

IR.c

#include <REGX52.H> #include "Timer0.h" #include "Int0.h" unsigned int IR_Time; //计时(时间差) unsigned char IR_State; //状态 unsigned char IR_Data[4]; //存储数据 unsigned char IR_pData; //0~31,即一个完整的信号有32位 unsigned char IR_DataFlag; //数据帧标志位 unsigned char IR_RepeatFlag; //连发帧标志位 unsigned char IR_Address; //地址码 unsigned char IR_Command; //数据码 //红外遥控初始化 void IR_Init() { Timer0_Init(); Int0_Init(); } / *功能:红外遥控获取收到数据帧标志位 *参数:无 *返回值:是否收到数据帧,1为收到,0为未收到 */ unsigned char IR_GetDataFlag() { if(IR_DataFlag) { IR_DataFlag=0; return 1; } return 0; } / *功能:红外遥控获取收到连发帧标志位 *参数:无 *返回值:是否收到连发帧,1为收到,0为未收到 */ unsigned char IR_GetRepeatFlag() { if(IR_RepeatFlag) { IR_RepeatFlag=0; return 1; } return 0; } / *功能:红外遥控获取收到的命令数据 *参数:无 *返回值:收到的命令数据 */ unsigned char IR_GetCommand() { return IR_Command; } / *功能:红外遥控获取收到的地址数据 *参数:无 *返回值:收到的地址数据 */ unsigned char IR_GetAddress() { return IR_Address; } //外部中断0函数,下降沿触发 void Int0_Routine() interrupt 0 { if(IR_State==0) //状态为0,说明是空闲状态 { Timer0_SetCounter(0); //设置定时器初始值 Timer0_Run(1); //开始计时 IR_State=1; //进入状态1,即准备接收信号 } else if(IR_State==1) { IR_Time=Timer0_GetCounter(); //读取计时的时间(时间差) Timer0_SetCounter(0); //定时器清0,重新计时间差 //计时为13.5ms,则收到了起始位(注意,11.0592MHz下为12442) if(IR_Time>12442-500&&IR_Time<12442+500) //如果是起始位 { IR_State=2; //进入状态2,即开始接收数据 } //计时为11.25ms,则收到了重复位(同样,11.0592MHz下为10368) else if(IR_Time>10368-500&&IR_Time<10368+500) { IR_RepeatFlag=1; //说明这一帧已经结束 Timer0_Run(0); //结束计时 IR_State=0; //回到空闲状态 } //接收出错 else { IR_State=1; } } else if(IR_State==2) { IR_Time=Timer0_GetCounter(); //读取计时的时间(时间差) Timer0_SetCounter(0); //定时器清0 //计时为1120us,则收到了逻辑0(注意,11.0592MHz下为1032us) if(IR_Time>1032-500&&IR_Time<1032+500) { IR_Data[IR_pData/8]&=~(0x01<<(IR_pData%8)); //数据对应位 置0 IR_pData++; } //计时为2250us,则收到了逻辑1(注意,11.0592MHz下为2074us) else if(IR_Time>2074-500&&IR_Time<2074+500) { IR_Data[IR_pData/8]|=(0x01<<(IR_pData%8)); //数据对应位 置1 IR_pData++; } //如果接受失败,这一帧作废 else { IR_pData=0; IR_State=1; } if(IR_pData>=32) //表示32位数据接受完毕 { IR_pData=0; //重新置0 if((IR_Data[0]==~IR_Data[1])&&(IR_Data[2]==~IR_Data[3])) { IR_Address=IR_Data[0]; //数据转移 IR_Command=IR_Data[2]; //数据转移 IR_DataFlag=1; } Timer0_Run(0); //定时器停止 IR_State=0; //置状态为0 } } }

此代码主要通过下降沿之间的时间差来判断逻辑0、逻辑1、起始位、重复位。

对于重复位直接返回状态0即可(不需要再进入状态2中改变地址码和数据码),并且在下一次下降沿到来时在进行判断时起始位还是重复位。

对于起始位,则让其进入状态2,记录地址码与数据码。

免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。 本文来自网络,若有侵权,请联系删除,如若转载,请注明出处:https://haidsoft.com/140132.html

(0)
上一篇 2025-05-28 20:20
下一篇 2025-05-28 20:33

相关推荐

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注微信