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


    前言

      最近学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的中断响应
    }
    View Code

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

    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);
                }
            }
        }
    }
    View Code

     

    上位机红外波形分析

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

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

    上位机程序及源码下载

     

     欢迎关注本人的个人博客YoungCoding.top

  • 相关阅读:
    Nginx介绍
    linux vi编辑
    MySql数据类型
    Mysql用户权限控制(5.7以上版本)
    Linux上安装MySQL
    Java得到指定日期的时间
    Spring Boot 整合Redis 实现缓存
    编写高效优雅Java程序
    JVM调优和深入了解性能优化
    JVM执行子程序
  • 原文地址:https://www.cnblogs.com/ToddleLobster/p/5873629.html
Copyright © 2020-2023  润新知