C# WPF燃气报警器记录读取串口工具

C# WPF燃气报警器记录读取串口工具

概要

  • 符合国标文件《GB+15322.2-2019.pdf》串口通信协议定义;
  • 可读取燃气报警器家用版设备历史记录信息等信息;

串口帧数据

串口通信如何确定一帧数据接收完成是个麻烦事,本文采用最后一次数据接收完成后再过多少毫秒认为一帧数据接收完成,开始解析出来。每次接收到数据更新一次recvTimems 。定时器mTimer定时周期10毫秒,定时器回调函数里判断接收时间超过20ms(这个时间的长短和串口波特率有关)认为一帧数据接收完成。接收数据时间差未超过20ms则将接收数据追加到rxBuf数据缓冲,

csharp 复制代码
long recvTimems = 0;    // 用于计算串口接收完一帧数据
int rxLen = 0;  // 串口接收到的数据长度
byte[] rxBuff = new byte[128];  // 串口数据接收缓存
private static Timer mTimer;    // 定时器,10ms执行一次

mTimer = new Timer(recvTimerCalback, null, 0, 10);  // 创建并启动定时器
 
private void recvTimerCalback(object obj)
{
    //Console.WriteLine("timer callback!" + recvTimems);
    this.Dispatcher.Invoke(new Action(()=> {
        // UI线程分离,更新UI数据显示
        if (((Environment.TickCount - recvTimems) >= 20) && (rxLen > 0))
        {
            // 串口接收时间超过X ms认为一帧数据接收完成
			
			这里解析处理接收数据.....
			
			// 一帧数据处理结束清空数据缓冲
			Array.Clear(rxBuff, 0, rxBuff.Length);
			rxLen = 0;
    	}

	}));  
}

private void SerialPort_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
    
    SerialPort comPort = (SerialPort)sender;
    try
    {
        recvTimems = Environment.TickCount; // 更新串口数据接收时间

        //rxBuff[rxLen] = mSerialPort.ReadByte();
        int readCnt = mSerialPort.BytesToRead;
        Console.WriteLine("in readCnt:" + readCnt);
        mSerialPort.Read(rxBuff, rxLen, readCnt);
        rxLen += readCnt;
        Console.WriteLine("out rxLen:" + rxLen);
    }
    catch (Exception ce)
    {
        MessageBox.Show(ce.Message);
    }            

}

布局文件

XAML

