C#如何实现串口调试工具
发表于:2025-01-20 作者:千家信息网编辑
千家信息网最后更新 2025年01月20日,C#如何实现串口调试工具,很多新手对此不是很清楚,为了帮助大家解决这个难题,下面小编将为大家详细讲解,有这方面需求的人可以来学习下,希望你能有所收获。前文由于经常用到串口调试, 尽管有现成的软件, 因
千家信息网最后更新 2025年01月20日C#如何实现串口调试工具
C#如何实现串口调试工具,很多新手对此不是很清楚,为了帮助大家解决这个难题,下面小编将为大家详细讲解,有这方面需求的人可以来学习下,希望你能有所收获。
前文
由于经常用到串口调试, 尽管有现成的软件, 因为前端时间涉及一个二次开发, 就因为一个RtsEnable设置, 折腾半天, 网上各种版本的也很多, 功能扩展的很开也多。所以现在自己做了一个够用版,基于自己的需求,简单的实现发送接收功能, 至于那些扩展功能可以自己根据需求添加。
正文
先上个运行效果图:
项目架构
该实例用的GalaSoft.Mvvm, 该插件可以直接在NuGet中并且添加。
1.串口参数 , 为了方便, 端口号并没有用动态加载的方式, 如下枚举结构:
namespace System.Windows.Data{ // // 摘要: // 提供将自定义逻辑应用于绑定的方法。 public interface IValueConverter { // // 摘要: // 转换值。 // // 参数: // value: // 绑定源生成的值。 // // targetType: // 绑定目标属性的类型。 // // parameter: // 要使用的转换器参数。 // // culture: // 要用在转换器中的区域性。 // // 返回结果: // 转换后的值。 如果该方法返回 null,则使用有效的 null 值。 object Convert(object value, Type targetType, object parameter, CultureInfo culture); // // 摘要: // 转换值。 // // 参数: // value: // 绑定目标生成的值。 // // targetType: // 要转换为的类型。 // // parameter: // 要使用的转换器参数。 // // culture: // 要用在转换器中的区域性。 // // 返回结果: // 转换后的值。 如果该方法返回 null,则使用有效的 null 值。 object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture); }}
2.串口参数配置类 ,
作用: 主要用于绑定界面的参数选项。
////// 串口参数设置类 /// public class ComParameterConfig : ViewModelBase { public ComParameterConfig() { Port = System.Enum.GetValues(typeof(Port)); CheckMode = System.Enum.GetValues(typeof(CheckMode)); StopBit = System.Enum.GetValues(typeof(StopBit)); BaudRate = new List() { 110, 300, 600, 1200, 2400, 4800, 9600, 14400, 19200, 38400, 56000, 57600, 115200, }; DataBit = new List () { 6, 7, 8 }; } private Array port; private Array checkMode; private Array stopBit; private List dataBit; private List baudRate; /// /// 端口 /// public Array Port { get { return port; } set { port = value; RaisePropertyChanged(); } } ////// 校验模式 /// public Array CheckMode { get { return checkMode; } set { checkMode = value; RaisePropertyChanged(); } } ////// 停止位 /// public Array StopBit { get { return stopBit; } set { stopBit = value; RaisePropertyChanged(); } } ////// 波特率 /// public ListBaudRate { get { return baudRate; } set { baudRate = value; RaisePropertyChanged(); } } /// /// 数据位 /// public ListDataBit { get { return dataBit; } set { dataBit = value; RaisePropertyChanged(); } } }
3.当前配置参数类
作用: 用于保存当前的串口参数、串口功能开关接收数据等业务。
核心代码:
////// 当前配置参数 /// public class CurrentParameter : ViewModelBase { #region Private private int baudRdate = 9600; private int dataBit = 8; private Port port; private CheckMode checkMode; private StopBit stopBit = StopBit.One; private SerialPort serialPort; private string dataReceiveInfo; private string sendData; private bool isOpen; private bool receiveFormat16 = true; private bool sendFormat16 = true; private int sendCount; private int receiveCount; #endregion #region UI绑定参数 ////// 发送数量 /// public int SendCount { get { return sendCount; } set { sendCount = value; RaisePropertyChanged(); } } ////// 接收数量 /// public int ReceiveCount { get { return receiveCount; } set { receiveCount = value; RaisePropertyChanged(); } } ////// 接收区16进制 /// public bool ReceiveFormat16 { get { return receiveFormat16; } set { receiveFormat16 = value; RaisePropertyChanged(); } } ////// 接收区数据 /// public string DataReceiveInfo { get { return dataReceiveInfo; } set { dataReceiveInfo = value; RaisePropertyChanged(); } } ////// 发送数据 /// public string SendData { get { return sendData; } set { sendData = value; RaisePropertyChanged(); } } ////// 发送区16进制 /// public bool SendFormat16 { get { return sendFormat16; } set { sendFormat16 = value; RaisePropertyChanged(); } } #endregion #region 串口参数信息 ////// 开关 /// public bool IsOpen { get { return isOpen; } set { isOpen = value; RaisePropertyChanged(); } } ////// 数据位 /// public int DataBit { get { return dataBit; } set { dataBit = value; RaisePropertyChanged(); } } ////// 波特率 /// public int BaudRdate { get { return baudRdate; } set { baudRdate = value; RaisePropertyChanged(); } } ////// 端口 /// public Port Port { get { return port; } set { port = value; RaisePropertyChanged(); } } ////// 校验 /// public CheckMode CheckMode { get { return checkMode; } set { checkMode = value; RaisePropertyChanged(); } } ////// 停止位 /// public StopBit StopBit { get { return stopBit; } set { stopBit = value; RaisePropertyChanged(); } } ////// COM /// public SerialPort SerialPort { get { return serialPort; } set { serialPort = value; RaisePropertyChanged(); } } #endregion #region 串口操作方法 ////// 开启串口 /// ///public bool Open() { if (serialPort != null && serialPort.IsOpen) { return Close(); } try { serialPort = new SerialPort(); serialPort.DataBits = this.DataBit; serialPort.StopBits = ComHelper.GetStopBits(this.StopBit.ToString()); serialPort.Parity = ComHelper.GetParity(this.CheckMode.ToString()); serialPort.PortName = this.Port.ToString(); serialPort.RtsEnable = true; serialPort.DataReceived += SerialPort_DataReceived; serialPort.Open(); if (serialPort.IsOpen) return IsOpen = true; else return IsOpen = false; } catch (Exception ex) { MessageBox.Show(ex.Message); } return IsOpen = false; } /// /// 关闭串口 /// ///public bool Close() { try { if (serialPort.IsOpen) { serialPort.Close(); return IsOpen = serialPort.IsOpen; } else { return IsOpen = serialPort.IsOpen; } } catch (Exception ex) { MessageBox.Show(ex.Message); return IsOpen = false; } } /// /// 发送数据 /// public void Send() { if (SendFormat16) { byte[] bytes = CRC.StringToHexByte(SendData); this.SerialPort.Write(bytes, 0, bytes.Length); SendCount = bytes.Length; //不做增量 } else { this.SerialPort.Write(SendData); SendCount = SendData.Length; } Messenger.Default.Send("", "PlaySendFlashing"); } ////// 清空接收区 /// public void Clear() { this.DataReceiveInfo = string.Empty; } ////// 清空发送区和缓存区 /// public void ClearText() { this.SendData = string.Empty; this.SendCount = 0; this.ReceiveCount = 0; } #endregion ////// 返回事件 /// /// /// private void SerialPort_DataReceived(object sender, SerialDataReceivedEventArgs e) { Messenger.Default.Send("", "PlayReciveFlashing"); byte[] readBuffer = new byte[SerialPort.ReadBufferSize]; SerialPort.Read(readBuffer, 0, readBuffer.Length); ReceiveCount = SerialPort.ReceivedBytesThreshold; //不做增量 if (ReceiveFormat16) { //不做增量 DataReceiveInfo = CRC.ByteToString(readBuffer, true); } else { DataReceiveInfo = Encoding.ASCII.GetString(readBuffer); } } }
4.核心MainViewModel类
作用: 关联首页的上下文, 通过DataContext绑定, 关联界面元素、命令等作用。
public class MainViewModel : ViewModelBase { ////// Initializes a new instance of the MainViewModel class. /// public MainViewModel() { ComParameterConfig = new ComParameterConfig(); CurrentParameter = new CurrentParameter(); } private ComParameterConfig comParameter; ////// 参数类 /// public ComParameterConfig ComParameterConfig { get { return comParameter; } set { comParameter = value; RaisePropertyChanged(); } } private CurrentParameter currentParameter; ////// 当前配置参数 /// public CurrentParameter CurrentParameter { get { return currentParameter; } set { currentParameter = value; RaisePropertyChanged(); } } #region Command private RelayCommand _ToOpen; public RelayCommand ToOpen { get { if (_ToOpen == null) { _ToOpen = new RelayCommand(Open); } return _ToOpen; } set { _ToOpen = value; } } ////// 根据配置打开端口 /// public void Open() { this.CurrentParameter.Open(); } private RelayCommand _ToClick; public RelayCommand ToClick { get { if (_ToClick == null) { _ToClick = new RelayCommand(Click); } return _ToClick; } set { _ToClick = value; } } ////// 发送数据 /// public void Click() { this.CurrentParameter.Send(); } private RelayCommand _ToClear; public RelayCommand ToClear { get { if (_ToClear == null) { _ToClear = new RelayCommand(Clear); } return _ToClear; } set { _ToClear = value; } } ////// 清空接收区 /// public void Clear() { this.CurrentParameter.Clear(); } private RelayCommand _ToClearText; public RelayCommand ToClearText { get { if (_ToClearText == null) { _ToClearText = new RelayCommand(ClearText); } return _ToClearText; } set { _ToClearText = value; } } ////// 清空界面值 /// public void ClearText() { this.CurrentParameter.ClearText(); } #endregion }
5.CRC校验核心类
作用:主要实现数据校验, 含ModbusCR标准校验
////// CRC校验 /// public class CRC { #region CRC16 public static byte[] CRC16(byte[] data) { int len = data.Length; if (len > 0) { ushort crc = 0xFFFF; for (int i = 0; i < len; i++) { crc = (ushort)(crc ^ (data[i])); for (int j = 0; j < 8; j++) { crc = (crc & 1) != 0 ? (ushort)((crc >> 1) ^ 0xA001) : (ushort)(crc >> 1); } } byte hi = (byte)((crc & 0xFF00) >> 8); //高位置 byte lo = (byte)(crc & 0x00FF); //低位置 return new byte[] { hi, lo }; } return new byte[] { 0, 0 }; } #endregion #region ToCRC16 public static string ToCRC16(string content) { return ToCRC16(content, Encoding.UTF8); } public static string ToCRC16(string content, bool isReverse) { return ToCRC16(content, Encoding.UTF8, isReverse); } public static string ToCRC16(string content, Encoding encoding) { return ByteToString(CRC16(encoding.GetBytes(content)), true); } public static string ToCRC16(string content, Encoding encoding, bool isReverse) { return ByteToString(CRC16(encoding.GetBytes(content)), isReverse); } public static string ToCRC16(byte[] data) { return ByteToString(CRC16(data), true); } public static string ToCRC16(byte[] data, bool isReverse) { return ByteToString(CRC16(data), isReverse); } #endregion #region ToModbusCRC16 public static string ToModbusCRC16(string s) { return ToModbusCRC16(s, true); } public static string ToModbusCRC16(string s, bool isReverse) { return ByteToString(CRC16(StringToHexByte(s)), isReverse); } public static string ToModbusCRC16(byte[] data) { return ToModbusCRC16(data, true); } public static string ToModbusCRC16(byte[] data, bool isReverse) { return ByteToString(CRC16(data), isReverse); } #endregion #region ByteToString public static string ByteToString(byte[] arr, bool isReverse) { try { byte hi = arr[0], lo = arr[1]; return Convert.ToString(isReverse ? hi + lo * 0x100 : hi * 0x100 + lo, 16).ToUpper().PadLeft(4, '0'); } catch (Exception ex) { throw (ex); } } public static string ByteToString(byte[] arr) { try { return ByteToString(arr, true); } catch (Exception ex) { throw (ex); } } #endregion #region StringToHexString public static string StringToHexString(string str) { StringBuilder s = new StringBuilder(); foreach (short c in str.ToCharArray()) { s.Append(c.ToString("X4")); } return s.ToString(); } #endregion #region StringToHexByte private static string ConvertChinese(string str) { StringBuilder s = new StringBuilder(); foreach (short c in str.ToCharArray()) { if (c <= 0 || c >= 127) { s.Append(c.ToString("X4")); } else { s.Append((char)c); } } return s.ToString(); } private static string FilterChinese(string str) { StringBuilder s = new StringBuilder(); foreach (short c in str.ToCharArray()) { if (c > 0 && c < 127) { s.Append((char)c); } } return s.ToString(); } ////// 字符串转16进制字符数组 /// /// ///public static byte[] StringToHexByte(string str) { return StringToHexByte(str, false); } /// /// 字符串转16进制字符数组 /// /// /// 是否过滤掉中文字符 ///public static byte[] StringToHexByte(string str, bool isFilterChinese) { string hex = isFilterChinese ? FilterChinese(str) : ConvertChinese(str); //清除所有空格 hex = hex.Replace(" ", ""); //若字符个数为奇数,补一个0 hex += hex.Length % 2 != 0 ? "0" : ""; byte[] result = new byte[hex.Length / 2]; for (int i = 0, c = result.Length; i < c; i++) { result[i] = Convert.ToByte(hex.Substring(i * 2, 2), 16); } return result; } #endregion }
WPF技术点:
1.自定义样式按钮
2.转换器用于绑定按钮
public class FontConverters : IValueConverter { public object Convert(object value, Type targetType, object parameter, CultureInfo culture) { if (value != null && bool.TryParse(value.ToString(), out bool result)) { if (result) { return "关闭串口"; } } return "打开串口"; } public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) { throw new NotImplementedException(); } }
//用于绑定UI的颜色状态显示 public class ColorConverters : IValueConverter { public object Convert(object value, Type targetType, object parameter, CultureInfo culture) { if (value != null && bool.TryParse(value.ToString(), out bool result)) { if (result) { return new SolidColorBrush((Color)System.Windows.Media.ColorConverter.ConvertFromString("#2E8B57")); } } return new SolidColorBrush((Color)System.Windows.Media.ColorConverter.ConvertFromString("#FF6347")); } public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) { throw new NotImplementedException(); } }
3.引用字体
4.绑定命令和元素
写在最后
主项目的结构图 , 如下:
看完上述内容是否对您有帮助呢?如果还想对相关知识有进一步的了解或阅读更多相关文章,请关注行业资讯频道,感谢您对的支持。
参数
串口
数据
字符
作用
转换器
配置
功能
方法
进制
增量
摘要
核心
界面
端口
需求
有效
元素
区域
区域性
数据库的安全要保护哪些东西
数据库安全各自的含义是什么
生产安全数据库录入
数据库的安全性及管理
数据库安全策略包含哪些
海淀数据库安全审计系统
建立农村房屋安全信息数据库
易用的数据库客户端支持安全管理
连接数据库失败ssl安全错误
数据库的锁怎样保障安全
上海童颜网络技术有限公司
审计部门网络安全责任制度
数据库中函数的类型有哪些
网络游戏和服务器有关系吗
数据库中enddo是啥意思
华为网络技术大赛 知乎
违反学生网络安全守则
报网络技术三级给证书吗
自贡网络技术参数
腾讯云轻量服务器登陆密码
网络安全专题教育感想
美国第一个白宫网络安全协调官
高校网络安全信息自查
山东租用服务器平台
法官解读网络安全法
医院信息网络安全性
怎样学软件开发编程
小程序直播平台搭建服务器
网络安全教育教师培训
济南数据中心服务器
阿里云服务器ecs绑定几个域名
安装数据库出现错误1406
幻塔不同服务器能添加好友吗
软件开发合同解除协议书范本
服务器证书查看
浪潮品牌服务器联系方式
软件开发视频播放添加进度条
数据库升迁什么意思
三级 网络技术 题库
温州智能软件开发系统