目标:实现一个将串口传输的16进制数据转换成需要的数据的上位机,并且显示数据

工具:vs2022,串口调试器

一、新建一个windows窗体应用

选择视图——工具箱,将所需控件添加到幕布上

右击控件属性修改控件名称、内容

二、打开串口

在form1.cs中编辑代码

/// <summary>
/// 打开串口
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void btnOpen_Click(object sender, EventArgs e)
{
    try
    {
        //安全打开串口。
        OpenPort();
        if (serialport.IsOpen)
        {
            btnClose.Enabled = true;
            btnOpen.Enabled = false;
            lblComStat.Text = "已打开 " + Convert.ToString(serialport.PortName) + "," + Convert.ToString(serialport.BaudRate) + "," + Convert.ToString(serialport.DataBits) + "," + Convert.ToString(serialport.Parity) + "," + Convert.ToString(serialport.StopBits);
        }
    }
    catch (Exception er)
    {
        
        //安全关闭当前串口。
        ClosePort();    
        MessageBox.Show("串口打开失败!" + er.Message, "串口调试助手");
        lblComStat.Text = "已关闭";
    }
}

三、接收指令

/// <summary>
/// 发送指令
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void btnSend_Click(object sender, EventArgs e)
{
    //自动打开串口。
    if (!serialport.IsOpen)
    {
        btnOpen_Click(null, null);
    }
}

/// <summary>
/// 端口
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void cbxPort_MouseDown(object sender, MouseEventArgs e)
{
    try
    {
        cbxPort.Items.Clear();
        //自动获取串行口名称
        foreach (string port in SerialPort.GetPortNames())
        {
            this.cbxPort.Items.Add(port);
        }
    }
    catch
    {
        MessageBox.Show("找不到通讯串口!", "串口调试助手");
    }
}

四、处理数据

/// <summary>
/// 接收数据
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void serialport_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
    try
    {
        // *** 正在接收状态指示。
        IsReceving = true;

        int Len = serialport.BytesToRead;
        byte[] data = new byte[Len];
        serialport.Read(data, 0, Len);
        int check_high = data[9] - 0x30;//校验低位
        int check_low = data[10] - 0x30;//校验高位
        int Xor_Value = data[1];//异或校验初始值,从符号位开始
        for (int i = 2; i < 9; i++)
        {
            Xor_Value ^= data[i];
        }//通过循环实现第二位至第九位的异或
        DateTime dt = DateTime.Now;
        string receiveTime = dt.ToString();

        // 检查数据开头是否为02
        if (data[0] != 0x02)
        {
            // 数据开头或结尾不符合要求,显示错误或者返回
            // 可以选择直接显示错误消息
            rtbxRecHex.Invoke(new EventHandler(delegate
            {
                rtbxRecHex.AppendText("[" + receiveTime + "]" + ":" + "错误:数据开头不符合要求\n");
                rtbxRecHex.ScrollToCaret();
            }));
            return;
        }
        // 检查数据长度是否为12
        if (data.Length != 12)
        {
            // 数据长度不符合要求,显示错误或者返回
            // 可以选择直接显示错误消息
            rtbxRecHex.Invoke(new EventHandler(delegate
            {
                rtbxRecHex.AppendText("[" + receiveTime + "]" + ":" + "错误:数据长度不符合要求\n");
                rtbxRecHex.ScrollToCaret();
            }));
            return;
        }


        // 检查数据结尾是否为03
        if (data[11] != 0x03)
        {
            // 数据开头或结尾不符合要求,显示错误或者返回
            // 可以选择直接显示错误消息
            rtbxRecHex.Invoke(new EventHandler(delegate
            {
                rtbxRecHex.AppendText("[" + receiveTime + "]" + ":" + "错误:数据结尾不符合要求\n");
                rtbxRecHex.ScrollToCaret();
            }));
            return;
        }
        // 检查数据是否和校验位一致
        if (check_low != (Xor_Value & 0x0F) || check_high != (Xor_Value >> 4))
        {
            // 数据开头或结尾不符合要求,显示错误或者返回
            // 可以选择直接显示错误消息
            rtbxRecHex.Invoke(new EventHandler(delegate
            {
                rtbxRecHex.AppendText("[" + receiveTime + "]" + ":" + "错误:数据校验失败\n");
                rtbxRecHex.ScrollToCaret();
            }));
            return;
        }
        // 重量为0时不显示数据
        if (data[2] == 0x30 && data[3] == 0x30 && data[4] == 0x30 && data[5] == 0x30 && data[6] == 0x30 && data[7] == 0x30)
        {
            return; // 如果数据为0,则不进行后续处理
        }


        // 如果数据符合要求,则继续处理
        string Hex = BitConverter.ToString(data).Replace("-", " ");
        Hex = Hex.ToUpper();
                     

        rtbxRecHex.Invoke(new EventHandler(delegate
        {
            // *** 正在处理十六进制数据。
            DoingHex = true;
            rtbxRecHex.AppendText("[" + receiveTime + "]" + ":" + Hex + "\n");
            if (rtbxRecHex.Text.Length > 10000)
            {
                rtbxRecHex.Text = string.Empty;
            }
            // 将控件的内容滚动到当前位置。
            rtbxRecHex.ScrollToCaret();
            // *** 完成处理十六进制数据。
            DoingHex = false;
        }));
        //添加小数点
        int InsertIndex = data[8] - 0x30;
        List<byte> modifiedData = new List<byte>(data);
        modifiedData.Insert(8 - InsertIndex, (byte)'.');
        data = modifiedData.ToArray();
        //删除数组里多余元素,分两次删除是因为每删除一次数组长度就会发生变化,元素对应位置也随着而变
        List<byte> delDate = new List<byte>(data);
        delDate.RemoveRange(9,4);
        data= delDate.ToArray();
        List<byte> delDate1 = new List<byte>(data);
        delDate1.RemoveAt(0);
        data = delDate1.ToArray();
        LastDatartbxRecHex.Invoke(new EventHandler(delegate
        {
            // *** 正在处理字符串。
            DoingStr = true;
            LastDatartbxRecHex.AppendText("[" + receiveTime + "]" + ":" + Encoding.GetEncoding("GB2312").GetString(data)+"\n");
            if (LastDatartbxRecHex.Text.Length > 10000)
            {
                LastDatartbxRecHex.Text = string.Empty;
            }
            // 将控件的内容滚动到当前位置。
            LastDatartbxRecHex.ScrollToCaret();
            // *** 完成处理字符串。
            DataCount++;
            DoingStr = false;
        }));

        while (DoingStr || DoingHex)
        {
            // 处理串口接收事件及其它系统消息。
            Application.DoEvents();
        }
        // *** 接收完成状态指示。
        IsReceving = false;
    }
    catch (Exception Err)
    {
        MessageBox.Show(Err.Message, "串口调试助手");
    }
}

重力传感器通过串口发送12位16进制数据,将其转换为带有正负的重量。

完整代码

using System.Collections.Generic;
using System.ComponentModel;
using System.Windows.Forms;
using Sunisoft.IrisSkin;
//using System.IO.Ports;
using System.Drawing;
using System.Data;
using System.Text;
using System.IO;
using System;
using System.IO.Ports;
using NPOI.HSSF.UserModel;
using NPOI.XSSF.UserModel;
using System.Text.RegularExpressions;





namespace SerialComm
{
    public partial class Form1 : Form
    {
        #region 全局变量
        //===================================================
        
        //申明全局变量。
        /// <summary>
        /// 皮肤引擎
        /// </summary>
        private SkinEngine se = new SkinEngine();
        /// <summary>
        /// 指令发送指针初始为0。
        /// </summary>
        public int CmdIdx = 0;
        /// <summary>
        /// 接收数据标志。
        /// </summary>
        bool IsReceving = false;
        /// <summary>
        /// 处理字符串标志。
        /// </summary>
        bool DoingStr = false;
        /// <summary>
        /// 处理十六进制标志。
        /// </summary>
        bool DoingHex = false;       
        //===================================================
        #endregion

        #region 构造函数
        //===================================================

        public Form1()
        {
            InitializeComponent();
        }

        //===================================================
        #endregion

        #region 页面初始化
        //===================================================

        /// <summary>
        /// 页面初始化
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Form1_Load(object sender, EventArgs e)
        {
            //加载串口
            BindPort();
        }

        //===================================================
        #endregion

