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

C#串口通信—向串口发送数据,同步接收返回数据

2019-11-17 02:37:45
字体:
来源:转载
供稿:网友

C#串口通信—向串口发送数据,同步接收返回数据

最近写C#串口通信程序,系统是B/S架构。SerialPort类有一个DataReceived事件,用来接收串口返回的数据,但这种方式在C/S架构下很好用,但B/S就不好处理了。所以写了一个同步模式接收返回数据的方法,不使用DataReceived事件。经过测试,可以正常使用。

一、MachineFactory类

为什么使用工厂类:售货机由不止一个厂家提供,接口协议都不一样。

using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.Reflection;using System.IO;using System.IO.Ports;namespace IMachineDll{    /// <summary>    /// 售货机工厂类    /// </summary>    public class MachineFactory    {        /// <summary>        /// 货机接口缓存        /// </summary>        PRivate static Dictionary<string, IMachine> dicMachine = new Dictionary<string, IMachine>();        /// <summary>        /// 锁变量        /// </summary>        public static object _lock = new object();        /// <summary>        /// 创建售货机类        /// </summary>        /// <param name="path">DLL物理路径</param>        /// <param name="dllName">DLL名称(不含扩展名),命名空间必须为DLL名称加“Dll”后缀,类名必须和DLL名称相同</param>        ///  <param name="com">串口名称,如:COM1</param>        public static IMachine Create(string path, string dllName, string com)        {            if (!dicMachine.ContainsKey(dllName)                || dicMachine[dllName] == null)            {                using (FileStream fs = new FileStream(path + dllName + ".dll", FileMode.Open, Fileaccess.Read))                {                    using (MemoryStream ms = new MemoryStream())                    {                        byte[] byteArray = new byte[4096];                        while (fs.Read(byteArray, 0, byteArray.Length) > 0)                        {                            ms.Write(byteArray, 0, byteArray.Length);                        }                        Assembly assembly = Assembly.Load(ms.ToArray());                        dicMachine[dllName] = (IMachine)assembly.CreateInstance(dllName + "Dll." + dllName, false, BindingFlags.Default, null, new object[] { com }, null, null);                    }                }            }            return dicMachine[dllName];        }    }}
View Code

二、Machine类

1、变量与构造函数

/// <summary>/// 串口资源/// </summary>private SerialPort serialPort = null;public Machine(string com){    serialPort = new SerialPort(com, 9600, Parity.None, 8, StopBits.One);    serialPort.ReadBufferSize = 1024;    serialPort.WriteBufferSize = 1024;}
View Code

2、向串口发送数据,同步接收返回数据的方法:

/// <summary>/// 向串口发送数据,读取返回数据/// </summary>/// <param name="sendData">发送的数据</param>/// <returns>返回的数据</returns>private byte[] ReadPort(byte[] sendData){    lock (MachineFactory._lock)    {        //打开连接        if (!serialPort.IsOpen) serialPort.Open();        //发送数据        serialPort.Write(sendData, 0, sendData.Length);        //读取返回数据        DateTime dt = DateTime.Now;        while (serialPort.BytesToRead == 0)        {            Thread.Sleep(1);            if (DateTime.Now.Subtract(dt).TotalMilliseconds > 5000) //如果5秒后仍然无数据返回,则视为超时            {                throw new Exception("主版无响应");            }        }        Thread.Sleep(50);        byte[] recData = new byte[serialPort.BytesToRead];        serialPort.Read(recData, 0, recData.Length);        //关闭连接        if (serialPort.IsOpen) serialPort.Close();        return recData;    }}
View Code

优化版:

/// <summary>/// 向串口发送数据,读取返回数据/// </summary>/// <param name="sendData">发送的数据</param>/// <returns>返回的数据</returns>private byte[] ReadPort(byte[] sendData){    lock (MachineFactory._lock)    {        //打开连接        if (!serialPort.IsOpen) serialPort.Open();        //发送数据        serialPort.Write(sendData, 0, sendData.Length);        //读取返回数据        DateTime dt = DateTime.Now;        while (serialPort.BytesToRead < 2)        {            Thread.Sleep(1);            if (DateTime.Now.Subtract(dt).TotalMilliseconds > 5000) //如果5秒后仍然无数据返回,则视为超时            {                throw new Exception("主版无响应");            }        }        List<byte> recList = new List<byte>();        byte[] recData = new byte[serialPort.BytesToRead];        serialPort.Read(recData, 0, recData.Length);        recList.AddRange(recData);        int length = recData[1] + 3; //报文数据总长度        while (recList.Count < length)        {            if (serialPort.BytesToRead > 0)            {                recData = new byte[serialPort.BytesToRead];                serialPort.Read(recData, 0, recData.Length);                recList.AddRange(recData);            }            Thread.Sleep(1);        }        //关闭连接        if (serialPort.IsOpen) serialPort.Close();        return recList.ToArray();    }}
View Code

3、发送联机指令:

/// <summary>/// 联机/// </summary>/// <param name="msg">传出错误信息</param>/// <returns>联机是否成功</returns>public bool Connect(out string msg){    byte[] sendData = new byte[] { 0x01, 0x01, 0x00, 0x00 };    CommonUtil.CalCheckCode(sendData);    byte[] recData = ReadPort(sendData);    if (recData.Length >= 4        && recData[0] == 0x01        && recData[1] == 0x02        && recData[2] == 0x00        && CommonUtil.ValidCheckCode(recData))    {        switch (recData[3])        {            case 0x00:                msg = "控制主板正在重启";                return false;            case 0x01:                msg = "联机成功";                return true;            case 0x02:                msg = "控制主板正在维护";                return false;            case 0x03:                msg = "控制主板收到的数据格式不正确";                return false;            default:                msg = "未知状态";                return false;        }    }    else if (IsRunning(recData, out msg) || !IsConnected(recData, out msg))    {        return false;    }    else    {        throw new Exception("货机返回的数据格式不正确");    }}
View Code

三、如何使用

1、Controller层代码(还不完善,仅测试,真实情况是根据硬件信息,确定调用哪个Dll使用哪个串口):

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