C#—串口和网口之间的通信详解

news2024/11/13 9:59:16

C#—串口和网口之间的通信

串口转网口、网口转串口,就是将网口发送来的数据包发送给串口设备,将串口设备返回的数据转发给网口客户端。

在C#中,将串口数据转换为网络数据并发送到网络,通常涉及以下步骤:

        1. 创建一个TCP/UDP客户端,以连接到远程服务器。

        2. 在串口接收中继站数据时,解析该数据以确定其格式和内容。

        3. 将解析后的数据打包成符合网络协议的格式。

        4. 使用网络客户端发送数据。

实现串口网口的转换实例

接下来就为大家介绍一下本次的实例:

1. 当串口事件接收到串口设备发来的消息时,将接收到的消息通过tcp进行发出给客户端,并且亮灯。

2. 当tcp服务器接收到网口客户端的消息时,将接收到的消息通过串口发出给串口设备,并且亮灯。

3. 项目中还有心跳机制,检测串口设备,将设备参数写入INI格式地址等操作。

提示: 本文中用到的serialPort1是winform的窗体控件

一、读取配置文件并设置串口网口对象

public partial class Form1 : Form
{
    IniHelper Ini;
    string[] botlvs = new string[] { "1200", "4800", "9600" ,"13200"};

    TcpListener listen;
    List<TcpClient> lists = new List<TcpClient>(); // 存放所有客户端
    Dictionary<TcpClient, DateTime> HearDic = new Dictionary<TcpClient, DateTime>(); // 存放心跳

    int heartTime=0,heartConnent=0;
    bool whetherHeart;

    public Form1()
    {
        InitializeComponent();

        // 1 读取配置文件
        string dirPath = Path.Combine(Application.StartupPath,"File");
        string filePath = Path.Combine(dirPath, "Setting.ini");
        Ini = new IniHelper(filePath);

        // 2 添加串口
        comboBox1.Items.AddRange(SerialPort.GetPortNames()); // 获取所有串口 拼接在下拉框的items中
        comboBox2.Items.AddRange(botlvs); // 添加波特率数组
        comboBox2.Items.Add("自定义"); // 添加一个
        comboBox3.Items.AddRange(new string[] { "5", "6", "7", "8" });
        comboBox4.Items.AddRange(new string[] {"无","奇校检","偶效验"});
        comboBox5.Items.AddRange(new string[] {"无","1","2","1.5"});

        this.serialPort1.DataReceived += SerialPort1_DataReceived;

        // 3 处理界面默认值
        readSetting();

        // 4 开始串口通信
        startChuanKou();

        // 5 开始网口通信
        startTCP();

    }
}

二、处理界面默认值

/// <summary>
/// 配置串口默认值
/// </summary>
void readSetting()
{
    // 配置串口
    comboBox1.SelectedItem = Ini.Read("Serialport", "name");
    string botelv = Ini.Read("Serialport", "botelv", "9601");
    int botelvIndex = Array.IndexOf(botlvs, botelv); // 获取botelv在数组里面的索引值
    if (botelvIndex != -1)
    {
        comboBox2.SelectedIndex = botelvIndex;
        comboBox2.DropDownStyle = ComboBoxStyle.DropDownList;
    }
    else
    {
        // 波特率在数组里面 自定义波特率情况
        comboBox2.DropDownStyle = ComboBoxStyle.DropDown; // 可编辑的下拉框
                                                          // DropDownList 不可编辑的下拉框
        comboBox2.Text = botelv;
    }
    // 处理数据位
    comboBox3.SelectedItem = Ini.Read("Serialport", "databit", "8");
    // 处理奇偶校检位
    comboBox4.SelectedIndex = Ini.Read("Serialport", "parity", 0);
    comboBox5.SelectedIndex = Ini.Read("Serialport", "stopbit", 0);

    comboBox1.DropDownStyle = ComboBoxStyle.DropDownList;
    comboBox3.DropDownStyle = ComboBoxStyle.DropDownList;
    comboBox4.DropDownStyle = ComboBoxStyle.DropDownList;
    comboBox5.DropDownStyle = ComboBoxStyle.DropDownList;

    // 网口数据的读取
    textBox3.Text = Ini.Read("NetWork", "port", "8080");
    if (Ini.Read("NetWork", "heartOn", false))
    {
        radioButton1.Checked = true;
    }
    else
    {
        radioButton1.Checked = true;
    }
    textBox4.Text = Ini.Read("NetWork", "heartTime", "60000"); 
    textBox5.Text = Ini.Read("NetWork", "heartData", ""); 
    checkBox1.Checked = Ini.Read("NetWork", "heartHex", false);

    heartConnent = int.Parse(textBox5.Text);
    heartTime = int.Parse(textBox4.Text);
    whetherHeart = checkBox1.Checked;
}

