工作中,LIS系统经常需要开发接口与仪器或流水线对接,串口通讯应该是最常见的几种通讯方式之一了。
至于串口是什么、串口通讯又是什么,这些基本概念就不多做介绍了。
这里就针对于我在串口开发中碰到过的一些问题,做一个简单的分享。
串口模拟
无论是开发还是测试,肯定都离不开串口的模拟测试,我们不大可能直接在电脑上安装两个串口,所以模拟串口就是最优解了,从网上可以很轻松的搜索到模拟串口的软件。
这里我建议使用Virtual Serial Port Driver
,大家可以搜索VSPD
下载:

安装什么的就不过多解释了,安装完成后我们可以打开并添加模拟串口或者删除模拟的串口,界面如下:

如果对应的串口被使用,也可以从这里看出其串口的状态:

当然我们可以在我们的电脑中查看现有的串口,设备管理器中可以查看:

串口调试工具
串口调试工具就是用于串口数据接收/发送的工具软件,比较简单易用的是“串口调试助手V2.2”。

但是使用中有几点需要注意:
- 偶尔会发生崩溃,这是串口调试工具的问题;
- 只能使用COM1-COM4这几个串口,有局限性;
- 与某些需要检测串口监听状态的仪器连接,虽然已经打开串口但是可能仪器仍然提示连接失败;
如果碰到以上问题,那就只能只能自己找解决方案,另外如果具备一定开发经验后,建议根据自身需求来定制自己的串口调试工具,可以避免以上问题。
串口监视精灵
除了串口调试助手以外,另外比较推荐的工具就是串口监视精灵了,顾名思义其就是类似于网口通讯中的抓包工具。
当初从网上找到这个工具的原因是之前LIS系统替换第三方LIS系统,有一个仪器的双工接口开发一直存在问题,所以想看一下第三方LIS怎么实现的双工通讯消息的交互。
当然如果开发的串口通讯工具中没有输出日志,也可以使用该工具进行监听。
一般我们网上能够找到的分为无DLL版和安装版,这里建议使用安装版。

上图为无Dll版,需要选择监听串口所在的进程,中文会乱码,能监听到串口的关闭但是打开的事件则没有输出。

上图是安装版,使用安装版需要注意如果系统是x64,第一次使用需要点击软件界面上的“启用64位系统驱动签名”,另外重启。如果监听不到数据,尝试先关闭通讯软件,打开监听后再打开通讯软件。
安装版能够监听到的数据就更完整一些,且每次数据的收发都统一显示为一条记录,这就比无Dll版本的更加友好,但是同样存在的问题是因为是ASC编码所以中文仍然是乱码,需要自己使用HEX编码进行转换。
另外安装版也附带有一个串口调试工具可以使用:

串口通讯开发
获取当前电脑的串口
引入System.IO.Ports
命名空间,然后可以使用SerialPort.GetPortNames()
获取当前电脑的所有串行端口名称。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| using System; using System.IO.Ports;
namespace SerialPortTestConsole { class Program { static void Main(string[] args) { string[] ports = SerialPort.GetPortNames(); foreach (string port in ports) { Console.WriteLine(port); } Console.ReadKey(); } } }
|
串口数据收发
引入System.IO.Ports
命名空间,然后实例化SerialPort
对象,使用Open
方法打开串口,DataReceived
事件进行数据接收,Write
方法可以进行数据发送。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76
| using System; using System.IO.Ports; using System.Text;
namespace SerialPortTestConsole { class Program { static void Main(string[] args) { SerialPort port = new SerialPort() { PortName = "COM1", BaudRate = 9600, DataBits = 8, Parity = Parity.None, StopBits = StopBits.One, Encoding = Encoding.ASCII, WriteBufferSize = 2048, ReadBufferSize = 4096, WriteTimeout = -1, ReadTimeout = -1, RtsEnable = false, DtrEnable = false, };
port.DataReceived += new SerialDataReceivedEventHandler((sender, e) => { while (port.BytesToRead > 0) { int length = port.BytesToRead; byte[] buffer = new byte[length]; port.Read(buffer, 0, length); Console.WriteLine(port.Encoding.GetString(buffer)); } });
if (!port.IsOpen) { try { port.Open(); Console.WriteLine($"串口打开成功:{port.PortName}"); } catch (Exception exception) { Console.WriteLine($"打开串口失败:{exception.Message}"); } }
if (port.IsOpen) { string input = ""; do { Console.WriteLine("请输入要发送的内容:"); input = Console.ReadLine(); if (!string.IsNullOrEmpty(input)) { byte[] buffer = port.Encoding.GetBytes(input); port.Write(buffer, 0, buffer.Length); } } while (!string.IsNullOrEmpty(input));
port.Close(); } port.Dispose(); } } }
|
一个简单的调试工具
通过以上例子基本上对串口数据手法有个简单的了解,这里我们设计一个工具,来实现串口调试工具的基本功能。
SerialPort
的属性/方法/事件基本没有什么好说的了,这里主要需要了解HEX数据的转换:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66
|
public static partial class StringExtension { public static string ToHex(this string input, Encoding e = null) { e = e ?? Encoding.UTF8; byte[] byteArray = e.GetBytes(input); return BitConverter.ToString(byteArray).Replace('-', ' '); }
public static string ReHex(this string input, Encoding e = null) { e = e ?? Encoding.UTF8; input = Regex.Replace(input, "[^0-9A-F]", ""); if (input.Length <= 0) return ""; byte[] vBytes = new byte[input.Length / 2]; for (int i = 0; i < vBytes.Length; i++) vBytes[i] = byte.Parse(input.Substring(i * 2, 2), NumberStyles.HexNumber); return e.GetString(vBytes); }
public static byte[] ReHexToBuffer(this string input) { input = Regex.Replace(input, "[^0-9A-F]", ""); if (string.IsNullOrEmpty(input)) return new byte[0]; byte[] vBytes = new byte[input.Length / 2]; for (int i = 0; i < vBytes.Length; i++) vBytes[i] = byte.Parse(input.Substring(i * 2, 2), NumberStyles.HexNumber); return vBytes; } }
public static partial class BufferExtension { public static string ToHex(this byte[] input) { return BitConverter.ToString(input).Replace('-', ' '); } }
|
然后就是简单实现后的效果:

源代码下载:https://github.com/hd2y/SerialPortTest