一、需求场景

最近有时间静下心来研究SDK,串口通讯的。要求实现识别cp210x和cp2303驱动的两款硬件,并且2303的优先级高,即有2303识别之,没有再识别210x;要求实现热插拔,拔掉自动断开,插上自动连接。

二、问题一:如何实现串口硬件的识别呢?

1、如果方便的话,SerialPort的Handshake这个字段值得深入研究,可以利用这个实现;

2、添加自定义的握手协议,本人用一个5字节的串进行校验(第三位是硬件版本标识),校验算法如下:

                    for (int i = ; i < btData.Length; i++)
{
if ((i % ) == ) commit = ;
if (btData[i].ToString().Equals(byteMitt[i % ]) || i % == )
commit++;
if (commit == )
{
SendMessage(EnumDataConverter.GetCommandStatus(SendCommandType.Test) +
intDeviceCount.ToString().PadLeft(, ''));
tpVersion = btData[].ToString();
IsConnected = true;
strDeviceName = tempPort.Value;
return true;
}
} //校验完毕没有成功,进入下次循环

二、热插拔的监听问题

经过实践,cp210x可以在串口设备表中查询到,cp2303不可不发现,故而采用查询计算机设备表的方式

备注:

System.IO.Ports.SerialPort.GetPortNames()只能获取设备名,不能获取详细信息(类型等),我下面用来进行一些比对的逻辑操作
  private void CreateUSBWatcher()
{
Ports = System.IO.Ports.SerialPort.GetPortNames();
//建立监听
ManagementScope scope = new ManagementScope("root\\CIMV2");
scope.Options.EnablePrivileges = true;
//建立插入监听
try
{
WqlEventQuery USBInsertQuery = new WqlEventQuery("__InstanceCreationEvent", "TargetInstance ISA 'Win32_PnPEntity'");
USBInsertQuery.WithinInterval = new TimeSpan(, , );
USBInsert = new ManagementEventWatcher(scope, USBInsertQuery);
USBInsert.EventArrived += USBInsert_EventArrived;
USBInsert.Start();
}
catch (Exception ex)
{
if (USBInsert != null)
{
USBInsert.Stop();
}
throw ex;
}
//建立拔出监听
try
{
WqlEventQuery USBRemoveQuery = new WqlEventQuery("__InstanceDeletionEvent", "TargetInstance ISA 'Win32_PnPEntity'");
USBRemoveQuery.WithinInterval = new TimeSpan(, , );
USBRemove = new ManagementEventWatcher(scope, USBRemoveQuery);
USBRemove.EventArrived += USBRemove_EventArrived;
USBRemove.Start();
}
catch (Exception ex)
{
if (USBRemove != null)
{
USBRemove.Stop();
}
throw ex;
}
}
        /// <summary>
/// USB设备插入
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void USBInsert_EventArrived(object sender, EventArrivedEventArgs e)
{
string[] tempPorts = System.IO.Ports.SerialPort.GetPortNames();
if (tempPorts.Count() == Ports.Count())
return;
else
Ports = tempPorts; if (IsConnected)
return; if (blnDesireConnected && Open())
commExecuteInterface?.DeviceArrivaled();
} /// <summary>
/// USB设备拔出
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void USBRemove_EventArrived(object sender, EventArrivedEventArgs e)
{
string[] tempPorts = System.IO.Ports.SerialPort.GetPortNames();
if (tempPorts.Count() == Ports.Count())
return;
else
Ports = tempPorts; if (!IsConnected)
return; IsConnected = false;
spUSB.Close();
commExecuteInterface?.DeviceRemoved();
}

三、调用Close方法会提示“ unsafe handler 已关闭”

微软的方法有问题的,微软的SerialPort的这个类有问题,一但断开硬件的连接,会触发部分对象资源的释放(SerialPort不是单纯的托管资源,非托管资源被释放了),因此调用Close会出问题,除非此进程完全退出,所以SerialPort的资源需要重置;SerialPort的初始化方法中有一个是有IContainer参数的,IContainer提供了非托管资源的管理方法,因此,把SerialPort对象放到一个容器中可解决Close问题;即,想实现热插拔,必须把SerialPort放到容器中!

                    spUSB = new SerialPort(container);
KeyValuePair<string, string> tempPort = queueSerialPorts.Dequeue();
spUSB.BaudRate = ;
spUSB.PortName = tempPort.Key; spUSB.Open();
SendMessage(EnumDataConverter.GetCommandStatus(SendCommandType.ECC)); //尝试让主控机复位 byte[] btData = ReadData();

四、IsOpen属性并不可靠,尽量少用

有问题可以加qq群:568055323

