C#3串口调试助手

这个是简单的小串口调试助手,主要是数据接收和数据发送,有些地方我也不懂,刚学C#.请大家多多指教

数据的收发都可以实现,好像十六进制显示和收发不太好,如果大家有改进的欢迎讨论。谢谢。

当时第一次做的时候,好多控件都不能用,那是因为我没绑定事件,请刚学的小伙伴们不要犯一样的错误哦。

事件就是这个了。


下面贴上代码:

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


namespace serialport
{
    public partial class Form1 : Form
    {
        #region 变量及委托声明
        // 关闭标志,表示串口正在关闭
        private bool closing = false;

        //监听标志, 用于安全关闭串口
        private bool listening = false;

        //累计接收字节
        private long receiveCount = 0;

        //累计发送字节
        private long sendCount = 0;

        //委托,用于跨线程调用
        delegate void InvokeTextPaly(string text);

        //List,用于二进制数据包的缓存,也可用数组缓存
        private List<byte> bufferRead = new List<byte>(4096);

        //数组,用于缓存一个长度完整的数据包
        byte[] dataCatchedArry = new byte[9];

        #endregion

        #region  CRC16校验码索引数组
        private byte[] crcHiArry = 
        {   0x00,  0xC1,  0x81,  0x40,  0x01,  0xC0,  0x80,  0x41,  0x01,  0xC0,  0x80, 0x41, 
            0x00, 0xC1, 0x81, 
            0x40,  0x01,  0xC0,  0x80,  0x41,  0x00,  0xC1,  0x81,  0x40,  0x00,  0xC1, 0x81, 
            0x40, 0x01, 0xC0, 
            0x80,  0x41,  0x01,  0xC0,  0x80,  0x41,  0x00,  0xC1,  0x81,  0x40,  0x00, 0xC1, 
            0x81, 0x40, 0x01, 
            0xC0,  0x80,  0x41,  0x00,  0xC1,  0x81,  0x40,  0x01,  0xC0,  0x80,  0x41, 0x01, 
            0xC0, 0x80, 0x41, 
            0x00,  0xC1,  0x81,  0x40,  0x01,  0xC0,  0x80,  0x41,  0x00,  0xC1,  0x81, 0x40,
            0x00, 0xC1, 0x81, 
            0x40,  0x01,  0xC0,  0x80,  0x41,  0x00,  0xC1,  0x81,  0x40,  0x01,  0xC0, 0x80, 
            0x41, 0x01, 0xC0, 
            0x80,  0x41,  0x00,  0xC1,  0x81,  0x40,  0x00,  0xC1,  0x81,  0x40,  0x01, 0xC0, 
            0x80, 0x41, 0x01, 
            0xC0,  0x80,  0x41,  0x00,  0xC1,  0x81,  0x40,  0x01,  0xC0,  0x80,  0x41, 0x00, 
            0xC1, 0x81, 0x40, 
            0x00,  0xC1,  0x81,  0x40,  0x01,  0xC0,  0x80,  0x41,  0x01,  0xC0,  0x80, 0x41, 
            0x00, 0xC1, 0x81, 
            0x40,  0x00,  0xC1,  0x81,  0x40,  0x01,  0xC0,  0x80,  0x41,  0x00,  0xC1, 0x81, 
            0x40, 0x01, 0xC0, 
            0x80,  0x41,  0x01,  0xC0,  0x80,  0x41,  0x00,  0xC1,  0x81,  0x40,  0x00, 0xC1, 
            0x81, 0x40, 0x01, 
            0xC0,  0x80,  0x41,  0x01,  0xC0,  0x80,  0x41,  0x00,  0xC1,  0x81,  0x40, 0x01, 
            0xC0, 0x80, 0x41, 
            0x00,  0xC1,  0x81,  0x40,  0x00,  0xC1,  0x81,  0x40,  0x01,  0xC0,  0x80, 0x41, 
            0x00, 0xC1, 0x81, 
            0x40,  0x01,  0xC0,  0x80,  0x41,  0x01,  0xC0,  0x80,  0x41,  0x00,  0xC1, 0x81, 
            0x40, 0x01, 0xC0, 
            0x80,  0x41,  0x00,  0xC1,  0x81,  0x40,  0x00,  0xC1,  0x81,  0x40,  0x01, 0xC0, 
            0x80, 0x41, 0x01, 
            0xC0,  0x80,  0x41,  0x00,  0xC1,  0x81,  0x40,  0x00,  0xC1,  0x81,  0x40, 0x01, 
            0xC0, 0x80, 0x41, 
            0x00,  0xC1,  0x81,  0x40,  0x01,  0xC0,  0x80,  0x41,  0x01,  0xC0,  0x80, 0x41, 
            0x00, 0xC1, 0x81, 
            0x40 };

