C# Windows多串口绑定

描述

有时工作测试中遇到要一拖多去进行串口通讯,例如多串口同时进行烧录,多串口对设备进行控制,指令发送等,平时我用的串口工具都是人为的一对一手动操作,用电脑同时一对多操作串口通讯我还真没用过,但是想到平时工作使用的场景蛮多的,感觉还是很有必要研究下,对工作生产还是很有效率的

首先做之前我们必须先了解下串口,主要了解串口在电脑重启后,COM口会不会变,插多个串口后COM口会不会变。了解这些是因为我们要依靠COM去绑定依赖关系,COM数据获取简单方便。经检验,串口插上后,更换USB插槽, COM口会跟着变;其他串口插上后不会改变之前插上去的串口的COM口,并重启后COM不会改变。所以我们绑定串口后就不要再插拔串口了,有可能会引起COM改变

效果图

目标

我们要做的主要实现一下功能

1. 监听USB设备插拔,有USB设备插拔时,更新COM口列表

2. 绑定的串口可以保存为配置文件,下次启动根据配置文件直接加载配置并绑定

3. 可以对目标设备绑定多个串口,可以删除绑定的COM口,绑定后COM列表将已绑定的信息移除

4. 可以观察到哪些绑定的串口是可用的,哪些是断开的

代码逻辑

为了方便知道哪根线接的哪个串口,合理的连接到对应的设备上,我增加了USB设备监听功能,当串口插上时,未绑定列表就会新增一条COM信息,我就知道该串口的COM名称了,然后再做绑定,这样也不容易出错

// 在生命周期loaded的时候初始化监听器
// 这里的代码适用与WPF,如果你是Winform,请查看我写的USB监听的博文
private void OnLayoutLoaded(object sender, RoutedEventArgs e)
{
	HwndSource hwndSource = PresentationSource.FromVisual(this) as HwndSource;
	if (null != hwndSource)
		hwndSource.AddHook(new HwndSourceHook(DevieceChanged));
}