html 复制代码
<Window x:Class="GasAlarmTestTool.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:GasAlarmTestTool"
        mc:Ignorable="d"
        Title="燃气报警器接口工具" Height="600" Width="800">
    <Grid>
        <TabControl>
            <TabItem>
                <TabItem.Header>
                    <StackPanel>
                        <Label>串口设置</Label>
                    </StackPanel>
                </TabItem.Header>
                <StackPanel Orientation="Horizontal">
                    <GroupBox Header="串口" Width="200">
                        <StackPanel>
                            <StackPanel Orientation="Horizontal">
                                <Label Margin="3" Height="25" Width="50">端口号</Label>
                                <ComboBox x:Name="comboBoxCOM" Margin="3" Height="20" Width="130" DragDrop.Drop="comboBoxCOM_Drop"/>
                            </StackPanel>
                            <StackPanel Orientation="Horizontal">
                                <Label Margin="3" Height="25" Width="50">波特率</Label>
                                <ComboBox x:Name="comboBoxBaudRate" Margin="3" Height="20" Width="130" SelectedIndex="0" IsEditable="True" >
                                    
                                </ComboBox>
                            </StackPanel>
                            <StackPanel Orientation="Horizontal">
                                <Label Margin="3" Height="25" Width="50">数据位</Label>
                                <ComboBox x:Name="comboBoxDataBit" Margin="3" Height="20" Width="130" SelectedIndex="3">
                                    <ComboBoxItem>5</ComboBoxItem>
                                    <ComboBoxItem>6</ComboBoxItem>
                                    <ComboBoxItem>7</ComboBoxItem>
                                    <ComboBoxItem>8</ComboBoxItem>
                                </ComboBox>
                            </StackPanel>
                            <StackPanel Orientation="Horizontal">
                                <Label Margin="3" Height="25" Width="50">停止位</Label>
                                <ComboBox x:Name="comboBoxStopBit" Margin="3" Height="20" Width="130" SelectedIndex="0">
                                    <ComboBoxItem>1位</ComboBoxItem>
                                    <ComboBoxItem>1.5位</ComboBoxItem>
                                    <ComboBoxItem>2位</ComboBoxItem>
                                </ComboBox>
                            </StackPanel>
                            <StackPanel Orientation="Horizontal">
                                <Label Margin="3" Height="25" Width="50">校验位</Label>
                                <ComboBox x:Name="comboBoxSdd" Margin="3" Height="20" Width="130" SelectedIndex="0">
                                    <ComboBoxItem>无校验</ComboBoxItem>
                                    <ComboBoxItem>奇校验</ComboBoxItem>
                                    <ComboBoxItem>偶校验</ComboBoxItem>
                                    <ComboBoxItem>1 校验</ComboBoxItem>
                                    <ComboBoxItem>0 校验</ComboBoxItem>
                                </ComboBox>
                            </StackPanel>
                            <StackPanel Orientation="Horizontal">
                                <Label Margin="3" Height="25" Width="50">流控位</Label>
                                <ComboBox x:Name="comboBoxlik" Margin="3" Height="20" Width="130" SelectedIndex="0" >
                                    <ComboBoxItem>无流控</ComboBoxItem>
                                    <ComboBoxItem>RTS/CTS</ComboBoxItem>
                                    <ComboBoxItem>XON/XOFF</ComboBoxItem>
                                </ComboBox>
                            </StackPanel>
                            <StackPanel Orientation="Horizontal" HorizontalAlignment="Center">
                                <Button x:Name="btnOpenCloseCom" Margin="3" Width="80" Height="25" Click="btnOpenCloseCom_Click">打开串口</Button>
                                <Button x:Name="btnClearRecv" Margin="3" Width="80" Height="25" Click="btnClearRecv_Click">清空接收</Button>
                            </StackPanel>
                        </StackPanel>
                    </GroupBox>
                    <GroupBox Header="接收数据" MinWidth="590" MaxWidth="1000">
                        <ScrollViewer>
                            <ScrollViewer.Content>
                                <TextBlock x:Name="textBlockRecv" MinWidth="300" MaxWidth="1000"></TextBlock>
                            </ScrollViewer.Content>
                        </ScrollViewer>
                    </GroupBox>
                </StackPanel>
            </TabItem>
            <TabItem>
                <TabItem.Header>
                    <StackPanel>
                        <Label>数据读取</Label>
                    </StackPanel>
                </TabItem.Header>
                <StackPanel Orientation="Horizontal">
                    <StackPanel Orientation="Vertical">
                        <GroupBox Header="记录总数">
                            <StackPanel Orientation="Vertical">
                                <Button x:Name="btnReadRecCount" Margin="3" Padding="5" Click="btnReadRecCount_Click">读取记录总数</Button>
                                <StackPanel Orientation="Horizontal">
                                    <Label>报警记录总数:</Label>
                                    <TextBox x:Name="txtBoxWarningCount">0</TextBox>
                                </StackPanel>
                                <StackPanel Orientation="Horizontal">
                                    <Label>报警恢复记录总数:</Label>
                                    <TextBox x:Name="txtBoxWarningRecoveryCount">0</TextBox>
                                </StackPanel>
                                <StackPanel Orientation="Horizontal">
                                    <Label>故障记录总数:</Label>
                                    <TextBox x:Name="txtBoxFaultCount">0</TextBox>
                                </StackPanel>
                                <StackPanel Orientation="Horizontal">
                                    <Label>故障恢复记录总数:</Label>
                                    <TextBox x:Name="txtBoxFaultRecoryCount">0</TextBox>
                                </StackPanel>
                                <StackPanel Orientation="Horizontal">
                                    <Label>掉电记录总数:</Label>
                                    <TextBox x:Name="txtBoxPoweroffCount">0</TextBox>
                                </StackPanel>
                                <StackPanel Orientation="Horizontal">
                                    <Label>上电记录总数:</Label>
                                    <TextBox x:Name="txtBoxPoweronCount">0</TextBox>
                                </StackPanel>
                                <StackPanel Orientation="Horizontal">
                                    <Label>传感器失效记录总数:</Label>
                                    <TextBox x:Name="txtSensorInvalidCount">0</TextBox>
                                </StackPanel>
                            </StackPanel>
                        </GroupBox>
                        <GroupBox Header="日期时间">
                            <StackPanel Orientation="Vertical">
                                <Button x:Name="btnReadDateTime" Click="btnReadDateTime_Click">读取日期时间</Button>
                                <TextBox x:Name="txtBoxDateTime">0000-00-00 00:00</TextBox>
                            </StackPanel>
                        </GroupBox>
                    </StackPanel>
                    <StackPanel Orientation="Vertical">
                        <GroupBox Header="读取指定记录">
                            <StackPanel Orientation="Horizontal">
                                <ComboBox x:Name="cmboxRecordType" Width="120" SelectedIndex="0">
                                    <ComboBoxItem>报警记录</ComboBoxItem>
                                    <ComboBoxItem>报警恢复记录</ComboBoxItem>
                                    <ComboBoxItem>故障记录</ComboBoxItem>
                                    <ComboBoxItem>故障恢复记录</ComboBoxItem>
                                    <ComboBoxItem>掉电记录</ComboBoxItem>
                                    <ComboBoxItem>上电记录</ComboBoxItem>
                                    <ComboBoxItem>传感器失效记录</ComboBoxItem>
                                </ComboBox>
                                <TextBox x:Name="txtBoxNumber" Width="50">1</TextBox>
                                <Button x:Name="btnReadRecord" Click="btnReadRecord_Click" ClickMode="Press">读取记录</Button>
                                <TextBox x:Name="txtBoxRecordInfo">0000/00/00  00:00</TextBox>
                            </StackPanel>
                        </GroupBox>
                    </StackPanel>
                </StackPanel>
            </TabItem>
        </TabControl>
    </Grid>
</Window>

代码文件

csharp 复制代码
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO.Ports;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

namespace GasAlarmTestTool
{
    /// <summary>
    /// MainWindow.xaml 的交互逻辑
    /// </summary>
    public partial class MainWindow : Window
    {
        private int warningCnt = 0;
        private int warningRecoveryCnt = 0;
        private int faultCnt = 0;
        private int faultRecoveryCnt = 0;
        private int poweroffCnt = 0;
        private int poweronCnt = 0;
        private int sensorInvalidCnt = 0;

        long recvTimems = 0;    // 用于计算串口接收完一帧数据
        int rxLen = 0;  // 串口接收到的数据长度
        byte[] rxBuff = new byte[128];  // 串口数据接收缓存
        private static Timer mTimer;    // 定时器,10ms执行一次

        SerialPort mSerialPort = new SerialPort(); 
        private StringBuilder lineBuilder = new StringBuilder();    // 用于存放串口接收数据
        private List<string> baudrateList = new List<string> { 
            "4800", 
            "9600", 
            "19200",
            "38400",
            "57600",
            "115200",
            "256000",
            "1000000",
            "2000000",
            "3000000"
        };

        public MainWindow()
        {
            InitializeComponent();

            // 获取所有可用串口端口,并添加到comboBoxCOM
            string[] ports = System.IO.Ports.SerialPort.GetPortNames();
            comboBoxCOM.ItemsSource = ports;
            comboBoxCOM.SelectedIndex = 0;  // 默认选择索引

            comboBoxBaudRate.ItemsSource = baudrateList;    // 波特率设置combobox数据源

            mTimer = new Timer(recvTimerCalback, null, 0, 10);  // 创建并启动定时器
        }

        /// <summary>
        /// 窗口关闭处理
        /// </summary>
        /// <param name="e"></param>
        protected override void OnClosing(System.ComponentModel.CancelEventArgs e)
        {            
            if (MessageBox.Show("确定要退出吗?", "确认", MessageBoxButton.YesNo) != MessageBoxResult.Yes)
            {
                // 用户选择"否",取消关闭
                e.Cancel = true;
            }

            mSerialPort.Close();
            mTimer.Dispose();

            base.OnClosing(e);
        }

        private string RecordInfoString(byte[] buf)
        {
            if (buf.Length < 11) {
                return "";
            }

            int index = buf[4];
            int year = buf[5] << 8 | buf[6];
            int month = buf[7];
            int day = buf[8];
            int hour = buf[9];
            int minute = buf[10];
            return  year.ToString() + "/" + month.ToString() + "/" + day.ToString() + "   " + hour.ToString() + ":" + minute.ToString();            
        }

