最近写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];}}
}

二、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;
}

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;}
}

优化版:

/// <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();}
}

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("货机返回的数据格式不正确");}
}

三、如何使用

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

#region 创建售货机接口
/// <summary>
/// 创建售货机接口
/// </summary>
private IMachine CreateMachine()
{//return MachineFactory.Create(Request.PhysicalApplicationPath + @"\bin\", "Machine", "COM1");return MachineFactory.Create(@"D:\售药机代码\Reception\Machine\bin\Debug\", "Machine", "COM1");
}
#endregion#region 联机
/// <summary>
/// 联机
/// </summary>
/// <param name="msg">错误信息</param>
/// <returns>联机是否成功</returns>
private bool Connect(out string msg)
{try{IMachine machine = CreateMachine();DateTime dt1 = DateTime.Now;while (!machine.Connect(out msg))  //联机{if (DateTime.Now.Subtract(dt1).TotalMilliseconds > 20000){msg = "联机超时";return false;}Thread.Sleep(50);}return true;}catch (Exception ex){msg = ex.Message;return false;}
}
#endregion#region 单次联机
/// <summary>
/// 单次联机
/// </summary>
public ActionResult Conn()
{string msg = null;Dictionary<string, object> dic = null;try{IMachine machine = CreateMachine();if (machine.Connect(out msg)) //联机成功{dic = new Dictionary<string, object>();dic["ok"] = true;dic["msg"] = "成功";return Content(JsonConvert.SerializeObject(dic));}else{dic = new Dictionary<string, object>();dic["ok"] = false;dic["msg"] = "联机失败:" + msg;return Content(JsonConvert.SerializeObject(dic));}}catch (Exception ex){dic = new Dictionary<string, object>();dic["ok"] = false;dic["msg"] = "错误:" + ex.Message;return Content(JsonConvert.SerializeObject(dic));}
}
#endregion#region 联机并使能硬纸币器
/// <summary>
/// 联机并使能硬纸币器
/// </summary>
public ActionResult ConnectEnable()
{string msg = null;Dictionary<string, object> dic = null;try{IMachine machine = CreateMachine();if (Connect(out msg) && machine.CoinEnable(out msg) && machine.PaperMoneyEnable(out msg)) //联机并使能硬纸币器成功{dic = new Dictionary<string, object>();dic["ok"] = true;dic["msg"] = "成功";return Content(JsonConvert.SerializeObject(dic));}else{dic = new Dictionary<string, object>();dic["ok"] = false;dic["msg"] = "硬币器使能失败:" + msg;return Content(JsonConvert.SerializeObject(dic));}}catch (Exception ex){dic = new Dictionary<string, object>();dic["ok"] = false;dic["msg"] = "错误:" + ex.Message;return Content(JsonConvert.SerializeObject(dic));}
}
#endregion

2、前台代码:

@{ViewBag.Title = "货机接口测试";Layout = null;
}<!DOCTYPE html>
<html>
<head><title>@ViewBag.Title</title><script type="text/javascript" src="~/Scripts/jquery-1.8.2.min.js"></script><script type="text/javascript" src="~/Scripts/LongPolling.js"></script>
</head>
<body><div style="padding: 20px;"><input type="button" value="联机" onclick="connect()" /><div style="font-size: 20px; line-height: 30px;"><div style="padding: 20px;"><span id="msg"> </span></div></div></div>
</body>
</html>
<script type="text/javascript">//联机function connect() {commonAjax({url: "@Url.Content("/MachineInterface/Conn")",callback: function (data) {if (data.ok) {var html = "联机成功";$("#msg").html(html);}else {alert(data.msg);}}});}
</script>

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

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

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

  2. MFC串口通信设置及发送、中断接收程序

    前一段做了个串口通信小软件,就是现实利用上位机软件通过串口通信对下位机(单片机)通信,校时LED点阵万年历,省去按键调节的麻烦,方便校时,省时省力. 为右击 串口通信控件,添加关联控件变量CMSCom ...

  3. linux串口发送键值,c51:串口通信,按键发送字符串

    原标题:c51:串口通信,按键发送字符串 一.程序功能 1.实现0-f的16位键盘输入功能,将键值由P1口输出. 2.不同的键值串口发送不同的 二.代码 //函数功能 //1.实现0~f的16位键盘功 ...

  4. android qt 串口通信,Qt串口通信开发之QSerialPort模块详细使用方法与实例

    Qt串口通信开发之QSerialPort模块详细使用方法与实例 发布时间:2020-10-23 12:19:05 来源:脚本之家 阅读:111 作者:沧海一笑-dj Qt串口通信基础及名词说明 串口通 ...

  5. 树莓派串口通信 USB串口通信 常用串口命令

    树莓派串口通信 USB串口通信 文章目录 树莓派串口通信 USB串口通信 准备 发送数据 接收数据 如果不知道树莓派怎么使用USB串口通信的,欢迎浏览我的另一篇博客文章: 树莓派使用USB串口通信 C ...

  6. Java串口通信读写串口导致程序崩溃问题

    最近心血来潮想用java实现与下位机的串口通讯,下位机使用STM32等间隔向串口发送八位的数据,上位机主要实现数据的接收和发送.过程中遇到的问题为:一旦执行到输入输出流对串口进行读写操作时,程序直接崩 ...

  7. 串口通信及串口转蓝牙相关知识

    之前没有接触过硬件相关的工作, 因此对硬件的知识一知半解. 最近由于项目需要, 用到了串口通信以及串口跟蓝牙之间通信相关的东西.记录下来, 希望对新手有所帮助. 如有疏漏之处, 欢迎指正. 1 串口通 ...

  8. 树莓派已经通过网络连接通过串口通信在串口调试小助手打印与操作

    在树莓派编译运行 树莓派已经通过网络连接通过串口通信在串口调试小助手打印C gcc xxx.c -lwiringPi 源码 #include <wiringSerial.h> #inclu ...

  9. 单片机第13课:串口通信---向计算机发送数据

    JP3接P0口. #include<reg51.h> #define uchar unsigned char uchar flag,num; // void initSer(); void ...

最新文章

  1. 根据PI/4 = 1 - 1/3 +1/5-1/7+1/9求圆周率
  2. github上的Lua in Erlang
  3. hdu1526 二分匹配+ floyd
  4. (SQLlite3 Source Code 系列之一) 前言
  5. android中给button加图标,Android,如何在我的代码中的TabButton中添加图标
  6. 信息奥赛一本通(1310:【例2.2】车厢重组)
  7. 移动端安卓IOS系统判断,用js判断 iPhone6 iPhone6 plus iphonex?
  8. tensorflow:图(Graph)的核心数据结构与通用函数(Utility function)
  9. python snap7开发手册_python-snap7开发笔记
  10. 流畅的python mobi 百度云_流畅的python【中文版】mobi下载
  11. python pandas合并多个excel,Python pandas实现excel工作表合并功能详解
  12. jqGrid设置三级表头和表头合并
  13. 光缆接续盒图标_光缆线路施工技术(超全)
  14. 创建区块计算次数_区块链计算的四个阶段
  15. PTA 1075 链表元素分类
  16. 博客园技术系列文章目录
  17. 计算机科学职业位置,计算机专业的职业生涯规划范文
  18. 安超云生态|携手中电福富 打造党政协同一体化云办公解决方案
  19. “人文素养老师”——马小平老师
  20. 花开云(织音)同款超级好看404页面源码

热门文章

  1. 无线联网功能硬件模块无法拆除的计算机禁止,2021年保密知识竞赛抢答题库及答案(共120题).docx...
  2. dump文件的创建及使用
  3. includes方法
  4. 【渝粤教育】国家开放大学2018年秋季 1013t金融统计分析 参考试题
  5. 批量查找替换excel单元格中的软回车(alt + enter)
  6. Configure交叉编译
  7. 下载xshell xftp
  8. 苹果屏和android屏哪个更真实,同是LCD屏,为什么iPhone的实际体验比安卓好许多...
  9. TopK推荐的评价指标
  10. “没有40K当什么程序员?”