使用 C# WinForm 制作简单的串口调试助手

使用 C# WinForm 制作简单的串口调试助手

很久之前就已经发现了C# WinForm开源的控件界面库Sunny.UI,于是想着做一个Demo来用上Sunny.UI界面库。于是就想着做一个串口调试助手的Demo。

下面我就创建一个工程,并且加载Sunny.UI控件库,我这个项目还加载了另一个库叫做SeeSharpTools.JY.GUI,但是没有使用其中的控件,添加它以备后面使用。

第一步:在VS2022编译器的NuGet管理工具中搜索Sunny.UI,然后下载下来。如下图笔者已经安装了Sunny.UI库:

微信截图_20240908170443

安装Sunny.UI库后,在项目的工具箱中会由该库。如下图:

微信截图_20240908171355

第二步:拖动控件布局界面。笔者的界面如上图所示。我们可以参考Sunny.UI库的说明文档修改控件的属性。Sunny.UI说明文档。以按钮为例,该说明书详细说明了每一个属性的作用,如下图:

微信截图_20240908172114

另外Sunny.UI库控件的属性单独进行了分类,如下图中笔者的按钮控件属性:

微信截图_20240908172019

界面布局完毕。

第三步:编写代码。

C# 为我们提供了串口类SerialPort,我们可以直接使用。

1.串口搜索按钮部分代码:

 private void m_btnSearch_Click(object sender, EventArgs e){try{string[] items = SerialPort.GetPortNames();m_ctrlPort.Items.Clear();m_ctrlPort.Items.AddRange(items);m_ctrlPort.SelectedIndex = m_ctrlPort.Items.Count > 0 ? 0 : -1;if (items.Length > 0){m_ctrlBaud.SelectedIndex = 10;m_ctrlData.SelectedIndex = 0;m_ctrlStop.SelectedIndex = 0;m_ctrlProof.SelectedIndex = 0;}else{MessageBox.Show("当前无串口连接!");}}catch (Exception ex){MessageBox.Show("无串口设备!/r/n请检查是否连接设备!/r/n请检查设备驱动!");}}

说明:

①我们调用SerialPort类的GetPortNames()可以获取当前计算机的串行端口名的数组。

②在C#中的CombBox控件比C++更加简单,可以直接在属性中添加字符串。具体如下图中的波特率:

微信截图_20240908193835