        private byte[] crcLoArry = 
        { 
        0x00,  0xC0,  0xC1,  0x01,  0xC3,  0x03,  0x02,  0xC2,  0xC6,  0x06,  0x07, 0xC7, 
        0x05, 0xC5, 0xC4,
        0x04,  0xCC,  0x0C,  0x0D,  0xCD,  0x0F,  0xCF,  0xCE,  0x0E,  0x0A,  0xCA, 0xCB, 
        0x0B, 0xC9, 0x09,
        0x08,  0xC8,  0xD8,  0x18,  0x19,  0xD9,  0x1B,  0xDB,  0xDA,  0x1A,  0x1E, 0xDE, 
        0xDF, 0x1F, 0xDD,
        0x1D,  0x1C,  0xDC,  0x14,  0xD4,  0xD5,  0x15,  0xD7,  0x17,  0x16,  0xD6, 0xD2, 
        0x12, 0x13, 0xD3,
        0x11,  0xD1,  0xD0,  0x10,  0xF0,  0x30,  0x31,  0xF1,  0x33,  0xF3,  0xF2, 0x32, 
        0x36, 0xF6, 0xF7,
        0x37,  0xF5,  0x35,  0x34,  0xF4,  0x3C,  0xFC,  0xFD,  0x3D,  0xFF,  0x3F, 0x3E, 
        0xFE, 0xFA, 0x3A,
        0x3B,  0xFB,  0x39,  0xF9,  0xF8,  0x38,  0x28,  0xE8,  0xE9,  0x29,  0xEB, 0x2B, 
        0x2A, 0xEA, 0xEE,
        0x2E,  0x2F,  0xEF,  0x2D,  0xED,  0xEC,  0x2C,  0xE4,  0x24,  0x25,  0xE5, 0x27, 
        0xE7, 0xE6, 0x26,
        0x22,  0xE2,  0xE3,  0x23,  0xE1,  0x21,  0x20,  0xE0,  0xA0,  0x60,  0x61, 0xA1, 
        0x63, 0xA3, 0xA2,
        0x62,  0x66,  0xA6,  0xA7,  0x67,  0xA5,  0x65,  0x64,  0xA4,  0x6C,  0xAC, 0xAD, 
        0x6D, 0xAF, 0x6F,
        0x6E,  0xAE,  0xAA,  0x6A,  0x6B,  0xAB,  0x69,  0xA9,  0xA8,  0x68,  0x78, 0xB8, 
        0xB9, 0x79, 0xBB,
        0x7B,  0x7A,  0xBA,  0xBE,  0x7E,  0x7F,  0xBF,  0x7D,  0xBD,  0xBC,  0x7C, 0xB4, 
        0x74, 0x75, 0xB5,
        0x77,  0xB7,  0xB6,  0x76,  0x72,  0xB2,  0xB3,  0x73,  0xB1,  0x71,  0x70, 0xB0, 
        0x50, 0x90, 0x91,
        0x51,  0x93,  0x53,  0x52,  0x92,  0x96,  0x56,  0x57,  0x97,  0x55,  0x95, 0x94, 
        0x54, 0x9C, 0x5C,
        0x5D,  0x9D,  0x5F,  0x9F,  0x9E,  0x5E,  0x5A,  0x9A,  0x9B,  0x5B,  0x99, 0x59, 
        0x58, 0x98, 0x88,
        0x48,  0x49,  0x89,  0x4B,  0x8B,  0x8A,  0x4A,  0x4E,  0x8E,  0x8F,  0x4F, 0x8D, 
        0x4D, 0x4C, 0x8C,
        0x44,  0x84,  0x85,  0x45,  0x87,  0x47,  0x46,  0x86 ,  0x82,  0x42,  0x43, 0x83, 
        0x41, 0x81, 0x80,
        0x40};
        #endregion

