C#读写串口数据源代码

  C#串口所在命名空间:using System.IO.Ports;该类提供了同步 I/O 和事件驱动的 I/O、对管脚和中断状态的访问以及对串行驱动程序属性的访问。


        SerialPort sp = null;
        /// <summary>
        /// 打开串口
        /// </summary>
        /// <param name="protName">串口号</param>
        /// <param name="baudRate">波特率</param>
        /// <param name="dataBit">数据位</param>
        /// <param name="stopBits">停止位</param>
        /// /// <param name="parity">校验位</param>
        /// <returns></returns>
        public bool OpenCom(string protName, int baudRate, int dataBit, float stopBits, int parity)
        {
            bool flag = true;
            if (sp == null)
            {
                sp = new SerialPort();
            }
            sp.PortName = protName;//串口号
            sp.BaudRate = baudRate;//波特率
            float f = stopBits;//停止位
            if (f == 0)
            {
                sp.StopBits = StopBits.None;
            }
            else if (f == 1.5)
            {
                sp.StopBits = StopBits.OnePointFive;
            }
            else if (f == 1)
            {
                sp.StopBits = StopBits.One;
            }
            else
            {
                sp.StopBits = StopBits.Two;
            }
            sp.DataBits = dataBit;//数据位
            if (parity == 0)
            {
                sp.Parity = Parity.None;
            }
            else if (parity == 1)
            {
                sp.Parity = Parity.Odd;
            }
            else if (parity == 2)
            {
                sp.Parity = Parity.Even;
            }
            else
            {
                sp.Parity = Parity.None;
            }
            // sp.ReadTimeout = 1000;//设置超时读取时间
            // sp.WriteTimeout = 1000;//超时写入时间
            try
            {
                if (!sp.IsOpen)
                {
                    sp.Open();
                }
            }
            catch (Exception)
            {
                flag = false;
            }
            return flag;
        }
        /// <summary>
        /// 关闭端口
        /// </summary>
        /// <returns></returns>
        public bool CloseCom()
        {
            try
            {
                if (sp.IsOpen)
                {
                    sp.Close();
                }
                return true;
            }
            catch
            {
                return false;
            }
        }

  在串口的打开方法中 SerialPort类对分别用[BaudRate]、[Parity]、[DataBits]、[StopBits]属性设置通讯格式中的波特率、校验 位、数据位、停止位,其中[Parity]和[StopBits]分别是枚举类型Parity、StopBits,Parity类型中枚举了 Odd(奇)、Even(偶)、Mark、None、Space,Parity枚举了None、One、OnePointFive、Two。

  项目中遇到一个问题是,一个界面开关几次后,再次关闭,要等到很长时间才能退出,等再次打开窗口,串口类接收数据的效率明显降低。

原因:当串口正在进行大量的数据处理和页面更新的时候,如何强制关闭串口,会造成串口死掉。

