基于STC12系列单片机的通用红外遥控信号分析程序(一)

发布时间:2024-07-23  

前言

  最近学51单片机学习到红外遥控解码与发送部分,开发板的相关教程只有NEC协议的解码,基本的解码套路是1838接收头输出管脚接单片机外部中断0,当接收到红外信号时产生下降沿触发中断,在中断函数中先延时9ms判断电平再延时4.5ms判断电平,从而跳过引导码;再分别延时560us、1690us左右不等的时间判断电平来解码“0”或“1”,直到结束;红外发送思路就是根据NEC协议及红外码值的二进制码分别控制高低电平,并延时相应的时间。但存在这么几个问题:


  1. 解码逻辑写死在中断处理函数中,不方便扩展、移植;


  2. 只能解码NEC协议的红外遥控信号,如果拿一款别的遥控器来,编码协议未知,整个程序就无能为力了;


  3. 接收到信号时实时解码,没有保存红外波形信息,不能输出波形进行分析;


  4. 只能发送NEC协议的红外遥控信号。


  恰逢外地出差,带了开发板却没带NEC的红外遥控器,手边只有空调、电视遥控器和一个带红外遥控功能的手机,于是就想利用51单片机做一个通用的红外遥控信号录波、解码、发送为一体的程序,直接录制红外波形,发送时也是直接按原波形发送,这样就做到了万能红外信号的学习与发送。同时将录制的波形数据发送到上位机进行显示、分析,这样就算拿到一款未知红外协议的遥控器,也可以做它的协议分析了。PS:本人没有示波器、逻辑分析仪,有这些装备的同学请随便看看。


红外遥控基本原理

  红外发射和接收的原理就不细说了,网上很多,也可以参见这篇文章《全面了解红外遥控(中文版)》,这是一个歪果仁写的,网友翻译,讲了基本原理,也介绍了各种常见的协议。


  需注意的是通常的介绍协议时说的表示逻辑“0”或“1”的高低电平是针对发射端的,而常用的一体化红外接收头如HS0038、VX1838等在无红外信号是输出高电平,有红外信号时输出低电平,也就是与发射端时相反的——发射端高电平发射红外线,接收端接收后产生低电平。这在解码时必须注意。


红外遥控录波硬件系统

  为了尽可能的提高录波时的分辨率,采用了1T模式的STC12C5A60S2单片机,之所以用STC12系列而没用更快的STC15系列时因为12系列DIP40封装与传统8051完全兼容,直接插51开发板上就能用。红外遥控接收头为HS0038,输出管脚接P3.2口(原理图中红外接收头只是随便找了个相近的元件做示意)。采用LCD1602做简单显示。原理图如下:

红外遥控录波程序实现

  本文章内只贴出关键程序,完整程序请点击下载,编译环境Keil4。


  原理:HS0038输出管脚接INT0中断,下降沿触发。当接收到红外信号后,HS0038输出管脚为低电平,进入中断处理函数,立即启动定时器0,等待红外输出管脚变为高电平,记录低电平时间;然后重置定时器0,等待红外输出管脚变为低电平,记录高电平时间;如此往复,直到某次等待超时或记录时间的数组已用完。


  录制的波形数据保存到一个unsigned char数组中,两两一组,以低电平开始(针对接收端而言),交替表示低电平、高电平的持续时间。格式为:


0x04, 0x24,    //低字节在前,实际数据为0x2404,低电平持续时间的计数值

0x84, 0x11,    //低字节在前,实际数据为0x1184,高电平持续时间的计数值

...

  该段程序不仅可以录制红外波形,还可以做简易的逻辑分析仪使用。录制波形时定时器0的计时时间为1us,所以该段程序的录波理论最小分辨率为1us,但由于中间计算过程等耗时会产生误差,所以最好用来录制电平持续时间大于10us的脉冲波形。


  录波的流程图如下:

//硬件

//@单片机          :    STC12C5A60S2

//@晶振            :    12.0MHz

 

void InitTimer0()    //定时器0初始化

{

    ET0 = 1;

    AUXR &= 0x7f;        //定时器时钟12T模式,1us

    TMOD &= 0xF0;        //设置定时器模式

    TMOD |= 0x01;        //设置16位定时器

    TL0 = 0x00;            //设置定时器初值

    TH0 = 0x00;            //设置定时器初值

    TF0 = 0;            //清除TF0标志

    TR0 = 0;            //暂不开启定时器0计时

    PT0 = 1;            //高优先级,必须,否则在外部中断0中就不能执行定时器0是否超时溢出

}


void Timer0Interrupt(void) interrupt 1 using 1

{

    timer0Overflow = true;    //超时溢出标志

}


void InitINT0()

{

    EX0 = 1;    //打开中断0

    IT0 = 1;    //1——下降沿触发;0——低电平触发

}


void INT0Interrupt() interrupt 0 using 2