        #region 窗口函数

        public Form1()
        {
            InitializeComponent();
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            GetPortName();
            if (comboBox_portName.Text == "")
                comboBox_portName.Text = "COM1";
            if (comboBox_dataBits.Text == "")
                comboBox_dataBits.Text = "8";
            if (comboBox_stopBits.Text == "")
                comboBox_stopBits.Text = "1";
            if (comboBox_rate.Text == "")
                comboBox_rate.Text = "9600";
            if (comboBox_paity.Text == "")
                comboBox_paity.Text = "None";
            OpenSerialPort();
            checkBox_hexSend_CheckedChanged(null, null);       //加载默认设置并配置
            checkBox_autoSend_CheckedChanged(null, null);
            //checkBox_wrap_CheckedChanged(null, null);
        }

        #endregion

        #region 初始化打开串口

        //获取当前串口名
        private void GetPortName()
        {
            comboBox_portName.Items.Clear();
            string[] portNames = SerialPort.GetPortNames();
            foreach (string name in portNames)
            {
                if (name != "")
                    comboBox_portName.Items.Add(name);
            }
            comboBox_portName.Text = global ::serialport.Properties.Settings.Default.PortName;  
        }

        //打开串口
        private void OpenSerialPort()
        {
            if (serialPort1.IsOpen)
            {
                return;
            }
            try
            {
                CheckConfig();
                serialPort1.Open();
                if (serialPort1.IsOpen)
                {
                    button_openClosePort.Text = "关闭串口";
                    label_powerLed.ForeColor = Color.Lime;
                    Label_mainMessage.ForeColor = Color.Green;
                    Label_mainMessage.Text = serialPort1.PortName + "已打开";
                }
            }
            catch
            {
                Label_mainMessage.ForeColor = Color.Red;
                Label_mainMessage.Text = "串口打开失败!";
            }
        }

        //关闭串口
        private void CloseSerialPort()
        {
            if (!serialPort1.IsOpen)
            {
                return;
            }
            try
            {
                closing = true;
                while (listening)
                    Application.DoEvents();
                serialPort1.Close();
                closing = false;
                if (!serialPort1.IsOpen)
                {
                    button_openClosePort.Text = "打开串口";
                    label_powerLed.ForeColor = Color.DarkGray;
                    Label_mainMessage.ForeColor = Color.Green;
                    Label_mainMessage.Text = serialPort1.PortName + "已关闭";
                }
            }
            catch
            {
                Label_mainMessage.ForeColor = Color.Red;
                Label_mainMessage.Text = "串口关闭失败!";
            }
        }

        //每次打开串口前需要重新检测参数并配置
        private void CheckConfig()
        {
            comboBox_portName_TextChanged(null, null);
            comboBox_rate_TextChanged(null, null);
            comboBox_dataBits_TextChanged(null, null);
            comboBox_stopBits_TextChanged(null, null);
            comboBox_paity_TextChanged(null, null);
            //  checkBox_RTS_CheckedChanged(null, null);
            // checkBox_DTR_CheckedChanged(null, null);
        }

        //用于刷新端口名称
        private void comboBox_portName_MouseDown(object sender, MouseEventArgs e)
        {
            GetPortName();
        }

