【问题标题】:automatically changing RTS for RS-485 communication自动更改 RS-485 通信的 RTS
【发布时间】:2014-08-11 19:17:43
【问题描述】:

我正在尝试在我的程序中设置半双工通信。我的 RS485 收发器使用 RTS 标志 (TIOCM_RTS) 在发送和接收之间来回切换。要发送/接收数据,我需要手动更改 RTS 标志:

  1. 将 RTS 设置为高。

  2. 发送数据。

  3. 将 RTS 设置为低。

    int setRTS(int level) {
        int status;
        ioctl(ser_port, TIOCMGET, &status);
        if(level) {
            status |= TIOCM_RTS;
        } else {
            status &= ~TIOCM_RTS;
        }
        ioctl(ser_port, TIOCMSET, &status);
        return 1;
    }
    

我的问题是:linux内核不应该能够自动切换RTS吗? 以及如何确保在调用 setRTS(0) 之前发送了数据?

【问题讨论】:

    标签: c linux serial-port rs485


    【解决方案1】:

    linux内核不应该可以自动切换RTS吗?

    是的,从 Linux 3.0 开始就有这样的内核框架。
    include/uapi/asm-generic/ioctls.h中有两个ioctl:

    #define TIOCGRS485      0x542E
    #define TIOCSRS485      0x542F
    

    在 RS-485 模式下检索和配置 tty 串行端口驱动程序。
    这些 ioctl 使用 struct serial_rs485:

     /*
      * Serial interface for controlling RS485 settings on chips with suitable
      * support. Set with TIOCSRS485 and get with TIOCGRS485 if supported by your
      * platform. The set function returns the new state, with any unsupported bits
      * reverted appropriately.
      */
    
     struct serial_rs485 {
             __u32   flags;                  /* RS485 feature flags */
     #define SER_RS485_ENABLED               (1 << 0)        /* If enabled */
     #define SER_RS485_RTS_ON_SEND           (1 << 1)        /* Logical level for
                                                                RTS pin when
                                                                sending */
     #define SER_RS485_RTS_AFTER_SEND        (1 << 2)        /* Logical level for
                                                                RTS pin after sent*/
     #define SER_RS485_RX_DURING_TX          (1 << 4)
             __u32   delay_rts_before_send;  /* Delay before send (milliseconds) */
             __u32   delay_rts_after_send;   /* Delay after send (milliseconds) */
             __u32   padding[5];             /* Memory is cheap, new structs
                                                are a royal PITA .. */
     };
    

    我已在 Atmel 和 Etrax SoC 上使用此 RS-485 功能,但在 Linux UART/USART 驱动程序中这些 ioctl 的实现非常少。
    如果您的驱动程序没有它,那么请考虑自己实现它。您可以使用 drivers/tty/serial/atmel_serial.c 中的实现作为指南。另请阅读Linux kernel document for RS485

    【讨论】:

    • 你明白为什么我需要 delay_rts_before_send 和 delay_rts_after_send 吗?我能看到的唯一原因是始终像 RS422 一样启用发射器。
    • RTS 控制线通常用于启用/禁用 RS485 发射器/线路驱动器。通常在发送之后添加一个短暂的延迟,以确保在发送器关闭之前所有位都在线。
    • 我明白这一点。但是为什么我需要 delay_rts_before_send 和 delay_rts_after_send 呢? OMAP 串行驱动程序仅检查 delay_rts_before_send 并自动反转第二阶段的值。拥有 delay_rts_before_send 和 delay_rts_after_send 让我有机会将两个相位设置为相同的级别,因此不会发生任何变化,即发射器要么一直启用,要么禁用。
    • “但为什么我需要两者...” -- 您似乎在抱怨界面中的功能/灵活性过多。如果您决定在您的情况下不需要延迟,那么只需在配置时分配一个零。见lxr.free-electrons.com/source/Documentation/serial/…延迟将被使用“如果需要”
    • 或者我现在看到,我描述了标志,但复制了变量;-) 我实际上是在抱怨逻辑级别 SER_RS485_RTS_ON_SEND 和 SER_RS485_RTS_AFTER_SEND。对于 RS485 半双工,它们实际上是互斥的。这就是为什么我问,为什么两者兼而有之。所以我看到的唯一目的是 RS422,您总是希望启用发射器并且您不想手动设置 RTS 标志,而是通过 serial_rs485 工具。
    【解决方案2】:

    这确实很棘手 - 要主动执行此操作,您需要知道最后一个字节何时清除 UART 引擎,或者至少何时进入(当缓冲区变空时)并添加根据波特率计算的延迟和字长。这确实值得在串行驱动程序本身中实现,所有这些都是可见的。

    然而,这个问题最常出现在共享总线上您还接收传输的所有内容。如果是这种情况,您可以使用 receiving 结束您自己的传输(假设您及时发现)作为禁用驱动程序的触发器。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-09-01
      • 2019-10-10
      • 1970-01-01
      • 1970-01-01
      • 2017-06-21
      • 1970-01-01
      • 2011-09-02
      • 1970-01-01
      相关资源
      最近更新 更多