        #region 调用方法
        //===================================================
        /// <summary>
        /// 加载串口
        /// </summary>
        private void BindPort()
        {
            try
            {
                //自动获取串行口名称
                foreach (string port in SerialPort.GetPortNames())
                {
                    this.cbxPort.Items.Add(port);
                }
                cbxPort.SelectedIndex = 0;
            }
            catch
            {
                MessageBox.Show("找不到通讯串口!", "串口调试助手");
            }
        }        

     
        /// <summary>
        /// 清除空格
        /// </summary>
        /// <param name="str"></param>
        /// <returns></returns>
        private string DelSpace(string str)
        {
            string TempStr = string.Empty;
            int Len = str.Length;
            for (int i = 0; i < Len; i++)
            {
                if (str[i] != ' ')
                {
                    TempStr += str[i];
                }
            }
            //Hex 位数检查。
            Len = TempStr.Length;
            if (Len % 2 != 0)
            {
                TempStr = '0' + TempStr;
            }
            return TempStr;
        }

        /// <summary>
        /// 重新打开串口
        /// </summary>
        private void ReOpenPort()
        {
            try
            {
                if (serialport.IsOpen)
                {
                    btnClose_Click(null, null);
                    //重新打开通讯串口。
                    if (!serialport.IsOpen)
                    {
                        btnOpen_Click(null, null);
                    }
                }
            }
            catch (Exception Err)
            {
                MessageBox.Show(Err.Message, "串口调试助手");
            }
        }

        /// <summary>
        /// 打开串口
        /// </summary>
        private void OpenPort()
        {
            //***避免串口死锁***
            //写超时,如果底层串口驱动效率问题,能有效的避免死锁。
            serialport.WriteTimeout = 1000;
            //读超时,同上。
            serialport.ReadTimeout = 1000;
            //回车换行。
            serialport.NewLine = "\r\n";
            //注册事件。
            serialport.DataReceived += new SerialDataReceivedEventHandler(this.serialport_DataReceived);   
            //***避免串口死锁***

            serialport.PortName = cbxPort.Text;
            serialport.BaudRate = int.Parse(cbxBaudRate.Text);
            serialport.DataBits = int.Parse(cbxDataBit.Text);
            serialport.Parity = (Parity)Enum.Parse(typeof(Parity), cbxParity.Text);
            serialport.StopBits = (StopBits)Enum.Parse(typeof(StopBits), cbxStopBit.Text);
            serialport.Open();
        }

        /// <summary>
        /// 关闭串口
        /// </summary>
        private void ClosePort()
        {
            //安全关闭当前串口。
            //***避免串口死锁***
            //注销串口中断接收事件,避免下次再执行进来,造成死锁。
            serialport.DataReceived -= this.serialport_DataReceived;
            while (IsReceving)
            {
                //处理串口接收事件及其它系统消息。
                Application.DoEvents();
            }
            //现在没有死锁,可以关闭串口。
            serialport.Close();                  
            //***避免串口死锁***
        }        

        //===================================================
        #endregion
       

        #region 事件函数
        //===================================================

        /// <summary>
        /// 打开串口
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnOpen_Click(object sender, EventArgs e)
        {
            try
            {
                //安全打开串口。
                OpenPort();
                if (serialport.IsOpen)
                {
                    btnClose.Enabled = true;
                    btnOpen.Enabled = false;
                    lblComStat.Text = "已打开 " + Convert.ToString(serialport.PortName) + "," + Convert.ToString(serialport.BaudRate) + "," + Convert.ToString(serialport.DataBits) + "," + Convert.ToString(serialport.Parity) + "," + Convert.ToString(serialport.StopBits);
                }
            }
            catch (Exception er)
            {
                
                //安全关闭当前串口。
                ClosePort();    
                MessageBox.Show("串口打开失败!" + er.Message, "串口调试助手");
                lblComStat.Text = "已关闭";
            }
        }

        /// <summary>
        /// 发送指令
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnSend_Click(object sender, EventArgs e)
        {
            //自动打开串口。
            if (!serialport.IsOpen)
            {
                btnOpen_Click(null, null);
            }
        }

        /// <summary>
        /// 端口
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void cbxPort_MouseDown(object sender, MouseEventArgs e)
        {
            try
            {
                cbxPort.Items.Clear();
                //自动获取串行口名称
                foreach (string port in SerialPort.GetPortNames())
                {
                    this.cbxPort.Items.Add(port);
                }
            }
            catch
            {
                MessageBox.Show("找不到通讯串口!", "串口调试助手");
            }
        }

        /// <summary>
        /// 接收数据
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void serialport_DataReceived(object sender, SerialDataReceivedEventArgs e)
        {
            try
            {
                // *** 正在接收状态指示。
                IsReceving = true;

                int Len = serialport.BytesToRead;
                byte[] data = new byte[Len];
                serialport.Read(data, 0, Len);
                int check_high = data[9] - 0x30;//校验低位
                int check_low = data[10] - 0x30;//校验高位
                int Xor_Value = data[1];//异或校验初始值,从符号位开始
                for (int i = 2; i < 9; i++)
                {
                    Xor_Value ^= data[i];
                }//通过循环实现第二位至第九位的异或
                DateTime dt = DateTime.Now;
                string receiveTime = dt.ToString();

                // 检查数据开头是否为02
                if (data[0] != 0x02)
                {
                    // 数据开头或结尾不符合要求,显示错误或者返回
                    // 可以选择直接显示错误消息
                    rtbxRecHex.Invoke(new EventHandler(delegate
                    {
                        rtbxRecHex.AppendText("[" + receiveTime + "]" + ":" + "错误:数据开头不符合要求\n");
                        rtbxRecHex.ScrollToCaret();
                    }));
                    return;
                }
                // 检查数据长度是否为12
                if (data.Length != 12)
                {
                    // 数据长度不符合要求,显示错误或者返回
                    // 可以选择直接显示错误消息
                    rtbxRecHex.Invoke(new EventHandler(delegate
                    {
                        rtbxRecHex.AppendText("[" + receiveTime + "]" + ":" + "错误:数据长度不符合要求\n");
                        rtbxRecHex.ScrollToCaret();
                    }));
                    return;
                }


                // 检查数据结尾是否为03
                if (data[11] != 0x03)
                {
                    // 数据开头或结尾不符合要求,显示错误或者返回
                    // 可以选择直接显示错误消息
                    rtbxRecHex.Invoke(new EventHandler(delegate
                    {
                        rtbxRecHex.AppendText("[" + receiveTime + "]" + ":" + "错误:数据结尾不符合要求\n");
                        rtbxRecHex.ScrollToCaret();
                    }));
                    return;
                }
                // 检查数据是否和校验位一致
                if (check_low != (Xor_Value & 0x0F) || check_high != (Xor_Value >> 4))
                {
                    // 数据开头或结尾不符合要求,显示错误或者返回
                    // 可以选择直接显示错误消息
                    rtbxRecHex.Invoke(new EventHandler(delegate
                    {
                        rtbxRecHex.AppendText("[" + receiveTime + "]" + ":" + "错误:数据校验失败\n");
                        rtbxRecHex.ScrollToCaret();
                    }));
                    return;
                }
                // 重量为0时不显示数据
                if (data[2] == 0x30 && data[3] == 0x30 && data[4] == 0x30 && data[5] == 0x30 && data[6] == 0x30 && data[7] == 0x30)
                {
                    return; // 如果数据为0,则不进行后续处理
                }


                // 如果数据符合要求,则继续处理
                string Hex = BitConverter.ToString(data).Replace("-", " ");
                Hex = Hex.ToUpper();
                             

                rtbxRecHex.Invoke(new EventHandler(delegate
                {
                    // *** 正在处理十六进制数据。
                    DoingHex = true;
                    rtbxRecHex.AppendText("[" + receiveTime + "]" + ":" + Hex + "\n");
                    if (rtbxRecHex.Text.Length > 10000)
                    {
                        rtbxRecHex.Text = string.Empty;
                    }
                    // 将控件的内容滚动到当前位置。
                    rtbxRecHex.ScrollToCaret();
                    // *** 完成处理十六进制数据。
                    DoingHex = false;
                }));
                //添加小数点
                int InsertIndex = data[8] - 0x30;
                List<byte> modifiedData = new List<byte>(data);
                modifiedData.Insert(8 - InsertIndex, (byte)'.');
                data = modifiedData.ToArray();
                //删除数组里多余元素,分两次删除是因为每删除一次数组长度就会发生变化,元素对应位置也随着而变
                List<byte> delDate = new List<byte>(data);
                delDate.RemoveRange(9,4);
                data= delDate.ToArray();
                List<byte> delDate1 = new List<byte>(data);
                delDate1.RemoveAt(0);
                data = delDate1.ToArray();
                LastDatartbxRecHex.Invoke(new EventHandler(delegate
                {
                    // *** 正在处理字符串。
                    DoingStr = true;
                    LastDatartbxRecHex.AppendText("[" + receiveTime + "]" + ":" + Encoding.GetEncoding("GB2312").GetString(data)+"\n");
                    if (LastDatartbxRecHex.Text.Length > 10000)
                    {
                        LastDatartbxRecHex.Text = string.Empty;
                    }
                    // 将控件的内容滚动到当前位置。
                    LastDatartbxRecHex.ScrollToCaret();
                    // *** 完成处理字符串。
                    DataCount++;
                    DoingStr = false;
                }));

                while (DoingStr || DoingHex)
                {
                    // 处理串口接收事件及其它系统消息。
                    Application.DoEvents();
                }
                // *** 接收完成状态指示。
                IsReceving = false;
            }
            catch (Exception Err)
            {
                MessageBox.Show(Err.Message, "串口调试助手");
            }
        }




