C#中我想判断头帧后截取后面的7位数据

串口发过来的数据,如何截取我想要的长度 在我判断头帧后 我只想要后面的7位,并可以把我截取的到数据写入文件内,如果有思路请直接贴代码,麻烦带上注释,如果按照需求可以正常运行 我会采纳

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.IO.Ports;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using static System.Windows.Forms.VisualStyles.VisualStyleElement;
 
namespace Ck
{
 
    public partial class Form1 : Form
    {
        string timeStr = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");
        
        private List<byte> buffer = new List<byte>(1024);
        byte[] receiveBuffer = new byte[10];
        public Form1()
        {
            InitializeComponent();
        }
        private void Form1_Load_1(object sender, EventArgs e)
        {
            comboBox1.Items.AddRange(System.IO.Ports.SerialPort.GetPortNames());
            serialPort1.DataReceived += new SerialDataReceivedEventHandler(serialPort1_DataReceived);
        }
        private void button1_Click(object sender, EventArgs e)
        {
            try
            {
                if (serialPort1.IsOpen)
                {
                    serialPort1.Close();
                    button1.Text = "点击打开串口";
                }
                else
                {
                    serialPort1.PortName = comboBox1.Text;
                    serialPort1.Open();
                    button1.Text = "点击关闭串口";
                }
            }
            catch (Exception ex)
            {
                //捕获可能发生的异常并进行处理
 
                //捕获到异常,创建一个新的对象,之前的不可以再用
                serialPort1 = new System.IO.Ports.SerialPort();
                //刷新COM口选项
                comboBox1.Items.Clear();
                comboBox1.Items.AddRange(System.IO.Ports.SerialPort.GetPortNames());
                //响铃并显示异常给用户
                System.Media.SystemSounds.Beep.Play();
                button1.Text = "打开串口";
                button1.BackColor = Color.ForestGreen;
                MessageBox.Show(ex.Message);
            }
 
        }
 
        private void serialPort1_DataReceived(object sender, SerialDataReceivedEventArgs e)
        {
            string abc;
            // 检查是否允许跨线程调用控件,这里为了简化代码直接禁用了该功能
            CheckForIllegalCrossThreadCalls = false;
 
 
            // 读取所有可用字节数
            int bytesToRead = serialPort1.BytesToRead;
 
            //用于存储接收到的数据
            byte[] receiveBuffer = new byte[bytesToRead];
 
            //从串口读取数据
            serialPort1.Read(receiveBuffer, 0, bytesToRead);
            buffer.AddRange(receiveBuffer);
            //将接收到的数据转换为字符串格式
            string receivedString = BitConverter.ToString(receiveBuffer).Replace("-", "");
            //将字符串追加至文本框中
            if (buffer[0] ==0x68)
            {
 
                StreamWriter sw = new StreamWriter(@"C:\Users\guoxiaoru\Desktop\ACVB.txt", true);
                sw.WriteLine(receivedString, "\n");
                sw.Close(); 
                
            }
 
        }  
    }
}
 
 

参考GPT和自己的思路:你可以在 serialPort1_DataReceived 方法中加入以下代码,来实现你的需求。在接收到头帧时,将后面的7位数据截取出来,并写入文件:

private void serialPort1_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
    // ...

    // 从串口读取数据
    serialPort1.Read(receiveBuffer, 0, bytesToRead);
    buffer.AddRange(receiveBuffer);

    // 如果接收到头帧 0x68
    if (buffer[0] == 0x68)
    {
        // 如果接收到的数据长度不足 8,说明数据不完整,等待下一次接收
        if (buffer.Count < 8) 
            return;

        // 截取后面的 7 个字节
        byte[] data = buffer.Skip(1).Take(7).ToArray();

        // 将字节数组转换为字符串,并写入文件
        string dataString = BitConverter.ToString(data).Replace("-", "");
        using (StreamWriter sw = new StreamWriter(@"C:\Users\guoxiaoru\Desktop\ACVB.txt", true))
        {
            sw.WriteLine(dataString);
        }

        // 清空缓冲区,等待下一次接收
        buffer.Clear();
    }
}


解释一下代码:

buffer 是一个 List,用于存储从串口接收到的数据。注意,该缓冲区不一定保存完整的数据帧,可能只保存了数据帧的一部分。
当接收到头帧时,先检查缓冲区中是否已经接收了完整的数据帧,如果数据不完整,则等待下一次接收。
使用 LINQ 的 Skip 和 Take 方法截取后面的 7 个字节。
使用 BitConverter 类将字节数组转换为字符串,并将字符串写入文件。使用 using 语句可以自动关闭文件流。
最后清空缓冲区,等待下一次接收。

该回答引用GPTᴼᴾᴱᴺᴬᴵ
根据您提供的代码,您可以在serialPort1_DataReceived方法中添加以下代码来截取头帧后的7位数据并将其写入文件:

private void serialPort1_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
    // ...

    // 判断头帧是否存在,头帧为0x68
    if (buffer[0] == 0x68)
    {
        // 如果数据长度不够,则继续等待数据
        if (buffer.Count < 8)
        {
            return;
        }

        // 获取需要的7个字节的数据
        byte[] data = buffer.Skip(1).Take(7).ToArray();

        // 将数据写入文件
        string filePath = @"C:\Users\guoxiaoru\Desktop\ACVB.txt";
        using (StreamWriter sw = new StreamWriter(filePath, true))
        {
            sw.WriteLine(BitConverter.ToString(data).Replace("-", ""));
        }

        // 清空缓存区
        buffer.Clear();
    }
}

代码中的Skip(1).Take(7)方法可以用于截取从第二个字节开始的7个字节数据,ToArray()方法将其转换为byte[]类型,BitConverter.ToString方法将byte[]转换为字符串并去掉其中的分隔符。最后,将字符串写入文件中。注意,代码中使用了using语句来自动关闭StreamWriter对象并释放资源。

参考GPT和自己的思路:

可以在数据接收事件serialPort1_DataReceived中,判断首帧是否是0x68,如果是的话,截取后面的7位数据并写入文件。代码如下:

private void serialPort1_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
    // 读取所有可用字节数
    int bytesToRead = serialPort1.BytesToRead;

    //用于存储接收到的数据
    byte[] receiveBuffer = new byte[bytesToRead];

    //从串口读取数据
    serialPort1.Read(receiveBuffer, 0, bytesToRead);
    buffer.AddRange(receiveBuffer);

    //首帧为0x68时
    if (buffer[0] == 0x68)
    {
        //截取后面的7位数据
        byte[] dataBytes = buffer.GetRange(1, 7).ToArray();

        //将接收到的数据转换为字符串格式
        string receivedString = BitConverter.ToString(dataBytes).Replace("-", "");

        //将字符串追加至文本框中
        StreamWriter sw = new StreamWriter(@"C:\Users\guoxiaoru\Desktop\ACVB.txt", true);
        sw.WriteLine(receivedString);
        sw.Close();

        //清空缓存
        buffer.Clear();
    }
}

其中,buffer是接收缓存列表,GetRange方法用于获取指定范围的数据,ToArray方法将列表转换为数组。最后需要清空缓存列表,以准备接收下一帧数据。

参考GPT和自己的思路:

可以使用字符串的 Substring 方法来截取需要的长度,具体可以在收到数据后先判断头帧,如果符合条件再进行截取操作:

private void serialPort1_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
    // 读取所有可用字节数
    int bytesToRead = serialPort1.BytesToRead;

    //用于存储接收到的数据
    byte[] receiveBuffer = new byte[bytesToRead];

    //从串口读取数据
    serialPort1.Read(receiveBuffer, 0, bytesToRead);

    buffer.AddRange(receiveBuffer);
    //将接收到的数据转换为字符串格式
    string receivedString = BitConverter.ToString(buffer.ToArray()).Replace("-", "");

    if (buffer[0] == 0x68)
    {
        // 截取后面的7位数据
        string data = receivedString.Substring(2, 14);

        // 写入文件
        using (StreamWriter sw = new StreamWriter(@"C:\Users\guoxiaoru\Desktop\ACVB.txt", true))
        {
            sw.WriteLine(data);
        }

        buffer.Clear();  // 清空缓存
    }
}

其中,Substring 方法的第一个参数表示起始位置,第二个参数表示要截取的长度。注意要将 buffer 转成数组再进行字符串操作,这里使用了 List 类型的 buffer 来保存数据。另外,在写入文件时要使用 using 语句来自动释放资源。

参考GPT和自己的思路,你可以在serialPort1_DataReceived事件处理程序中,对读取的数据进行处理,提取所需的字节并将其写入文件中。以下是对代码的修改建议:

