首页 > 学院 > 开发设计 > 正文

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

2019-11-17 04:16:46
字体:
来源:转载
供稿:网友

这几天要完成个任务,就是利用一个红外线适配器接受红外线遥控器的信号,在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);  
            }  
        }  
    }  
}

 


发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表