RS485 串行通信

1. 简介

EIA-485,也称为 TIA/EIA-485 或 RS-485,是一种标准,定义了平衡数字多点系统中使用的驱动器和接收器的电气特性。该标准广泛用于工业自动化中的通信,因为它可以在长距离和电气噪声环境中有效使用。

3. 内核中已有的数据结构

Linux 内核提供 struct serial_rs485 来处理 RS485 通信。此数据结构用于在平台数据和 ioctl 中设置和配置 RS485 参数。

设备树还可以提供 RS485 启动时间参数[1]。当驱动程序调用 uart_get_rs485_mode() 时,串行核心会从设备树提供的值填充 struct serial_rs485

任何能够作为 RS232 和 RS485 工作的设备驱动程序都应在 struct uart_port 中实现 rs485_config 回调并提供 rs485_supported。串行核心调用 rs485_config 以响应 TIOCSRS485 ioctl(见下文)执行特定于设备的部分。rs485_config 回调接收指向已清理的 struct serial_rs485 的指针。在调用 rs485_config 之前,使用 rs485_supported 清理用户空间提供的 struct serial_rs485,该值指示驱动程序为 struct uart_port 支持哪些 RS485 功能。TIOCGRS485 ioctl 可用于读取与当前配置匹配的 struct serial_rs485

struct serial_rs485

用于控制 RS485 设置的串行接口。

定义:

struct serial_rs485 {
    __u32 flags;
#define SER_RS485_ENABLED               _BITUL(0);
#define SER_RS485_RTS_ON_SEND           _BITUL(1);
#define SER_RS485_RTS_AFTER_SEND        _BITUL(2);
#define SER_RS485_RX_DURING_TX          _BITUL(4);
#define SER_RS485_TERMINATE_BUS         _BITUL(5);
#define SER_RS485_ADDRB                 _BITUL(6);
#define SER_RS485_ADDR_RECV             _BITUL(7);
#define SER_RS485_ADDR_DEST             _BITUL(8);
#define SER_RS485_MODE_RS422            _BITUL(9);
    __u32 delay_rts_before_send;
    __u32 delay_rts_after_send;
    union {
        __u32 padding[5];
        struct {
            __u8 addr_recv;
            __u8 addr_dest;
            __u8 padding0[2];
            __u32 padding1[4];
        };
    };
};

成员

flags

RS485 功能标志。

delay_rts_before_send

发送前的延迟(毫秒)。

delay_rts_after_send

发送后的延迟(毫秒)。

{unnamed_union}

anonymous

padding

已弃用,请改用 padding0padding1。不要与 addr_recvaddr_dest 一起使用(因为重叠)。

{unnamed_struct}

anonymous

addr_recv

RS485 寻址模式的接收过滤器(仅当设置了 SER_RS485_ADDR_RECV 时使用)。

addr_dest

RS485 寻址模式的目标地址(仅当设置了 SER_RS485_ADDR_DEST 时使用)。

padding0

填充(设置为零)。

padding1

填充(设置为零)。

描述

用于控制具有适当支持的芯片上的 RS485 设置的串行接口。如果您的平台支持,则使用 TIOCSRS485 设置,使用 TIOCGRS485 获取。设置函数返回新状态,所有不受支持的位都会相应地恢复。

标志位为

  • SER_RS485_ENABLED - 启用 RS485。

  • SER_RS485_RTS_ON_SEND - 发送时 RTS 引脚的逻辑电平。

  • SER_RS485_RTS_AFTER_SEND - 发送后 RTS 引脚的逻辑电平。

  • SER_RS485_RX_DURING_TX - 全双工 RS485 线路。

  • SER_RS485_TERMINATE_BUS - 启用总线端接(如果支持)。

  • SER_RS485_ADDRB - 启用 RS485 寻址模式。

  • SER_RS485_ADDR_RECV - 启用接收地址过滤器(启用 addr_recv)。需要 SER_RS485_ADDRB

  • SER_RS485_ADDR_DEST - 目标地址(启用 addr_dest)。需要 SER_RS485_ADDRB

  • SER_RS485_MODE_RS422 - 启用 RS422。需要 SER_RS485_ENABLED

4. 用户级别的使用

在用户级别,可以使用之前的 ioctl 获取/设置 RS485 配置。例如,要设置 RS485,您可以使用以下代码

#include <linux/serial.h>

/* Include definition for RS485 ioctls: TIOCGRS485 and TIOCSRS485 */
#include <sys/ioctl.h>

/* Open your specific device (e.g., /dev/mydevice): */
int fd = open ("/dev/mydevice", O_RDWR);
if (fd < 0) {
        /* Error handling. See errno. */
}

struct serial_rs485 rs485conf;

/* Enable RS485 mode: */
rs485conf.flags |= SER_RS485_ENABLED;

/* Set logical level for RTS pin equal to 1 when sending: */
rs485conf.flags |= SER_RS485_RTS_ON_SEND;
/* or, set logical level for RTS pin equal to 0 when sending: */
rs485conf.flags &= ~(SER_RS485_RTS_ON_SEND);

/* Set logical level for RTS pin equal to 1 after sending: */
rs485conf.flags |= SER_RS485_RTS_AFTER_SEND;
/* or, set logical level for RTS pin equal to 0 after sending: */
rs485conf.flags &= ~(SER_RS485_RTS_AFTER_SEND);

/* Set rts delay before send, if needed: */
rs485conf.delay_rts_before_send = ...;

/* Set rts delay after send, if needed: */
rs485conf.delay_rts_after_send = ...;

/* Set this flag if you want to receive data even while sending data */
rs485conf.flags |= SER_RS485_RX_DURING_TX;

if (ioctl (fd, TIOCSRS485, &rs485conf) < 0) {
        /* Error handling. See errno. */
}

/* Use read() and write() syscalls here... */

/* Close the device when finished: */
if (close (fd) < 0) {
        /* Error handling. See errno. */
}

5. 多点寻址

Linux 内核为多点 RS-485 串行通信线路提供寻址模式。寻址模式在 struct serial_rs485 中通过 SER_RS485_ADDRB 标志启用。struct serial_rs485 有两个附加标志和字段,用于启用接收和目标地址。

地址模式标志
  • SER_RS485_ADDRB:启用寻址模式(也在 termios 中设置 ADDRB)。

  • SER_RS485_ADDR_RECV:启用接收(筛选器)地址。

  • SER_RS485_ADDR_DEST:设置目标地址。

地址字段(通过对应的 SER_RS485_ADDR_* 标志启用)
  • addr_recv:接收地址。

  • addr_dest:目标地址。

一旦设置了接收地址,通信只能与特定设备发生,其他对等方将被过滤掉。由接收方强制执行过滤。如果未设置 SER_RS485_ADDR_RECV,则会清除接收地址。

注意:并非所有支持 RS485 的设备都支持多点寻址。

6. 参考资料