C#如何实现串口调试工具
发表于:2024-09-25 作者:千家信息网编辑
千家信息网最后更新 2024年09月25日,C#如何实现串口调试工具,很多新手对此不是很清楚,为了帮助大家解决这个难题,下面小编将为大家详细讲解,有这方面需求的人可以来学习下,希望你能有所收获。前文由于经常用到串口调试, 尽管有现成的软件, 因
千家信息网最后更新 2024年09月25日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安全错误
数据库的锁怎样保障安全
手机底部不停跳连接服务器
计算机网络技术什么时候学
网络安全法自媒体
国家推动网络安全 建设
十进制排序数据库
荒野的召唤多人游戏找不到服务器
经济技术开发区奥斯网络技术
江西联荻互联网科技有限公司
软件开发测试男生发色
软件开发计划测试计划的制定
计算机网络安全维护包含哪些
mdb 数据库 图片
天地劫有多少个服务器
2021年云服务器排行
蜀山论剑网络安全大会完整版
数据库安全方面措施
数据库技术的应用研究
怎么获取外国的大数据库
徐州网络安全专家
云服务器加空间太贵
临汾软件开发公司电话
河南手机软件开发有用吗
济南crm软件开发制作
网络安全建设全本答案
占美i54200u能刷服务器吗
小型软件开发服务至上
数据库一般用什么样的cpu
软件开发和网站建设那个好
软件开发前端H
江西省数盾信息技术网络安全研究