如何在 C# 中以正确的顺序从串行端口获取数组数据

本文关键字:顺序 串行端口 获取 数据 数组 | 更新日期: 2023-09-27 18:37:07

我在下面的程序中的目的是从微控制器获取16字节的数据并处理数据以获得适当的指令。这里有很多相关的问题和答案,但我在下面的问题中找不到任何内容。我可以从 MCU 获得 16 个字节。字节值是正确的,我可以在 dataGridView 中看到它们,但字节序列正在更改。例如,首先 MCUData[0] = 0x01 , MCUData[1] = 0xFE , MCUData[2] = 0xCC 然后它变为 MCUData[0] = 0xFE , MCUData[1] = 0xCC , MCUData[2] = 0x01。İt 就像在字节数组中移动我的数据时遇到一些问题。我确定我的MCU正在正确发送数据,因为我签入了串行终端程序之一。我的代码在下面

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.IO.Ports;
using System.Threading;
namespace SerialCommunicationMCU
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
            dataGridView1.Columns.Add("MCUData", "Byte Name");
            dataGridView1.Columns.Add("MCUData", "Byte Value");
        }
        public System.IO.Ports.SerialPort SerialPc;

        #region Variables
        public string AvailablePort;
        public string[] Ports = SerialPort.GetPortNames();
        byte[] MCUData = new byte[16];
        #endregion

        private void Connect_Click(object sender, EventArgs e)
        {
            DataGreedByteNameShow();
            SerialConnectandRead();
            ConnectButton.Enabled = false;
            DisconnectButton.Enabled = true;
        }
        private void Disconnect_Click(object sender, EventArgs e)
        {
            SerialPc.Close();
            ConnectButton.Enabled = true;
            DisconnectButton.Enabled = false;
        }
        public void SerialConnectandRead()
        {
            SerialPc = new SerialPort(AvailablePort, 115200, Parity.None, 8, StopBits.One);
            try
            {
                SerialPc.Open();
                SerialPc.DataReceived += new SerialDataReceivedEventHandler(SerialPc_DataReceived);
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.ToString(), "Serial Port Error");
            }
        }
        private void SerialPc_DataReceived(object sender, SerialDataReceivedEventArgs e)
        {
            SerialPc.DiscardNull = false;
            SerialPc.Read(MCUData, 0, 16);
            SerialPc.ReceivedBytesThreshold = 16;
            DataGreedByteValueShow();
        }
        private void Form1_Load(object sender, EventArgs e)
        {
            foreach (string port in Ports)
            {
                comboBox1.Items.Add(port);
            }
            DisconnectButton.Enabled = false;
        }
        public void DataGreedByteNameShow()
        {
            dataGridView1.Rows.Add("MCUData[0]");
            dataGridView1.Rows.Add("MCUData[1]");
            dataGridView1.Rows.Add("MCUData[2]");
            dataGridView1.Rows.Add("MCUData[3]");
            dataGridView1.Rows.Add("MCUData[4]");
            dataGridView1.Rows.Add("MCUData[5]");
            dataGridView1.Rows.Add("MCUData[6]");
            dataGridView1.Rows.Add("MCUData[7]");
            dataGridView1.Rows.Add("MCUData[8]");
            dataGridView1.Rows.Add("MCUData[9]");
            dataGridView1.Rows.Add("MCUData[10]");
            dataGridView1.Rows.Add("MCUData[11]");
            dataGridView1.Rows.Add("MCUData[12]");
            dataGridView1.Rows.Add("MCUData[13]");
            dataGridView1.Rows.Add("MCUData[14]");
            dataGridView1.Rows.Add("MCUData[15]");
        }
        private void DataGreedByteValueShow()
        {
            dataGridView1.Rows[0].Cells[1].Value = MCUData[0];
            dataGridView1.Rows[1].Cells[1].Value = MCUData[1];
            dataGridView1.Rows[2].Cells[1].Value = MCUData[2];
            dataGridView1.Rows[3].Cells[1].Value = MCUData[3];
            dataGridView1.Rows[4].Cells[1].Value = MCUData[4];
            dataGridView1.Rows[5].Cells[1].Value = MCUData[5];
            dataGridView1.Rows[6].Cells[1].Value = MCUData[6];
            dataGridView1.Rows[7].Cells[1].Value = MCUData[7];
            dataGridView1.Rows[8].Cells[1].Value = MCUData[8];
            dataGridView1.Rows[9].Cells[1].Value = MCUData[9];
            dataGridView1.Rows[10].Cells[1].Value = MCUData[10];
            dataGridView1.Rows[11].Cells[1].Value = MCUData[11];
            dataGridView1.Rows[12].Cells[1].Value = MCUData[12];
            dataGridView1.Rows[13].Cells[1].Value = MCUData[13];
            dataGridView1.Rows[14].Cells[1].Value = MCUData[14];
            dataGridView1.Rows[15].Cells[1].Value = MCUData[15];
        }
        private void comboBox1_SelectedIndexChanged(object sender, EventArgs e)
        {
            AvailablePort = comboBox1.SelectedItem.ToString();
        }
    }
}

如何在 C# 中以正确的顺序从串行端口获取数组数据

根据 MSDN 文档:http://msdn.microsoft.com/en-us/library/ms143549(v=vs.110).aspx

从串行端口输入缓冲区读取多个字节并写入 这些字节以指定的偏移量放入字节数组中。

public int Read(
    byte[] buffer,
    int offset,
    int count
)

以下是当前代码使用该函数的方式:

