串口通信之屎山代码

先看winform整体布局

以下是整体代码以及注释

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.IO;
using System.IO.Ports;

namespace WindowsFormsApp2
{
    public partial class Form1 : Form
    {
        String serialPortName;

        public Form1()
        {
            InitializeComponent();
            serialPort1.DataReceived += new SerialDataReceivedEventHandler(serialPort1_DataReceived);
        }
        private void Form1_Load(object sender, EventArgs e)
        {
            string[] ports = System.IO.Ports.SerialPort.GetPortNames(); // 获取本机可用串口端口
            comboBoxPort.Items.AddRange(ports);
            comboBoxPort.SelectedIndex = comboBoxPort.Items.Count > 0 ? 0 : -1; // 有可用端口显示第一个

            string[] Bauds = new string[] { "自定義", "4800", "9600", "12800", "19200", "38400" };
            comboBoxBaudrate.DataSource = Bauds;
            comboBoxBaudrate.SelectedIndex = 2;

            int[] datas = new int[] { 5, 6, 7, 8 };
            comboBoxDataBits.DataSource = datas;
            comboBoxDataBits.SelectedIndex = 3;

            string[] stopBits = new string[] { "1", "1.5", "2" };
            comboBoxStopbit.DataSource = stopBits;
            comboBoxStopbit.SelectedIndex = 0;

            string[] paritys = new string[] { "無", "奇校驗", "偶校驗" };
            comboBoxCheck.DataSource = paritys;
            comboBoxCheck.SelectedIndex = 0;
        }

        /// <summary>
        /// 重写系统消息函数
        /// </summary>
        /// <param name="m"></param>
        protected override void WndProc(ref Message m)
        {
            base.WndProc(ref m);
        }

        /// <summary>
        /// 串口数据接收
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void serialPort1_DataReceived(object sender, System.IO.Ports.SerialDataReceivedEventArgs e)
        {
            // 获取当前串口可读取的字节数
            int len = serialPort1.BytesToRead;
            // 根据len的大小创建一个byte数组buff用于存储从串口读取的数据
            byte[] buff = new byte[len];
            // 从串口读取数据到buff数组中,从索引0开始,读取长度为len的字节
            serialPort1.Read(buff, 0, len);

            // 将byte数组buff中的数据转换成默认编码(通常是ASCII)的字符串str
            string str = Encoding.Default.GetString(buff);

            Invoke((new Action(() => {
                if (checkBox3.Checked)  // 黑底白字
                {
                    textBoxRecv.BackColor = Color.Black;
                    textBoxRecv.ForeColor = Color.White;
                }
                else
                {
                    textBoxRecv.BackColor = SystemColors.Window; // 默认窗口背景色
                    textBoxRecv.ForeColor = SystemColors.WindowText; // 默认文本颜色
                }

                if (checkBoxHexShow.Checked)    // Hex(16进制显示)
                {
                    // 调用byteToHexStr方法将buff数组转换为十六进制字符串
                    string hexStr = byteToHexStr(buff);

                    if (checkBoxRtsShow.Checked && checkBox5.Checked && checkBoxDtrShow.Checked) // 同时选择 时间戳、RTS、DTR显示
                    {
                        textBoxRecv.AppendText($"[{DateTime.Now:yyyy-MM-dd HH:mm:ss.fff}] RTS:{serialPort1.RtsEnable} DTR:{serialPort1.DtrEnable} {hexStr}{Environment.NewLine}");
                    }
                    else if (checkBoxRtsShow.Checked && checkBox5.Checked)   // 同时选择 时间戳和RTS显示
                    {
                        textBoxRecv.AppendText($"[{DateTime.Now:yyyy-MM-dd HH:mm:ss.fff}] RTS:{serialPort1.RtsEnable} {hexStr}{Environment.NewLine}");
                    }
                    else if (checkBoxDtrShow.Checked && checkBox5.Checked)   // 同时选择 时间戳和DTR显示
                    {
                        textBoxRecv.AppendText($"[{DateTime.Now:yyyy-MM-dd HH:mm:ss.fff}] DTR:{serialPort1.DtrEnable} {hexStr}{Environment.NewLine}");
                    }
                    else if (checkBoxDtrShow.Checked && checkBoxRtsShow.Checked)   // 同时选择 RTS和DTR显示
                    {
                        textBoxRecv.AppendText($"RTS:{serialPort1.RtsEnable} DTR:{serialPort1.DtrEnable} {hexStr}{Environment.NewLine}");
                    }
                    else if (checkBox5.Checked)  // 只显示时间戳
                    {
                        textBoxRecv.AppendText($"[{DateTime.Now:yyyy-MM-dd HH:mm:ss.fff}] {hexStr}{Environment.NewLine}");
                    }
                    else if (checkBoxRtsShow.Checked)  // 只显示RTS
                    {
                        textBoxRecv.AppendText($"RTS:{serialPort1.RtsEnable} {hexStr}{Environment.NewLine}");
                    }
                    else if (checkBoxRtsShow.Checked)  // 只显示DTR
                    {
                        textBoxRecv.AppendText($"DTR:{serialPort1.DtrEnable} {hexStr}{Environment.NewLine}");
                    }
                    else // 不选择任何项
                    {
                        textBoxRecv.AppendText($"{hexStr}{Environment.NewLine}");
                    }
                }
                else   // 直接将ASCII字符串str追加到文本框中
                {
                    if (checkBoxRtsShow.Checked && checkBox5.Checked && checkBoxDtrShow.Checked) // 同时选择 时间戳、RTS、DTR显示
                    {
                        textBoxRecv.AppendText($"[{DateTime.Now:yyyy-MM-dd HH:mm:ss.fff}] RTS:{serialPort1.RtsEnable} DTR:{serialPort1.DtrEnable} {str} {Environment.NewLine}");
                    }
                    else if (checkBoxRtsShow.Checked && checkBox5.Checked)   // 同时选择 时间戳和RTS显示
                    {
                        textBoxRecv.AppendText($"[{DateTime.Now:yyyy-MM-dd HH:mm:ss.fff}] RTS:{serialPort1.RtsEnable} {str}{Environment.NewLine}");
                    }
                    else if (checkBoxDtrShow.Checked && checkBox5.Checked)   // 同时选择 时间戳和DTR显示
                    {
                        textBoxRecv.AppendText($"[{DateTime.Now:yyyy-MM-dd HH:mm:ss.fff}] DTR:{serialPort1.DtrEnable} {str}{Environment.NewLine}");
                    }
                    else if (checkBoxDtrShow.Checked && checkBoxRtsShow.Checked)   // 同时选择 RTS和DTR显示
                    {
                        textBoxRecv.AppendText($"RTS:{serialPort1.RtsEnable} DTR:{serialPort1.DtrEnable} {str}{Environment.NewLine}");
                    }
                    else if (checkBox5.Checked) // 只选择 时间戳显示
                    {
                        textBoxRecv.AppendText($"[{DateTime.Now:yyyy-MM-dd HH:mm:ss.fff}] {str}{Environment.NewLine}");
                    }
                    else if (checkBoxRtsShow.Checked) // 只选择 RTS显示
                    {
                        textBoxRecv.AppendText($"RTS:{serialPort1.RtsEnable} {str}{Environment.NewLine}");
                    }
                    else if (checkBoxDtrShow.Checked) // 只选择 DTR显示
                    {
                        textBoxRecv.AppendText($"DTR:{serialPort1.DtrEnable} {str}{Environment.NewLine}");
                    }
                    else // 不选择任何额外选项
                    {
                        textBoxRecv.AppendText($"{str}{Environment.NewLine}");
                    }
                }
            })));
        }