        /// <summary>
        /// 串口接收处理定时器回调
        /// </summary>
        /// <param name="obj"></param>
        private void recvTimerCalback(object obj)
        {
            //Console.WriteLine("timer callback!" + recvTimems);
            this.Dispatcher.Invoke(new Action(()=> {
                // UI线程分离,更新UI数据显示
                if (((Environment.TickCount - recvTimems) >= 20) && (rxLen > 0))
                {
                    // 串口接收时间超过X ms认为一帧数据接收完成

                    uint HEAD = rxBuff[0];
                    uint C1 = rxBuff[1];
                    uint C2 = rxBuff[2];
                    uint L = rxBuff[3];
                    uint CS = rxBuff[L + 4];
                    uint END = rxBuff[L + 5];
                    
                    // 打印串口结束缓存数据
                    uint _CS = 0;   // 计算接收数据校验和

                    uint index = 0;
                    UInt32 temp = 0;
                    for (int i = 0; i < rxLen; i++)
                    {
                        if (i < (rxLen - 2))
                        {
                            temp += rxBuff[i];
                        }
                        Console.WriteLine(rxBuff[i].ToString("X2"));
                    }
                    _CS = (uint)(temp % 0xFF);

                    if ((0xAA == rxBuff[0]) && (0x55 == END))
                    {
                        // TODO: 接收到一帧完整数据
                        Console.WriteLine("RS232 RECV ONE FRAME!" + CS.ToString("X2") + ", " + _CS.ToString("X2"));

                        if (CS == _CS)
                        {
                            // TODO: CHECKSUM8 校验和正确
                            Console.WriteLine("CheckSum OK");
                            if (0x00 == C2)
                            {
                                if (0x00 == C1)
                                {
                                    // TODO: 查询各类记录总数
                                    warningCnt = rxBuff[4]; // 探测器报警记录总数
                                    warningRecoveryCnt = rxBuff[5]; // 探测器报警恢复记录总数
                                    faultCnt = rxBuff[6];   // 探测器故障记录总数
                                    faultRecoveryCnt = rxBuff[7]; // 探测器故障恢复记录总数
                                    poweroffCnt = rxBuff[8];    // 探测器掉电记录总数
                                    poweronCnt = rxBuff[9];     // 探测器上电记录总数
                                    sensorInvalidCnt = rxBuff[10];  // 传感器失效记录总数

                                    txtBoxWarningCount.Text = warningCnt.ToString();
                                    txtBoxWarningRecoveryCount.Text = warningRecoveryCnt.ToString();
                                    txtBoxFaultCount.Text = faultCnt.ToString();
                                    txtBoxFaultRecoryCount.Text = faultRecoveryCnt.ToString();
                                    txtBoxPoweroffCount.Text = poweroffCnt.ToString();  
                                    txtBoxPoweronCount.Text = poweronCnt.ToString();
                                }
                            }
                            else if (0x01 == C2)
                            {
                                // 报警记录
                                txtBoxRecordInfo.Text = RecordInfoString(rxBuff);
                            }
                            else if (0x02 == C2)
                            {
                                // 报警恢复记录
                                txtBoxRecordInfo.Text = RecordInfoString(rxBuff);
                            }
                            else if (0x03 == C2)
                            {
                                // 故障记录
                                txtBoxRecordInfo.Text = RecordInfoString(rxBuff);
                            }
                            else if (0x04 == C2)
                            {
                                // 故障恢复记录
                                txtBoxRecordInfo.Text = RecordInfoString(rxBuff);
                            }
                            else if (0x05 == C2)
                            {
                                // 掉电记录
                                txtBoxRecordInfo.Text = RecordInfoString(rxBuff);
                            }
                            else if (0x06 == C2)
                            {
                                // 上电记录
                                txtBoxRecordInfo.Text = RecordInfoString(rxBuff);
                            }
                            else if (0x07 == C2)
                            {
                                // 传感器失效记录
                                txtBoxRecordInfo.Text = RecordInfoString(rxBuff);

                            }
                            else if (0x08 == C2)
                            {
                                // TODO: 日期时间
                                int year = rxBuff[4] << 8 | rxBuff[5];
                                int month = rxBuff[6];
                                int day = rxBuff[7];
                                int hour = rxBuff[8];
                                int minute = rxBuff[9];
                                txtBoxDateTime.Text = year.ToString() + "/" + month.ToString() + "/" + day.ToString() + "   "+hour.ToString() + ":"+minute.ToString();                                
                            }

                        }
                        else
                        {
                            // TODO: CHECKSUM8 校验和有误
                            Console.WriteLine("CheckSum ERR");
                        }
                    }
                    Array.Clear(rxBuff, 0, rxBuff.Length);
                    rxLen = 0;
                }

            }));                        
        }