SerialPc.Read(MCUData, 0, 16);

缓冲区是一个全局变量,定义为:

byte[] MCUData = new byte[16];

这是可用于解决问题的一种方法:

    List<byte> MCUDataOverTime = new List<byte>();        
    private void SerialPc_DataReceived(object sender, SerialDataReceivedEventArgs e)
    {
        SerialPc.DiscardNull = false;
        SerialPc.Read(MCUData, 0, 16);
        MCUDataOverTime.AddRange(MCUData);
        SerialPc.ReceivedBytesThreshold = 16;
        DataGreedByteValueShow();
    }
    private void DataGreedByteValueShow()
    {
        if (MCUDataOverTime.Count >= 16)
        {
            dataGridView1.Rows[0].Cells[1].Value = MCUDataOverTime[0];
            dataGridView1.Rows[1].Cells[1].Value = MCUDataOverTime[1];
            dataGridView1.Rows[2].Cells[1].Value = MCUDataOverTime[2];
            dataGridView1.Rows[3].Cells[1].Value = MCUDataOverTime[3];
            dataGridView1.Rows[4].Cells[1].Value = MCUDataOverTime[4];
            dataGridView1.Rows[5].Cells[1].Value = MCUDataOverTime[5];
            dataGridView1.Rows[6].Cells[1].Value = MCUDataOverTime[6];
            dataGridView1.Rows[7].Cells[1].Value = MCUDataOverTime[7];
            dataGridView1.Rows[8].Cells[1].Value = MCUDataOverTime[8];
            dataGridView1.Rows[9].Cells[1].Value = MCUDataOverTime[9];
            dataGridView1.Rows[10].Cells[1].Value = MCUDataOverTime[10];
            dataGridView1.Rows[11].Cells[1].Value = MCUDataOverTime[11];
            dataGridView1.Rows[12].Cells[1].Value = MCUDataOverTime[12];
            dataGridView1.Rows[13].Cells[1].Value = MCUDataOverTime[13];
            dataGridView1.Rows[14].Cells[1].Value = MCUDataOverTime[14];
            dataGridView1.Rows[15].Cells[1].Value = MCUDataOverTime[15];
        }
    }

上面的代码将解决您的值随时间变化的问题。 它首先发生,因为每次调用SerialPc_DataReceived()时,您都对其进行了设置,以便每个"读取"都会将其结果存储在MCUData字节数组中。 因此,它最终将覆盖您的 MCUData 数组,因为您已将起始偏移量硬编码为 0。

这就是为什么您的数据看起来正在转移的原因。 您必须了解,从根本上说,这些流不会方便地为您存储数据,其中索引为 0 表示时间的开始(流首次打开和启动的时间)。 如果您希望它以这种方式工作,则必须自己存储它。

请注意,上面的代码不会尝试清空串行输入缓冲区。 每次调用 DataReceived 时进行读取时,您都会提取 16 个字节,但我想知道 MCU 是否发送的比每条数据接收消息发送的要多得多。

编辑:

    List<byte> MCUDataOverTime = new List<byte>();        
    private void SerialPc_DataReceived(object sender, SerialDataReceivedEventArgs e)
    {
        SerialPc.DiscardNull = false;
        int readcount = 0;
        byte [] temp;
        do
        {
            readcount = SerialPc.Read(MCUData, 0, 16);
            if (readcount > 0)
            {
                temp = new byte[readcount];
                Array.Copy(MCUData, 0, temp, 0, readcount);
                MCUDataOverTime.AddRange(temp);
                SerialPc.ReceivedBytesThreshold = 16;
                DataGreedByteValueShow();
            }
        } while (readcount > 0);
    }
    private void DataGreedByteValueShow()
    {
        if (MCUDataOverTime.Count >= 16)
        {
            dataGridView1.Rows[0].Cells[1].Value = MCUDataOverTime[0];
            dataGridView1.Rows[1].Cells[1].Value = MCUDataOverTime[1];
            dataGridView1.Rows[2].Cells[1].Value = MCUDataOverTime[2];
            dataGridView1.Rows[3].Cells[1].Value = MCUDataOverTime[3];
            dataGridView1.Rows[4].Cells[1].Value = MCUDataOverTime[4];
            dataGridView1.Rows[5].Cells[1].Value = MCUDataOverTime[5];
            dataGridView1.Rows[6].Cells[1].Value = MCUDataOverTime[6];
            dataGridView1.Rows[7].Cells[1].Value = MCUDataOverTime[7];
            dataGridView1.Rows[8].Cells[1].Value = MCUDataOverTime[8];
            dataGridView1.Rows[9].Cells[1].Value = MCUDataOverTime[9];
            dataGridView1.Rows[10].Cells[1].Value = MCUDataOverTime[10];
            dataGridView1.Rows[11].Cells[1].Value = MCUDataOverTime[11];
            dataGridView1.Rows[12].Cells[1].Value = MCUDataOverTime[12];
            dataGridView1.Rows[13].Cells[1].Value = MCUDataOverTime[13];
            dataGridView1.Rows[14].Cells[1].Value = MCUDataOverTime[14];
            dataGridView1.Rows[15].Cells[1].Value = MCUDataOverTime[15];
        }
    }

我会将 MCUData 的大小增加到 1024 字节或更多,因为 16 字节似乎有点小。 您需要做的下一件事是跟踪每帧的起点和终点。 我猜在你的微控制器的情况下,它总是16,但一般来说,你应该让微控制器抛出null值或一个特殊的符号字符串来指示消息的结束。