对于红外接收的通信原理有很多,常用的有通过脉宽调制(PWM)和脉时调制(PPM)两种方法,最近小编就在尝试写基于51单片机的脉时调制的红外接收程序,有一些心得,与大家分享分享。

原理分析

通常的红外遥控器是将二进制脉冲码调制在38KHz的载波上,经缓冲放大后送至红外发光二极管,转化为红外信号发射出去。
因为二进制脉冲码的形式有很多种,所以要开发红外接收设备,一定要知道红外遥控器的载码方式和载波频率,我们才可以选取一体化红外接收头和制定解码方案

下面是我使用的红外接收头的实物与原理图

在这里插入图片描述

在这里插入图片描述

原理图可以看到,我使用的一体红外接收头有三个引脚,分别是VCC、GND和数据引脚(用来传输数据)

数据形式

现在我们已经知道了它是由一根数据引脚来传输数据,那数据又是怎么传输?传输一次的数据格式又是什么呢?

在这里插入图片描述

在这儿,可以很明显的看到,数据是由五段数据组成。

首先它会给一个9ms的低电平,4.5ms的高电平组成的起始码,告诉我们接下来要传输数据了,然后开始传输32位二进制的数据码。

由于它只有一根数据引脚,所以我们要通过这一根数据引脚来判断它传输的数据是二进制的 ‘ 0 ’ 还是 ‘ 1 ’ 。

在这里插入图片描述

在这儿可以看到,无论数据传输 ‘ 0 ’ 还是 ‘ 1 ’ ,都会先传输0.56ms,也就是560us的低电平,这样用来判断上一个数据结束,下一个数据开始,至于传输的数据就是用接下来的高电平时间来判断。

高电平时间为565um就是数据 ‘ 0 ’ ,1690um就是数据 ‘ 1 ’ 。由于在现实数据传输中受到环境因素的影响,所以我们需要取一个中间值来判断,超过这个中间值就是数据 ‘ 1 ’ ,反之就是数据 ‘ 0 ’ 。
代码

理论讲了这么久了,估计都枯燥了吧,接下来就开始分析代码吧。
重点:代码格式一定要规范!

void main(void)
{
//我们使用的是51单片机,所以可以使用定时器来计时。
//对于延时函数,确实很方便,但是小编强烈不推荐使用延时函数,能用定时器解决的尽量不使用延时函数。
//延时函数时间不准确,至于为什么不使用延时函数,小编之后会单独写一篇来解释。
    TMOD = 0x01;//这儿打开定时器1,用来计时。
    TR0 = 0;    //关闭允许定时器1计时,当我们需要定时器1计时的时候再打开。
    IT0 = 1;
    EX0 = 1;    //这两句是51单片机的外部中断1允许,并且下降沿触发,因为红外数据最开始是9ms低电平,所以可以使用外部中断(不使用中断也行)。
    EA = 1;        //打开总中断
    while (1)
    {
        //while(1)循环中的代码后面会单独列出。
    }
}

以上就是我们程序需要打开的配置
接下来就是外部中断程序

bit InFrared_Way = 0;            //在程序的开头我定义了一个一字节的变量,至于作用,接下来会讲。

void Int_0(void) interrupt 0    //外部中断程序
{
//最开始我是直接在外部中断里面写红外解码程序,但是我发现无论如何都无法进入中断程序(可能是我代码的问题)。
//然后我又想到我的老师跟我说过外部中断程序越简洁越好,我就改成了现在这样。
    InFrared_Way  = 1;            //让变量置1,从而在主程序里判断接受到红外信号。
}

下面是主函数while(1)里面的代码

    if (InFrared_Way == 1)    //判断是否接收到红外信号,若是能接收到信号,则进入函数。
    {
        EX0 = 0;            //关闭外部中断,防止干扰。
        TR0 = 1;            //允许定时器1计时。
        InFrared_Init();    //这是我写的红外接收函数,下面会提到,这儿不做过多解释。
        TR0 = 1;            //关闭允许定时器1计时。
        EX0 = 1;            //打开外部中断。
        InFrared_Way = 0;    //清零InFrared_Way ,标志着已经结束红外接收。
    }

只剩下了红外接收函数了

sbit INIR = P3^2;                //51单片机的引脚定义,我的51板子上数据引脚连接的是P3^2引脚。
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;    //数据左移一位,使接收位默认为0,因为数据是由低位开始接收。
                if (TH0 >= 7)    //判断是否超过中间值,超过就是数据1。
                {
                    Data[i] |= 0x80;    //数据写1,默认为0,所以只需要有写1的操作。
                }
            }
        }
    }
}

到此为止,全部函数就分享出来啦!

当然,不想一段代码一段代码的去复制,小编贴心的把上面代码合成的放在下面了!

#include <STC12C5A60S2>        //这个根据自己的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;
                }
            }
        }
    }
}

以为完了?当然没有

小编的代码里面并没有处理4组数据,是因为每个人使用的显示的东西不同,小编是使用的0.96寸的OLED来处理的4组数据,有些人可能会使用数码管来显示。因为这儿只是讨论红外,所以并没有介绍到其他的东西。

(以下仅仅代表个人看法,如果有大佬愿意指导在下,感恩不尽!)
对于这四组数据,我最开始使用的遥控器上的 0 — 9 这10个数据的第三组数据是顺序连着的。

例如:

0 的数据码如果是 0x10 ,那么 1 的数据码就是 0x11 。

但是,我换了一个遥控器之后,0 — 9 的数据码并不是连在一起的,所以,目前的我认为,不能光看了 0 的数据码就可以判断 1 — 9 的数据码,而需要实事求是的每一个去验证。
谢谢大家!点个赞关注下博主吧,嘻嘻