三、配置串口数据

/// <summary>
/// 配置串口数据
/// </summary>
void startChuanKou()
{
    // 配置串口对象
    try
    {
        this.serialPort1.PortName = comboBox1.Text;
        this.serialPort1.BaudRate = int.Parse(comboBox2.Text);
        this.serialPort1.DataBits = int.Parse(comboBox3.Text);
        this.serialPort1.StopBits = (StopBits)comboBox5.SelectedIndex;
        this.serialPort1.Parity = (Parity)comboBox4.SelectedIndex;

        this.serialPort1.Open();
        // 亮灯
        this.panel1.BackColor = Color.Green;
    }
    catch (Exception ex)
    {
        MessageBox.Show(ex.Message);
        if (this.serialPort1.IsOpen)
        {
            serialPort1.Close();
            // 灭灯
            this.panel1.BackColor = Color.DarkGray;
        }
    }
}

四、实现tcp网口通信

/// <summary>
/// TCP网口通信
/// </summary>
void startTCP()
{
    if (!int.TryParse(textBox3.Text,out int port) || port<1 || port>65563)
    {
        MessageBox.Show("请输入正确端口号!!!","提示");
    }
    // 开启服务器 接收客户端
    listen = new TcpListener(System.Net.IPAddress.Any, port);
    listen.Start(99); // 开启监听
    panel2.BackColor = Color.Green;

    // 把多个客户端接收到数组里面
    new Task(() =>
    {
        while (true)
        {
            try
            {
                // 接收客户端
                TcpClient c1 = listen.AcceptTcpClient();
                if (!lists.Contains(c1) && !HearDic.ContainsKey(c1))
                {
                    // 把客户端添加到数里面 群发需要
                    if (whetherHeart)
                    {
                        lists.Add(c1);
                        HearDic.Add(c1, DateTime.Now);
                    }
                    else lists.Add(c1);

                    // 接受客户端发来的消息
                    tcpReceive(c1);
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
                foreach (var c in lists)
                {
                    c.Close();
                }
                panel2.BackColor = Color.Green;
            }
        }
    }).Start();
}

/// <summary>
/// 接收网口消息
/// </summary>
void tcpReceive(TcpClient client)
{
    NetworkStream stream = client.GetStream();
    Task.Run(() =>
    {
        byte[] body = new byte[1024];
        while (client.Connected)
        {
            try
            {
                int count = stream.Read(body, 0, body.Length);
                if (count != 0)
                {
                    if (whetherHeart&& body[0] == heartConnent)
                    {
                        try
                        {
                            if (DateTime.Now - HearDic[client] <= new TimeSpan(0, 0, heartTime))
                            {
                                HearDic[client] = DateTime.Now;
                            }
                            else
                            {
                                HearDic.Remove(client);
                                lists.Remove(client);
                                MessageBox.Show(client.Client.RemoteEndPoint.ToString() + "断开");
                                break;
                            }
                        }
                        catch (Exception ex)
                        {
                            MessageBox.Show(ex.Message);
                            break;
                        }
                    }
                    else
                    {
                        serialPort1.Write(body, 0, body.Length);
                        网口接收消息亮灯();
                    }
                }
                else
                {
                    HearDic.Remove(client);
                    lists.Remove(client);
                }
                
            }
            catch (Exception ex)
            {
                listen.Start();
                MessageBox.Show(ex.Message);
                break;
            }
        }
    });
}
/// <summary>
/// 是否设置心跳
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void radioButton1_CheckedChanged(object sender, EventArgs e)
{
    if (checkBox1.Checked)
        whetherHeart = true;
    else whetherHeart = false;
}

五、实现接收串口数据发送给网口并且亮灯

/// <summary>
/// 接收串口数据
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void SerialPort1_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
    try
    {
        byte[] bs = new byte[serialPort1.WriteBufferSize]; // 定义一个字节数组
        int count = serialPort1.Read(bs, 0, bs.Length); // 读取数据到字节数组里面
        if (count == 0)
        {
            // 关闭串口
            if (this.serialPort1.IsOpen)
            {
                serialPort1.Close();
                // 灭灯
                this.panel1.BackColor = Color.DarkGray;
            }
        }
        // 1 接收到1串口数据 需要让panel3更改颜色(亮灯) 封装方法控制效果
        串口接收消息亮灯();

        // 2 转发给所有客户端数据 串口转网口就是把串口数据通过网络转给其他客户端
        foreach (var item in lists)
        {
            item.GetStream().Write(bs,0,bs.Length);
        }
    }
    catch (Exception ex)
    {
        MessageBox.Show(ex.Message);
        if (this.serialPort1.IsOpen)
        {
            serialPort1.Close();
            // 灭灯
            this.panel1.BackColor = Color.DarkGray;
        }
    }
}

