【问题标题】:Serial Message Separation串行消息分离
【发布时间】:2025-12-04 11:35:01
【问题描述】:

我正在尝试在微控制器和 c# windows 应用程序之间实现串行通信。

我在计算机到微控制器的方向上一切正常。但是我很难弄清楚如何在另一个方向上实现通信。

我的消息由 4 个字节组成

  • B0 – 正在发送的值的地址/名称
  • B1 – 高字节
  • B2 – 低字节
  • B3 – 校验和 = 字节 0-2 相加

为了确保接收到完整的消息,如果字节之间的时间超过 20 毫秒,我让微控制器放弃正在接收的当前消息,这似乎运行良好,并且可以容忍可能导致丢失的通信故障同步。

我不确定如何在 c# 应用程序中实现这种延迟,因为我知道您对时间的精细控制要少得多。

我已经看到其他发送开始和停止字符的 ASCII 协议,但我不确定在发送二进制数据时如何实现这一点,其中我的值可以采用字节中可能的任何值,并且可能恰好是开始或停止字符是。

由于资源有限,我需要保持微控制器方面的基本功能,并且控制器的主要任务需要非常精确(低于我们的范围),将 ascii 转换为十进制可能具有。

是否有人对我应该如何从微处理器或计算机端实现这一点提出建议。

编辑
我已经查看了这里的其他一些问题,但它们似乎都指的是更大的基于 ASCII 的消息。

【问题讨论】:

  • 不管怎样,我使用过的协议大多指定了开始/结束消息标记,通常是字节值 2 和 3,然后使用转义算法来表示实际数据值数据中的 3(结束标记)(有时称为 DLE 编码。

标签: c# synchronization serial-port communication microcontroller


【解决方案1】:

这是一个非常糟糕的主意。它假设电线另一端的机器能够提供相同的保证。在微控制器上,20 毫秒完全没有问题。一台启动 Linux 或 Windows 的机器,没办法。忙于写入串行端口的线程很容易丢失处理器数百毫秒。 C# 中的垃圾回收。

只是不要针对特殊情况进行优化,没有意义。超时应该在 second 范围内,比您预期的最坏情况大十倍。通过构建协议使协议更加可靠。总是一个开始字节,让接收器有机会重新同步。还不如包括一个长度字节,你迟早会需要它。优先使用 CRC 而不是校验和。查看 RFC916 以获取可恢复的协议建议,尽管被广泛忽略。我使用它时效果很好,虽然它需要额外的工作才能使连接尝试可靠,但您必须刷新接收缓冲区。

【讨论】:

  • 这是一个很好的建议,但有一个问题,.net 内核中的串行端口是否基于 ReadTimeout 和 readByte 功能,因为它只是包装了 win32 API?另外,windows在调度时不是有16ms的分辨率吗(假设他有一个专门的读取线程,只有一个循环)?
  • 是的。当字节在驱动程序的传输缓冲区中时完全没有问题,它被中断处理程序清空。问题是从用户模式程序中获取字节到传输缓冲区。使用这样的协议,程序一次写入一个字节的可能性很大。这不是您可以测试的东西,它发生得太少了。如果你没有办法从协议故障中恢复,那就结束了。
【解决方案2】:

您可以使用以下命令将read timeout 设置为20ms,

serialPort.ReadTimeout = 20;

这会使读取操作在 20ms 后超时,在这种情况下你可以做你想做的。

不要在此超时中使用ReadExisting,因为它不依赖于读取超时,
而是使用Read()readByte() 并检查Timeout Exception

即使写入成功,WriteTimeout 也可以做到同样的事情。所以要小心。

【讨论】: