让多个线程轮询同一串行端口的正确方法是什么



我对与硬件交互非常陌生。我目前正在使用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编辑的更新

我建议以下两种方法之一来处理您设备中的通信:

  1. 实现一个请求/响应机制,用于向通过串行端口到您的设备的特定数据值(例如当前值),设备解析该请求并返回相应的值
  2. 让您的设备返回"帧"中的所有值,例如。[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"发送数据(以字符串形式发送)

  • 在计算机中接收数据:

    1. 检测封装中的SOH和ETX
    2. 验证BCC为true(已完成的包)或false(已损坏的包)
    3. 使用解析数据;作为分隔符//data1=01:20 data2=02:0E03
    4. 分析数据1和数据2时使用:作为分隔符//data1=20 data2=0E03
    5. 将十六进制转换为十进制,并将data2除以10以获得浮点格式的当前值

最新更新