        private void comboBox_portName_TextChanged(object sender, EventArgs e)
        {
            try
            {
                if (serialPort1.IsOpen)
                {
                    CloseSerialPort();
                    CheckConfig();
                    //  serialPort1.PortName = comboBox_portName.Text;
                    OpenSerialPort();
                }
                else
                {
                    serialPort1.PortName = comboBox_portName.Text;
                }
            }
            catch
            {
                //Label_mainMessage.ForeColor = Color.Red;
                //Label_mainMessage.Text = "串口号配置错误!";
            }
        }

        private void comboBox_rate_TextChanged(object sender, EventArgs e)
        {
            try
            {
                serialPort1.BaudRate = Convert.ToInt32(comboBox_rate.Text);
            }
            catch
            {
                Label_mainMessage.Text = "波特率配置错误!";
            }
        }

        private void comboBox_dataBits_TextChanged(object sender, EventArgs e)
        {
            try
            {
                serialPort1.DataBits = Convert.ToInt32(comboBox_dataBits.Text);
            }
            catch
            {
                Label_mainMessage.Text = "数据位配置错误!";
            }
        }

        private void comboBox_stopBits_TextChanged(object sender, EventArgs e)
        {
            try
            {
                if (comboBox_stopBits.Text == "1")
                    serialPort1.StopBits = StopBits.One;
                else if (comboBox_stopBits.Text == "1.5")
                    serialPort1.StopBits = StopBits.OnePointFive;
                else if (comboBox_stopBits.Text == "2")
                    serialPort1.StopBits = StopBits.Two;
            }
            catch
            {
                Label_mainMessage.Text = "停止位配置错误!";
            }
        }

        private void comboBox_paity_TextChanged(object sender, EventArgs e)
        {
            try
            {
                switch (comboBox_paity.Text)
                {
                    case "None":
                        serialPort1.Parity = Parity.None; break;
                    case "Odd":
                        serialPort1.Parity = Parity.Odd; break;
                    case "Even":
                        serialPort1.Parity = Parity.Even; break;
                    case "Mark":
                        serialPort1.Parity = Parity.Mark; break;
                    case "Space":
                        serialPort1.Parity = Parity.Space; break;
                }
            }
            catch
            {
                Label_mainMessage.Text = "校验位配置错误!";
            }
        }

        /*     private void checkBox_RTS_CheckedChanged(object sender, EventArgs e)
             {
                 serialPort1.DtrEnable = checkBox_DTR.Checked;
             }

             private void checkBox_DTR_CheckedChanged(object sender, EventArgs e)
             {
                 serialPort1.RtsEnable = checkBox_RTS.Checked;
             }
             */
        //串口开关按钮 Click事件

        private void button_openClosePort_Click(object sender, EventArgs e)
        {
            if (button_openClosePort.Text == "打开串口")
                OpenSerialPort();
            else
                CloseSerialPort();
        }
        //点击help,弹出新窗口
        private void label_help_Click(object sender, EventArgs e)
        {

        }
      
        #endregion

        #region 数据接收

        //跨线程更新控件,用于显示串口接收到的数据 
        private void AppenTextBox(string text)
        {
            if (textBox_receive.InvokeRequired)
            {
                InvokeTextPaly d = new InvokeTextPaly(AppenTextBox);   //声明并初始化委托
                this.Invoke(d, new object[] { text });
            }
            else
            {
                Label_receiveCount.Text = receiveCount.ToString();
                if (button_stopOn.Text == "恢复显示") //表示当前暂停显示,窗口不再更新数据
                    return;
                if (checkBox_wrap.Checked)   //每次获得的数据之间是否换行
                    textBox_receive.AppendText(text + "\r\n");
                else
                    textBox_receive.AppendText(text);
            }
        }
        //串口接收中断事件

        //清除窗口
        private void button_clear_Click(object sender, EventArgs e)
        {
            textBox_receive.Clear();
            receiveCount = sendCount = 0;
            Label_receiveCount.Text = Label_sendCount.Text = "0";

        }

        //显示格式 CheckedChang事件
        private void check_hexPlay_CheckedChanged(object sender, EventArgs e)
        {
            //PS:太乱了,尝试更简单有效的代码
            StringBuilder buildHexPlay = new StringBuilder();
            if (textBox_receive.Text.Length == 0)  //窗口为空,不需要转换
                return;
            if (check_hexPlay.Checked)   //将字符转换为HEX格式显示
            {
                char[] bufString = new char[textBox_receive.Text.Length];
                bufString = textBox_receive.Text.ToArray();
                foreach (char c in bufString)
                {
                    if (c == '\r' || c == '\n')
                        continue;  //过滤自动换行添加的回车符号,BUG:同时会把有效的回车符号也过滤掉
                    buildHexPlay.Append(Convert.ToString(Convert.ToByte(c), 16) + " ");
                }
                textBox_receive.Text = buildHexPlay.ToString().ToUpper();
            }
            else  //将HEX转为字符显示
            {

                string[] bufString = new string[textBox_receive.Text.Length];
                char[] split = { ' ', '\n', '\r' };    //将空格,回车符过滤,BUF:可能存在
                bufString = textBox_receive.Text.Trim().Split(split);
                foreach (string ss in bufString)
                {
                    if (ss != "")  //由于有回车符"\r\n"存在,所以得到的SS可能为""
                        buildHexPlay.Append(Convert.ToChar(Convert.ToByte(ss, 16)));
                }
                textBox_receive.Text = buildHexPlay.ToString();
            }
        }

        #endregion

        #region 数据发送

           //添加CRC16校验码
        private void addCRC16(ref List<byte> sendhex)
        {
            byte crcHi = 0xff;
            byte crcLo = 0xff;
            byte index = 0;
            for (int i = 0; i < sendhex.Count; i++)
            {
                index = Convert.ToByte(sendhex[i] ^ crcLo);
                crcLo = Convert.ToByte(crcHi ^ crcHiArry[index]);
                crcHi = crcLoArry[index];
            }
            sendhex.Add(crcLo);
            sendhex.Add(crcHi);
            //return Convert.ToUInt16((crcHi << 8 | crcLo));
        }

       //发送按钮 Click事件
          private void button_send_Click(object sender, EventArgs e)
          {
              if (!serialPort1.IsOpen)
              {
                  Label_mainMessage.ForeColor = Color.Red;
                  Label_mainMessage.Text = "串口未打开!";
                  return;
              }
            StringBuilder buildSend = new StringBuilder();
           // buildSend.Clear(); 
              int count = 0;    //发送字符的长度
              try
              {
                  if (checkBox_hexSend.Checked)   //发送16进制
                  {
                      List<byte> bufferSend = new List<byte>();
                     // buildSend.Clear();                 
                      string sendSting = textBox_sendString.Text.Trim(); //删去前导和后置空格符
                      string s = "";
                      while (sendSting.Length > 1)   //奇数个16进制数据最后一个被抛弃
                      {
                          s = sendSting.Substring(0, 2);
                          buildSend.Append(s + " ");
                          bufferSend.Add(Convert.ToByte(s, 16));   //将字符s 如“1A” 转化为字节31,送入字节列表BufferSend
                          sendSting = sendSting.Remove(0, 2);
                          sendSting = sendSting.Trim();  //删去前导空格符
                      }
                      textBox_sendString.Text = buildSend.ToString().ToUpper(); //格式化显示发送的数据

                    if (checkBox_CRC16.Checked)   //加上了CRC16校验码,并将完整的报文显示在另一个TEXTBOX上
                      {
                          addCRC16(ref bufferSend);
                         // buildSend.Clear();
                          foreach (byte b in bufferSend.ToArray())
                          {
                              buildSend.Append(b.ToString("X2") + " ");
                          }
                        //  textBox_dataCatched.Text = buildSend.ToString().ToUpper();
                      }
                      serialPort1.Write(bufferSend.ToArray(), 0, bufferSend.ToArray().Length);
                      count = bufferSend.Count;
                  }
                  else  //asc编码直接发送,发送字符
                  {
                    /*  if (checkBox_sendNewLine.Checked)  //发送新行
                      {
                          serialPort1.WriteLine(textBox_sendString.Text);
                          count = textBox_sendString.Text.Length + 2;
                      }
                      else
                      {*/
                          serialPort1.Write(textBox_sendString.Text);
                          count = textBox_sendString.Text.Length;
                  //    }
                  }
                  sendCount += count;
                  Label_sendCount.Text = sendCount.ToString();
                  //也可直接使用用LABEL.TEXT的值来表示,少一个全局变量,其实LABEL.TEXT对于主窗口就是一个全局变量
                  //Label_sendCount.Text = Convert .ToString ( Convert.ToInt64(Label_sendCount.Text) + count );  //原来长度加上新发送的长度
              }
              catch
              {
                  MessageBox.Show("发送失败,请检查发送数据是否正确!", "提示");
              }
          }