/// <summary>
/// 串口消息亮灯
/// </summary>
void 串口接收消息亮灯()
{
    this.Invoke(new Action(async () => 
    {
        this.textBox1.Text = (int.Parse(this.textBox1.Text) + 1).ToString();
        // 亮灯
        panel3.BackColor = Color.Green;
        await Task.Delay(200);
        panel3.BackColor = Color.Gray;

    }));
}

INI格式操作对象

public class IniHelper
{
    public string FileName { get; set; }
    public IniHelper(string name)
    {
        this.FileName = name;
    }

    // 1 先导入C语言读取ini文件的方法

    // GetPrivateProfileString() 获取ini配置文件的数据
    // static 静态的变量 只能生命在当前文件中,不能在其他源文件进行使用。
    // extern 用来声明外部的符号 可以跨文件使用。
    [DllImport("Kernel32.dll")] //导入方法所在dll文件
    public static extern Int32 GetPrivateProfileString(
        string sectionName, //段名 
        string keyName,//键名
        string defaultName,//当键不存在默认值。
        StringBuilder returnValue,// 读取到数据
        uint size,// 读取数据的大小
        string fileName// ini文件路径
        );


    // 2 添加加写入ini文件的C方法
    [DllImport("Kernel32.dll")]
    public static extern Int32 WritePrivateProfileString(
      string sectionName, //段名 
      string keyName,//键名
      string value,//设置的值
      string fileName// ini文件路径
      );



    // 不直接使用上面的两个C语言的方法 再封装到方法中
    // 读取ini数据的方法
    // ReadDate("Second","B","Setting.ini") "10"
    public static string ReadDate(string sectionName, string keyName, string fileName)
    {
        StringBuilder sb = new StringBuilder(512); //512是存储的大小
        GetPrivateProfileString(sectionName, keyName, string.Empty, sb, 512, fileName);

        return sb.ToString();

    }

    /// <summary>
    /// 读取数据
    /// </summary>
    /// <param name="sectionName">段名</param>
    /// <param name="keyName">键名</param>
    /// <returns>string</returns>
    public string Read(string sectionName, string keyName)
    {
        return ReadDate(sectionName, keyName, this.FileName);

    }


    /// <summary>
    /// 读取数据
    /// </summary>
    /// <param name="sectionName">段名</param>
    /// <param name="keyName">键名</param>
    /// <param name="defaultValue">默认值</param>
    /// <returns>string</returns>
    public string Read(string sectionName, string keyName, string defaultValue)
    {
        string v = Read(sectionName, keyName);
        if (string.IsNullOrEmpty(v))
        {
            return defaultValue;
        }
        return v;
    }

    /// <summary>
    /// 读取数据
    /// </summary>
    /// <param name="sectionName">段名</param>
    /// <param name="keyName">键名</param>
    /// <param name="defaultValue">默认值</param>
    /// <returns>int</returns>
    public int Read(string sectionName, string keyName, int defaultValue)
    {
        string v = Read(sectionName, keyName);
        if (int.TryParse(v, out int value))
        {
            return value;
        }
        else
        {
            return defaultValue;
        }
    }

