C#实现在PC端读取红外线遥控器信号

王朝学院·作者佚名  2009-04-16
窄屏简体版  字體: 小  |  中  |  大  |  超大  

这几天要完成个任务,就是利用一个红外线适配器接受红外线遥控器的信号,在PC上读取信号,并判断按的是哪个键,因为整个项目的需要,要求用C#实现。

首先,需要一个红外线适配器(废话~),因为我是用本本开发的,而我的本本没有串口,所以就用了一个USB的红外线适配器,这里需要一个USB转串口的驱动,网上搜一下就有了,CSDN的下载里也有朋友上传。

驱动装上之后,就可以进行开发了。.net 为我们提供了一个串口类(有且仅有一个~~),就是SerialPort类,在名称空间System.IO.Ports里。要实例化一个SerialPort类,我们必须知道串口的名字,使用方法System.IO.Ports.SerialPort.GetPortNames()可以获得当前电脑可用的串口,如果计算机上有多个串口,计算机很难判断哪个串口是用来接受红外线数据的,因此只能由用户决定,这里我们可以用一个comboBox将可用串口列出来,供用户选择

view plaincopy to clipboardprint?

string[] ports = System.IO.Ports.SerialPort.GetPortNames();

foreach (string port in ports)

{

combComName.Items.Add(port);

}

string[] ports = System.IO.Ports.SerialPort.GetPortNames();

foreach (string port in ports)

{

combComName.Items.Add(port);

}

用户选择完之后就可以通过构造方法实例化一个SerialPort对象了。对于一般的红外线遥控器,使用以下的参数就可以了。

view plaincopy to clipboardprint?

port = new SerialPort( combComName.SelectedItem.ToString() , 9600, Parity.None, 8, StopBits.One);

port.Open();

port = new SerialPort( combComName.SelectedItem.ToString() , 9600, Parity.None, 8, StopBits.One);

port.Open();

打开串口之后,我们就可以读取串口信号了。这里我们使用read方法。由于一条按键信号一般为32位,这里我们就只接收32位数据了。

view plaincopy to clipboardprint?

byte[] buffer = new byte[36];

System.Threading.Thread.Sleep(100);

port.Read(buffer, 0, 36);

byte[] buffer = new byte[36];

System.Threading.Thread.Sleep(100);

port.Read(buffer, 0, 36);

接下来是要把byte转化成为16进制代码。可以写一个函数

view plaincopy to clipboardprint?

private string BytesToHexString(byte[] buffer, int offset, int length)

{

string info = "";

for (int i = offset; i < offset + length; i++)

{

info += string.Format("{0:X} ", buffer[i]).Trim();

}

return info;

}

private string BytesToHexString(byte[] buffer, int offset, int length)

{

string info = "";

for (int i = offset; i < offset + length; i++)

{

info += string.Format("{0:X} ", buffer[i]).Trim();

}

return info;

}

好的,现在如果我们用上述方法把接收到的信号显示出来,应该是类似于这样的:

00FEFCFEFEFCFEFEFC0000000000000000FCFCFCFC00F8F8F000000000F00000

而且即使是同一个按键,有时候编码还会有不一样的。

对于一般的红外遥控器来说,不可能会是这么长的编码的,例如NEC的编码规则就是:用户识别码(8位)+ 用户识别码反码(8位)+ 数据码(8位)+ 数据码反码(8位)。经过一番研究,将上述编码按字节分开:

00 FE FC FE FE FC FE FE FC 00 00 00 00 00 00 00 00 FC FC FC FC 00 F8 F8 F0 00 00 00 00 F0 00 00 00 00 00 00

如果把00当做0,把FE、FC这些当做1,改写一下:

0 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 1 1 1 1 0 1 1 1 0 0 0 0 1 0 0

再把这些0、1代码8位分成一组,末尾多余的0去掉,转化为16进制:

7F807B84

哈哈,看到这里应该清楚了吧,经过这样一番转换的信号完全符合NEC的编码规则,而我使用的遥控器确实就是采用了NEC的芯片的。

回头分析一下,我猜想产生这样情况的原因可能是和串口设置的波特率有关,因为我们我们不知道红外遥控器的频率,不知道一个脉冲式多少时间,因此在较高波特率的情况下,0信号变成了多个0,1信号变成了多个1,至于为什么会有FC、FE这样不一样的编码,我猜想应该是因为一个脉冲的末尾电压不稳定造成的。

知道了这些,接下来的事情就简单了,写个函数转化一下就可以了,下面我附上源码。具体实现的时候我用到了DataReceived事件对串口数据进行监听,这样只要遥控器有信号过来就可以显示了。

view plaincopy to clipboardprint?

using System;

using System.Collections.Generic;

using System.ComponentModel;

using System.Data;

using System.Drawing;

using System.Linq;

using System.Text;

using System.Windows.Forms;

using System.IO.Ports;

namespace testseral

{

public partial class Form1 : Form

{

private SerialPort port;

private const int CodeLength = 32;

delegate void SetInfo(string info);

public Form1()

{

InitializeComponent();

}

private void button1_Click(object sender, EventArgs e)

{

//初始化并打开串口

port = new SerialPort( combComName.SelectedItem.ToString() , 9600, Parity.None, 8, StopBits.One);

port.Open();

//监听串口数据

port.DataReceived += new SerialDataReceivedEventHandler(port_DataReceived);

btOpen.Enabled = false;

btClose.Enabled = true;

}

private void button2_Click(object sender, EventArgs e)

{

port.Close();

btOpen.Enabled = true;

btClose.Enabled = false;

}

void port_DataReceived(object sender, SerialDataReceivedEventArgs e)

{

byte[] buffer = new byte[CodeLength];

System.Threading.Thread.Sleep(100);

int length = port.Read(buffer, 0, CodeLength);

if (length < CodeLength)

return;

this.Invoke(new SetInfo(DataReceived), BytesToHexString(buffer, 0, length));

}

private string BytesToHexString(byte[] buffer, int offset, int length)

{

string info = "";

for (int i = offset; i < offset + length; i++)

{

info += string.Format("{0:X2} ", buffer[i]).Trim();

}

return info;

}

protected void DataReceived(string info)

{

rtbSerialInfo.Text += SignalToHexCode( info );

}

//将原始的二进制信号转化为二进制编码

private string SignalToBinaryCode(string Signal)

{

if (string.IsNullOrEmpty(Signal))

{

return null;

}

else

{

string Code = "";

for (int i = 0; i < CodeLength*2; i = i + 2)

{

if (Signal.Substring(i,1).Equals( "0") )

{

Code = Code + "0";

}

else

{

Code = Code + "1";

}

}

return Code;

}

}

//将二进制编码转化为16进制编码

private string SignalToHexCode(string Signal)

{

Signal = SignalToBinaryCode(Signal);

if (!string.IsNullOrEmpty(Signal))

{

string HexCode = "";

string HexCodePiece = "";

for (int i = 0; i < CodeLength; i = i + 4)

{

HexCodePiece = Signal.Substring(i, 4);

HexCode = HexCode + Convert.ToString(Convert.ToInt32(HexCodePiece, 2), 16);

}

return HexCode;

}

else

return null;

}

private void comboBox1_DropDown(object sender, EventArgs e)

{

//获得所有串口

combComName.Items.Clear();

string[] ports = System.IO.Ports.SerialPort.GetPortNames();

foreach (string port in ports)

{

combComName.Items.Add(port);

}

}

}

}

 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
 
© 2005- 王朝網路 版權所有 導航