        /// <summary>
        /// 串口
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void cbxPort_SelectedIndexChanged(object sender, EventArgs e)
        {
            //重新打开串口
            ReOpenPort();
        }

        /// <summary>
        /// 波特率
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void cbxBaudRate_SelectedIndexChanged(object sender, EventArgs e)
        {
            //重新打开串口
            ReOpenPort();
        }

        /// <summary>
        /// 数据位
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void cbxDataBit_SelectedIndexChanged(object sender, EventArgs e)
        {
            //重新打开串口
            ReOpenPort();
        }

        /// <summary>
        /// 校验位
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void cbxParity_SelectedIndexChanged(object sender, EventArgs e)
        {
            //重新打开串口
            ReOpenPort();
        }

        /// <summary>
        /// 停止位
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void cbxStopBit_SelectedIndexChanged(object sender, EventArgs e)
        {
            //重新打开串口
            ReOpenPort();
        }

  
        /// <summary>
        /// 关闭串口
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnClose_Click(object sender, EventArgs e)
        {
           
            //安全关闭串口。
            ClosePort();
            if (!serialport.IsOpen)
            {
                btnOpen.Enabled = true;
                btnClose.Enabled = false;
                lblComStat.Text = "已关闭";
            }
        }

        /// <summary>
        /// 退出
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnQuit_Click(object sender, EventArgs e)
        {
            btnClose_Click(null, null);
            this.Close();
        }

        private void rtbxRecStr_TextChanged(object sender, EventArgs e)
        {

        }

        private void Form1_FormClosed(object sender, FormClosedEventArgs e)
        {
            MessageBox.Show("wwww!", "串口调试助手");
        }

        private void Form1_oad(object sender, EventArgs e)
        {

        }

        private void button1_Click(object sender, EventArgs e)
        {
            //清除接收
            rtbxRecHex.Text = string.Empty;
        }

        private void LastDataClr_Click(object sender, EventArgs e)
        {
            //清除接收
            DataCount=0;
            LastDatartbxRecHex.Text = string.Empty;
        }

       
        private void saveFileDialog1_FileOk(object sender, CancelEventArgs e)
        {

        }

        private void TimeStr_Tick(object sender, EventArgs e)
        {

        }

        private void label6_Click(object sender, EventArgs e)
        {

        }

        private void timer1_Tick(object sender, EventArgs e)
        {
            DateTime dt = System.DateTime.Now;
            label1.Text = dt.ToString();
           
        }      
       
        //===================================================
        #endregion

        private void label1_Click(object sender, EventArgs e)
        {
            object Systemtime = null;
            _ = Systemtime;
        }

        private void gpPortSet_Enter(object sender, EventArgs e)
        {

        }
    }
}

测试结果

最终可成功获得数据

Logo

旨在为数千万中国开发者提供一个无缝且高效的云端环境,以支持学习、使用和贡献开源项目。

更多推荐