{

    UINT8 i;

    UINT8  cH, cL;

    TR0 = 1;     //定时器0开始计数

    EX0 = 0;    //关闭外部中断0的中断响应


    usedLength = 1;    //如果没有接收到有效信号,串口发送1次共4字节数据,用来跟串口收发失败的情况区分

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

    {

        while (!IR_In)

        {

            if (timer0Overflow)

            {

                usedLength = i;

                goto endfor; //65ms,超时,跳出循环

            }

        }

        TR0 = 0;

        cL = TL0;    //取定时数据

        cH = TH0;

        TL0 = 0x00;    //初始化

        TH0 = 0x00;

        timer0Overflow = false;

        TR0 = 1;     //定时器0开始计数


        waveData[4 * i + 0] = cL;

        waveData[4 * i + 1] = cH;


        while (IR_In)

        {

            if (timer0Overflow)

            {

                usedLength = i;

                goto endfor; //65ms,超时,跳出循环

            }

        }

        TR0 = 0;

        cL = TL0;    //取定时数据

        cH = TH0;

        TL0 = 0x00;    //初始化

        TH0 = 0x00;

        timer0Overflow = false;

        TR0 = 1;     //定时器0开始计数


        waveData[4 * i + 2] = cL;

        waveData[4 * i + 3] = cH;


        usedLength = i;

    }

endfor:

    TR0 = 0;    //关闭定时器0

    timer0Overflow = false;

    TL0 = 0x00;

    TH0 = 0x00;


    if (usedLength > 2)    //至少录制了一组有效数据,显示录制的数据长度

    {

        Lcd1602Clear();


        setPos(0, 0);

        writeData('L');

        writeData(':');

        writeData((usedLength + 1) * 4 / 100 + '0');

        writeData((usedLength + 1) * 4 / 10 % 10 + '0');

        writeData((usedLength + 1) * 4 % 10 + '0');

    }


    IE0 = 0;    //若接收信号过程中产生了下降沿,IE0则为1,此处需清除外部中断0的中断标志

    EX0 = 1;    //打开外部中断0的中断响应

}


按键发送数据,同时添加了一个按键做清空缓存数组用,程序如下:


void main()

{

    UINT16 n;


    InitSys();


    while (1)

    {

        Key_Send = 1;

        if ( Key_Send != 1)

        {

            DelayX10ms(1);

            Key_Send = 1;

            if (Key_Send != 1)

            {

                for (n = 0; n < usedLength; n++)

                {

                    //将波形数据串口发送到上位机

                    UartSendByte(waveData[4 * n + 0]);

                    UartSendByte(waveData[4 * n + 1]);

                    UartSendByte(waveData[4 * n + 2]);

                    UartSendByte(waveData[4 * n + 3]);

                }


                while (!Key_Send);    //等待弹起

            }

        }


        Key_Clear = 1;

        if ( Key_Clear != 1)

        {

            DelayX10ms(1);

            Key_Clear = 1;

            if (Key_Clear != 1)

            {

                //清空波形缓存数组

                for (n = 0; n < MAX_BUFFER_LENGTH; n++)

                {

                    waveData[n] = 0;

                }

                SystemReady();

                while (!Key_Send);

            }

        }

    }

}



上位机红外波形分析


录制完波形后,波形数据通过串口发送到上位机,得到类似下图的十六进制数据,进行数据处理后就可以进行分析解码了。


为方便分析,我用C#简单写了个小程序,可以很方便的绘制波形,并将每帧的2字节数据直接转换为时间长度,方便对照各种红外协议分析。如下图,该段红外信号已9220us的高电平开始,紧随一个4484us的低电平,与NEC协议中“9ms高电平+4.5ms低电平”的引导码格式相符,分析其后面的电平持续时间,可知这段红外信号为NEC格式信号。

文章来源于:电子工程世界    原文链接
本站所有转载文章系出于传递更多信息之目的,且明确注明来源,不希望被转载的媒体或个人可与我们联系,我们将立即进行删除处理。

我们与500+贴片厂合作,完美满足客户的定制需求。为品牌提供定制化的推广方案、专属产品特色页,多渠道推广,SEM/SEO精准营销以及与公众号的联合推广...详细>>

利用葫芦芯平台的卓越技术服务和新产品推广能力,原厂代理能轻松打入消费物联网(IOT)、信息与通信(ICT)、汽车及新能源汽车、工业自动化及工业物联网、装备及功率电子...详细>>

充分利用其强大的电子元器件采购流量,创新性地为这些物料提供了一个全新的窗口。我们的高效数字营销技术,不仅可以助你轻松识别与连接到需求方,更能够极大地提高“闲置物料”的处理能力,通过葫芦芯平台...详细>>

我们的目标很明确:构建一个全方位的半导体产业生态系统。成为一家全球领先的半导体互联网生态公司。目前,我们已成功打造了智能汽车、智能家居、大健康医疗、机器人和材料等五大生态领域。更为重要的是...详细>>

我们深知加工与定制类服务商的价值和重要性,因此,我们倾力为您提供最顶尖的营销资源。在我们的平台上,您可以直接接触到100万的研发工程师和采购工程师,以及10万的活跃客户群体...详细>>

凭借我们强大的专业流量和尖端的互联网数字营销技术,我们承诺为原厂提供免费的产品资料推广服务。无论是最新的资讯、技术动态还是创新产品,都可以通过我们的平台迅速传达给目标客户...详细>>

我们不止于将线索转化为潜在客户。葫芦芯平台致力于形成业务闭环,从引流、宣传到最终销售,全程跟进,确保每一个potential lead都得到妥善处理,从而大幅提高转化率。不仅如此...详细>>