    /// <summary>
    /// 读取数据
    /// </summary>
    /// <param name="sectionName">段名</param>
    /// <param name="keyName">键名</param>
    /// <param name="defaultValue">默认值</param>
    /// <returns>bool</returns>
    public bool Read(string sectionName, string keyName, bool defaultValue)
    {
        string v = Read(sectionName, keyName);
        if (bool.TryParse(v, out bool value))
        {
            return value;
        }
        else
        {
            // 不能转成bool
            if (v == "1" || v == "OK" || v == "ON" || v == "YES")
            {
                return true;
            }
            else if (v == "0" || v == "NO" || v == "OFF" || v.ToUpper() == "OFF")
            {
                // 如果值为以上几种情况 值为false
                return false;
            }
            else
            {
                return defaultValue;
            }
        }
    }


    /// <summary>
    /// 读取数据
    /// </summary>
    /// <param name="sectionName">段名</param>
    /// <param name="keyName">键名</param>
    /// <param name="defaultValue">默认值</param>
    /// <returns>double</returns>
    public double Read(string sectionName, string keyName, double defaultValue)
    {
        string v = Read(sectionName, keyName);
        if (double.TryParse(v, out double value))
        {
            return value;
        }
        else
        {
            return defaultValue;
        }
    }



    public static int WriteData(string s1, string k1, string v, string file)
    {
        return WritePrivateProfileString(s1, k1, v, file);
    }

    /// <summary>
    /// 写入数据
    /// </summary>
    /// <param name="sectionName">段名</param>
    /// <param name="keyName">健名</param>
    /// <param name="value">值</param>
    /// <returns>int</returns>
    public int Write(string sectionName, string keyName, string value)
    {
        return WriteData(sectionName, keyName, value, this.FileName);
    }

    /// <summary>
    /// 写入数据
    /// </summary>
    /// <param name="sectionName">段名</param>
    /// <param name="keyName">健名</param>
    /// <param name="value">值</param>
    /// <returns>int</returns>
    public int Write(string sectionName, string keyName, int value)
    {
        return WriteData(sectionName, keyName, value.ToString(), this.FileName);
    }

    /// <summary>
    /// 写入数据
    /// </summary>
    /// <param name="sectionName">段名</param>
    /// <param name="keyName">健名</param>
    /// <param name="value">值</param>
    /// <returns>int</returns>
    public int Write(string sectionName, string keyName, bool value)
    {
        return WriteData(sectionName, keyName, value ? "1" : "0", this.FileName);
    }

    /// <summary>
    /// 写入数据
    /// </summary>
    /// <param name="sectionName">段名</param>
    /// <param name="keyName">健名</param>
    /// <param name="value">值</param>
    /// <returns>int</returns>
    public int Write(string sectionName, string keyName, DateTime value)
    {
        return WriteData(sectionName, keyName, value.ToString("yyyy-MM-dd HH-mm:ss"), this.FileName);
    }

}

完整代码

public partial class Form1 : Form
{
    IniHelper Ini;
    string[] botlvs = new string[] { "1200", "4800", "9600" ,"13200"};

    TcpListener listen;
    List<TcpClient> lists = new List<TcpClient>(); // 存放所有客户端
    Dictionary<TcpClient, DateTime> HearDic = new Dictionary<TcpClient, DateTime>(); // 存放心跳

    int heartTime=0,heartConnent=0;
    bool whetherHeart;

    public Form1()
    {
        InitializeComponent();

        // 1 读取配置文件
        string dirPath = Path.Combine(Application.StartupPath,"File");
        string filePath = Path.Combine(dirPath, "Setting.ini");
        Ini = new IniHelper(filePath);

        // 2 添加串口
        comboBox1.Items.AddRange(SerialPort.GetPortNames()); // 获取所有串口 拼接在下拉框的items中
        comboBox2.Items.AddRange(botlvs); // 添加波特率数组
        comboBox2.Items.Add("自定义"); // 添加一个
        comboBox3.Items.AddRange(new string[] { "5", "6", "7", "8" });
        comboBox4.Items.AddRange(new string[] {"无","奇校检","偶效验"});
        comboBox5.Items.AddRange(new string[] {"无","1","2","1.5"});

        this.serialPort1.DataReceived += SerialPort1_DataReceived;

        // 3 处理界面默认值
        readSetting();

        // 4 开始串口通信
        startChuanKou();

        // 5 开始网口通信
        startTCP();

    }

    
    /// <summary>
    /// TCP网口通信
    /// </summary>
    void startTCP()
    {
        if (!int.TryParse(textBox3.Text,out int port) || port<1 || port>65563)
        {
            MessageBox.Show("请输入正确端口号!!!","提示");
        }
        // 开启服务器 接收客户端
        listen = new TcpListener(System.Net.IPAddress.Any, port);
        listen.Start(99); // 开启监听
        panel2.BackColor = Color.Green;

        // 把多个客户端接收到数组里面
        new Task(() =>
        {
            while (true)
            {
                try
                {
                    // 接收客户端
                    TcpClient c1 = listen.AcceptTcpClient();
                    if (!lists.Contains(c1) && !HearDic.ContainsKey(c1))
                    {
                        // 把客户端添加到数里面 群发需要
                        if (whetherHeart)
                        {
                            lists.Add(c1);
                            HearDic.Add(c1, DateTime.Now);
                        }
                        else lists.Add(c1);

                        // 接受客户端发来的消息
                        tcpReceive(c1);
                    }
                }
                catch (Exception ex)
                {
                    MessageBox.Show(ex.Message);
                    foreach (var c in lists)
                    {
                        c.Close();
                    }
                    panel2.BackColor = Color.Green;
                }
            }
        }).Start();
    }