2.连接按钮部分的代码如下:

 private void m_btnConnect_Click(object sender, EventArgs e){if (!m_serialPort.IsOpen){if (m_ctrlPort.SelectedItem == null){MessageBox.Show("请选择正确的串口", "提示");return;}// 设置串口参数m_serialPort.PortName = m_ctrlPort.Text.ToString();m_serialPort.BaudRate = Convert.ToInt32(m_ctrlBaud.SelectedItem.ToString());m_serialPort.DataBits = Convert.ToInt32(m_ctrlData.SelectedItem.ToString());// 设置停止位if (m_ctrlStop.Text == "One"){m_serialPort.StopBits = StopBits.One;}else if (m_ctrlStop.Text == "Two"){m_serialPort.StopBits = StopBits.Two;}else if (m_ctrlStop.Text == "OnePointTwo"){m_serialPort.StopBits = StopBits.OnePointFive;}else if (m_ctrlStop.Text == "None"){m_serialPort.StopBits = StopBits.None;}// 设置奇偶校验位if (m_ctrlProof.Text == "Odd"){m_serialPort.Parity = Parity.Odd;}else if (m_ctrlProof.Text == "Even"){m_serialPort.Parity = Parity.Even;}else if (m_ctrlProof.Text == "None"){m_serialPort.Parity = Parity.None;}try{m_ctrlPort.Enabled = false;m_ctrlBaud.Enabled = false;m_ctrlData.Enabled = false;m_ctrlStop.Enabled = false;m_ctrlProof.Enabled = false;m_btnSearch.Enabled = false;m_serialPort.Open();m_btnConnect.Text = "断开";m_Led.OnColor = Color.FromArgb(110, 190, 40);}catch (Exception ex){MessageBox.Show("串口打开失败!");}m_serialPort.DataReceived += new SerialDataReceivedEventHandler(SerialDataReceive);}else if (m_btnConnect.Text == "断开"){m_ctrlPort.Enabled = true;m_ctrlBaud.Enabled = true;m_ctrlData.Enabled = true;m_ctrlStop.Enabled = true;m_ctrlProof.Enabled = true;m_btnSearch.Enabled = true;m_serialPort.DiscardInBuffer();m_serialPort.Close();m_btnConnect.Text = "连接";m_Led.OnColor = Color.Red;}}

说明:

①上述代码设置好串口参数后,调用SerialPort类的Open()函数即可连接串口。

②DataReceived:SerialPort 类的 DataReceived 事件是在接收到数据时触发的。当串口接收缓冲区中有数据时,就会引发此事件。DataReceived 事件提供了一个 SerialDataReceivedEventArgs 对象,该对象包含有关事件的详细信息。请注意,DataReceived 事件处理程序应该尽可能快地执行,以避免阻塞其他事件的接收。

③定义DataReceived事件触发的串口接收函数和显示函数,代码如下:

#region(接收串口数据)
// 串口缓冲区
List<byte> pBuffer = new List<byte>(4096);
// 串口缓冲区最大字节数
int nBufferMaxSize = 4096;private void SerialDataReceive(object sender, SerialDataReceivedEventArgs e)
{if (m_serialPort.IsOpen == false){m_serialPort.Close();return;}// 读取缓存的数据长度int nByteLen = m_serialPort.BytesToRead;byte [] bRecv = new byte[nByteLen];// 将读取的数据存入缓存数组中m_serialPort.Read(bRecv,0,nByteLen);string strText = "接收的字节数:";statusStrip1.Items[1].Text = strText + nByteLen.ToString();pBuffer.Clear();// 将接收的数据存入缓冲区pBuffer.AddRange(bRecv);byte[] rBuffer = new byte[9192];pBuffer.CopyTo(0, rBuffer, 0, pBuffer.Count);Task.Run(() =>PrintfData(rBuffer, pBuffer.Count, 1));}
#endregion#region (打印数据)
void PrintfData(byte[] buffer,int nLength,int nTR)
{Int16 nLen;StringBuilder sb = new StringBuilder();if (nTR == 0)sb.Append("发送:");elsesb.Append("接收:");string strRecv = "";if (uiRB_ASCII_Recv.Checked){strRecv = sb.ToString();strRecv += Encoding.Default.GetString(buffer);}else if(uiRB_HEX_Recv.Checked){// 转为字节显示for (nLen = 0; nLen < nLength; nLen++){sb.Append(buffer[nLen].ToString());sb.Append(" ");}strRecv = sb.ToString();}MethodInvoker mi = new MethodInvoker(()=>{ if(m_tbReceive.Lines.Count() > 20)m_tbReceive.Clear();m_tbReceive.AppendText(strRecv + "\r\n");});BeginInvoke(mi);
}
#endregion

说明:

①上述代码使用了异步Task,其中调用Task.Run的函数,Task.Run是在线程池上执行任务。关于Run函数的详细说明可以参考官方文档。Run().

②MethodInvoker类的说明:在C#中,MethodInvoker 是一个委托(delegate),它定义了与具有无返回值参数的方法匹配的签名。换句话说,MethodInvoker 是一个可以引用任何不接受参数且不返回值的方法的委托。MethodInvoker通常用于Windows Forms应用程序中,当你需要在非UI线程上更新UI控件时。由于UI控件只能由创建它们的线程(通常是主UI线程)进行操作,所以当你在后台线程中更新UI时,需要使用 MethodInvoker 来确保UI更新操作在正确的线程上执行。

③这两个类对于我来说,接触的也是比较少,只能先放在这里,以后用到的话再来详细查看说明。

3.发送按钮部分的代码如下:

 private void m_btnSend_Click(object sender, EventArgs e){if (m_serialPort.IsOpen){string strData = m_tbSend.Text;int nBufferLen = strData.Length;byte[] sendData = new Byte[nBufferLen];sendData = System.Text.Encoding.Default.GetBytes(strData);//转码try{// 写数据m_serialPort.Write(sendData, 0, sendData.Length);Task.Run(() => PrintfData(sendData, sendData.Length, 0));string strText = "发送的字节数:";statusStrip1.Items[0].Text = strText + sendData.Length.ToString();}catch{MessageBox.Show("发送失败!");}}else{MessageBox.Show("串口未打开!");}}

说明:

①使用SerialPort类的Write函数向串口缓冲区中写入数据。

第四步、代码调试结果。

软件运行后界面如下图,可以实现基本的数据收发:

微信截图_20240908230054

关于Sunnu.UI控件库的使用就到这里了,有关串口的介绍还有很多细节的地方,如果想了解更多细节,大家可以直接去看别人的开源代码。

说明:另外也可以直接使用工具箱中提供的串口组件:SerialPort。关于SerialPort组件的使用,大家可以参考这篇文章。源码开源C#桌面应用开发:串口调试助手

本人水平有限,代码有不足之处请谅解。欢迎大家一起交流学习。

源码地址

参考文献:

1.C#开发: 通信篇-串口调试助手

2.C#开发串口调试助手的详细教程

3.Sunny.UI说明文档

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/52389.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

使用stripe进行在线支付、退款、订阅、取消订阅功能(uniapp+h5)

stripe官网:Stripe 登录 | 登录 Stripe 管理平台 然后在首页当中打开测试模式,使用测试的公钥跟私钥进行开发 测试卡号 4242 4242 4242 4242 1234 567 在线支付 stripe的在线支付有两种,第一种就是无代码,第二中就是使用api进行自定义,一般来说推荐第二种进行开发 无…

哈希表 和 算法

1.哈希表的作用&#xff1a;将我们要存储的数据&#xff0c;通过关键字与位置的关系函数&#xff0c;来确定具体的位置。 2.写哈希表时常出现的问题&#xff1a;哈希冲突/矛盾&#xff1a;当多个数据满足哈希函数的映射时出现 解决的方法为&#xff1a; 1&#xff09;开放地址…

[C#学习笔记]LINQ

视频地址&#xff1a;LINQ入门示例及新手常犯的错误_哔哩哔哩_bilibili 强烈推荐学习C#和WPF的朋友关注此UP&#xff0c;知识点巨多&#xff0c;讲解透彻&#xff01; 一、基本概念 语言集成查询(Language-Intergrated Query) 常见用途 .Net原生集合(List&#xff0c;Arra…

SEO 分类策略权威指南

如果你在 SEO 领域工作了一段时间&#xff0c;你可能熟悉网站分类法的概念。这是指网站内容的组织方式以及用户找到他们正在寻找的内容的难易程度。 例如&#xff0c;考虑一个专门从事服装的电子商务网站。结构良好的分类可能包括主要类别&#xff0c;例如男装、女装和配饰&am…

【深度学习讲解笔记】第1章-机器学习基础(2)

模型与函数构造 之前讲到&#xff0c;模型是由机器学习决定参数值的函数&#xff0c;通过训练&#xff0c;机器可以找出最好的一组参数使得函数的输出最优。常见的模型有线性模型&#xff0c;指数模型&#xff0c;对数模型等。在线性模型中&#xff0c;w和b是可学习的参数&…

基于SpringBoot的智能制造云平台系统的设计与实现计算机毕设

一、选题背景与意义&#xff08;300字左右&#xff09; 根据工业4.0智能制造生态链中云工厂在实际生产当中的工作流程进行充分调研和整理出来的&#xff0c;描述最终用户在本系统中对于生产订单的处理、排产、以及生产的完整在线处理流程和业务需求的文档。 针对制造业而言&a…

TikTok直播为什么要用独立IP

TikTok直播作为一种受欢迎的社交媒体形式&#xff0c;吸引了越来越多的用户和内容创作者。在进行TikTok直播时&#xff0c;选择使用独立IP地址是一种被广泛推荐的做法。本文将探讨为什么在TikTok直播中更推荐使用独立IP&#xff0c;并解释其优势和应用。 独立IP是指一个唯一的互…

基于CNN卷积神经网络迁移学习的图像识别实现

基于CNN卷积神经网络迁移学习的图像识别实现 基于CNN卷积神经网络迁移学习的图像识别实现写在前面一&#xff0c;原理介绍迁移学习的基本方法1.样本迁移&#xff08;Instance based TL&#xff09;2.特征迁移&#xff08;Feature based TL&#xff09;3.模型迁移&#xff08;Pa…

C++(一)----C++基础

1.C的发展史 C语言诞生后&#xff0c;很快普及使用&#xff0c;但是随着编程规模增大且越来越复杂&#xff0c;并且需要高度的抽象和建模时&#xff0c;C语言的诸多短板便表现了出来&#xff0c;为了解决软件危机&#xff0c;上世纪八十年代&#xff0c;计算机界提出了oop&…

如何理解有效值电流?电流的均方根值

电流的有效值就是电流的均方根。 有效值电流定义&#xff1a;将一直流电与一交流电分别通过相同阻值的电阻&#xff0c;如果相同时间内两电流通过电阻产生的热量相同&#xff0c;就说这一直流电的电流值是这一交流电的有效值。 如果说电流就是直流电&#xff0c;那么电流的有效…

Flutter MacOS 去掉窗口导航栏

操作步骤 用xcode打开Flutter项目&#xff0c;点击Runner——>Runner——>Resources——>MainMenu 点击APP_NAME&#xff0c;在右侧勾选窗口选项来控制是否有窗口或者关闭缩小按钮。我这里并没有取消勾选Show Title Bar&#xff0c;因为当我取消勾选后&#xff0c;窗…

已经存在的项目如何变成git的一个repository

已经存在的项目如何被git管理 背景&#xff1a; 有一套代码很敏感&#xff0c;可能动不动就要不能正常工作(硬件开发常事)&#xff0c;那改动一下下就要有个记录&#xff0c;就决定用git管理 已经有了服务里里docker里运行的gitbucket,已经有了开发用的电脑上的git客户端&…

【Python基础】Python函数

本文收录于 《Python编程入门》专栏&#xff0c;从零基础开始&#xff0c;分享一些Python编程基础知识&#xff0c;欢迎关注&#xff0c;谢谢&#xff01; 文章目录 一、前言二、函数的定义与调用三、函数参数3.1 位置参数3.2 默认参数3.3 可变数量参数&#xff08;或不定长参数…

【项目】云备份

云备份 云备份概述框架 功能演示服务端客户端 公共模块文件操作模块目录操作模块 服务端模块功能划分功能细分模块数据管理热点管理 客户端模块功能划分功能细分模块数据管理目录检查文件备份 云备份 概述 自动将本地计算机上指定文件夹中需要备份的文件上传备份到服务器中。…

【Visual Studio 报错】vs 在使用二进制写入文件时弹窗报错:使用简体中文 gb2312 编码加载文件

如以下报错 解决办法 解决方法&#xff1a;文件->高级保存选项->将文件编码形式改为“UTF-8带签名” 若找不到高级保存选项&#xff0c;可以跟着下面路径把该选项调出来 &#xff1a;工具->自定义->命令->菜单栏中改成文件->预览右边点添加命令->类别中…

【C++ Primer Plus习题】14.1

大家好,这里是国中之林! ❥前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。点击跳转到网站。有兴趣的可以点点进去看看← 问题: 解答: main.cpp #include <iostream> #include "wine.h" …

传知代码-机器情绪及抑郁症算法(四)!(论文复现)

代码以及视频讲解 本文所涉及所有资源均在传知代码平台可获取 计算机来理解你的情绪&#xff1a;情感计算的发展 近年来&#xff0c;多模态情感分析&#xff08;MSA&#xff09;受到越来越多的关注&#xff0c;多模态情感分析是一个综合了视觉、听觉等语言和非语言信息的重要…

Parsec问题解决方案

Parsec目前就是被墙了&#xff0c;有解决方案但治标不治本&#xff0c;如果想稳定串流建议是更换稳定的串流软件&#xff0c;以下是一些解决方案 方案一&#xff1a;在%appdata%/Parsec/config.txt中&#xff0c;添加代理 app_proxy_address 127.0.0.1 app_proxy_scheme http…

Qt篇——Qt在msvc编译下提示“C2001:常量中有换行符“的错误

在pro文件中添加以下配置即可&#xff1a; msvc{QMAKE_CFLAGS /utf-8QMAKE_CXXFLAGS /utf-8 }

双指针(7)_单调性_三数之和

个人主页&#xff1a;C忠实粉丝 欢迎 点赞&#x1f44d; 收藏✨ 留言✉ 加关注&#x1f493;本文由 C忠实粉丝 原创 双指针(7)_单调性_三数之和 收录于专栏【经典算法练习】 本专栏旨在分享学习C的一点学习笔记&#xff0c;欢迎大家在评论区交流讨论&#x1f48c; 目录 1. 题目…