【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中文讨论组: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






本文转自yefanqiu51CTO博客,原文链接:http://blog.51cto.com/yfsoft/397260,如需转载请自行联系原作者

相关文章
|
10月前
|
NoSQL Shell C语言
用GCC开发STM32,正点原子开发板的一个库函数版本例程示例
用GCC开发STM32,正点原子开发板的一个库函数版本例程示例
用GCC开发STM32,正点原子开发板的一个库函数版本例程示例
|
10月前
野火F1开发板STM32案例-外部中断(按键)使用
野火F1开发板STM32案例-外部中断(按键)使用
72 0
|
10月前
|
C语言
野火F1开发板STM32案例-MultiButton移植
野火F1开发板STM32案例-MultiButton移植
129 0
|
10月前
|
芯片
野火F1开发板STM32案例 0.96 oled综合库使用
野火F1开发板STM32案例 0.96 oled综合库使用
151 0
stm32f407探索者开发板(五)——跑马灯实验(寄存器版本)
stm32f407探索者开发板(五)——跑马灯实验(寄存器版本)
257 0
stm32f407探索者开发板(五)——跑马灯实验(寄存器版本)
|
人工智能
stm32f407探索者开发板(三)——GPIO工作原理(内部结构说明、八种输入输出分析、GPIO寄存器说明)(下)
stm32f407探索者开发板(三)——GPIO工作原理(内部结构说明、八种输入输出分析、GPIO寄存器说明)(下)
295 0
stm32f407探索者开发板(三)——GPIO工作原理(内部结构说明、八种输入输出分析、GPIO寄存器说明)(下)
|
存储 芯片
stm32f407探索者开发板(三)——GPIO工作原理(内部结构说明、八种输入输出分析、GPIO寄存器说明)(上)
stm32f407探索者开发板(三)——GPIO工作原理(内部结构说明、八种输入输出分析、GPIO寄存器说明)(上)
547 0
stm32f407探索者开发板(三)——GPIO工作原理(内部结构说明、八种输入输出分析、GPIO寄存器说明)(上)
|
开发工具
【STM32 .Net MF开发板学习-01】Hello world
我们抛弃掉所谓的模拟器,我们在真机上体验一下运行最简单的“Hello world”程序的效果。
695 0
【STM32 .Net MF开发板学习-02】GPIO测试
示例很简单,主要是按钮和LED灯的测试,红牛和EM-STM3210E的按钮和LED有所不同,所以有针对性的对二者pin都做了定义(这些信息,你可以直接看开发板相对应的原理图,很容易就可以获得相关Pin脚的定义)。
476 0
【STM32 .Net MF开发板学习-03】TinyGUI绘图示例
.Net Micro Framework官方图形库是WPF,由于目前ST Cortex-M3开发板RAM太小,最大才512K(常见是128K或256k),并且Cortex-M3的CPU主频也不太高,运行WPF图形框架显得过于重了,所以我这边推出了轻量级图形库TinyGUI
575 0