51_红外遥控

红外遥控器,顾名思义,是通过红外光来进行数据传输的。被广泛应用在各种家电产品上,例如电视、空调、车载MP3等。它是如此的普遍,以至于让人都快忘记了它的存在。 只要温度高于绝对零度(-273.15°C)的物体都会发出红外光,因此它无处不在。因此,使用红外光进行通信时,需要对光波有一些特殊的要求,这样才能使它能够在众多的同类信号中被识别出来。 首先是波长,一般来说红外发射管发出的光波波长以850nm和940nm两种比较常见。 然后是频率,发射端以一个固定的频率来发射红外光,一般以37.91KHZ比较常见,也有的地方直接说成是38KHZ。同时,接收端只识别该频率下的信号,只要发射频率与接收频率正负相差不超过1KHZ,都可以正常工作;如果相差超过2KHZ,会出现失灵或者距离短等情况。

第二类接收管如图所示,也是要使用的接收管。和前面几种管子的最大区别在于它有三只脚,而功能也大大增强了。它的内部电路包括红外监测二极管,放大器,限幅器,带通滤波器,积分电路,比较器等。 通过内部电路,还原出发射端的信号波形,可以直接被单片机使用。因此也被称为一体化红外接收头。

 

 

也就是说,它输出的是符合数字电路要求的数字信号了,可以直接拿来使用。所以,虽然外型上只是多了一个引脚,但实际内部功能增加了很多很多,大大简化了电路设计者的工作。另外,此类接收头的内部放大增益比较大,很容易引起干扰,因此一般厂家建议在供电脚加上4.7uf以上的电容进行滤波。 常用型号有IRM3638、HS0038和VS1838等。其接口电路如图所示

 

 

这里使用的遥控器用的是NEC协议,因此这里着重讲解该协议下信号是如何传播的。首先,遥控器内部一般会使用455KHZ的晶体做为振荡源,通过内部分频电路将其调制为频率37.91KHZ、占空比三分之一的振荡信号。 遥控器闲置时,发射端无输出。当有按键按下时,会发送一串信号驱动红外发射端发射红外线,信号格式如下:一段引导码、两个字节的用户码(由厂家定义)、一个字节的按键数据、一个字节的按键数据反码,最后跟一个停止位(编程时基本不考虑)。

 

有两个事情要注意: 1、该图是遥控器发出的信号格式,并不是接收端收到的信号格式,两者是不一样的; 2、图中高电平的位置并不是真的高电平,而是被频率37.91KHZ、三分之一占空比的信号填充的。 那么接收端收到的信号是什么样?首先,闲置状态下,它是高电平的。当收到37.91KHZ的红外光时,接收端调制出的信号是低电平,无红外光时,又恢复为高电平。所以,将上图中的信号全部取反,即为红外接收端输出的信号格式。

接下来,了解一下数据的传输过程中是如何定义0和1这两种状态的。以接收端的状态来考虑,空闲的状态下引脚输出高电平。 当表示一个bit位为0时,先输出一个0.56ms的低电平,然后输出一个0.565ms的高电平; 当表示一个bit位为1时,先输出一个0.56ms的低电平,然后输出一个1.69ms的高电平。

 

要想识别发送的指令是什么,就要先知道遥控器上每个按键对应的数据码是什么,而这部分内容,需要跟遥控器供应商索取。记住,即便是外形一模一样的遥控器,只要厂家不同,也有可能相同位置的按键数据码不一样。这里选购的遥控器用户码为0x00FF,按键对应的数据码如图所示

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
/*******************************************************************************
* 实验名              : 1602显示红外线值实验
* 使用的IO      : 电机用P1口,键盘使用P3.0、P3.1、P3.2、P3.3
* 实验效果       : LCD1602显示出读取到的红外线的值
*   注意                   :
*******************************************************************************/
#include<reg51.h>
#include"lcd.h"
 
sbit IRIN=P3^2;
 
unsigned char code CDIS1[13]={" Red Control "};
unsigned char code CDIS2[13]={" IR-CODE:--H "};
unsigned char IrValue[6];
unsigned char Time;
void IrInit();
void DelayMs(unsigned int );
/*******************************************************************************
* 函数名         : main
* 函数功能         : 主函数
* 输入           : 无
* 输出             : 无
*******************************************************************************/
 
