温馨提示×

温馨提示×

您好,登录后才能下订单哦!

密码登录×
登录注册×
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》

C#如何实现串口调试工具

发布时间:2022-01-26 11:44:00 来源:亿速云 阅读:241 作者:柒染 栏目:开发技术

C#如何实现串口调试工具,很多新手对此不是很清楚,为了帮助大家解决这个难题,下面小编将为大家详细讲解,有这方面需求的人可以来学习下,希望你能有所收获。

前文

由于经常用到串口调试, 尽管有现成的软件, 因为前端时间涉及一个二次开发, 就因为一个RtsEnable设置, 折腾半天, 网上各种版本的也很多, 功能扩展的很开也多。所以现在自己做了一个够用版,基于自己的需求,简单的实现发送接收功能, 至于那些扩展功能可以自己根据需求添加。

正文

先上个运行效果图:

C#如何实现串口调试工具

项目架构

该实例用的GalaSoft.Mvvm, 该插件可以直接在NuGet中并且添加。

C#如何实现串口调试工具

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.串口参数配置类 ,

作用: 主要用于绑定界面的参数选项。

/// <summary>     /// 串口参数设置类     /// </summary>     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<int>() { 110, 300, 600, 1200, 2400, 4800, 9600, 14400, 19200, 38400, 56000, 57600, 115200, };             DataBit = new List<int>() { 6, 7, 8 };         }         private Array port;         private Array checkMode;         private Array stopBit;         private List<int> dataBit;         private List<int> baudRate;         /// <summary>         /// 端口         /// </summary>         public Array Port         {             get { return port; }             set { port = value; RaisePropertyChanged(); }         }         /// <summary>         /// 校验模式         /// </summary>         public Array CheckMode         {             get { return checkMode; }             set { checkMode = value; RaisePropertyChanged(); }         }         /// <summary>         /// 停止位         /// </summary>         public Array StopBit         {             get { return stopBit; }             set { stopBit = value; RaisePropertyChanged(); }         }         /// <summary>         /// 波特率         /// </summary>         public List<int> BaudRate         {             get { return baudRate; }             set { baudRate = value; RaisePropertyChanged(); }         }         /// <summary>         /// 数据位         /// </summary>         public List<int> DataBit         {             get { return dataBit; }             set { dataBit = value; RaisePropertyChanged(); }         }     }

3.当前配置参数类

作用: 用于保存当前的串口参数、串口功能开关接收数据等业务。

核心代码:

