51单片机的红外接收解码

276 阅读4分钟

51单片机的红外接收解码

通常的红外遥控器是将二进制脉冲码调制在38KHz的载波上,经缓冲放大后送至红外发光二极管,转化为红外信号发射出去。

以下是常用的红外接收头的实物

image.png

发送数据格式

image.png

起始码是一个9ms的低电平,4.5ms的高电平,紧随其后的为数据码。

数据码‘ 0 ’和 ‘ 1 ’表示方法如下:

image.png

程序根据起始码和数据码的高低电平时间特征进行程序判断即可顺利解码,在实际应用中我们需要进行中容错处理,将时间增加或减少一定数量,防止实际产品中的误差而产生错误。

对于单片机来说,读取IO电平时间是一个比较基础的操作。

下面的代码利用单片机IO中断,再读取IO定时器计数值的方法来获取IO变化时间,最后通过时间按照IR数据时间来解码。

其实还有很多种方法都可以实现此功能,比如用单片机的定时器的捕获功能,获取IO变化时间。还可以用一个定时器中断,固定时间读IO的电平状态来判断时间达到解码目的。

最简单的方法是利用带IR解码功能的单片机,直接读取IR数据。

IR发射只需按照编码时间控制IO变化再进行输出即可。

IR接收解码代码如下:

void main(void)

{

//程序使用一个定时器来计时。在IO变化时产生中断,来读取定时器的计数值。

   TMOD = 0x01;//打开定时器1,

   TR0 = 0; //关闭允许定时器1

   IT0 = 1;

   EX0 = 1;   //开外部中断1,下降沿触发,注意与单片机IO对应。

   EA = 1;          //开总中断

   while (1)

   {

          if (InFrared_Way == 1)   //判断是否接收到红外信号,若是能接收到信号,则进入函数。

{

   EX0 = 0;          //关闭外部中断。

   TR0 = 1;          //允许定时器1计时。

   InFrared_Init(); // 初始化

   TR0 = 1;          //关闭允许定时器1计时。

   EX0 = 1;          //打开外部中断。

   InFrared_Way = 0; //清零InFrared_Way ,已经结束红外接收。

}

   }

}

中断函数:

bit InFrared_Way = 0; //外部中断接收标志位,主要起到通知主函数中一个中断进入,可以执行解码工作了,这是一个全局变量。

void Int_0(void) interrupt 0 //外部中断程序

{

InFrared_Way  = 1;       //让变量置1,从而在主程序里判断接受到红外信号。

}

接收处理类函数如下:

sbit INIR = P3^2; //51单片机的引脚定义,注意一定要是带中断功能的引脚,有些IO是不带中断功能的所以不能用。

unsigned char Data[4] = {0}; //定义四组8位的数据,刚好储存红外信号的32位数据。

红外接收处理函数:

void InFrared_Init(void)

{

unsigned char i, j;          //定义4个数据,每个数据8个位,i表示数据,j表示位。

TH0 = 0;

TL0 = 0;                 //定时器1清0

while (INIR == 0 && TH0 <= 35);  //等待9ms低电平。

if (INIR == 1)           //判断是否为高电平。

{

   while (INIR == 1 && TH0 <= 55);  //等待4.5ms高电平。

//开始接收数据。

   for (i = 0; i < 4; i++)

   {

       for (j = 0; j < 8; j++)   //接收4组8位数据。

       {

          TH0 = 0;

          TL0 = 0;                 //定时器1时间清0。

          while (INIR == 0 && TH0 <= 3);   //等待560us低电平。

          while (INIR == 1); //判断高电平时间。

          Data[i] >>= 1; //数据左移一位。

          if (TH0 >= 7)  //判断是否大于阈值。

          {

              Data[i] |= 0x80;  //数据写1

          }

       }

   }

}

}

整体代码:

#include //这个根据自己的51单片机芯片来修改。

sbit INIR = P3^2; //这个根据自己定义引脚,注意要带中断功能。

bit InFrared_Way = 0;

unsigned char Data[4] = {0};

void InFrared_Init(void);

void main(void)

{

   TMOD = 0x01;

   TR0 = 0;

   IT0 = 1;

   EX0 = 1;

   EA = 1;

   while (1)

   {

          if (InFrared_Way == 1)

          {

                 EX0 = 0;

                 TR0 = 1;

                 InFrared_Init();

                 TR0 = 1;

                 EX0 = 1;

                 InFrared_Way = 0;

          }

   }

}

void Int_0(void) interrupt 0

{

   InFrared_Way  = 1;

}

void InFrared_Init(void)

{

   unsigned char i, j;

  

   TH0 = 0;

   TL0 = 0;

   while (INIR == 0 && TH0 <= 35);

   if (INIR == 1)

   {

          while (INIR == 1 && TH0 <= 55);

          for (i = 0; i < 4; i++)

          {

                 for (j = 0; j < 8; j++)

                 {

                        TH0 = 0;

                        TL0 = 0;

                        while (INIR == 0 && TH0 <= 3);

                        while (INIR == 1);

                        Data[i] >>= 1;

                        if (TH0 >= 7)

                        {

                               Data[i] |= 0x80;

                        }

                 }

          }

   }

}

当IR数据解码出来后,数据就可以使用了,如用串口发送出去,或直接进行输出控制,还可以进行数据加解密码处理等等。

这里只是一个比较简单的IR解码方法,在抗干扰,单片机利用率和数据处理上都还有很大的优化空间。有兴趣的可以参考前面提到的其它解码方法去实现代码、优化代码。据我所知,很多的无线通信也是采用的这种方式。