    /// <summary>
    /// 接收网口消息
    /// </summary>
    void tcpReceive(TcpClient client)
    {
        NetworkStream stream = client.GetStream();
        Task.Run(() =>
        {
            byte[] body = new byte[1024];
            while (client.Connected)
            {
                try
                {
                    int count = stream.Read(body, 0, body.Length);
                    if (count != 0)
                    {
                        if (whetherHeart&& body[0] == heartConnent)
                        {
                            try
                            {
                                if (DateTime.Now - HearDic[client] <= new TimeSpan(0, 0, heartTime))
                                {
                                    HearDic[client] = DateTime.Now;
                                }
                                else
                                {
                                    HearDic.Remove(client);
                                    lists.Remove(client);
                                    MessageBox.Show(client.Client.RemoteEndPoint.ToString() + "断开");
                                    break;
                                }
                            }
                            catch (Exception ex)
                            {
                                MessageBox.Show(ex.Message);
                                break;
                            }
                        }
                        else
                        {
                            serialPort1.Write(body, 0, body.Length);
                            网口接收消息亮灯();
                        }
                    }
                    else
                    {
                        HearDic.Remove(client);
                        lists.Remove(client);
                    }
                    
                }
                catch (Exception ex)
                {
                    listen.Start();
                    MessageBox.Show(ex.Message);
                    break;
                }
            }
        });
    }

    /// <summary>
    /// 配置串口数据
    /// </summary>
    void startChuanKou()
    {
        // 配置串口对象
        try
        {
            this.serialPort1.PortName = comboBox1.Text;
            this.serialPort1.BaudRate = int.Parse(comboBox2.Text);
            this.serialPort1.DataBits = int.Parse(comboBox3.Text);
            this.serialPort1.StopBits = (StopBits)comboBox5.SelectedIndex;
            this.serialPort1.Parity = (Parity)comboBox4.SelectedIndex;

            this.serialPort1.Open();
            // 亮灯
            this.panel1.BackColor = Color.Green;
        }
        catch (Exception ex)
        {
            MessageBox.Show(ex.Message);
            if (this.serialPort1.IsOpen)
            {
                serialPort1.Close();
                // 灭灯
                this.panel1.BackColor = Color.DarkGray;
            }
        }
    }