private void serialPort1_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
    // 读取所有可用字节数
    int bytesToRead = serialPort1.BytesToRead;

    //用于存储接收到的数据
    byte[] receiveBuffer = new byte[bytesToRead];

    //从串口读取数据
    serialPort1.Read(receiveBuffer, 0, bytesToRead);
    buffer.AddRange(receiveBuffer);

    //找到头帧并提取后面的7个字节
    int startIndex = buffer.IndexOf(0x68);
    if (startIndex >= 0 && buffer.Count >= startIndex + 8)
    {
        byte[] data = buffer.Skip(startIndex + 1).Take(7).ToArray();

        //将接收到的数据转换为字符串格式
        string receivedString = BitConverter.ToString(data).Replace("-", "");

        //将字符串追加至文本框中
        StreamWriter sw = new StreamWriter(@"C:\Users\guoxiaoru\Desktop\ACVB.txt", true);
        sw.WriteLine(receivedString);
        sw.Close();

        //从缓存中移除已处理的数据
        buffer.RemoveRange(0, startIndex + 8);
    }
}

在该代码中,我们使用List类型的buffer变量来存储从串口接收到的数据。我们首先检查缓冲区中是否存在头帧(0x68),如果存在,则提取后面的7个字节,并将它们写入指定的文本文件中。最后,我们将已处理的数据从缓存中移除,以便后续处理。

以下答案由GPT-3.5大模型与博主波罗歌共同编写:
根据您的需求,以下是对您的代码进行修改并加入数据截取的部分,我会在代码中加入注释来解释具体做法:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.IO.Ports;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using static System.Windows.Forms.VisualStyles.VisualStyleElement;
 
namespace Ck
{
    public partial class Form1 : Form
    {
        string timeStr = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");
        private List<byte> buffer = new List<byte>(1024);
        byte[] receiveBuffer = new byte[10];
        public Form1()
        {
            InitializeComponent();
        }
        private void Form1_Load_1(object sender, EventArgs e)
        {
            comboBox1.Items.AddRange(System.IO.Ports.SerialPort.GetPortNames());
            serialPort1.DataReceived += new SerialDataReceivedEventHandler(serialPort1_DataReceived);
        }
        private void button1_Click(object sender, EventArgs e)
        {
            try
            {
                if (serialPort1.IsOpen)
                {
                    serialPort1.Close();
                    button1.Text = "点击打开串口";
                }
                else
                {
                    serialPort1.PortName = comboBox1.Text;
                    serialPort1.Open();
                    button1.Text = "点击关闭串口";
                }
            }
            catch (Exception ex)
            {
                //捕获可能发生的异常并进行处理
 
                //捕获到异常,创建一个新的对象,之前的不可以再用
                serialPort1 = new System.IO.Ports.SerialPort();
                //刷新COM口选项
                comboBox1.Items.Clear();
                comboBox1.Items.AddRange(System.IO.Ports.SerialPort.GetPortNames());
                //响铃并显示异常给用户
                System.Media.SystemSounds.Beep.Play();
                button1.Text = "打开串口";
                button1.BackColor = Color.ForestGreen;
                MessageBox.Show(ex.Message);
            }
        }
 
        private void serialPort1_DataReceived(object sender, SerialDataReceivedEventArgs e)
        {
            // 检查是否允许跨线程调用控件,这里为了简化代码直接禁用了该功能
            CheckForIllegalCrossThreadCalls = false;
 
            // 读取所有可用字节数
            int bytesToRead = serialPort1.BytesToRead;
 
            //用于存储接收到的数据
            byte[] receiveBuffer = new byte[bytesToRead];
 
            //从串口读取数据
            serialPort1.Read(receiveBuffer, 0, bytesToRead);
            buffer.AddRange(receiveBuffer);
 
            //将接收到的数据转换为字符串格式
            string receivedString = BitConverter.ToString(receiveBuffer).Replace("-", "");
 
            //判断头帧
            if (buffer[0] == 0x68)
            {
                //截取后面的7位数据
                byte[] dataBuffer = buffer.Skip(1).Take(7).ToArray();
                string dataString = BitConverter.ToString(dataBuffer).Replace("-", "");
 
                //将截取到的数据追加到文件里
                StreamWriter sw = new StreamWriter(@"C:\Users\guoxiaoru\Desktop\ACVB.txt", true);
                sw.WriteLine(dataString);
                sw.Close(); 
 
                //清空缓存
                buffer.Clear();
            }
        }  
    }
}

主要修改如下:

  1. 在DataReceived事件中,加入了截取后7位数据的逻辑。
  2. 在DataReceived事件中,加入了将截取到的数据写入文件的逻辑。
  3. 在截取数据时,使用了LINQ的Skip和Take方法,代码更加简洁。

这段代码可以在判断到头帧后,截取后面的数据并将其写入文件中。注意这段代码只能根据第一个字节来判断头帧,您如果需要更加准确的判断头帧的逻辑,请自行修改。
如果我的回答解决了您的问题,请采纳!