          //16进制发送 CheckedChanged事件
          private void checkBox_hexSend_CheckedChanged(object sender, EventArgs e)
          {
            
          }

            
        //自动发送 CheckedChanged事件
        private void checkBox_autoSend_CheckedChanged(object sender, EventArgs e)
        {
            if (checkBox_autoSend.Checked)
            {
                numericUpDown_period.Enabled = false;
                timer1.Interval = (int)numericUpDown_period.Value;
                timer1.Start();
            }
            else
            {
                numericUpDown_period.Enabled = true;
                timer1.Stop();
            }
        }

        //定时器1触发事件,用于自动发送
        private void timer1_Tick(object sender, EventArgs e)
        {
                if (serialPort1.IsOpen)
                     button_send_Click(null, null);
            timer1.Interval = (int)numericUpDown_period.Value;
        }

        //按键检测,用于检测16进制输入数据是否有效
        private void textBox_sendString_KeyPress(object sender, KeyPressEventArgs e)
        {
            if (checkBox_hexSend.Checked)
            {

            }
            else
            {
            }
        }

        //暂停显示按钮 Click事件
        private void button_stopOn_Click(object sender, EventArgs e)
        {
            button_stopOn.Text = (button_stopOn.Text == "暂停显示") ? "恢复显示" : "暂停显示";
        }

        #endregion
    }
}
PS:这个代码是在师兄给我代码的基础上实现的,如果师兄看见了请不要拍我 可怜



  • 0
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 9
    评论
要编写一个C#串口调试助手,你可以按照以下步骤进行开发: 1. 确定你想要实现的功能,并设计界面。你可以使用Visual Studio的Winform来创建一个窗体应用程序。\[1\] 2. 设置串口参数。在你的应用程序中,你需要设置串口的波特率、数据位、停止位和校验位等参数,以便与硬件进行通信。\[3\] 3. 编写事件处理器。根据你的设计,为每个组件编写相应的事件处理器。例如,当点击发送按钮时,你需要将文本框中的数据发送出去。确保你清楚每个组件会触发什么事件,并实现相应的功能。\[3\] 4. 进行测试和调试。在编写完每个组件的事件处理器后,及时编译和运行你的应用程序,以便及早发现和解决问题。\[3\] 通过按照以上步骤进行开发,你可以编写一个简单的C#串口调试助手。如果你想学习更多关于Winform的知识,你可以点击链接学习。\[2\] #### 引用[.reference_title] - *1* *2* [C#开发串口调试助手的详细教程](https://blog.csdn.net/weixin_49959955/article/details/123653122)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] - *3* [C#实现【串口助手】【入门级别】【小白进】](https://blog.csdn.net/qq_43535543/article/details/127702042)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 9
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值