        /// <summary>
        /// 构建十六进制,用于接收数据显示出来
        /// </summary>
        /// <param name="bytes"></param>
        /// <returns></returns>
        public static string byteToHexStr(byte[] bytes)
        {
            string hexStr = ""; //用于存储转换后的十六进制字符串
            try
            {
                if (bytes != null) // 检查传入的字节数组是否为null
                {
                    for (int i = 0; i < bytes.Length; i++) // 遍历字节数组中的每一个元素
                    {
                        //X2 用于将字节数据格式化为两位的大写十六进制字符串,不足两位时在前面补0
                        hexStr += bytes[i].ToString("X2");
                        hexStr += " "; // 在每个十六进制值后面添加一个空格
                    }
                }
                return hexStr; // 返回构建好的十六进制字符串
            }
            catch (Exception)
            {
                return hexStr; // 如果发生异常,则返回初始的空字符串hexStr
            }
        }

        /// <summary>
        /// 打开关闭串口
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void buttonClearSend_Click(object sender, EventArgs e)
        {
            if (buttonPortOnOff.Text == "打开串口")
            {
                try
                {
                    serialPort1.PortName = comboBoxPort.Text; // 获取选择的串口端口
                    serialPortName = comboBoxPort.Text;
                    serialPort1.BaudRate = int.Parse(comboBoxBaudrate.Text);    // 获取选择的波特率
                    serialPort1.DataBits = int.Parse(comboBoxDataBits.Text);    // 获取选择的数据位

                    // 设置停止位
                    if (comboBoxStopbit.Text == "1") { serialPort1.StopBits = StopBits.One; }
                    else if (comboBoxStopbit.Text == "1.5") { serialPort1.StopBits = StopBits.OnePointFive; }
                    else if (comboBoxStopbit.Text == "2") { serialPort1.StopBits = StopBits.Two; }

                    // 设置奇偶校验
                    if (comboBoxCheck.Text == "無") { serialPort1.Parity = Parity.None; }
                    else if (comboBoxCheck.Text == "偶校驗") { serialPort1.Parity = Parity.Even; }
                    else if (comboBoxCheck.Text == "奇校驗") { serialPort1.Parity = Parity.Odd; }

                    // 打开串口
                    serialPort1.Open();
                    buttonPortOnOff.Text = "关闭串口";
                }
                catch (Exception ex)
                {
                    MessageBox.Show("串口打开失败" + ex.ToString(), "警告",
                        MessageBoxButtons.OK, MessageBoxIcon.Error);
                }
            }
            else
            {
                try
                {
                    serialPort1.Close();
                }
                catch (Exception ex)
                {
                    MessageBox.Show("發生錯誤" + ex.ToString(), "警告", MessageBoxButtons.OK, MessageBoxIcon.Error);
                }
                buttonPortOnOff.Text = "打开串口";
            }
        }

