串口接收数据的时候,textbox1 只显示了2位数据,在写入文件只写入了8位数据 我发送的68 20 DF 68 02 02 35 41 49 16 我希望显示我发送的所有数据
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.IO;
using System.IO.Ports;
using System.Linq;
using System.Net;
using System.Net.NetworkInformation;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using static System.Windows.Forms.VisualStyles.VisualStyleElement;
using static System.Windows.Forms.VisualStyles.VisualStyleElement.ToolBar;
namespace xiaoniu
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void Form1_Load(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 Button4_Click(object sender, EventArgs e) //全选所有功能
{
RadioButton5.Checked = true;
checkBox1.Checked = true;
checkBox2.Checked = true;
}
private void RadioButton5_CheckedChanged(object sender, EventArgs e) //控制器类
{
}
private void SerialPort1_DataReceived(object sender, SerialDataReceivedEventArgs e) //串口类
{
CheckForIllegalCrossThreadCalls = false;
byte ReceiveData;
ReceiveData =(byte)SerialPort1.ReadByte();
string str = Convert.ToString(ReceiveData, 16).ToUpper();
StreamWriter sw = new StreamWriter(@"C:\Users\g'x'r\Desktop\jieshou.txt", true);//写入文件夹
textBox1.Text = str;
sw.Write(str);
sw.Close();
}
}
}
参考GPT和自己的思路,您的代码存在一些问题,包括:
只读取了一个字节的数据,因此无法读取完整的数据帧。
在数据接收事件处理程序中,创建了一个StreamWriter对象,每次接收到一个字节的数据就将其写入文件,这将导致文件中包含不完整的数据,而且文件也无法关闭。
下面是修改后的代码,注释中标明了修改的地方:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.IO;
using System.IO.Ports;
using System.Linq;
using System.Net;
using System.Net.NetworkInformation;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using static System.Windows.Forms.VisualStyles.VisualStyleElement;
using static System.Windows.Forms.VisualStyles.VisualStyleElement.ToolBar;
namespace xiaoniu
{
public partial class Form1 : Form
{
// 声明一个byte数组,用于存储接收到的数据
byte[] receiveBuffer = new byte[10];
// 声明一个变量,用于记录已经接收的数据字节数
int receivedBytes = 0;
public Form1()
{
InitializeComponent();
}
private void Form1_Load(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;
// 在接收到的数据中读取一个字节
byte receivedByte = (byte)SerialPort1.ReadByte();
// 将接收到的字节存储到缓冲区中
receiveBuffer[receivedBytes] = receivedByte;
// 记录已经接收的字节数
receivedBytes++;
// 判断是否已经接收完
if (receivedBytes == receiveBuffer.Length)
{
// 将接收到的数据转换为十六进制字符串
string receivedString = BitConverter.ToString(receiveBuffer);
// 将接收到的数据显示到文本框中
textBox1.AppendText(receivedString + " ");
// 将接收到的数据写入到文件中
using (StreamWriter sw = new StreamWriter(@"C:\Users\g'x'r\Desktop\jieshou.txt", true))
{
sw.Write(receivedString + " ");
}
// 清空接收缓冲区和已接收的字节数
receivedBytes = 0;
Array.Clear(receiveBuffer, 0, receiveBuffer.Length);
}
}
在这段代码中,我们引入了一个接收缓冲区 receiveBuffer 和已接收的字节数 receivedBytes。每当串口接收到一个字节时,就将其存储到缓冲区中,并增加已接收的字节数。当已接收的字节数达到了缓冲区的长度时,就说明已经接收完了一个完整的数据包。接着,我们将接收到的数据转换为十六进制字符串,并显示在文本框中,同时将其写入到文件中。最后,我们清空接收缓冲区和已接收的字节数,以便接收下一个数据包。
基于chatGPT的回答,在串口接收数据的处理函数 SerialPort1_DataReceived 中,你使用了 SerialPort1.ReadByte() 一次读取一个字节,但是你的数据是由多个字节组成的,因此你需要在接收到完整的数据包之后再进行处理。可以使用一个缓冲区来存储接收到的数据,当缓冲区中的数据长度达到一个完整数据包的长度时,再进行处理。
此外,你在每次接收到数据时,都将数据转换为十六进制字符串并写入到文件中。这可能会导致你看到的数据不是原始数据。如果你只想将原始数据写入文件中,可以将接收到的字节直接写入文件,而不是将其转换为字符串。另外,为了避免重复打开文件,可以将文件流的创建放在函数外部,这样每次接收数据时都可以直接写入文件。
下面是修改后的代码示例:
public partial class Form1 : Form
{
private byte[] receiveBuffer = new byte[10]; // 缓冲区大小为一个完整数据包的长度
private int receiveLength = 0; // 当前缓冲区中的数据长度
private FileStream fs;
public Form1()
{
InitializeComponent();
fs = new FileStream(@"C:\Users\g'x'r\Desktop\jieshou.txt", FileMode.Append, FileAccess.Write);
}
private void Form1_FormClosing(object sender, FormClosingEventArgs e)
{
fs.Close();
}
// 省略其它函数
private void SerialPort1_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
CheckForIllegalCrossThreadCalls = false;
int bytesToRead = SerialPort1.BytesToRead;
if (bytesToRead > receiveBuffer.Length - receiveLength) {
// 如果缓冲区空间不足,清空缓冲区并重置长度
receiveLength = 0;
Array.Clear(receiveBuffer, 0, receiveBuffer.Length);
MessageBox.Show("数据包长度超过缓冲区大小");
return;
}
SerialPort1.Read(receiveBuffer, receiveLength, bytesToRead);
receiveLength += bytesToRead;
if (receiveLength >= receiveBuffer.Length) {
// 缓冲区已满,接收到完整的数据包
StringBuilder sb = new StringBuilder();
foreach (byte b in receiveBuffer) {
sb.Append(b.ToString("X2"));
sb.Append(" ");
}
string hexString = sb.ToString().TrimEnd();
textBox1.Text = hexString;
fs.Write(receiveBuffer, 0, receiveBuffer.Length); // 将原始字节数据写入文件
fs.Flush();
receiveLength = 0; // 重置缓冲区长度
Array.Clear(receiveBuffer, 0, receiveBuffer.Length);
}
}
}
回答不易,还请采纳!!!
以下答案由GPT-3.5大模型与博主波罗歌共同编写:
在串口接收数据时,使用ReadByte方法只会读取一个字节,如果接收到的数据是多个字节,需要在数据接收事件SerialPort1_DataReceived中使用循环来读取所有的数据。同时,在将数据显示到TextBox1和写入文件中,也需要保证显示的是所有接收到的数据,而不是每次只显示一个字节的数据。以下是修改后的代码:
public partial class Form1 : Form
{
private string receivedData = ""; // 存储已接收到的数据
public Form1()
{
InitializeComponent();
}
private void Form1_Load(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();
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)
{
byte[] buffer = new byte[SerialPort1.BytesToRead]; // buffer保存当前所有可读取的数据
SerialPort1.Read(buffer, 0, buffer.Length);
foreach (byte data in buffer) // 遍历所有接收到的数据
{
string str = Convert.ToString(data, 16).ToUpper();
receivedData += str; // 将已接收到的数据拼接起来
textBox1.Text = receivedData;
}
StreamWriter sw = new StreamWriter(@"C:\Users\g'x'r\Desktop\jieshou.txt", true);
sw.Write(receivedData); // 将所有接收到的数据写入文件
sw.Close();
}
}
如果我的回答解决了您的问题,请采纳!