/// <summary>     /// 当前配置参数     /// </summary>     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绑定参数         /// <summary>         /// 发送数量         /// </summary>         public int SendCount         {             get { return sendCount; }             set { sendCount = value; RaisePropertyChanged(); }         }         /// <summary>         /// 接收数量         /// </summary>         public int ReceiveCount         {             get { return receiveCount; }             set { receiveCount = value; RaisePropertyChanged(); }         }         /// <summary>         /// 接收区16进制         /// </summary>         public bool ReceiveFormat16         {             get { return receiveFormat16; }             set { receiveFormat16 = value; RaisePropertyChanged(); }         }         /// <summary>         /// 接收区数据         /// </summary>         public string DataReceiveInfo         {             get { return dataReceiveInfo; }             set { dataReceiveInfo = value; RaisePropertyChanged(); }         }         /// <summary>         /// 发送数据         /// </summary>         public string SendData         {             get             {                 return sendData;             }             set { sendData = value; RaisePropertyChanged(); }         }         /// <summary>         /// 发送区16进制         /// </summary>         public bool SendFormat16         {             get { return sendFormat16; }             set { sendFormat16 = value; RaisePropertyChanged(); }         }         #endregion         #region 串口参数信息         /// <summary>         /// 开关         /// </summary>         public bool IsOpen         {             get { return isOpen; }             set { isOpen = value; RaisePropertyChanged(); }         }         /// <summary>         /// 数据位         /// </summary>         public int DataBit         {             get { return dataBit; }             set { dataBit = value; RaisePropertyChanged(); }         }         /// <summary>         /// 波特率         /// </summary>         public int BaudRdate         {             get { return baudRdate; }             set { baudRdate = value; RaisePropertyChanged(); }         }         /// <summary>         /// 端口         /// </summary>         public Port Port         {             get { return port; }             set { port = value; RaisePropertyChanged(); }         }         /// <summary>         /// 校验         /// </summary>         public CheckMode CheckMode         {             get { return checkMode; }             set { checkMode = value; RaisePropertyChanged(); }         }         /// <summary>         /// 停止位         /// </summary>         public StopBit StopBit         {             get { return stopBit; }             set { stopBit = value; RaisePropertyChanged(); }         }         /// <summary>         /// COM         /// </summary>         public SerialPort SerialPort         {             get { return serialPort; }             set { serialPort = value; RaisePropertyChanged(); }         }         #endregion         #region 串口操作方法         /// <summary>         /// 开启串口         /// </summary>         /// <returns></returns>         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;         }         /// <summary>         /// 关闭串口         /// </summary>         /// <returns></returns>         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;             }         }         /// <summary>         /// 发送数据         /// </summary>         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");         }         /// <summary>         /// 清空接收区         /// </summary>         public void Clear()         {             this.DataReceiveInfo = string.Empty;         }         /// <summary>         /// 清空发送区和缓存区         /// </summary>         public void ClearText()         {             this.SendData = string.Empty;             this.SendCount = 0;             this.ReceiveCount = 0;         }         #endregion         /// <summary>         /// 返回事件         /// </summary>         /// <param name="sender"></param>         /// <param name="e"></param>         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     {         /// <summary>         /// Initializes a new instance of the MainViewModel class.         /// </summary>         public MainViewModel()         {             ComParameterConfig = new ComParameterConfig();             CurrentParameter = new CurrentParameter();         }         private ComParameterConfig comParameter;         /// <summary>         /// 参数类         /// </summary>         public ComParameterConfig ComParameterConfig         {             get { return comParameter; }             set { comParameter = value; RaisePropertyChanged(); }         }         private CurrentParameter currentParameter;         /// <summary>         /// 当前配置参数         /// </summary>         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;             }         }         /// <summary>         /// 根据配置打开端口         /// </summary>         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;             }         }         /// <summary>         /// 发送数据         /// </summary>         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;             }         }         /// <summary>         /// 清空接收区         /// </summary>         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;             }         }         /// <summary>         /// 清空界面值         /// </summary>         public void ClearText()         {             this.CurrentParameter.ClearText();         }         #endregion     }

5.CRC校验核心类

作用:主要实现数据校验, 含ModbusCR标准校验

/// <summary>     /// CRC校验     /// </summary>     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();         }         /// <summary>         /// 字符串转16进制字符数组         /// </summary>         /// <param name="hex"></param>         /// <returns></returns>         public static byte[] StringToHexByte(string str)         {             return StringToHexByte(str, false);         }         /// <summary>         /// 字符串转16进制字符数组         /// </summary>         /// <param name="str"></param>         /// <param name="isFilterChinese">是否过滤掉中文字符</param>         /// <returns></returns>         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.自定义样式按钮

