一、需求场景

最近有时间静下心来研究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. Windows的安全模型

    1. 安全身份 Windows的安全模型是以用户为线索的,用户的身份是在登录系统时验证的. 除了用户外,还可以有一些特殊实体需要拥有安全的身份,以便进行验证,比如groups, domain等等. W ...

  2. 2019杭电多校第四场hdu6621 K-th Closest Distance(二分答案+主席树)

    K-th Closest Distance 题目传送门 解题思路 二分答案+主席树 先建主席树,然后二分答案mid,在l和r的区间内查询[p-mid, p+mid]的范围内的数的个数,如果大于k则说明 ...

  3. vue-router 动态路由

    上一篇文章我们已经配置好了路由,下面,来说说如何实现动态路由. 比如,我想在 news 页点击列表项,跳转到对应项,如图所示: 这里引用的数据是豆瓣电影,地址: http://api.douban.c ...

  4. Linux特殊位SUID、SGID、SBIT

    Linux特殊位SUID.SGID.SBIT 前言 Linux中的文件权限一般有x.w.r,在某个情况下有需要用到s.t,即特殊位. 进程运行时能够访问哪些资源或文件,不取决于进程文件的属主属组,而是 ...

  5. Pregel 消息传递机制

  6. linux常用命令-3文件与目录相关命令

    cd .. #返回上一级目录 cd ../.. #返回上两级目录 cd - #返回上次所在目录 cp file1 file2 #将file1复制为file2 cp -a dir1 dir2 #复制一个 ...

  7. Dockfile中的命令如何在.sh中执行

    有类似如下内容的Dokefile文件.1 RUN cd /tmp/patch \ && /lib/python3./site-packages/moduleA/a.* \ && ...

  8. Mysql 编译报错 g++: internal compiler error: Killed (program cc1plus) 解决办法

    g++: internal compiler error: Killed (program cc1plus) 解决办法 g++: internal compiler error: Killed (pr ...

  9. 【缓存】缓存穿透、缓存雪崩、key重建方案

    一.缓存穿透预防及优化 缓存穿透是指查询一个根本不存在的数据,缓存层和存储层都不会命中,但是出于容错的考虑,如果从存储层查不到数据则不写入缓存层,如图 11-3 所示整个过程分为如下 3 步: 缓存层 ...

  10. Delphi里面弹出对话框的方法

    1.procedure   ShowMessage(const   Msg:   string); 单元:Dialogsor   QDialogs 例子:showmessage( 'hello '); ...