解决方法:在串口方法接收数据的时候加入一个变量,先控制停止串口数据的接收,然后关闭串口,这样就不会串口死掉很长时间后才关闭的现象。

        public bool SwitchDeviceState(int StateNum)
        {
            if (sp == null)
            {
                return false;
            }
            byte[] data = new byte[8];
            data[0] = 0x55;//帧头
            data[1] = 0xAA;//帧头
            data[2] = 0x06;//帧长度
            data[3] = 0x02;//设备地址
            data[4] = 0x00;//通道号(改变设备状态时,通道号为0,表示整个设备)
            data[5] = 0x02;//命令码
            switch (StateNum)
            {
                //命令数据
                case 0: data[6] = 0x00; break;//空闲
                case 1: data[6] = 0x01; break;//循环刺激
                case 2: data[6] = 0x02; break;//肌电反馈
                case 4: data[6] = 0x04; break;//抓握采集
                case 5: data[6] = 0x05; break;//电流标定
            }
            return DataWrite(2, data);
        }
        /// <summary>
        /// 向模拟板发送数据命令 
        /// </summary>
        /// <param name="verifyIndex">开始计算校验位的位置</param>
        /// <param name="b"></param>
        /// <returns></returns>
        public bool DataWrite(int verifyIndex, byte[] b)
        {
            bool flag = true;
            try
            {
                int numAdjust = 0;
                for (; verifyIndex < b.Length - 1; verifyIndex++)
                {
                    numAdjust += Convert.ToInt32(b[verifyIndex].ToString());
                }
                if (numAdjust > 0xff)
                {
                    string strAdjust = Convert.ToString(numAdjust, 16);
                    numAdjust = Convert.ToInt32(strAdjust.Substring(strAdjust.Length - 2), 16);
                }
                b[b.Length - 1] = (byte)numAdjust;
                sp.Write(b, 0, b.Length);
            }
            catch
            {
                flag = false;
            }
            return flag;
        }

  在此方面中C++语言有比较好的封装方法,C#语言我自身没有找到之前比较好的示例,于是自己写了一些简单的方法,已经可以成功向下位机模拟板进行数据发送

  DataWrite 方法中首先由verifyIndex位开始计算校验数据,c#中先把十六进制的byte转换为Int32类型相加减,然后再转换为byte类型得到校验 位。最后使用 sp.Write(b, 0, b.Length)方法把整个byte数组发送出去,这里要注意的是发送的数据一定要使用byte[] 数组的形式,且发送的都必须时十六进制的数据,以后在接收模拟板的数据时也是一样。其中原因有待查看。

  Serial发送数据的方法有Write和WriteLine,其中WriteLine可发送字符串并在字符串末尾加入换行符。此处采用的是Write方式


3.注册对象的数据接收事件的方法(可以在串口操作类的构造函数中注册)
  SerialPort中串口数据的读取与写入有较大的不同。由于串口不知道数据何时到达,因此有两种方法可以实现串口数据的读取。
一、线程实时读串口,即 每个一段时间抓取串口缓冲区的数据;
二、事件触发方式实现。由于线程实时读串口的效率不是十分高效,因此比较好的方法是事件触发的方式。在 SerialPort类中有DataReceived事件,当串口的读缓存有数据到达时则触发DataReceived事件,其中 SerialPort.ReceivedBytesThreshold属性决定了当串口读缓存中数据多少个时才触发DataReceived事件,默认为 1。

 sp.DataReceived += new SerialDataReceivedEventHandler(sp_DataReceived);
            sp.ReceivedBytesThreshold = 1;//事件发生前内部输入缓冲区的字节数,每当缓冲区的字节达到此设定的值,就会触发对象的数据接收事件

 

        void sp_DataReceived(object sender, SerialDataReceivedEventArgs e)
        {
            byte[] Resoursedata = new byte[sp.BytesToRead];
            sp.Read(Resoursedata, 0, Resoursedata.Length);//在此就可以读取到当前缓冲区内的数据
            //执行数据操作
            sp.DiscardInBuffer();//丢弃传输缓冲区数据
            sp.DiscardOutBuffer();//每次丢弃接收缓冲区的数据
        }

  首先SerialPort类读取数据的方法有多种,但是有的读是同步,有的是异步,同步就是和主程序保持一致,只有运行完了ReadByte之后才能运行程序之后的代码,异步就是重新开启一个线程来处理这些问题,主程序不受到干扰,继续运行。

  serialPort中有6个读的方法:

  1. Read();
  2. ReadLine();
  3. ReadByte();
  4. ReadChar();
  5. ReadExisting();
  6. ReadTo();

  ReadTo和ReadExisting是异步读取,剩下的都是同步读取。


  我在程序测试中使用ReadTo和ReadExisting获取缓冲区的数据,由于这两个方法的接收类型都是String类型,并且显示出来都是一些编码 混乱的字符,需要进一步编码格式转换。因此此处选择的是Read同步读取数据,接收数据的类型是一个byte数据,接下来更容易对数据进行下一步的处理和 操作。如何考虑系统运行效率的问题(在没秒钟内模拟板可能向上位机发送非常庞大的数据量),可以考虑在开一个线程来控制模拟板数据的读取,然后仍然使用 Read方法进行数据的读取。

来源:http://www.cnblogs.com/eye-like/p/3546501.html

评论(0)网络
阅读(273)喜欢(0)不喜欢(0)Asp.Net/C#