    /// <summary>
    /// 配置串口默认值
    /// </summary>
    void readSetting()
    {
        // 配置串口
        comboBox1.SelectedItem = Ini.Read("Serialport", "name");
        string botelv = Ini.Read("Serialport", "botelv", "9601");
        int botelvIndex = Array.IndexOf(botlvs, botelv); // 获取botelv在数组里面的索引值
        if (botelvIndex != -1)
        {
            comboBox2.SelectedIndex = botelvIndex;
            comboBox2.DropDownStyle = ComboBoxStyle.DropDownList;
        }
        else
        {
            // 波特率在数组里面 自定义波特率情况
            comboBox2.DropDownStyle = ComboBoxStyle.DropDown; // 可编辑的下拉框
                                                              // DropDownList 不可编辑的下拉框
            comboBox2.Text = botelv;
        }
        // 处理数据位
        comboBox3.SelectedItem = Ini.Read("Serialport", "databit", "8");
        // 处理奇偶校检位
        comboBox4.SelectedIndex = Ini.Read("Serialport", "parity", 0);
        comboBox5.SelectedIndex = Ini.Read("Serialport", "stopbit", 0);

        comboBox1.DropDownStyle = ComboBoxStyle.DropDownList;
        comboBox3.DropDownStyle = ComboBoxStyle.DropDownList;
        comboBox4.DropDownStyle = ComboBoxStyle.DropDownList;
        comboBox5.DropDownStyle = ComboBoxStyle.DropDownList;

        // 网口数据的读取
        textBox3.Text = Ini.Read("NetWork", "port", "8080");
        if (Ini.Read("NetWork", "heartOn", false))
        {
            radioButton1.Checked = true;
        }
        else
        {
            radioButton1.Checked = true;
        }
        textBox4.Text = Ini.Read("NetWork", "heartTime", "60000"); 
        textBox5.Text = Ini.Read("NetWork", "heartData", ""); 
        checkBox1.Checked = Ini.Read("NetWork", "heartHex", false);

        heartConnent = int.Parse(textBox5.Text);
        heartTime = int.Parse(textBox4.Text);
        whetherHeart = checkBox1.Checked;
    }

    /// <summary>
    /// 接收串口数据
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    private void SerialPort1_DataReceived(object sender, SerialDataReceivedEventArgs e)
    {
        try
        {
            byte[] bs = new byte[serialPort1.WriteBufferSize]; // 定义一个字节数组
            int count = serialPort1.Read(bs, 0, bs.Length); // 读取数据到字节数组里面
            if (count == 0)
            {
                // 关闭串口
                if (this.serialPort1.IsOpen)
                {
                    serialPort1.Close();
                    // 灭灯
                    this.panel1.BackColor = Color.DarkGray;
                }
            }
            // 1 接收到1串口数据 需要让panel3更改颜色(亮灯) 封装方法控制效果
            串口接收消息亮灯();

            // 2 转发给所有客户端数据 串口转网口就是把串口数据通过网络转给其他客户端
            foreach (var item in lists)
            {
                item.GetStream().Write(bs,0,bs.Length);
            }
        }
        catch (Exception ex)
        {
            MessageBox.Show(ex.Message);
            if (this.serialPort1.IsOpen)
            {
                serialPort1.Close();
                // 灭灯
                this.panel1.BackColor = Color.DarkGray;
            }
        }
    }

    /// <summary>
    /// 串口消息亮灯
    /// </summary>
    void 串口接收消息亮灯()
    {
        this.Invoke(new Action(async () => 
        {
            this.textBox1.Text = (int.Parse(this.textBox1.Text) + 1).ToString();
            // 亮灯
            panel3.BackColor = Color.Green;
            await Task.Delay(200);
            panel3.BackColor = Color.Gray;

        }));
    }

    /// <summary>
    /// 网口消息亮灯
    /// </summary>
    void 网口接收消息亮灯()
    {
        this.Invoke(new Action(async () =>
        {
            this.textBox2.Text = (int.Parse(this.textBox2.Text) + 1).ToString();
            // 亮灯
            panel4.BackColor = Color.Green;
            await Task.Delay(200);
            panel4.BackColor = Color.Gray;

        }));
    }


    /// <summary>
    /// 是否设置心跳
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    private void radioButton1_CheckedChanged(object sender, EventArgs e)
    {
        if (checkBox1.Checked)
            whetherHeart = true;
        else whetherHeart = false;
    }

    /// <summary>
    /// 重启
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    private async void button1_Click(object sender, EventArgs e)
    {
        // 关闭串口
        if (this.serialPort1.IsOpen)
        {
            serialPort1.Close();
        }
        // 灭灯
        this.panel1.BackColor = Color.Gray;
        // 停掉TCP
        foreach (var c in lists)
        {
            c.Close();
        }
        listen.Stop();
        panel2.BackColor = Color.Gray;

        await Task.Delay(1000);

        // 开启TCP
        startTCP();

        // 开启串口
        startChuanKou();


    }

    /// <summary>
    /// 保存
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    private void button2_Click(object sender, EventArgs e)
    {

    }


