【STM32 Net MF開發板學習-14】紅外遙控器編碼識別
分享一下我老師大神的人工智慧教程!零基礎,通俗易懂!http://blog.csdn.net/jiangjunshow
也歡迎大家轉載本篇文章。分享知識,造福人民,實現我們中華民族偉大復興!
一年前我寫過一篇博文《自制電腦紅外遙控接收器(PC軟解碼)》,文中介紹藉助幾個簡單的器件通過PC串列埠,來獲取紅外遙控器的按鍵資訊。現在我們已經學會了如何用PWM技術驅動智慧小車
這次我們紅外接收的硬體電路更為簡單,僅需紅外接收頭、兩個電阻,一個電容即可,其原理圖如下:
我所選取的具體器件型號如下:
1、100歐電阻
2、18K歐電阻
3、電容104(0.1uF)
4、HS0038A紅外接收頭
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