RS-485串口通信:简易指南与代码示例

RS-485串口通信:简易指南与代码示例RS 485 是一种 定义了电气特性 传输速率 线路拓扑等细节 RS485 是一种广泛应用于工业领域的半双工串行通信协议

大家好,欢迎来到IT知识分享网。

RS-485串口通信:简易指南与代码示例

1. RS-485介绍

RS-485是一种物理层通信标准,定义了电气特性、传输速率、线路拓扑等细节

RS485是一种广泛应用于工业领域的半双工串行通信协议。RS485可以支持多达32个设备在同一总线上通信。RS485的最大传输速率可以达到10Mbps,但实际应用中,速率和传输距离成反比关系。

RS485使用差分信号传输,这意味着它通过一对互补信号线(通常标记为A和B)传输数据。

在RS485总线的两端需要连接终端电阻(通常为120欧姆),以匹配线路阻抗,防止信号反射。

RS-485串口通信:简易指南与代码示例

RS-485与RS-232的差异只体现在物理层上,它们的协议层是相同的,也是使用串口数据包的形式传输数据。

RS-485串口通信:简易指南与代码示例

2. RS485为何更抗干扰

这里说一下为什么RS485会更为抗干扰:

我们知道普通的 TTL 串口只适合短距离传输。TTL 通信是通过电压的高低变化来传输数据的,由于其单端传输方式,对静电和电磁干扰非常敏感,容易受到干扰而导致信号周期混乱,从而造成数据错误。因此,TTL 适合的传输距离通常较短。

而RS485使用两根互相扭绞的线*(A 和 B 线)*来传输数据,当一根线上的电压升高时另一根线上的电压会相应降低,这就是前面所说的差分信号传输,接收端可以通过对比两根线的电压差来过滤干扰信号。这样就可以有效抵消外部电磁干扰。

总线的两端加上的终端电阻也可以减少信号反射和误码率。

3. 简单的通信测试

接线时记住A对A,B对B

  • 查看波特率
    stty -F /dev/ttyACM0 # ttyACM0 替换为自己的串口 
  • 设置波特率
    stty -F /dev/ttyACM0  
  • 接收端
    cat /dev/ttyACM0 
  • 发送端
    echo "Hello, RS485" > /dev/ttyACM0 

4. 回环测试

在硬件上,普通的TTL串口信号通过一个转换芯片(这种芯片可以将TTL电平的单端信号转换为RS-485电平的差分信号)处理后可以转换为RS-485信号。

我进行了单机测试,将A和B端连接在一起进行回环测试,结果证实RS-485确实不能进行回环通信。

5. 使用C程序测试RS-485

5.1 发送端 sender.c

#include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <fcntl.h> #include <termios.h> #include <string.h> #define SERIAL_PORT "/dev/ttyACM0" #define BAUDRATE B // 波特率,与串口模块配置一致 #define DELAY_US  // 发送间隔,单位微秒 int main() { 
    int fd; struct termios options; // 打开串口 fd = open(SERIAL_PORT, O_RDWR | O_NOCTTY | O_NDELAY); if (fd == -1) { 
    perror("open_port: Unable to open port"); return 1; } // 获取当前串口配置 if (tcgetattr(fd, &options) != 0) { 
    perror("tcgetattr failed"); close(fd); return 1; } // 设置波特率 cfsetispeed(&options, BAUDRATE); cfsetospeed(&options, BAUDRATE); // 无校验,8位数据位,1位停止位 options.c_cflag &= ~PARENB; options.c_cflag &= ~CSTOPB; options.c_cflag &= ~CSIZE; options.c_cflag |= CS8; // 设置为本地连接,使能接收 options.c_cflag |= (CLOCAL | CREAD); // 设置为原始模式 options.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG); // 禁用软件流控制 options.c_iflag &= ~(IXON | IXOFF | IXANY); // 禁用硬件流控制 options.c_cflag &= ~CRTSCTS; // 设置新的串口设置 if (tcsetattr(fd, TCSANOW, &options) != 0) { 
    perror("tcsetattr failed"); close(fd); return 1; } // 循环发送数据 char write_buffer[256]; while (1) { 
    // 获取用户输入 printf("Enter message to send (max 255 characters): "); fgets(write_buffer, sizeof(write_buffer), stdin); // 移除换行符 write_buffer[strcspn(write_buffer, "\n")] = 0; // 发送数据 int bytes_written = write(fd, write_buffer, strlen(write_buffer)); if (bytes_written < 0) { 
    perror("write failed"); close(fd); return 1; } printf("Sent: %s\n", write_buffer); usleep(DELAY_US); // 发送间隔 } // 关闭串口 close(fd); return 0; } 

5.2 接收端 recriver.c

#include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <fcntl.h> #include <termios.h> #include <string.h> #define SERIAL_PORT "/dev/ttyACM0" #define BAUDRATE B // 波特率,与串口模块配置一致 int main() { 
    int fd; struct termios options; // 打开串口 fd = open(SERIAL_PORT, O_RDWR); if (fd == -1) { 
    perror("open_port: Unable to open port"); return 1; } // 获取当前串口配置 if (tcgetattr(fd, &options) != 0) { 
    perror("tcgetattr failed"); close(fd); return 1; } // 设置波特率 cfsetispeed(&options, BAUDRATE); cfsetospeed(&options, BAUDRATE); // 无校验,8位数据位,1位停止位 options.c_cflag &= ~PARENB; options.c_cflag &= ~CSTOPB; options.c_cflag &= ~CSIZE; options.c_cflag |= CS8; // 设置为本地连接,使能接收 options.c_cflag |= (CLOCAL | CREAD); // 设置为原始模式 options.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG); // 禁用软件流控制 options.c_iflag &= ~(IXON | IXOFF | IXANY); // 禁用硬件流控制 options.c_cflag &= ~CRTSCTS; // 设置新的串口设置 if (tcsetattr(fd, TCSANOW, &options) != 0) { 
    perror("tcsetattr failed"); close(fd); return 1; } // 循环接收数据 while (1) { 
    char read_buffer[256]; int bytes_read = read(fd, read_buffer, sizeof(read_buffer) - 1); if (bytes_read < 0) { 
    perror("read failed"); close(fd); return 1; } read_buffer[bytes_read] = '\0'; printf("Received: %s\n", read_buffer); } // 关闭串口 close(fd); return 0; } 

5.3 Makefile

为了方便编译,这里附上一个简单的Makefile

CC = arm-linux-gnueabihf-gcc CFLAGS = -Wall all: sender receiver sender: sender.c $(CC) $(CFLAGS) -o sender sender.c receiver: receiver.c $(CC) $(CFLAGS) -o receiver receiver.c clean: rm -f sender receiver 

先运行接收端再运行发送端

send:

RS-485串口通信:简易指南与代码示例

receive:

RS-485串口通信:简易指南与代码示例

可以进行进一步的优化,将SERIAL_PORT等由外部传参而入,这样方便对多个串口进行测试。


参考资料:

https://doc.embedfire.com/mcu/stm32/f407batianhu/std/zh/latest/book/RS485.html

END


免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。 本文来自网络,若有侵权,请联系删除,如若转载,请注明出处:https://haidsoft.com/123047.html

(0)
上一篇 2025-10-12 08:00
下一篇 2025-10-12 08:15

相关推荐

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注微信