        /// <summary>
        /// 串口数据接收函数
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void SerialPort_DataReceived(object sender, SerialDataReceivedEventArgs e)
        {
            
            SerialPort comPort = (SerialPort)sender;
            try
            {
                recvTimems = Environment.TickCount; // 更新串口数据接收时间

                //rxBuff[rxLen] = mSerialPort.ReadByte();
                int readCnt = mSerialPort.BytesToRead;
                Console.WriteLine("in readCnt:" + readCnt);
                mSerialPort.Read(rxBuff, rxLen, readCnt);
                rxLen += readCnt;
                Console.WriteLine("out rxLen:" + rxLen);

#if false
                byte[] data = new byte[mSerialPort.BytesToRead];
                mSerialPort.Read(data, 0, data.Length);
                Console.WriteLine(data.Length);
                foreach (byte b in data)
                { 
                    Console.WriteLine(b.ToString("X2"));                    
                }
#endif
                

            }
            catch (Exception ce)
            {
                MessageBox.Show(ce.Message);
            }            

        }

        private void btnOpenCloseCom_Click(object sender, RoutedEventArgs e)
        {

            if (mSerialPort.IsOpen)
            {
                mSerialPort.Close();
                btnOpenCloseCom.Content = "打开串口";
                Console.WriteLine("关闭串口成功");
                Debug.WriteLine("关闭串口成功");
                comboBoxBaudRate.IsEnabled = true;
                comboBoxCOM.IsEnabled = true;
                comboBoxDataBit.IsEnabled = true;
                comboBoxStopBit.IsEnabled = true;
                comboBoxSdd.IsEnabled = true;
                comboBoxlik.IsEnabled = true;
            }
            else
            {
                mSerialPort.PortName = comboBoxCOM.SelectedItem.ToString();
                mSerialPort.BaudRate = 4800; // 波特率
                mSerialPort.DataBits = 8;   // 数据位
                mSerialPort.StopBits = StopBits.One;    // 停止位
                mSerialPort.Parity = Parity.None;   // 校验位
                mSerialPort.Handshake = Handshake.None;
                //mSerialPort.ReadTimeout = 1500; // 读超时
                //mSerialPort.Encoding = Encoding.UTF8; // 编码方式
                //mSerialPort.RtsEnable = true;

                mSerialPort.DataReceived += SerialPort_DataReceived;

                Console.WriteLine("baudrate SelectedIndex:" + comboBoxBaudRate.SelectedIndex);
                Console.WriteLine("baudrate SelectedValue:" + comboBoxBaudRate.SelectedValue);
                Console.WriteLine("baudrate Text:" + comboBoxBaudRate.Text);


                if (comboBoxBaudRate.SelectedIndex < 0)
                {
                    mSerialPort.BaudRate = Convert.ToInt32(comboBoxBaudRate.Text);
                }
                else 
                {
                    switch (comboBoxBaudRate.SelectedValue)
                    {
                        case "4800":
                            mSerialPort.BaudRate = 4800;
                            break;
                        case "9600":
                            mSerialPort.BaudRate = 9600;
                            break;
                        case "19200":
                            mSerialPort.BaudRate = 19200;
                            break;
                        case "38400":
                            mSerialPort.BaudRate = 38400;
                            break;
                        case "57600":
                            mSerialPort.BaudRate = 57600;
                            break;
                        case "115200":
                            mSerialPort.BaudRate = 115200;
                            break;
                        case "256000":
                            mSerialPort.BaudRate = 256000;
                            break;
                        case "1000000":
                            mSerialPort.BaudRate = 1000000;
                            break;
                        case "2000000":
                            mSerialPort.BaudRate = 2000000;
                            break;
                        case "3000000":
                            mSerialPort.BaudRate = 3000000;
                            break;                       
                        default:
                            MessageBox.Show("波特率设置有误!");
                            break;
                    }
                }

                Console.WriteLine("端口:" + mSerialPort.PortName  + ",波特率:" + mSerialPort.BaudRate);

                // mSerialPort.Write("Hello world"); // 写字符串口
                // mSerialPort.Write(new byte[] { 0xA0, 0xB0, 0xC0}, 0, 3); // 写入3个字节数据

                //Debug.WriteLine("Hello world");
                //MessageBox.Show("端口名:" + mSerialPort.PortName);

                try
                {
                    mSerialPort.Open();
                    btnOpenCloseCom.Content = "关闭串口";
                    Console.WriteLine("打开串口成功");
                    Debug.WriteLine("打开串口成功");

                    comboBoxBaudRate.IsEnabled = false;
                    comboBoxCOM.IsEnabled = false;
                    comboBoxDataBit.IsEnabled = false;
                    comboBoxStopBit.IsEnabled = false;
                    comboBoxSdd.IsEnabled = false;
                    comboBoxlik.IsEnabled = false;
                }
                catch (Exception ex)
                {
                    MessageBox.Show(ex.Message);
                }
            }

        }

