跳到主要内容

21_RS485简单讲解

RS485简单讲解

  • 参考代码

    • Linux 4.9.88

      Documentation\serial\serial-rs485.txt
    • Linux 5.4

      Documentation\driver-api\serial\serial-rs485.rst

1. RS485线路图

RS485使用A、B两条差分线传输数据:

  • 要发送数据时
    • 把SP3485的DE(Driver output Enable)引脚设置为高
    • 通过TxD引脚发送1给SP3485,SP3485会驱动A、B引脚电压差为+2~+6V
    • 通过TxD引脚发送0给SP3485,SP3485会驱动A、B引脚电压差为-6~-2V
    • SP3485自动把TxD信号转换为AB差分信号
    • 对于软件来说,通过RS485发送数据时,跟一般的串口没区别,只是多了DE引脚的设置
  • 要读取数据时
    • 把SP3485的nRE(Receiver Output Enable)引脚设置为低
    • SP3485会根据AB引脚的电压差驱动RO为1或0
    • RO的数据传入UART的RxD引脚
    • 对于软件来说,通过RS485读取数据时,跟一般的串口没区别,只是多了nRE引脚的设置
  • nRE和DE使用同一个引脚时,可以简化成这样:
    • 发送:设置DE为高,发送,设置DE为低
    • 接收:无需特殊设置

image-20210817090221769

2. RS485应用编程

2.1 标准用法

在Linux的串口驱动中,它已经支持RS485,可以使用RTS引脚控制RS485芯片的DE引脚,分两种情况

  • 有些UART驱动:使用UART的RTS引脚
  • 有些UART驱动:使用GPIO作为RTS引脚,可以通过设备树指定这个GPIO

image-20210817152819642

在使用RS485发送数据前,把RTS设置为高电平就可以。

通过serial_rs485结构体控制RTS,示例代码如下:

#include <linux/serial.h>

/* 用到这2个ioctl: TIOCGRS485, TIOCSRS485 */
#include <sys/ioctl.h>

struct serial_rs485 rs485conf;

/* 打开串口设备 */
int fd = open ("/dev/mydevice", O_RDWR);
if (fd < 0) {
/* 失败则返回 */
return -1;
}

/* 读取rs485conf */
if (ioctl (fd, TIOCGRS485, &rs485conf) < 0) {
/* 处理错误 */
}

/* 使能RS485模式 */
rs485conf.flags |= SER_RS485_ENABLED;

/* 当发送数据时, RTS为1 */
rs485conf.flags |= SER_RS485_RTS_ON_SEND;

/* 或者: 当发送数据时, RTS为0 */
rs485conf.flags &= ~(SER_RS485_RTS_ON_SEND);

/* 当发送完数据后, RTS为1 */
rs485conf.flags |= SER_RS485_RTS_AFTER_SEND;

/* 或者: 当发送完数据后, RTS为0 */
rs485conf.flags &= ~(SER_RS485_RTS_AFTER_SEND);

/* 还可以设置:
* 发送数据之前先设置RTS信号, 等待一会再发送数据
* 等多久? delay_rts_before_send(单位ms)
*/
rs485conf.delay_rts_before_send = ...;

/* 还可以设置:
* 发送数据之后, 等待一会再清除RTS信号
* 等多久? delay_rts_after_send(单位ms)
*/
rs485conf.delay_rts_after_send = ...;

/* 如果想在发送RS485数据的同时也接收数据, 还可以这样设置 */
rs485conf.flags |= SER_RS485_RX_DURING_TX;

if (ioctl (fd, TIOCSRS485, &rs485conf) < 0) {
/* 处理错误 */
}

/* 使用read()和write()就可以读、写数据了 */

/* 关闭设备 */
if (close (fd) < 0) {
/* 处理错误 */
}

2.2 自己控制引脚

发送之前,自己设置GPIO控制DE引脚。

3. 驱动速览

3.1 IMX6ULL

源码为:Linux-4.9.88/drivers/tty/serial/imx.c

image-20210817110742798

3.2 STM32MP157

源码为:Linux-5.4/drivers/tty/serial/stm32-usart.c

STM32MP157的UART功能强大,可以配置它:

  • 发送数据时自动设置RTS信号
  • 设置时间值:RTS使能后过多久发送数据,发送完数据后过多久取消RTS
  • 配置好后,在发送RS485数据时就不需要显示地控制RTS了

image-20210817111648083

3.3 使用GPIO的RS485驱动

这里只是举个例子。

源码为:Linux-4.9.88/drivers/tty/serial/omap-serial.c

1. 从设备树获得用作RTS的GPIO

image-20210817112330418

2. 发送数据前设置GPIO

image-20210817112526468