文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

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

2023-06-29 00:00

关注

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

前文

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

正文

先上个运行效果图:

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

项目架构

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

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

串口参数 , 为了方便, 端口号并没有用动态加载的方式, 如下枚举结构:

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);    }}

串口参数配置类 ,

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

/// <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(); }        }    }

当前配置参数类

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

核心代码:

/// <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);            }        }    }

核心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    }

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技术点:

自定义样式按钮

<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>

转换器用于绑定按钮

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();        }    }

引用字体

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

绑定命令和元素

<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#如何实现串口调试工具

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

阅读原文内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     807人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     351人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     314人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     433人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     221人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-后端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