我对与硬件交互非常陌生。我目前正在使用Windows窗体在C#中构建GUI。我正在使用串行端口/usb与硬件设备进行交互。我试图实现的是让多个线程在不同的时间轮询设备。应定期(至少每秒)检索一些数据,如温度、电流、功率等,并在GUI上更新以供用户查看。而其他数据只有在用户按下表单上的按钮时才会检索到。多线程处理是解决这个问题的正确方法吗?如果没有,还有什么更好的解决方案?举例说明将不胜感激。谢谢你们抽出时间!
更新:我正在尝试使用串行端口。DataReceived事件,正如你们中的许多人所建议的那样,还有一个终止符"\r"来解析串行端口的单个回复。然后我调用一个名为DisplayText的方法来处理这个字符串。我现在的问题是,我不知道如何弄清楚字符串代表什么。它是否代表温度、电流等
private char terminator = 'r';
private void SerialPorts_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
try
{
output += serialPort1.ReadExisting();
if (output.IndexOf((char)this.terminator) > -1)
{
string workingString = output.Substring(0, output.IndexOf(terminator));
output = output.Substring(output.IndexOf(terminator) + 1);
this.Invoke(new EventHandler((s, a)=>DisplayText(s, a, workingString)));
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
private void DisplayText(object sender, EventArgs e, string s)
{
Console.WriteLine(s); // for testing only
richTextBox1.AppendText(s); // for testing only
}
我认为让多个线程轮询单个端口并尝试同步不是一个好主意。
最好有一个线程来进行轮询,并将所有值存储在某个"中间"对象(singleton、静态字段等)中,而不是同步对该存储的访问。
因此,一个线程轮询端口,收集值并将其存储在某个地方,而其他线程则从那里获取值。
您可以使用互斥锁保护所有串行端口访问功能,并以在每次离散操作(例如读取温度)后关闭串行端口的方式设计应用程序。一种可能的方法是编写一个包装器API,它将:
-
检查互斥锁是否已解锁(如果已锁定则返回错误代码),
-
打开串行端口
-
读取所需值
-
关闭串行端口并清除互斥
-
返回读取值
但是,使用此解决方案,您将面临各种死锁,并且必须实施额外的应用程序级别检查来防止这种情况发生。
如上所述,一个更好的解决方案是让单个线程定期轮询串行端口,并不断更新您选择的数据结构中的所有值。
对于只需要在用户输入后读取的值,您必须实现MessageQueue来请求这些数据。
响应OP编辑的更新
我建议以下两种方法之一来处理您设备中的通信:
- 实现一个请求/响应机制,用于向通过串行端口到您的设备的特定数据值(例如当前值),设备解析该请求并返回相应的值
- 让您的设备返回"帧"中的所有值,例如。[SOF][D0…Dn][EOF],其中"D0……Dn"是预定序列;SOF和EOF可以是您选择(您也可以选择完全跳过这些,并依赖用于界定帧的字节数)
如果您不能选择 更改设备中的代码,则设备必须按照某种顺序报告值,因此,保持接收数据的序列号是可行的。但是,如果不了解有关设备功能的更多细节,就很难提出解决方案。
我现在的问题是我不知道如何计算字符串代表。它是否代表温度、电流等
使用简单的协议发送温度、电流等。
SOH+DATA+ETX+BCC-
SOH=0x02;
ETX=0x03;
BCC=0x0-0xFF,将所有DATA+ETX的值异或。
DATA=使用";"作为温度(Temp)和电流(Curr)之间的分隔符
示例:
TempCmd=0x01
温度值=32摄氏度=0x20
CurrCmd=0x02
CurrValue=1.4安培=0x0E->接收器上的结果必须除以10。
SOH+DATA+ETX+BCC-
SOH+TempCmd:TempValue;CurrCmd:CurrValue+ETX+BCC
02+01:20;02:0E+03+BCC
BCC=01 xor':'xor 20 xor';'xor 02 xor':'xor 0E xor 03
-
从微控制器"0201:20;02:0E03;XX"发送数据(以字符串形式发送)
-
在计算机中接收数据:
- 检测封装中的SOH和ETX
- 验证BCC为true(已完成的包)或false(已损坏的包)
- 使用解析数据;作为分隔符//data1=01:20 data2=02:0E03
- 分析数据1和数据2时使用:作为分隔符//data1=20 data2=0E03
- 将十六进制转换为十进制,并将data2除以10以获得浮点格式的当前值