    /// <summary>
    /// 波特率下拉框触发变化的时候调用
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    private void comboBox2_SelectedIndexChanged(object sender, EventArgs e)
    {
        if (comboBox2.SelectedItem.ToString() == "自定义")
        {
            // 切换到自定义选项上
            comboBox2.DropDownStyle = ComboBoxStyle.DropDown;
        }
        else
        {
            comboBox2.DropDownStyle = ComboBoxStyle.DropDownList;
        }
    }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1983229.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

C# Unity 面向对象补全计划 七大原则 之 里氏替换(LSP) 难度:☆☆☆ 总结:子类可以当父类用,牛马是马,骡马也是马

本文仅作学习笔记与交流&#xff0c;不作任何商业用途&#xff0c;作者能力有限&#xff0c;如有不足还请斧正 本系列作为七大原则和设计模式的进阶知识&#xff0c;看不懂没关系 请看专栏&#xff1a;http://t.csdnimg.cn/mIitr&#xff0c;尤其是关于继承的两篇文章&#xff…

相机无须标定,使用基础矩阵F实现多相机内参自标定

Abstract 从给定的基本矩阵中进行两个摄像头的自我校准问题是几何计算机视觉中的基本问题之一。在已知主点和正方形像素的假设下&#xff0c;Bougnoux公式提供了一种计算两个未知焦距的方法。然而&#xff0c;在许多实际情况下&#xff0c;由于常见的奇异性&#xff0c;公式会…

xshell无法连接Ubuntu20.4

在之前红帽版本里&#xff0c;直接下了就可以用xshell直接连接&#xff0c;但是Ubuntu20.4不能直接连接&#xff0c;我开始以为是密码错了&#xff0c;但是我想了想vscode连接不需要密码&#xff0c;一样连接不上&#xff0c;我就在网上找了很多方法&#xff0c;最后终于连接上…

总线学习4--UART

想来串口通信是我第一次接触嵌入式就知道的&#xff0c;一直调试也是用串口线&#xff0c;但是里面的原理还真不清楚。这次难得把环境弄出来了&#xff0c;就顺便学学。 一 环境搭建 还是老规矩&#xff0c;废话不多说&#xff0c;干就完事。 这次用的树莓派zero小板&#x…

云计算实训19——上线一个静态的前端系统(续)

上线一个静态的前端系统(续) 准备工作 在eleme服务器上&#xff1a; 启动服务 启动rpcbind [rooteleme-static ~]# systemctl restart rpcbind 启动nfs [rooteleme-static ~]# systemctl restart nfs 在static-server主机上&#xff1a; 1.重启服务 启动smb [rootstatic…

重塑汽车制造未来:3D插图技术大师,零误差高效驱动新时代

在当今快速革新的汽车制造领域&#xff0c;高效、精准的产品设计与制造流程已成为众多车企破浪前行的核心引擎。但随着市场竞争的日益激烈&#xff0c;在产品设计与制造中&#xff0c;传统二维CAD设计的局限性越发明显——设计周期长、沟通成本高、错误频发及资源利用低效等问题…

AI算力租赁是什么,哪些行业会有需求?

一、AI算力租赁的定义与概述 AI算力租赁是指基于人工智能&#xff08;AI&#xff09;应用需求&#xff0c;将所需的计算能力&#xff08;即算力&#xff09;通过租赁服务的方式提供给企业和个人用户。这种服务允许用户根据需要租用人工智能计算资源&#xff0c;如图形处理单元…

[网鼎杯2018]Unfinish解题,五分钟带你解题

目录 前期准备 ​编辑 扫描目录 寻找注入点 构建payload&#xff1a; 开始注入&#xff1a; 寻找过滤规则 绕过过滤 构建python脚本 提交flag 总结 前期准备 这道题是2018年网鼎杯的一道题&#xff0c;是比较经典的一道sql二次注入的题&#xff0c;我们一起来看一下 …

B1.3 程序状态寄存器PSTATE的介绍

快速链接: . 👉👉👉 ARMv8/ARMv9架构入门到精通-[目录] 👈👈👈 付费专栏-付费课程 【购买须知】个人博客笔记导读目录(全部) B1.3 进程状态,PSTATE* 程序状态寄存器或PSTATE,是程序状态信息的抽象。所有指令集都提供操作 PSTATE 元素的指令。 以下 PSTATE 信…

第二十一天内容

上午 4、mysql基础命令 5、mysql操作命令 ------------------------------------------------------------------------------------------------------------------------------- 下午 1、脚本安装mysql 2、mysql命令回顾 3、mysql用户权限设置 4、命令练习 6、权限角色 7、…

按xls标签替换docx及xls内容

WPSoffice环境下&#xff0c;需要批量替换doc文档及xls表格某些内容&#xff0c;在windows下&#xff0c;可以用VBA宏实现&#xff0c;先建一个标签表格&#xff0c;然后按标签批量替换。但在Linux下&#xff0c;WPS表格宏不能跨文档操作WPS文字&#xff0c;于是想用python实现…

工程架构简析

文内项目 Github&#xff1a;XIAOJUSURVEY 架构 架构的设计最终是为了场景可以快速扩展&#xff0c;基于工程底座&#xff0c;使用者能够专注于业务领域的深入。 B端&#xff1a;面向问卷管理者&#xff0c;专注于问卷管理、问卷投放和数据分析三大核心能力的建设。&#xff0…

vue3实现商品图片放大镜效果(芋道源码yudao-cloud 二开笔记)

今天开发一个防某商城的商品图片放大镜&#xff0c;鼠标移动到图片位置时&#xff0c;右侧出现一个已放大的图片效果。 示例如下&#xff1a; 下图的图片的放大效果和小图的切换封装成了组件PicShow.vue&#xff0c;可根据需求自行修改&#xff0c;如下&#xff1a; 第一步&…

鸿蒙应用服务开发【钱包服务(ArkTS)】

介绍 基于Stage模型&#xff0c;提供钱包交通卡和Pass卡的开卡、预览卡、查询卡信息、更新卡片信息、删除卡片、初始化钱包环境等功能。 效果预览 具体实现 交通卡 在hms.core.payment.walletTransitCard中定义了钱包交通卡接口API&#xff0c;示例接口如下&#xff1a; /*…

【漏洞复现】用友NC Cloud系统queryPsnInfo接口SQL注入

文章目录 0x00 漏洞描述影响范围 0x01 测绘工具0x02 漏洞复现0x03 Nuclei检测脚本0x04 修复建议0x05 免责声明 0x00 漏洞描述 用友NC Cloud存是一款大型企业数字化平台。 在受影响的版本中&#xff0c;攻击者可以通过未授权访问 /ncchr/pm/obj/queryPsnInfo 接口&#xff0c;利…

综合安防管理平台LntonCVS视频监控汇聚平台视频数据智能化与资源共享方案

随着全球城市化进程的加快&#xff0c;智慧城市概念日益受到重视。在这一趋势下&#xff0c;LntonCVS视频汇聚平台作为新型智慧城市的重要智能基础设施之一&#xff0c;扮演着关键角色。该平台整合、接入和管理城市中各类视频资源&#xff0c;涵盖公共安全视频、交通监控、城市…

【五大海内外高校支持】2024年数字经济与计算机科学国际学术会议(DECS2024)

大会官网&#xff1a;www.icdecs.net 大会时间&#xff1a;2024年9月20-22日 大会地点&#xff1a;中国-厦门 截稿日期&#xff1a;详情见官网 支持单位 马来西亚理工大学 北京科技大学经济管理学院 南京信息工程大学 马来西亚敦胡先翁大学 大会嘉宾 大会主席 罗航…

opencascade AIS_ViewController源码学习 视图控制、包含鼠标事件等

opencascade AIS_ViewController 前言 用于在GUI和渲染线程之间处理视图器事件的辅助结构。 该类实现了以下功能&#xff1a; 缓存存储用户输入状态&#xff08;鼠标、触摸和键盘&#xff09;。 将鼠标/多点触控输入映射到视图相机操作&#xff08;平移、旋转、缩放&#xff0…

Mybatis(Day 18)

数据持久化是将内存中的数据模型转换为存储模型&#xff0c;以及将存储模型转换为内存中数据模型的统称。MyBatis 支持定制化 SQL、存储过程以及高级映射&#xff0c;可以在实体类和 SQL 语句之间建立映射关系&#xff0c;是一种半自动化的 ORM 实现。ORM&#xff08;Object Re…

系统运维——PXE自动安装系统

摘要 PXE&#xff08;Preboot Execution Environment&#xff0c;预启动执行环境&#xff09;是一种允许计算机通过网络启动操作系统而无需本地存储设备的技术。本文详细介绍了 PXE 的定义、架构、原理、应用场景及常见命令体系。以 RedHat7 为例&#xff0c;展示如何配置和使…