void main()
{
    unsigned char i;
    IrInit();  
    LcdInit();
    LcdWriteCom(0x80);
    for(i=0;i<13;i++)
    {
        LcdWriteData(CDIS1[i]);
    }
    LcdWriteCom(0x80+0x40);
    for(i=0;i<13;i++)
    {
        LcdWriteData(CDIS2[i]);
    }
    while(1)
    {
        IrValue[4]=IrValue[2]>>4;         //高位
        IrValue[5]=IrValue[2]&0x0f;     //低位   
        if(IrValue[4]>9)
        {
            LcdWriteCom(0xc0+0x09);         //设置显示位置
            LcdWriteData(0x37+IrValue[4]);  //将数值转换为该显示的ASCII码
        }
        else
        {
            LcdWriteCom(0xc0+0x09);
            LcdWriteData(IrValue[4]+0x30);  //将数值转换为该显示的ASCII码
        }  
        if(IrValue[5]>9)
        {
            LcdWriteCom(0xc0+0x0a);
            LcdWriteData(IrValue[5]+0x37);      //将数值转换为该显示的ASCII码
        }
        else
        {
            LcdWriteCom(0xc0+0x0a);
            LcdWriteData(IrValue[5]+0x30);      //将数值转换为该显示的ASCII码
        }  
    }
}                                   
/*******************************************************************************
* 函数名         : DelayMs()
* 函数功能         : 延时
* 输入           : x
* 输出             : 无
*******************************************************************************/
 
void DelayMs(unsigned int x)   //0.14ms误差 0us
{
 unsigned char i;
  while(x--)
 {
  for (i = 0; i<13; i++)
 {}
 }
}
/*******************************************************************************
* 函数名         : IrInit()
* 函数功能         : 初始化红外线接收
* 输入           : 无
* 输出             : 无
*******************************************************************************/
 
void IrInit()
{
    IT0=1;//下降沿触发
    EX0=1;//打开中断0允许
    EA=1;   //打开总中断
 
    IRIN=1;//初始化端口
}
/*******************************************************************************
* 函数名         : ReadIr()
* 函数功能         : 读取红外数值的中断函数
* 输入           : 无
* 输出             : 无
*******************************************************************************/
 
void ReadIr() interrupt 0
{
    unsigned char j,k;
    unsigned int err;
    Time=0;                 
    DelayMs(70);
 
    if(IRIN==0)     //确认是否真的接收到正确的信号
    {   
         
        err=1000;               //1000*10us=10ms,超过说明接收到错误的信号
        /*当两个条件都为真是循环,如果有一个条件为假的时候跳出循环,免得程序出错的时
        侯,程序死在这里*/ 
        while((IRIN==0)&&(err>0))    //等待前面9ms的低电平过去        
        {          
            DelayMs(1);
            err--;
        }
        if(IRIN==1)         //如果正确等到9ms低电平
        {
            err=500;
            while((IRIN==1)&&(err>0))         //等待4.5ms的起始高电平过去
            {
                DelayMs(1);
                err--;
            }
            for(k=0;k<4;k++)     //共有4组数据
            {              
                for(j=0;j<8;j++) //接收一组数据
                {
 
                    err=60;    
                    while((IRIN==0)&&(err>0))//等待信号前面的560us低电平过去
//                  while (!IRIN)
                    {
                        DelayMs(1);
                        err--;
                    }
                    err=500;
                    while((IRIN==1)&&(err>0))     //计算高电平的时间长度。
                    {
                        DelayMs(1);//0.14ms
                        Time++;
                        err--;
                        if(Time>30)
                        {
                            EX0=1;
                            return;
                        }
                    }
                    IrValue[k]>>=1;    //k表示第几组数据
                    if(Time>=8)          //如果高电平出现大于565us,那么是1
                    {
                        IrValue[k]|=0x80;
                    }
                    Time=0;     //用完时间要重新赋值                        
                }
            }
        }
        if(IrValue[2]!=~IrValue[3])
        {
            return;
        }
    }          
}

  

 

posted @   xiaoberber  阅读(766)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· winform 绘制太阳,地球,月球 运作规律
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· 上周热点回顾(3.3-3.9)
· AI 智能体引爆开源社区「GitHub 热点速览」
· 写一个简单的SQL生成工具
点击右上角即可分享
微信分享提示