如何在 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();
}
}
}
根据 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值或一个特殊的符号字符串来指示消息的结束。