\begingroup

我目前正在尝试使用 arduino 通过 SP3078EEN RS485 收发器发送 RS485。我让 arduino 代码将 DE 引脚设置为高电平,等待 1 毫秒,然后将数据缓冲区写入并刷新到连接到收发器 DI 引脚的串行。之后,它将 DE 引脚再次设置为低电平。除了我的示波器和 PC 读取数据后,我得到了一个额外的 0x00 字节(通过 RS485 到 USB 转换器测量)之外,这几乎全部按预期工作。

下面是我代码的重要部分以及 Di(驱动器输入)、A(RS485 正输出)和 DE(驱动器启用)的示波器测量值。我还提供了电路的简化示意图。我能看到的唯一可能导致这种情况的原因是当我将 DE 从高切换到低时,“A”信号上似乎发生了电容放电。我不知道为什么会发生这种情况或如何解决它。我试过在 RO、RE 和 DI 上放置上拉/下拉电阻,但没有成功。我还尝试增加预写延迟并添加后写延迟,但同样无济于事。

如果有人能帮助我解决这个问题我将不胜感激。

示波器

代码:

void setup() {
    Serial0.begin(19200, SERIAL_8E1);
    Serial1.begin(19200, SERIAL_8E1);
}

void loop() {

    // Setting the buffer to a static value for debugging purposes
    byte buffer1 = { 0x01, 0x03, 0x00, 0x00, 0x00, 0x04, 0x44, 0x09 };

    // Set the DE_1 pin high to enable writing to the RS485 bus
    digitalWriteFast(DE_1_PIN, HIGH);

    delay(1);

    // Write the buffer to the RS485 bus
    Serial1.write(buffer1, 8); 
    Serial1.flush();
    
    // Disable writing
    digitalWriteFast(DE_1_PIN, LOW);

    delay(1000);
}


超级简化的原理图

\endgroup

5

  • \begingroup
    哎呀,抱歉,我复制代码和拍摄示波器图像时似乎更改了缓冲区。请放心,我根据代码获得了所有正确的值,除了末尾的额外 0x00。我已编辑问题以反映正确的值。
    \endgroup


    – 

  • 1
    \begingroup
    我们公司也遇到过同样的问题,结果(正如 Tom 在他的回答中所写)是芯片的故障安全偏置无法正常工作。虽然从未真正理解为什么它不起作用。但我们采取了安全措施,并加入了外部故障安全偏置,从而解决了问题。我建议查看以下资源:
    \endgroup


    – 

  • \begingroup
    感谢@LarsPetersson 提供的资源!
    \endgroup


    – 

  • \begingroup
    为什么在禁用 DE 之前要刷新缓冲区?
    \endgroup


    – 

  • \begingroup
    @MrGerber 参考 Arduino 网站,等待传出的串行数据传输完成。写入将在此之前返回,因为它是异步的并立即返回,并且数据缓冲区传输使用中断在后台进行。
    \endgroup


    – 


最佳答案
2

\begingroup

ATTiny 不会发送额外的 0x0。而是由于 RS485 总线显然处于低空闲状态,而不是高空闲状态。

因此,当 DE 引脚变为低电平时,它会导致总线从高电平变为低电平,这被视为起始位。然后您将解码一个 NULL (0x0) 值,但由于缺少停止位,因此会出现帧错误。

根据 SP3078E 数据表,它应该具有故障安全偏置,这样当不驱动时,接收器会处于高空转状态。我不确定为什么没有发生这种情况。也许您有另一个连接了反极性(AB 交换)的设备?或者示波器探头提供了足够的负载来克服偏置(探测 B 引脚有帮助吗)?

您可以尝试添加自己的故障安全偏置。它由一对 kOhm 大小的电阻器(例如 2.2kOhm 或 4.7kOhm)组成,一个将 B 线拉至 +5V,另一个将 A 线拉至 GND。结合 120R 终端,这将在 AB 之间产生约 ~65-130mV,当总线浮动时,应该可以轻松地将其检测为“1”。

\endgroup

4

  • \begingroup
    非常感谢!我不确定为什么芯片的故障保护功能无法按预期工作,但我在 A 和 +5V 之间以及 B 和 GND 之间添加了一个 4.7k 偏置电阻,这已经起作用了!我身上没有 2.2k 电阻,但我会尽快尝试使用它们。这肯定是问题所在,现在我通过添加偏置使其工作正常。
    \endgroup


    – 

  • \begingroup
    @PatrickVoorhoeve 4.7k 就可以了,如果我没记错的话,上次我遇到这个问题的时候,有 2.2k 是闲置的。
    \endgroup


    – 

  • \begingroup
    我不相信这种故障保护。当 MCU 正在(重新)启动时,在 RO 引脚上安装外部上拉电阻几乎是标准做法。那么你就不需要在总线另一侧安装上拉电阻了。
    \endgroup


    – 


  • \begingroup
    @Lundin 解释说,问题并不在于 ATTiny 接收到了额外的空字符,因此 RO 上拉不会产生影响(他试过了)。他有一个 USB-RS485 适配器,它正在接收额外的 NULL 字符,示波器解码也是如此。这是因为当 DE 引脚变为低电平时,RS-485 总线会浮动到 GND,而不是保持正确(故障安全!)偏置。因此,每个连接的设备都将开始接收额外的数据包,因为线路已经移动到触发起始位的点。
    \endgroup


    – 


\begingroup

除了 Tom 的回答之外,在软件方面,您必须绝对处理溢出错误 – 这对于每个 UART 驱动程序都是强制性的。溢出意味着在 MCU 清除之前的 Rx 标志之前接收到数据,帧意味着传入数据不符合标准帧格式(由于 EMI、错误的波特率、坏时钟等)。

缺乏错误处理似乎是问题的根源:您似乎依赖于某个不执行错误处理或未被告知执行错误处理的库。

至少在 RX 过程中清除这些标志,并在出现数据时丢弃它们。否则,最终结果将变成“脆弱软件”,只要有人在串行电缆附近打喷嚏,它就会停止工作……

\endgroup