• 【STM32 .Net MF开发板学习14】红外遥控器编码识别


     一年前我写过一篇博文《自制电脑红外遥控接收器(PC软解码)》,文中介绍借助几个简单的器件通过PC串口,来获取红外遥控器的按键信息。现在我们已经学会了如何用PWM技术驱动智能小车(参见《PWM驱动智能小车),正好缺少一个遥控机制,所以本篇文章先介绍一下,.NET Micro Framework开发板如何获取红外遥控信息,下一篇文章将介绍用遥控器驱动智能小车相关实现细节。

        这次我们红外接收的硬件电路更为简单,仅需红外接收头、两个电阻,一个电容即可,其原理图如下:   

      

         我所选取的具体器件型号如下:

     1100欧电阻

    218K欧电阻

    3、电容1040.1uF

    4HS0038A红外接收头

        5、电压接入3.3v

        实际的器件连接图如下:   

            

         以上是红外接收部分,至于红外发送,我想每个家庭基本上都会有电视遥控器(此外还有机顶盒遥控器,DVD遥控器、空调遥控器等等),我的想法是红外接收设备可以接收任何红外遥控器发出的按键信息,这样用户就不需要再采购相关的遥控器设备了。   

     但是非常困难的是,电视遥控器厂家不同,型号各异,其红外遥控编码更是千差万别,如果一一对其解码,不仅工作量巨大,并且实际操作上不甚可能,因为短时间内也无法获取这些遥控器进行解码测试。

    遥控器所发送的功能指令码一般采用多位二进制串行码,其编码规律为:头脉冲、系统码、资料码、资料反码和结束位。头脉冲用做一帧命令的起始位;系统码用于区别不同类的电器;资料码用于完成命令功能。不过这仅仅是一般规律,对有些遥控器适用,对另一类就不适用。

    所以综上,我还是借鉴了我一年前所写的那篇文章中的思想,采集红外遥控器的按键特征(高低电平持续时间的集合)来识别红外遥控器按键,这样就绕过了对红外遥控器进行解码的难点,程序只需要比对按键特征就可以识别红外按键(需要预先采集并存储按键特征)。

    红外信号采集的底层代码如下:

    void IR_GPIO_ISR( GPIO_PIN Pin, BOOL PinState, void* Param )

    {

         if(!IR_RunFlag)

         {

            IR_RunFlag = TRUE;

                IR_Count = 0;

                IR_DataCount=0;

                IR_Index = 0;

                IR_Time[IR_Index]=0;

                IR_PinState = CPU_GPIO_GetPinState(IR_Pin);       

                CPU_TIMER_Start(IR_Timer);

         }

    }

    void IR_TIMER_ISR(void* param)

    {

     if(++IR_Time[IR_Index]>100 || IR_Index>250)

     {

        CPU_TIMER_Stop(IR_Timer);   

             IR_RunFlag=FALSE; 

             IR_Count = IR_Index;

             if(IR_DataCount==0)

        {

           memcpy(IR_TimeData,IR_Time,IR_Count);

                //GenerateEvent(0xF1,IR_Count); //产生事件

                IR_DataCount=IR_Count;

        }

             return;

     }   

     if(IR_PinState != CPU_GPIO_GetPinState(IR_Pin))

     {

          IR_PinState=!IR_PinState;

          IR_Time[++IR_Index]=0;

     }

    }

    INT8 IRController::Initialize( UINT8 param0, INT32 param1, HRESULT &hr )

    {

        if(param0>7 || IR_Pin<0) return -1;

        IR_Timer = param0;

        IR_Pin = (GPIO_PIN)param1; 

        CPU_GPIO_EnableInputPin(IR_Pin, TRUE, IR_GPIO_ISR, GPIO_INT_EDGE_LOW, RESISTOR_PULLUP);

        //36M 100us

        CPU_TIMER_Initialize(IR_Timer,360,9,IR_TIMER_ISR,NULL);      

        return 0;

    }

    INT8 IRController::Uninitialize( UINT8 param0, INT32 param1, HRESULT &hr )

    {

         CPU_TIMER_Stop(IR_Timer);       

         CPU_GPIO_DisablePin(IR_Pin,RESISTOR_DISABLED,FALSE,GPIO_ALT_MODE_0);

        return 0;

    }

    INT32 IRController::GetData( CLR_RT_TypedArray_UINT8 param0, INT32 param1, HRESULT &hr )

    {

        if(param1>250 || param1>param0.GetSize()) return -1;

        for(int i=0;i<param1;i++)

        {

           param0.SetValue(i,IR_TimeData[i]);

        }

             IR_DataCount = 0;

        return 0;

    }

    INT32 IRController::GetCount( HRESULT &hr )

    {

        return IR_DataCount;

    }

    其托管代码封装接口如下:

        public sealed class IRController

        {

            public IRController(byte timer, int pin);

            public event IRController.IREventHandler IREvent;

            public delegate void IREventHandler(byte[] buff, DateTime time);

    }

    其接口非常简单,声明类时填入的参数,第一个是timer,定时器号(0~7),第二个就是红外接收头输出管脚所接的开发板主芯片Pin脚。

    此外就是一个接收事件,一旦接收到红外数据,则通过这个事件输送给用户程序。

    为了便于识别相关按键,我在用户程序中提供了一个键识别类,用户只需要填入相关按键的识别码(也就是IREvent事件所提供的红外数据),既可以判断出按键名称。需要注意的是,有些遥控器奇数次和偶数次按键其输出的编码不同。

    public class IRData

        {

            //按键数据

            static byte[] bytForward0 = new byte[] { 18, 18, 18, 17, 37, 16, 18, 18, 18, 17, 18, 18, 17, 36, 36, 17, 18, 17, 19, 17, 18, 17, 19 };

            static byte[] bytForward1 = new byte[] { 18, 18, 36, 17, 18, 17, 18, 18, 17, 18, 18, 18, 17, 36, 35, 18, 18, 17, 18, 18, 18, 17, 18 };

            static byte[] bytLeft0 = new byte[] { 18, 18, 17, 18, 37, 16, 19, 17, 18, 17, 19, 17, 18, 17, 18, 36, 36, 16, 19, 17, 18, 36, 17 };

            static byte[] bytLeft1 = new byte[] { 19, 17, 36, 17, 18, 17, 19, 17, 18, 17, 19, 17, 18, 17, 18, 35, 37, 16, 19, 17, 18, 35, 18 };

            static byte[] bytRight0 = new byte[] { 18, 18, 17, 18, 37, 16, 18, 18, 18, 17, 18, 18, 17, 18, 18, 36, 36, 16, 19, 17, 17, 18, 18 };

            static byte[] bytRight1 = new byte[] { 18, 18, 36, 17, 18, 17, 18, 18, 18, 17, 18, 18, 17, 18, 18, 36, 36, 16, 18, 18, 18, 17, 18 };

            static byte[] bytStop0 = new byte[] { 18, 18, 17, 18, 37, 16, 18, 18, 18, 17, 18, 18, 17, 18, 18, 18, 18, 35, 17, 18, 37, 34, 18 };

            static byte[] bytStop1 = new byte[] { 18, 18, 36, 17, 18, 17, 18, 18, 17, 18, 18, 18, 17, 18, 18, 18, 17, 36, 17, 18, 37, 34, 18 };

            static byte[] bytBack0 = new byte[] { 18, 18, 18, 17, 37, 16, 19, 17, 18, 17, 19, 17, 18, 35, 36, 17, 18, 17, 19, 17, 18, 35, 18 };

            static byte[] bytBack1 = new byte[] { 18, 18, 36, 17, 18, 17, 19, 17, 18, 17, 18, 18, 18, 35, 36, 17, 18, 17, 19, 17, 18, 35, 18 };

            public enum Key

            {

                None = 0,

                Forward,

                Left,

                Right,

                Back,

                Stop,

            };

            //检测按键数据

            private static bool CheckData(byte[] data, byte[] flag, int count)

            {

                if (data.Length != flag.Length || data.Length != count) return false;

                for (int i = 0; i < count; i++)

                {

                    if (System.Math.Abs(data[i] - flag[i]) > 3) return false;

                }

                return true;

            }

            //检测遥控器按键

            public static Key GetKey(byte[] buff)

            {

                if (CheckData(buff, bytForward0, bytForward0.Length)) return Key.Forward;

                if (CheckData(buff, bytForward1, bytForward1.Length)) return Key.Forward;

                if (CheckData(buff, bytLeft0, bytLeft0.Length)) return Key.Left;

                if (CheckData(buff, bytLeft1, bytLeft1.Length)) return Key.Left;

                if (CheckData(buff, bytRight0, bytRight0.Length)) return Key.Right;

                if (CheckData(buff, bytRight1, bytRight1.Length)) return Key.Right;

                if (CheckData(buff, bytBack0, bytBack0.Length)) return Key.Back;

                if (CheckData(buff, bytBack1, bytBack1.Length)) return Key.Back;

                if (CheckData(buff, bytStop0, bytStop0.Length)) return Key.Stop;

                if (CheckData(buff, bytStop1, bytStop1.Length)) return Key.Stop;

                return Key.None;

            }

     }

    示例中所用的遥控器是Philips的一款,其编码较短,仅23个,而其它遥控器一般都有60多个数据。

    IRController的具体使用示例如下:

    public static void Main()

            {

                IRController IR = new IRController(3, (int)GPIO_NAMES.PB12);

                IR.IREvent += new IRController.IREventHandler(IR_Click);               

                while (true)

                {

                    Thread.Sleep(1000);

                }

            }     

            static void IR_Click(byte[] buff, DateTime time)

            {

                IRData.Key key = IRData.GetKey(buff);

                if (key != IRData.Key.None)

                {

                    string KeyName = "";

                    switch (key)

                    {

                        case IRData.Key.Forward:

                            KeyName = "Forward";

                            break;

                        case IRData.Key.Left:

                            KeyName = "Left";

                            break;

                        case IRData.Key.Right:

                            KeyName = "Right";

                            break;

                        case IRData.Key.Back:

                            KeyName = "Back";

                            break;

                        case IRData.Key.Stop:

                            KeyName = "Stop";

                            break;

                    }        

                    Debug.Print(KeyName);

                }

                else

                {

                    //打印按键数据

                    string Info = "";

                    for (int i = 0; i < buff.Length; i++)

                    {

                        Info += buff[i].ToString() + ",";

                    }

                    Debug.Print("[" + buff.Length.ToString() + "]" + Info);

                }

       }

    程序编译部署后,按红外遥控器按键,开发板在超级终端的输出如下图所示(已经输入按键标识的按键,按键后其输出信息就是按键名了):

         好了,我们已经可以成功接收红外信号了,并且可以正确识别我们标定的按键了,这样我们就可以驱动智能小车前后左右移动了,相关内容敬请关注下篇博文。

         文中相关器件:

    http://item.taobao.com/auction/item_detail.htm?item_num_id=7660457192

     

    注:需要红牛开发板固件在 V1.0.0以上

    本文源码:http://www.sky-walker.com.cn/yefan/MFV40/SourceCode/IRTest.rar

    MF快速参考: .NET Micro Framework 快速入门

    MF中文讨论组:http://space.cnblogs.com/group/MFSoft/

    微软官方论坛:MSDN微软中文技术论坛(.NET Micro Framework)

    开发板简明手册:http://blog.sina.com.cn/s/blog_6b938f630100kh0k.html

    【低价开发板】http://item.taobao.com/item.htm?id=7117999726
  • 相关阅读:
    网络分析(二)定向与非定向
    Flex 找不到html文件,不能自动生成html问题解决
    常用的功能点记录
    git常规操作命令整理
    语境驱动测试7原则
    探索式测试的问与答
    测试建模:Google ACC
    探索式测试:基于测程的测试管理(SessionBased Test Management)
    用Excel展示SQL Server中的数据 (III): IronPython与自动化
    在Ajax中使用Flash实现跨域数据读取
  • 原文地址:https://www.cnblogs.com/yefanqiu/p/1834924.html
Copyright © 2020-2023  润新知