以下是格式规范化后的代码:using System;
using System.Collections.Generic;
using System.Compone ...
在这个基础上,用C#添加串口接收的功能 XYZ_XYZ 发表于 2024-03-04 22:27
在这个基础上,用C#添加串口接收的功能
下面是在C#代码中添加串口接收功能的修改:
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.IO.Ports;
using System.Windows.Forms;
namespace 串口数据显示
{
public partial class Form1 : Form
{
private SerialPort serialPort = null;
private bool isSerialPortOpen = false;
public Form1()
{
InitializeComponent();
this.comboBox1.DropDown += new System.EventHandler(this.comboBox1_DropDown);
this.button1.Click += new System.EventHandler(this.button1_Click);
this.button2.Click += new System.EventHandler(this.button2_Click);
this.FormClosing += new System.Windows.Forms.FormClosingEventHandler(this.Form1_FormClosing);
// 注册串口数据接收事件
this.serialPort.DataReceived += new SerialDataReceivedEventHandler(serialPort_DataReceived);
}
private void comboBox1_DropDown(object sender, EventArgs e)
{
string[] ports = SerialPort.GetPortNames();
comboBox1.Items.Clear();
foreach (string port in ports)
{
comboBox1.Items.Add(port);
}
if (comboBox1.Items.Count > 0)
{
comboBox1.SelectedIndex = 0;
}
}
private void button1_Click(object sender, EventArgs e)
{
if (isSerialPortOpen)
{
// 如果串口已打开,则关闭串口
if (serialPort != null && serialPort.IsOpen)
{
serialPort.Close();
serialPort.Dispose();
}
isSerialPortOpen = false;
button1.Text = "打开";
}
else
{
// 如果串口未打开,则打开串口
try
{
if (serialPort == null)
{
serialPort = new SerialPort();
}
if (!serialPort.IsOpen && comboBox1.SelectedItem != null)
{
serialPort.PortName = comboBox1.SelectedItem.ToString();
serialPort.BaudRate = 115200;
serialPort.Parity = Parity.None;
serialPort.StopBits = StopBits.One;
serialPort.DataBits = 8;
serialPort.Handshake = Handshake.None;
serialPort.Open();
isSerialPortOpen = true;
button1.Text = "关闭";
}
else
{
MessageBox.Show("请选择一个串口或串口已经打开");
}
}
catch (Exception ex)
{
MessageBox.Show("打开串口时出错: " + ex.Message);
if (serialPort != null)
{
serialPort.Close();
serialPort.Dispose();
}
}
}
}
private void button2_Click(object sender, EventArgs e)
{
if (isSerialPortOpen)
{
try
{
// 发送0x99给串口
byte[] sendData = { 0x99 };
serialPort.Write(sendData, 0, sendData.Length);
}
catch (Exception ex)
{
MessageBox.Show("发送数据时出错: " + ex.Message);
}
}
else
{
MessageBox.Show("请先打开串口");
}
}
private void serialPort_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
try
{
// 从串口读取接收到的数据
string receivedData = serialPort.ReadLine();
// 在界面上显示接收到的数据
this.Invoke(new Action(() =>
{
textBox1.AppendText(receivedData + Environment.NewLine);
}));
}
catch (Exception ex)
{
MessageBox.Show("接收数据时出错: " + ex.Message);
}
}
private void Form1_FormClosing(object sender, FormClosingEventArgs e)
{
if (serialPort != null && serialPort.IsOpen)
{
serialPort.Close();
serialPort.Dispose();
}
}
}
}
以上代码在原有的基础上添加了`serialPort_DataReceived`方法作为串口数据接收事件处理函数。在该方法中,我们使用`ReadLine()`方法从串口读取接收到的数据,并把它显示在`textBox1`控件上。
希望这次的修改能够满足你的需求!如果还有其他问题,请随时提问。
以上回复来自 FishC AI 小助理,如未能正确解答您的问题,请继续追问。 FishC 发表于 2024-3-4 22:27
下面是在C#代码中添加串口接收功能的修改:
以上代码在原有的基础上添加了`serialPort_DataReceived ...
System.NullReferenceException:“未将对象引用设置到对象的实例。”
XYZ_XYZ 发表于 2024-03-04 22:31
System.NullReferenceException:“未将对象引用设置到 ...
System.NullReferenceException是一个常见的异常,它通常出现在访问一个未初始化或为空的对象时。在你的代码中,出现了这个异常的原因可能是以下几种情况:
1. 在使用serialPort对象之前,没有将其实例化。在Form1类的构造函数中,你应该添加以下代码来实例化serialPort对象:
serialPort = new SerialPort();
2. 串口选择的comboBox1的SelectedItem属性为空。在button1_Click事件处理程序中,在打开串口之前,你需要检查comboBox1.SelectedItem是否为空,如果为空,则应该给用户一个提示。
在解决以上问题之后,你的代码应该能够正常运行,避免出现NullReferenceException异常。如果还有其他问题,请提供完整的错误信息和相关代码,以便更好地帮助你。
以上回复来自 FishC AI 小助理,如未能正确解答您的问题,请继续追问。 FishC 发表于 2024-3-4 22:31
System.NullReferenceException是一个常见的异常,它通常出现在访问一个未初始化或为空的对象时。在你 ...
请帮我把修改好的完整代码打印出来 XYZ_XYZ 发表于 2024-03-04 22:35
请帮我把修改好的完整代码打印出来
当然!下面是你修改过后的完整代码,请注意我添加的注释:
using System;
using System.IO.Ports;
using System.Windows.Forms;
namespace SerialPortApp
{
public partial class Form1 : Form
{
// 创建一个SerialPort对象
private SerialPort serialPort;
public Form1()
{
InitializeComponent();
// 实例化SerialPort对象
serialPort = new SerialPort();
// 将可用串口添加到comboBox1中
string[] ports = SerialPort.GetPortNames();
comboBox1.Items.AddRange(ports);
}
private void button1_Click(object sender, EventArgs e)
{
try
{
// 检查串口选择是否为空
if (comboBox1.SelectedItem == null)
{
MessageBox.Show("请选择串口!");
return;
}
// 配置串口参数
serialPort.PortName = comboBox1.SelectedItem.ToString();
serialPort.BaudRate = 9600; // 波特率设置为9600bps
serialPort.DataBits = 8; // 数据位设置为8位
serialPort.StopBits = StopBits.One; // 停止位设置为1位停止位
serialPort.Parity = Parity.None; // 校验位设置为无校验
// 打开串口
serialPort.Open();
MessageBox.Show("串口已打开!");
// 向串口发送数据
string sendData = "Hello, Serial!";
serialPort.Write(sendData);
// 从串口接收数据
string recvData = serialPort.ReadExisting();
MessageBox.Show("接收到的数据:" + recvData);
}
catch (Exception ex)
{
MessageBox.Show("发生错误:" + ex.Message);
}
finally
{
// 关闭串口
if (serialPort.IsOpen)
{
serialPort.Close();
MessageBox.Show("串口已关闭!");
}
}
}
}
}
希望这次的代码能够正常运行,并且满足你的需求!如果还有其他问题,请随时提问。
以上回复来自 FishC AI 小助理,如未能正确解答您的问题,请继续追问。 @FishC 我想用C#写一个上位机软件。
功能:打开软件,comBox1能够自动获取可用的串口端口。点击button1,打开串口;再点击button1,关闭串口。 XYZ_XYZ 发表于 2024-03-06 23:18
@FishC 我想用C#写一个上位机软件。
功能:打开软件 ...
当然可以!我们来一步步实现这个功能。
首先,你需要在界面上添加一个ComboBox控件(comBox1)和两个Button控件(button1和button2),并给button1设置初始文本为"打开串口"。然后,在Form的Load事件中,我们需要使comBox1能够自动获取可用的串口端口。
using System.IO.Ports;
// Form的Load事件
private void Form1_Load(object sender, EventArgs e)
{
string[] ports = SerialPort.GetPortNames(); // 获取所有可用的串口端口
comBox1.Items.AddRange(ports); // 将可用的端口添加到comBox1中
}
接下来,我们需要在button1的Click事件中实现打开和关闭串口的功能。我们需要创建一个SerialPort对象,并判断当前串口的状态来执行相应的操作。
SerialPort serialPort;
// button1的Click事件
private void button1_Click(object sender, EventArgs e)
{
if (serialPort == null)
{
// 如果serialPort为空,则表示串口未打开,需要打开串口
string portName = comBox1.SelectedItem.ToString(); // 获取选中的串口端口
serialPort = new SerialPort(portName, 9600, Parity.None, 8, StopBits.One); // 创建串口对象
try
{
serialPort.Open(); // 打开串口
button1.Text = "关闭串口"; // 修改button1的文本为"关闭串口"
}
catch (Exception ex)
{
// 打开串口失败,显示错误信息
MessageBox.Show("打开串口失败:" + ex.Message);
serialPort = null; // 将serialPort设置为空
}
}
else
{
// 如果serialPort不为空,则表示串口已经打开,需要关闭串口
serialPort.Close(); // 关闭串口
serialPort.Dispose(); // 释放串口资源
serialPort = null; // 将serialPort设置为空
button1.Text = "打开串口"; // 修改button1的文本为"打开串口"
}
}
至此,我们完成了上位机软件的基本功能。用户可以选择需要连接的串口端口,并通过点击button1来打开或关闭串口。希望对你有所帮助!
以上回复来自 FishC AI 小助理,如未能正确解答您的问题,请继续追问。 FishC 发表于 2024-3-6 23:18
当然可以!我们来一步步实现这个功能。
首先,你需要在界面上添加一个ComboBox控件(comBox1)和两个B ...
我还要实现,下拉comBox1,能够显示出可用的串口 XYZ_XYZ 发表于 2024-03-06 23:36
我还要实现,下拉comBox1,能够显示出可用的串口
很好,我们可以在下拉comBox1的时候动态获取可用的串口,并将它们显示在下拉列表中。请按照以下步骤进行修改:1. 在Form的Load事件中,添加一个事件处理程序来处理串口状态更改事件。using System.IO.Ports;// Form的Load事件private void Form1_Load(object sender, EventArgs e){ string[] ports = SerialPort.GetPortNames(); // 获取所有可用的串口端口 comBox1.Items.AddRange(ports); // 将可用的端口添加到comBox1中 // 串口状态更改事件处理程序 SerialPort.SerialPinChangedEventHandler pinChangedHandler = new SerialPort.SerialPinChangedEventHandler(SerialPort_PinChanged); SerialPort.DataReceivedEventHandler dataReceivedHandler = new SerialPort.DataReceivedEventHandler(SerialPort_DataReceived); foreach (string portName in ports) { SerialPort serialPort = new SerialPort(portName); serialPort.PinChanged += pinChangedHandler; serialPort.DataReceived += dataReceivedHandler; serialPort.Open(); serialPort.Close(); }}2. 添加两个事件处理程序,分别用于处理串口状态更改事件和接收到数据事件。// 处理串口状态更改事件private void SerialPort_PinChanged(object sender, SerialPinChangedEventArgs e){ SerialPort serialPort = (SerialPort)sender; // 如果串口打开,则重新获取可用的串口端口 if (serialPort.IsOpen) { string[] ports = SerialPort.GetPortNames(); comBox1.Items.Clear(); comBox1.Items.AddRange(ports); }}// 处理接收到数据事件private void SerialPort_DataReceived(object sender, SerialDataReceivedEventArgs e){ // 在这里处理接收到的数据}3. 在Form的Activated事件中,添加一个事件处理程序来处理串口状态更改事件。这是为了在程序已经打开的情况下,当用户切换回上位机软件时能够刷新可用的串口列表。private void Form1_Activated(object sender, EventArgs e){ comBox1.DroppedDown = true;}现在,当程序加载时会获取可用的串口并显示在下拉comBox1中。当串口状态发生更改时,会自动更新可用的串口列表。同时,当用户切换回上位机软件时,也会自动刷新可用的串口列表。希望对你有所帮助!
以上回复来自 FishC AI 小助理,如未能正确解答您的问题,请继续追问。 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.IO.Ports;
using System.Windows.Forms;
using static System.Windows.Forms.VisualStyles.VisualStyleElement;
namespace 串口数据显示
{
public partial class Form1 : Form
{
private SerialPort serialPort = null;
private bool isSerialPortOpen = false;
public Form1()
{
InitializeComponent();
this.comboBox1.DropDown += new System.EventHandler(this.comboBox1_DropDown);
this.button1.Click += new System.EventHandler(this.button1_Click);
this.button2.Click += new System.EventHandler(this.button2_Click);
this.FormClosing += new System.Windows.Forms.FormClosingEventHandler(this.Form1_FormClosing);
}
private void comboBox1_DropDown(object sender, EventArgs e)
{
string[] ports = SerialPort.GetPortNames();
comboBox1.Items.Clear();
foreach (string port in ports)
{
comboBox1.Items.Add(port);
}
if (comboBox1.Items.Count > 0)
{
comboBox1.SelectedIndex = 0;
}
}
private void button1_Click(object sender, EventArgs e)
{
if (isSerialPortOpen)
{
// 如果串口已打开,则关闭串口
if (serialPort != null && serialPort.IsOpen)
{
serialPort.Close();
serialPort.Dispose();
}
isSerialPortOpen = false;
button1.Text = "打开";
}
else
{
// 如果串口未打开,则打开串口
try
{
if (serialPort == null)
{
serialPort = new SerialPort();
}
if (!serialPort.IsOpen && comboBox1.SelectedItem != null)
{
serialPort.PortName = comboBox1.SelectedItem.ToString();
serialPort.BaudRate = 115200;
serialPort.Parity = Parity.None;
serialPort.StopBits = StopBits.One;
serialPort.DataBits = 8;
serialPort.Handshake = Handshake.None;
serialPort.DataReceived += new SerialDataReceivedEventHandler(DataReceivedHandler);
serialPort.Open();
isSerialPortOpen = true;
button1.Text = "关闭";
}
else
{
MessageBox.Show("请选择一个串口或串口已经打开");
}
}
catch (Exception ex)
{
MessageBox.Show("打开串口时出错: " + ex.Message);
if (serialPort != null)
{
serialPort.Close();
serialPort.Dispose();
}
}
}
}
private void Form1_FormClosing(object sender, FormClosingEventArgs e)
{
if (serialPort != null && serialPort.IsOpen)
{
serialPort.Close();
serialPort.Dispose();
}
}
private void button3_Click(object sender, EventArgs e)
{
textBox1.Clear();
textBox2.Clear();
textBox3.Clear();
textBox4.Clear();
textBox5.Clear();
}
private void button4_Click(object sender, EventArgs e)
{
if (isSerialPortOpen)
{
try
{
// 定义要发送的16进制数据
byte[] sendData = { 0xFF, 0x99, 0x01, 0x00, 0x9A, 0xFE };
// 将发送的字节数组转换为字符串,方便显示在textBox1中
string sendStr = BitConverter.ToString(sendData).Replace("-", " ");
// 在textBox1中显示发送的数据
textBox1.AppendText("发送数据: " + sendStr + "\r\n");
// 通过串口发送数据
serialPort.Write(sendData, 0, sendData.Length);
}
catch (Exception ex)
{
// 显示发送数据时发生的错误
MessageBox.Show("发送数据时出错: " + ex.Message);
}
}
else
{
// 如果串口未打开,则提示用户先打开串口
MessageBox.Show("请先打开串口");
}
}
private void button5_Click(object sender, EventArgs e)
{
if (isSerialPortOpen)
{
try
{
// 定义要发送的16进制数据
byte[] sendData = { 0xFF, 0x33, 0x01, 0x00, 0x34, 0xFE };
// 将发送的字节数组转换为字符串,方便显示在textBox1中
string sendStr = BitConverter.ToString(sendData).Replace("-", " ");
// 在textBox1中显示发送的数据
textBox1.AppendText("发送数据: " + sendStr + "\r\n");
// 通过串口发送数据
serialPort.Write(sendData, 0, sendData.Length);
}
catch (Exception ex)
{
// 显示发送数据时发生的错误
MessageBox.Show("发送数据时出错: " + ex.Message);
}
}
else
{
// 如果串口未打开,则提示用户先打开串口
MessageBox.Show("请先打开串口");
}
}
private void button6_Click(object sender, EventArgs e)
{
if (isSerialPortOpen)
{
try
{
// 定义要发送的16进制数据
byte[] sendData = { 0xFF, 0x99, 0x02, 0x00, 0x9B, 0xFE };
// 将发送的字节数组转换为字符串,方便显示在textBox1中
string sendStr = BitConverter.ToString(sendData).Replace("-", " ");
// 在textBox1中显示发送的数据
textBox1.AppendText("发送数据: " + sendStr + "\r\n");
// 通过串口发送数据
serialPort.Write(sendData, 0, sendData.Length);
}
catch (Exception ex)
{
// 显示发送数据时发生的错误
MessageBox.Show("发送数据时出错: " + ex.Message);
}
}
else
{
// 如果串口未打开,则提示用户先打开串口
MessageBox.Show("请先打开串口");
}
}
private void button7_Click(object sender, EventArgs e)
{
if (isSerialPortOpen)
{
try
{
// 定义要发送的16进制数据
byte[] sendData = { 0xFF, 0x33, 0x02, 0x00, 0x35, 0xFE };
// 将发送的字节数组转换为字符串,方便显示在textBox1中
string sendStr = BitConverter.ToString(sendData).Replace("-", " ");
// 在textBox1中显示发送的数据
textBox1.AppendText("发送数据: " + sendStr + "\r\n");
// 通过串口发送数据
serialPort.Write(sendData, 0, sendData.Length);
}
catch (Exception ex)
{
// 显示发送数据时发生的错误
MessageBox.Show("发送数据时出错: " + ex.Message);
}
}
else
{
// 如果串口未打开,则提示用户先打开串口
MessageBox.Show("请先打开串口");
}
}
// 定义 DataReceivedHandler 方法
private void DataReceivedHandler(object sender, SerialDataReceivedEventArgs e)
{
SerialPort sp = (SerialPort)sender;
string indata = sp.ReadExisting();
if (indata.StartsWith(""))
{
string[] dataParts = indata.Split(' ');
if (dataParts.Length >= 5)
{
UpdateTextBoxes(dataParts);
}
}
}
// 另一个方法来更新文本框,以避免代码重复
private void UpdateTextBoxes(string[] dataParts)
{
if (textBox2.InvokeRequired)
{
textBox2.Invoke(new MethodInvoker(delegate { textBox2.Text = dataParts; }));
}
else
{
textBox2.Text = dataParts;
}
if (textBox3.InvokeRequired)
{
textBox3.Invoke(new MethodInvoker(delegate { textBox3.Text = dataParts; }));
}
else
{
textBox3.Text = dataParts;
}
if (textBox4.InvokeRequired)
{
textBox4.Invoke(new MethodInvoker(delegate { textBox4.Text = dataParts; }));
}
else
{
textBox4.Text = dataParts;
}
if (textBox5.InvokeRequired)
{
textBox5.Invoke(new MethodInvoker(delegate { textBox5.Text = dataParts; }));
}
else
{
textBox5.Text = dataParts;
}
}
private void button8_Click(object sender, EventArgs e)
{
if (isSerialPortOpen)
{
try
{
// 定义要发送的字符串
string sendStr = "*1 2050 2121 510 004 ";
// 将字符串转换为字节数组
byte[] sendData = Encoding.ASCII.GetBytes(sendStr);
// 添加发送的字符串到 textBox1 中
textBox1.AppendText(sendStr + "\r\n");
// 发送数据到串口
serialPort.Write(sendData, 0, sendData.Length);
}
catch (Exception ex)
{
MessageBox.Show("发送数据时出错: " + ex.Message);
}
}
else
{
MessageBox.Show("请先打开串口");
}
}
private void button2_Click(object sender, EventArgs e)
{
if (isSerialPortOpen)
{
try
{
// 定义要发送的字符串
string sendStr = "*1 2048 3000 525 400";
// 将字符串转换为字节数组
byte[] sendData = Encoding.ASCII.GetBytes(sendStr);
// 添加发送的字符串到 textBox1 中
textBox1.AppendText(sendStr + "\r\n");
// 发送数据到串口
serialPort.Write(sendData, 0, sendData.Length);
}
catch (Exception ex)
{
MessageBox.Show("发送数据时出错: " + ex.Message);
}
}
else
{
MessageBox.Show("请先打开串口");
}
}
}
}
@FishC 我串口发送数据的时候,我的DataReceivedHandler函数,并没有触发到。请帮我检查一下代码不合理的地方。 XYZ_XYZ 发表于 2024-03-08 23:47
using System;
using System.Collections.Generic;
...
在您的代码中,将DataReceivedHandler方法与DataReceived事件绑定的部分有问题。在您的button1_Click方法中,您应该添加以下代码:
serialPort.DataReceived += new SerialDataReceivedEventHandler(DataReceivedHandler);
这样,当串口接收到数据时,DataReceived事件将触发DataReceivedHandler方法。
另外,在DataReceivedHandler方法中,您使用ReadExisting方法来获取接收到的数据。但是,ReadExisting方法将返回缓冲区中所有的字节,并且不保证接收到的数据长度为您期望的格式。建议您使用ReadLine或ReadTo方法来读取特定的结束字符或字符串,以确保接收到完整的数据。
下面是您修改后的代码:
using System;
using System.IO.Ports;
using System.Windows.Forms;
namespace 串口数据显示
{
public partial class Form1 : Form
{
private SerialPort serialPort = null;
private bool isSerialPortOpen = false;
public Form1()
{
InitializeComponent();
this.comboBox1.DropDown += new EventHandler(this.comboBox1_DropDown);
this.button1.Click += new EventHandler(this.button1_Click);
this.FormClosing += new FormClosingEventHandler(this.Form1_FormClosing);
this.serialPort = new SerialPort();
this.serialPort.DataReceived += new SerialDataReceivedEventHandler(DataReceivedHandler);
}
private void comboBox1_DropDown(object sender, EventArgs e)
{
string[] ports = SerialPort.GetPortNames();
comboBox1.Items.Clear();
foreach (string port in ports)
{
comboBox1.Items.Add(port);
}
if (comboBox1.Items.Count > 0)
{
comboBox1.SelectedIndex = 0;
}
}
private void button1_Click(object sender, EventArgs e)
{
if (isSerialPortOpen)
{
// 如果串口已打开,则关闭串口
if (serialPort != null && serialPort.IsOpen)
{
serialPort.Close();
serialPort.Dispose();
}
isSerialPortOpen = false;
button1.Text = "打开";
}
else
{
// 如果串口未打开,则打开串口
try
{
if (!serialPort.IsOpen && comboBox1.SelectedItem != null)
{
serialPort.PortName = comboBox1.SelectedItem.ToString();
serialPort.BaudRate = 115200;
serialPort.Parity = Parity.None;
serialPort.StopBits = StopBits.One;
serialPort.DataBits = 8;
serialPort.Handshake = Handshake.None;
serialPort.Open();
isSerialPortOpen = true;
button1.Text = "关闭";
}
else
{
MessageBox.Show("请选择一个串口或串口已经打开");
}
}
catch (Exception ex)
{
MessageBox.Show("打开串口时出错: " + ex.Message);
if (serialPort != null)
{
serialPort.Close();
serialPort.Dispose();
}
}
}
}
private void Form1_FormClosing(object sender, FormClosingEventArgs e)
{
if (serialPort != null && serialPort.IsOpen)
{
serialPort.Close();
serialPort.Dispose();
}
}
// 定义 DataReceivedHandler 方法
private void DataReceivedHandler(object sender, SerialDataReceivedEventArgs e)
{
SerialPort sp = (SerialPort)sender;
string indata = sp.ReadLine();
// 处理接收到的数据
if (indata.StartsWith(""))
{
string[] dataParts = indata.Split(' ');
if (dataParts.Length >= 5)
{
UpdateTextBoxes(dataParts);
}
}
}
// 另一个方法来更新文本框,以避免代码重复
private void UpdateTextBoxes(string[] dataParts)
{
if (textBox2.InvokeRequired)
{
textBox2.Invoke(new MethodInvoker(delegate { textBox2.Text = dataParts; }));
}
else
{
textBox2.Text = dataParts;
}
if (textBox3.InvokeRequired)
{
textBox3.Invoke(new MethodInvoker(delegate { textBox3.Text = dataParts; }));
}
else
{
textBox3.Text = dataParts;
}
if (textBox4.InvokeRequired)
{
textBox4.Invoke(new MethodInvoker(delegate { textBox4.Text = dataParts; }));
}
else
{
textBox4.Text = dataParts;
}
if (textBox5.InvokeRequired)
{
textBox5.Invoke(new MethodInvoker(delegate { textBox5.Text = dataParts; }));
}
else
{
textBox5.Text = dataParts;
}
}
// 其他按钮事件处理方法...
}
}
希望这可以解决您的问题!如果还有其他问题,请随时提问。
以上回复来自 FishC AI 小助理,如未能正确解答您的问题,请继续追问。 #include "mainwindow.h"
#include "ui_mainwindow.h"
#include "lusb0_usb.h"
#define m_dev_VENDOR 0xC251 /* Vendor ID of the m_dev */
#define m_dev_PRODUCT 0x3505 /* Product ID of the m_dev */
#define m_dev_DATA_SIZE 10240 /* Number of bytes to get at once */
char RecTraData = {0};
struct usb_bus *bus;
struct usb_device * m_dev = NULL;
struct usb_dev_handle *m_dev_handle;
int OpenUSB(void)
{
int ret;
QString str;
/* 第1步:USB 初始化 */
usb_init();
/* 第2步:寻找系统上的usb总线,任何usb设备都通过usb总线和计算机总线通信。进而和其他设备通信。此函数返回总线数 */
ret = usb_find_busses();
if(ret < 0)
{
qDebug("usb_find_busses失败 \n") ;
}
/* 第3步:寻找总线上的usb设备,这个函数必要在调用usb_find_busses()后使用。以上的三个函数都是一开始就要用到的,此函数返回设备数量 */
ret = usb_find_devices();
if(ret < 0)
{
str = str.asprintf("寻找USB设备失败:%d", ret);
qDebug() << str;
return -1;
}
else
{
/* 成功 */
str = str.asprintf("寻找USB设备成功:%d", ret);
qDebug() << str;
}
/*第4步:这个函数返回总线的列表,在高一些的版本中已经用不到了 */
for(bus = usb_get_busses(); bus; bus = bus->next)
{
struct usb_device *dev;
for(dev = bus->devices; dev; dev = dev->next)
{
if(dev->descriptor.idVendor == m_dev_VENDOR && dev->descriptor.idProduct == m_dev_PRODUCT)
m_dev=dev;
}
}
if(!m_dev)
{
str = str.asprintf("设备查找失败:%d", -2);
qDebug() << str;
return -2;
}
/*第5步:
打开要使用的设备,在对硬件进行操作前必须要调用usb_open 来打开设备,这里大家看到有两个结构体
usb_dev_handle 和 usb_device 是我们在开发中经常碰到的,有必要把它们的结构看一看。在libusb 中
的usb.h和usbi.h中有定义。
这里我们不妨理解为返回的 usb_dev_handle 指针是指向设备的句柄,而行参里输入就是需要打开的设备。
*/
m_dev_handle = usb_open(m_dev);
if(!m_dev_handle)
{
str = str.asprintf("设备打开失败:%d", -3);
qDebug() << str;
return -3;
}
/*第6步:
设置当前设备使用的configuration,参数configuration 是你要使用的configurtation descriptoes中的
bConfigurationValue, 返回0成功,<0失败( 一个设备可能包含多个configuration,比如同时支持高速和
低速的设备就有对应的两个configuration,详细可查看usb标准)
*/
if(usb_set_configuration(m_dev_handle, 1) < 0)
{
qDebug() << "config失败" ;
return -4;
}
/*
第7步:
注册与操作系统通信的接口,这个函数必须被调用,因为只有注册接口,才能做相应的操作。
Interface 指 bInterfaceNumber. (usb_release_interface 与之相对应,也是必须调用的函数)
*/
if(usb_claim_interface(m_dev_handle, 0) < 0) //claim_interface 0指向第一个设备
{
qDebug() << "Interface失败" ;
return -5;
}
return 1;
}
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
// 动态填充 comboBox_DZXG
for (int i = 0; i <= 255; ++i) {
ui->comboBox_DZXG->addItem(QString::number(i));
}
// 动态填充 comboBox_DZ
for (int i = 0; i <= 255; ++i) {
ui->comboBox_DZ->addItem(QString::number(i));
}
// 动态填充 comboBox_TD
for (int i = 1; i <= 12; ++i) {
ui->comboBox_TD->addItem(QString::number(i));
}
// 动态填充 comboBox_SJ
for (int i = 0; i <= 15; ++i) {
ui->comboBox_SJ->addItem(QString::number(i));
}
// 连接 pushButton_SJ 的 clicked() 信号到槽函数
connect(ui->pushButton_SJ, &QPushButton::clicked, this, &MainWindow::onPushButtonSJClicked);
// 动态填充 comboBox_DZ_all
for (int i = 0; i <= 255; ++i) {
ui->comboBox_DZ_all->addItem(QString::number(i));
}
// 为每个通道的衰减comboBox动态添加值
for (int channel = 1; channel <= 12; ++channel) {
QString comboBoxName = QString("comboBox_SJ_TD_%1").arg(channel);
QComboBox *comboBox = this->findChild<QComboBox *>(comboBoxName);
if (comboBox) {
// 清除现有项(如果有的话)
comboBox->clear();
// 添加新的十六进制值
for (int value = 0; value <= 15; ++value) {
comboBox->addItem(QString::number(value)); // 直接添加十进制数字
}
} else {
// 如果没有找到组合框,可以打印一个错误或警告
qDebug() << "ComboBox" << comboBoxName << "not found";
}
}
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::onPushButtonSJClicked()
{
// 假设你已经有了以下变量,它们代表了组合包所需的各个部分
QString dzHex = QString::number(ui->comboBox_DZ->currentIndex(), 16).toUpper().rightJustified(2, '0'); // 地址
QString tdHex = QString::number(ui->comboBox_TD->currentIndex() + 1, 16).toUpper().rightJustified(2, '0'); // 通道
QString sjHex = QString::number(ui->comboBox_SJ->currentIndex(), 16).toUpper().rightJustified(2, '0'); // 衰减值
// 构建HEX包(不包括校验和)
QByteArray hexPacket;
// 帧头1: 5A
hexPacket.append(static_cast<char>(0x5A));
// 帧头2: A5
hexPacket.append(static_cast<char>(0xA5));
// 命令分类: FD
hexPacket.append(static_cast<char>(0xFD));
// 地址: dzHex
hexPacket.append(QByteArray::fromHex(dzHex.toLatin1()));
// 通道: tdHex
hexPacket.append(QByteArray::fromHex(tdHex.toLatin1()));
// 衰减值: sjHex
hexPacket.append(QByteArray::fromHex(sjHex.toLatin1()));
// 计算校验和: 通常是对除了帧头和校验和之外的所有字节进行求和,然后取低8位
quint8 checksum = 0;
for (int i = 2; i < hexPacket.size(); ++i) { // 跳过帧头(索引0和1)
checksum += static_cast<quint8>(hexPacket.at(i));
}
checksum &= 0xFF; // 取低8位
// 添加校验和到HEX包
hexPacket.append(static_cast<char>(checksum));
// // 获取hexPacket的指针和大小
// const char* dataPtr = hexPacket.constData();
// int dataSize = hexPacket.size();
// 打印HEX包(用于调试)
qDebug() << "HEX Packet:" << hexPacket.toHex().toUpper();
}
void MainWindow::on_pushButton_SJ_all_clicked()
{
// 获取地址值
int address = ui->comboBox_DZ_all->currentIndex(); // 假设这里返回的是地址的索引值,你可能需要转换它
// 转换为十六进制字符串,假设地址是单个字节
QString dzHex = QString::number(address, 16).toUpper().rightJustified(2, '0');
// 初始化HEX包
QByteArray hexPacket;
// 添加帧头
hexPacket.append(static_cast<char>(0x5A)); // 帧头1: 5A
hexPacket.append(static_cast<char>(0xA5)); // 帧头2: A5
// 添加命令分类
hexPacket.append(static_cast<char>(0xFC)); // 命令分类: FC
// 添加地址
hexPacket.append(QByteArray::fromHex(dzHex.toLatin1()));
// 添加通道衰减值
for (int i = 1; i <= 12; ++i) {
QString comboBoxName = QString("comboBox_SJ_TD_%1").arg(i);
QComboBox *comboBox = findChild<QComboBox *>(comboBoxName);
if (comboBox) {
int attenuation = comboBox->currentIndex(); // 假设这里返回的是衰减值的索引值
QString attenuationHex = QString::number(attenuation, 16).toUpper().rightJustified(2, '0');
hexPacket.append(QByteArray::fromHex(attenuationHex.toLatin1()));
}
}
// 计算校验和
quint8 checksum = 0;
for (int i = 2; i < hexPacket.size(); ++i) { // 从命令分类开始计算
checksum += static_cast<quint8>(hexPacket.at(i));
}
checksum &= 0xFF; // 取低8位
// 添加校验和
hexPacket.append(static_cast<char>(checksum));
// 打印HEX包(用于调试)
qDebug() << "HEX Packet:" << hexPacket.toHex().toUpper();
}
void MainWindow::on_pushButton_openUSB_clicked()
{
// QString debugstr;
int usbstatus;
// char str;
if (UsbOpenFlag == 0)//如果USB没打开
{
/* 打开USB连接 */
usbstatus = OpenUSB();
if (usbstatus == -1)
{
ui->label_stateUSB->setText("USB开关状态:寻找USB设备失败");
}
else if (usbstatus == -2)
{
ui->label_stateUSB->setText("USB开关状态:设备查找失败,VID和PID不匹配");
}
else if (usbstatus == -3)
{
ui->label_stateUSB->setText("USB开关状态:设备打开失败");
}
else if (usbstatus == -4)
{
ui->label_stateUSB->setText("USB开关状态:设备打开失败4");
}
else if (usbstatus == -5)
{
ui->label_stateUSB->setText("USB开关状态:设备打开失败5");
}
else
{
/* 打开成功 */
UsbOpenFlag = 1;
ui->label_stateUSB->setText("USB开关状态:设备打开成功");
ui->pushButton_openUSB->setText("关闭USB");
}
}
else
{
UsbOpenFlag = 0;
DataSampleStart = 0;
usb_release_interface(m_dev_handle, 0);
//usb_reset(m_dev_handle);
usb_close(m_dev_handle);
ui->label_stateUSB->setText("USB开关状态:关闭");
ui->pushButton_openUSB->setText("打开USB");
}
}
@FishC 以上是我用QT写的上位机,它现在的问题是,当我关闭USB设备后重新打开,ret = usb_find_devices();ret得到的数是0
XYZ_XYZ 发表于 2024-06-11 15:38
#include "mainwindow.h"
#include "ui_mainwindow.h ...
你好!根据你提供的代码,我发现在重新打开USB设备之前,并没有调用`usb_release_interface`和`usb_close`来释放之前打开的设备资源。这可能导致在重新打开设备时出现问题。
你可以在关闭USB设备之前添加以下代码来释放资源:
if (m_dev_handle) {
usb_release_interface(m_dev_handle, 0);
usb_close(m_dev_handle);
m_dev_handle = NULL;
}
这样,在重新打开设备时就能够正确地找到设备了。
另外,你还可以尝试在重新打开设备之前先调用`usb_reset`函数来复位USB设备:
usb_reset(m_dev_handle);
这样做有助于确保设备处于可用状态,并且可以避免一些潜在的通信问题。
更正以上的问题后,你的代码应该可以正常打开和关闭USB设备了。希望对你有帮助!如果还有其他问题,请随时提问。
以上回复来自 FishC AI 小助理,如未能正确解答您的问题,请继续追问。 我记得用python写很方便来着,哦说错了,好像是labview,b站有别人写好的,可以直接拿来用
页:
1
[2]