        /// <summary>
        /// 清空接收数据
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void buttonClearRecv_Click(object sender, EventArgs e)
        {
            textBoxRecv.Clear();
        }

        /// <summary>
        /// 发送数据
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void buttonSendData_Click(object sender, EventArgs e)
        {
            string str = textBoxSend.Text; // 获取文本框里的数据
            try
            {
                if (str.Length > 0)
                {
                    byte[] bytesToSend; // 初始化一個byte字節數組
                    if (comboBoxEncoding.Checked)
                    {
                        // 移除所有空格,然后每两个字符解析为一个字节
                        str = str.Replace(" ", "");
                        int numberChars = str.Length; // 获取移除空格后的字符串长度,并存储在变量中40

                        // 创建一个新的byte数组,其大小为numberChars除以2(因为每个字节由两个字符表示)40/2
                        bytesToSend = new byte[numberChars / 2];

                        // 循环遍历字符串,步长为2,即每次处理两个字符
                        for (int i = 0; i < numberChars; i += 2)
                        {
                            // 使用Substring方法从当前索引i开始提取两个字符组成的子串
                            bytesToSend[i / 2] = Convert.ToByte(str.Substring(i, 2), 16);
                        }
                    }
                    else // 默认为ASCII编码
                    {
                        bytesToSend = Encoding.ASCII.GetBytes(str);
                    }
                    serialPort1.Write(bytesToSend, 0, bytesToSend.Length); // 使用字节数组发送
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show($"发送数据失败: {ex.Message}", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }

        /// <summary>
        /// 清除发送数据
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void buttonClearSend_Click1(object sender, EventArgs e)
        {
            textBoxSend.Clear();
        }

        /// <summary>
        /// 保存接收到的数据
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void button2_Click(object sender, EventArgs e)
        {
            string str = textBoxRecv.Text;
            bool isSaved = SaveSendRecord(str, "Active");
            if (isSaved)
            {
                ShowNotification("数据保存成功!");
            }
        }

        /// <summary>
        /// 保存数据
        /// </summary>
        /// <param name="data"></param>
        /// <returns></returns>
        private bool SaveSendRecord(string data, string txt)
        {
            try
            {
                string filePath = Path.Combine(Application.StartupPath, $"{txt}.txt");
                // 使用File.AppendAllText方法将数据追加到文件末尾,并加上换行符
                File.AppendAllText(filePath, $"{DateTime.Now}: {Environment.NewLine} {data}\n");
                return true; // 如果保存成功返回true
            }
            catch (Exception ex)
            {
                // 处理异常情况
                Console.WriteLine($"保存失败: {ex.Message}");
                return false; // 如果保存失败返回false
            }
        }

        /// <summary>
        /// 保存成功弹窗
        /// </summary>
        /// <param name="message"></param>
        private void ShowNotification(string message)
        {
            Label notificationLabel = new Label
            {
                Text = message,
                AutoSize = false,
                Width = this.ClientSize.Width,
                Height = 25,
                BackColor = System.Drawing.ColorTranslator.FromHtml("#4CAF50"), // 设置为绿色背景
                ForeColor = System.Drawing.SystemColors.Window,
                Font = new System.Drawing.Font("Microsoft Sans Serif", 9F, System.Drawing.FontStyle.Bold),
                TextAlign = System.Drawing.ContentAlignment.MiddleCenter
            };
            // 将通知标签添加到窗体顶部
            this.Controls.Add(notificationLabel);
            notificationLabel.Location = new System.Drawing.Point(0, 0);

            // 启动计时器自动移除通知
            Timer timer = new Timer { Interval = 1500 }; // 1.5秒后自动隐藏
            timer.Tick += (s, ev) =>
            {
                notificationLabel.Visible = false;
                timer.Stop();
            };
            timer.Start();
        }
    }
}

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值