private IntPtr DevieceChanged(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
{
	if (msg == WM_DEVICECHANGE)
	{
		switch (wParam.ToInt32())
		{
			case DBT_DEVICEARRIVAL:
				Console.WriteLine("串口连接成功!");
				break;
			case DBT_DEVICEREMOVECOMPLETE:
				Console.WriteLine("串口断开!");
				break;
		}
		if(wParam.ToInt32() == DBT_DEVICEARRIVAL || wParam.ToInt32() == DBT_DEVICEREMOVECOMPLETE)
		{
			// 这里用线程主要事因为,有时一个串口设备有2个COM口,在线程里面等待两个口都连接
			// 上后,再刷新界面,只用刷新一次
			Thread thread = new Thread(new ThreadStart(OnDiveceChanged));
			thread.Start();
		}
	}
	return IntPtr.Zero;
}

private bool isUpdataComsList = false;
private object lockObj = new object();
private void OnDiveceChanged()
{
	lock (lockObj)
	{
		if (isUpdataComsList) return;
		isUpdataComsList = true;
	}
	Thread.Sleep(1000);
	m_SyncContext.Post(UpdataComsList, null);
}

设备绑定:如果单设备的话,我们只需要将COM口和设备对应即可,用键值对的方式存储,例如----->DUT1:COM3,DUT2:COM8。等你需要连接串口时, 你根据自己的编号取对应的COM口即可,比如自己的编号为“DUT2”,那我们就连接COM8的串口即可

对于一个设备时需要连接多个串口, 而且需要控制多个设备时,我引入了Tag的概念,比如说功能1的Tag为CMS1,功能2的Tag为CMS2,在保存数据的形式还是键值对的方式,不过值变成了一个对象,对象里保存了COM口信息和TAG信息。例如DUT1:[{Serial:COM3,Tag:CMS1},{Serial:COM5,Tag:CMS2}],当某一个设备在使用某一项功能时,只要知道保存的TAG,就可以获取到配置的串口

我保存的串口是以XML形式保存的,可以根据自己喜欢的方式进行选择

解析保存的配置文件略

public static  void SaveSerialsBindInfo(Dictionary<string,List<SerialsBindInfo>> infos)
{
	CheckSaveConfigFilesPath();
	XmlDocument xmlDoc = new XmlDocument();
	XmlElement root = xmlDoc.CreateElement("SerialsConfig");
	xmlDoc.AppendChild(root);
	XmlElement DutBindInfoElement;
	foreach (KeyValuePair<string, List<SerialsBindInfo>> kv in infos){
		if (kv.Value.Count == 0) continue;
		DutBindInfoElement = xmlDoc.CreateElement("DutBindInfo");
		DutBindInfoElement.SetAttribute("DutNum" , kv.Key);
		XmlElement SerialNameElement;
		XmlElement RemarkElement;
		foreach (SerialsBindInfo serialInfo in kv.Value)
		{
			if (serialInfo.SerialName.Trim().Length == 0 && serialInfo.Remark.Trim().Length == 0) continue;
			XmlElement BindInfoItemElement = xmlDoc.CreateElement("InfoItem");
			SerialNameElement = xmlDoc.CreateElement("SerialName");
			SerialNameElement.InnerText = serialInfo.SerialName;
			RemarkElement = xmlDoc.CreateElement("Remark");
			RemarkElement.InnerText = serialInfo.Remark;
			BindInfoItemElement.AppendChild(SerialNameElement);
			BindInfoItemElement.AppendChild(RemarkElement);
			DutBindInfoElement.AppendChild(BindInfoItemElement);
		}
		root.AppendChild(DutBindInfoElement);
	}
	xmlDoc.Save(FilePathConfig.SerialsBindConfigPath);
}

COM口绑定后,需要将已绑定的串口从待绑定的列表中删除,不然串口多了比较乱,分不清哪一个是哪一个,列表只显示待绑定的

如果解除绑定后,也需要将解除的COM添加到待绑定列表里面

如果从COM1切换到COM2,这里面既有添加,也有删除,为了方便和满足上面的3种需求,我就先将所有COM获取,再将已经绑定的数据从所有COM中移除,就只剩未绑定的了

private void SerialsSelectionChanged(object sender, SelectionChangedEventArgs e)
{
	ComboBox comboBox = (ComboBox)sender;
	Label SelectItem = (Label)comboBox.SelectedItem;
	if (SelectItem == null) return;
	string content = (string)SelectItem.Content;
	if (ContentNone.Equals(content))
		comboBox.Items.Clear();
	else
		unBindSerials.Remove(content);
	DockPanel itemLayout = (DockPanel)comboBox.Parent;
	// 先刷新刚刚选中的COM口的UI
	UpdataBindData(itemLayout);
	// 再过滤未绑定的数据
	FilterUnbindComs();
	// 刷新未绑定列表的UI
	UpdateComsList();
}

private void FilterUnbindComs()
{
	// 清除历史数据
	unBindSerials.Clear();
	// 遍历所有的COM,包含绑定和未绑定的所有COM口
	foreach (string ComName in allComsList)
	{
		bool isContains = false;
		// 遍历查找是否该COM口已经绑定
		foreach (List<SerialsBindInfo> ComsInfos in bindData.Values)
		{
			foreach (SerialsBindInfo info in ComsInfos)
			{
				if (ComName.Equals(info.SerialName))
				{
					isContains = true;
					break;
				}
			}
		}
		// 如果没绑定,则添加进未绑定列表
		if(!isContains) unBindSerials.Add(ComName);
	}
}

现在绑定和保存都可以了,但是有时候设备会出异常,我们首先要看看串口设备是不是正常的,串口都没接好,肯定没办法正常工作

检测的办法就是获取当前所有串口(当前所有可用串口),对比绑定数据,看看绑定的串口是否在当前可用串口列表中,如果没有在串口列表,则用红色的图标标记,便于工程人员检修时方便观察检修

//默认Image是显示的,当判断到符合条件时,将其隐藏
if (serialsBindInfo == null || serialsBindInfo.SerialName == null || serialsBindInfo.SerialName.Trim().Length == 0 || allComsList.Contains(serialsBindInfo.SerialName))
	EnableImage.Visibility = Visibility.Hidden;

小结

串口绑定其实很简单的,只要是思想:如何一对多。上面逻辑可以帮助大家将多路串口连接,并可以多机控制

如果你喜欢我的文章请长按点赞哦

猜你喜欢

转载自blog.csdn.net/baoolong/article/details/127390812