.Net串口通讯中的若干问题(C#多串口硬件识别、热插拔、Close方法报错问题、IsOpen的可靠性问题)的更多相关文章

  1. vue中使用ts后,父组件获取执行子组件方法报错问题

    一.问题产生背景: 子组件的一个方法: update () { this.$nextTick(() => { this.ul_slots.forEach((ul, cur_slots_index ...

  2. 项目实体类使用@Data注解,但是项目业务类中使用getA(),setA()方法报错,eclipse中配置lombok

    @Data注解来源与Lombok,可以减少代码中大量的set get方法,大量减少冗余代码,但是今天部署项目时候,发现实体类使用@Data注解,但是项目业务类中使用getA(),setA()方法报错. ...

  3. eclipse中运行 main 方法报错,找不到类

    eclipse (maven 项目)中运行 main 方法报错,找不到类 ** 发现:在 eclipse中的 "Marker" 控制面板中 ,发现问题所在 只要删除 maven 仓 ...

  4. C# 16进制与字符串、字节数组之间的转换(串口通讯中)

    1.c#中如何将十进制数的字符串转化成十六进制数的字符串//十进制转二进制 Console.WriteLine("十进制166的二进制表示: "+Convert.ToString( ...

  5. C#串口通讯中常用的16进制的字节转换

    1.对于通讯协议的十六进制数值进行简单转换 //二进制转十进制Console.WriteLine("二进制 111101 的十进制表示: "+Convert.ToInt32(&qu ...

  6. php中使用end方法报错

    <b>Strict Standards</b>:  Only variables should be passed by reference in <b> 1.如果 ...

  7. Node.js中读取文件后用Json.parse方法报错

    今天,在调试一个node项目时,发现了一个很大的坑,在此分享给大家! 大家都知道,Json.parse()方法对格式要求是很严格的,格式不对极其容易报错,但是有时候格式看似是正确的也会报错. 比如这一 ...

  8. Node.js中读取文件后用Json.parse方法报错解决方案

    今天,在调试一个node项目时,发现了一个很大的坑,在此分享给大家! 大家都知道,Json.parse()方法对格式要求是很严格的,格式不对极其容易报错,但是有时候格式看似是正确的也会报错. 比如这一 ...

  9. django中使用POST方法报错 URL via POST, but the URL doesn't end in a slash

    该方式是因为URL路径没有使用slash(斜线"/")结尾造成的. 因此在使用POST的JavaScript函数的路径参数中,路径URL必须使用/结尾.

随机推荐

  1. 戏说 .NET GDI+系列学习教程(三、Graphics类的应用_验证码扩展)

    从别人那拷贝的 #region 定义和初始化配置字段 //用户存取验证码字符串 public string validationCode = String.Empty; //生成的验证码字符串 pub ...

  2. 移动APP和传统软件测试的区别[转载]

    目录 1. 移动App比PC 上的程序测试要复杂 2. 移动APP测试中如何设计Test Case 3. 让自己成为真实的用户 4. 关注用户体验测试 5. 少做UI自动化,多做后台接口的自动化 6. ...

  3. 中山大学深圳研究院“智能金融和区块链技术”论坛(理论+实战PPT)

    中山大学深圳研究院在昨天11月15号在深圳南山区虚拟大学园举办了"智能金融和区块链技术"论坛. 本次论坛邀请了中山大学移动互联网与金融大数据实验室郑子彬教授团队系统地介绍智能金融及 ...

  4. 如何在vue-cli 中适当的配置,来满足自己项目需求 ?

    1. 改变index.js 中端口号host host:'localhost' 改为 host: '0.0.0.0' 然后换成自己的ip 访问: 2. 在vue 中运行cnpm run start 中 ...

  5. find out the installed and runing tomcat version in Linux

    To find out the Tomcat version, find this file – version.sh for *nix or version.bat for Windows. Thi ...

  6. 枚举对象中的属性 for . . in

    枚举对象中的属性:把对象中所有的属性和值都取出来 使用 for . . . in 语句 语法: for(var  变量  in  对象){ } for  . . . in 语句  对象中有几个属性,循 ...

  7. 2018-2-13-win10-uwp-入门

    title author date CreateTime categories win10 uwp 入门 lindexi 2018-2-13 17:23:3 +0800 2018-2-13 17:23 ...

  8. yes - 不断输出一个字符串,直到杀死其为止

    SYNOPSIS(总览) yes [OPTION]... [STRING]... DESCRIPTION(描述) 不断输出包括所有指定STRING(s)的一行,或者是`y'. --help 显示帮助并 ...

  9. scip 练习2.20

    (define (same-parity x . z) (define (q? y) (= (remainder y ) )) (define (o? y) (= (remainder y ) )) ...

  10. delphi DBGrid简单自绘(字体颜色、背景等)

    delphi DBGrid简单自绘(字体颜色.背景等)  从网上找的代码 应该是C#写的,其实delphi 的操作类似: 1 2 3 4 5 6 7 8 9 10 11 12 13 void __fa ...