<Style x:Key="CommonButtonBase" TargetType="{x:Type Button}">                 <Setter Property="BorderBrush" Value="Transparent"/>                 <Setter Property="BorderThickness" Value="0"/>                 <Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}"/>                 <Setter Property="HorizontalContentAlignment" Value="Center"/>                 <Setter Property="VerticalContentAlignment" Value="Center"/>                 <Setter Property="Padding" Value="1"/>                 <Setter Property="Cursor" Value="Hand"/>                 <Setter Property="Template">                     <Setter.Value>                         <ControlTemplate TargetType="{x:Type Button}">                             <Border x:Name="border" BorderBrush="{TemplateBinding BorderBrush}"                                              CornerRadius="4"                                             BorderThickness="{TemplateBinding BorderThickness}"                                              Background="{TemplateBinding Background}"                                              SnapsToDevicePixels="true">                                 <ContentPresenter HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"                                                Margin="{TemplateBinding Padding}" RecognizesAccessKey="True"                                                SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"                                                VerticalAlignment="{TemplateBinding VerticalContentAlignment}"/>                             </Border>                             <ControlTemplate.Triggers>                                 <Trigger Property="IsEnabled" Value="False">                                     <Setter Property="Background" Value="#000000"/>                                     <Setter Property="Opacity" Value="0.1"/>                                 </Trigger>                                 <Trigger Property="IsMouseOver" Value="true">                                     <Setter Property="Foreground" Value="#FFFF00"/>                                 </Trigger>                                 <Trigger Property="IsMouseOver" Value="false">                                     <Setter Property="Foreground" Value="White"/>                                 </Trigger>                             </ControlTemplate.Triggers>                         </ControlTemplate>                     </Setter.Value>                 </Setter>             </Style>                      <Style TargetType="{x:Type Button}" x:Key="Btn0093EABase" BasedOn="{StaticResource CommonButtonBase}">                 <Setter Property="Background" Value="#0093EA"/>                 <Setter Property="Foreground" Value="White"/>                 <Setter Property="FontSize" Value="22"/>                 <Setter Property="Height" Value="40"/>                 <Setter Property="Margin" Value="5"/>             </Style>

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.引用字体

   <TextBlock Text="&#xe6e4;" Margin="20 5 0 5" FontFamily="pack://application:,,,/Font/#iconfont"                                     Foreground="White" FontSize="30" VerticalAlignment="Center"/>

4.绑定命令和元素

<TextBlock Text="端     口:"  Style="{DynamicResource TxtComStyle}"/>                         <ComboBox  Grid.Row="0" Grid.Column="2" Style="{StaticResource ComboBoxStyle}" SelectedItem="{Binding CurrentParameter.Port}"                                   ItemsSource="{Binding ComParameterConfig.Port}"                                    />                         <TextBlock Text="波 特 率:" Style="{DynamicResource TxtComStyle}"/>                         <ComboBox  Grid.Row="0" Grid.Column="2" Style="{StaticResource ComboBoxStyle}" SelectedItem="{Binding CurrentParameter.BaudRdate}"                                    ItemsSource="{Binding ComParameterConfig.BaudRate}"                                    />                         <TextBlock Text="数 据 位:" Style="{DynamicResource TxtComStyle}"/>                         <ComboBox  Grid.Row="0" Grid.Column="2" Style="{StaticResource ComboBoxStyle}"  SelectedItem="{Binding CurrentParameter.DataBit}"                                    ItemsSource="{Binding ComParameterConfig.DataBit}"                                    />                         <TextBlock Text="校 验 位:" Style="{DynamicResource TxtComStyle}"/>                         <ComboBox  Grid.Row="0" Grid.Column="2" Style="{StaticResource ComboBoxStyle}"  SelectedItem="{Binding CurrentParameter.CheckMode}"                                    ItemsSource="{Binding ComParameterConfig.CheckMode}"                                    />                         <TextBlock Text="停 止 位:" Style="{DynamicResource TxtComStyle}"/>                         <ComboBox  Grid.Row="0" Grid.Column="2" Style="{StaticResource ComboBoxStyle}"  SelectedItem="{Binding CurrentParameter.StopBit}"                                    ItemsSource="{Binding ComParameterConfig.StopBit}"                                    />                         <TextBlock Text="状     态:" Style="{DynamicResource TxtComStyle}"/>                         <TextBlock Text="&#xe692;" Style="{DynamicResource TxtComStyle1}"  Foreground="{Binding CurrentParameter.IsOpen,Converter={StaticResource ColorConverters}}" />

写在最后

主项目的结构图 , 如下:

C#如何实现串口调试工具

看完上述内容是否对您有帮助呢?如果还想对相关知识有进一步的了解或阅读更多相关文章,请关注亿速云行业资讯频道,感谢您对亿速云的支持。

向AI问一下细节

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

AI