        private void btnClearRecv_Click(object sender, RoutedEventArgs e)
        {
            lineBuilder.Clear();
            textBlockRecv.Text = lineBuilder.ToString();
        }

        private void comboBoxCOM_Drop(object sender, DragEventArgs e)
        {
            string[] ports = System.IO.Ports.SerialPort.GetPortNames();
            comboBoxCOM.ItemsSource = ports;
            comboBoxCOM.SelectedIndex = 0;
        }

        private void comboBoxBaudRate_DataContextChanged(object sender, DependencyPropertyChangedEventArgs e)
        {
            ComboBoxItem obj = (ComboBoxItem)sender;


        }

        private void btnReadRecCount_Click(object sender, RoutedEventArgs e)
        {
            if (mSerialPort.IsOpen)
            {
                mSerialPort.Write(new byte[] { 0xAA, 0x00, 0x00, 0x00, 0xAA, 0x55 }, 0, 6); // 写入3个字节数据         
            }
            else
            {
                MessageBox.Show("请先打开串口!");
            }
        }

        private void btnReadDateTime_Click(object sender, RoutedEventArgs e)
        {
            if (mSerialPort.IsOpen)
            {
                mSerialPort.Write(new byte[] { 0xAA, 0x00, 0x08, 0x00, 0xB2, 0x55 }, 0, 6);
            }
            else
            {
                MessageBox.Show("请先打开串口!");
            }
        }

        private void btnReadRecord_Click(object sender, RoutedEventArgs e)
        {            
            int index = Convert.ToInt32(txtBoxNumber.Text);
            if (index < 1 || index > 255)
            {
                MessageBox.Show("记录索引:1~255!");
            }
            else 
            {
                byte C1 = (byte)Convert.ToInt32(txtBoxNumber.Text);
                byte C2 = (byte)(cmboxRecordType.SelectedIndex);
                byte CS = (byte)((0xAA + C1 + C2)%0xFF);
                if (mSerialPort.IsOpen)
                {
                    byte[] Data = new byte[16];
                    Data[0] = 0xAA;
                    Data[1] = C1;   // 指定记录条数
                    Data[2] = (byte)(C2 + 1);   // C2 记录分类从1开始
                    Data[3] = 0x00;
                    Data[4] = CS;
                    Data[5] = 0x55;
                    mSerialPort.Write(Data, 0, 6);
                }
                else
                {
                    MessageBox.Show("请先打开串口!");
                }
            }
        }
    }
}

运行效果


源码下载

下载源码

相关推荐
LyaJpunov6 分钟前
C++中move和forword的区别
开发语言·c++
程序猿练习生10 分钟前
C++速通LeetCode中等第9题-合并区间
开发语言·c++·leetcode
一名路过的小码农20 分钟前
C/C++动态库函数导出 windows
c语言·开发语言·c++
m0_6312704023 分钟前
标准c语言(一)
c语言·开发语言·算法
万河归海42823 分钟前
C语言——二分法搜索数组中特定元素并返回下标
c语言·开发语言·数据结构·经验分享·笔记·算法·visualstudio
Messiah___28 分钟前
【论文阅读】Slim Fly: A Cost Effective Low-Diameter Network Topology 一种经济高效的小直径网络拓扑
开发语言·php
充值内卷37 分钟前
WPF入门教学四 WPF控件概述
windows·ui·wpf
农民小飞侠1 小时前
python AutoGen接入开源模型xLAM-7b-fc-r,测试function calling的功能
开发语言·python
指尖流烟1 小时前
C#调用图表的使用方法
开发语言·c#
敲代码不忘补水1 小时前
Python 项目实践:简单的计算器
开发语言·python·json·项目实践