服务器测评网
我们一直在努力

Linux串口通信代码如何实现收发与配置参数?

在Linux系统中,串口通信是一种常见且重要的设备交互方式,广泛应用于嵌入式开发、工业控制、设备调试等场景,通过串口,程序可以与外部设备进行双向数据传输,实现指令下发、状态监控等功能,本文将从串口基础概念、Linux串口设备文件、核心编程接口、代码实现示例及注意事项等方面,详细介绍Linux串口编程的相关知识。

Linux串口通信代码如何实现收发与配置参数?

Linux串口设备与基础配置

Linux系统将串口设备抽象为特殊的字符设备文件,通常位于/dev目录下,常见的串口设备文件包括/dev/ttyS0(COM1)、/dev/ttyS1(COM2)等,用于内置串口;而USB转串口设备通常表现为/dev/ttyUSB0/dev/ttyACM0等形式,在编程前,需确认设备文件是否存在并具有读写权限,可通过ls -l /dev/tty*命令查看,必要时使用chmod调整权限。

串口通信的核心参数包括波特率、数据位、停止位、校验位和流控,这些参数必须与通信两端设备保持一致,否则会导致数据传输错误,常见的配置为:波特率9600、数据位8、停止位1、无校验位、无流控,在Linux中,可通过stty命令快速测试串口配置,如stty -F /dev/ttyS0 9600 cs8 -cstopb -parenb命令可将串口设置为上述常用参数。

串口编程核心API

Linux串口编程主要通过文件I/O操作实现,其核心步骤与普通文件读写类似,但需额外配置串口属性,以下是关键API及流程:

Linux串口通信代码如何实现收发与配置参数?

  1. 打开串口设备
    使用open()函数打开串口设备文件,需指定O_RDWR(读写模式)和O_NOCTTY(防止终端成为控制终端)标志,
    int fd = open("/dev/ttyS0", O_RDWR | O_NOCTTY | O_NDELAY);
    其中O_NDELAY表示非阻塞模式,若需阻塞模式可省略该标志。

  2. 配置串口属性
    打开串口后,需通过termios结构体配置串口参数,主要步骤包括:

    • 获取当前配置:tcgetattr(fd, &oldtio)
    • 修改配置:设置波特率(cfsetispeed/cfsetospeed)、数据位(cs8)、停止位(CSTOPB)、校验位(PARENB)等
    • 应用配置:tcsetattr(fd, TCSANOW, &newtio)
      示例代码片段:

      struct termios options;
      tcgetattr(fd, &options);
      cfsetispeed(&options, B9600);
      cfsetospeed(&options, B9600);
      options.c_cflag &= ~PARENB;   // 无校验位
      options.c_cflag &= ~CSTOPB;   // 1位停止位
      options.c_cflag &= ~CSIZE;    // 清除数据位设置
      options.c_cflag |= CS8;       // 8位数据位
      tcsetattr(fd, TCSANOW, &options);
  3. 读写串口数据

    Linux串口通信代码如何实现收发与配置参数?

    • 读数据:使用read()函数读取串口缓冲区数据,如int n = read(fd, buf, sizeof(buf));
    • 写数据:使用write()函数向串口发送数据,如write(fd, "Hello", 5);
      默认情况下,read()为阻塞调用,可设置VTIME(超时 deciseconds)和VMIN(最小读取字符数)实现非阻塞读取,options.c_cc[VMIN] = 1; options.c_cc[VTIME] = 0;表示读取至少1个字符或超时。
  4. 关闭串口
    使用close()函数关闭串口设备,如close(fd);,若需确保数据发送完成,可在关闭前调用tcdrain(fd)等待输出缓冲区清空。

完整代码示例

以下是一个简单的串口收发程序示例,实现从串口读取数据并回显:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <termios.h>
#include <string.h>
int main() {
    int fd = open("/dev/ttyS0", O_RDWR | O_NOCTTY | O_NDELAY);
    if (fd < 0) {
        perror("Failed to open serial port");
        return -1;
    }
    struct termios options;
    tcgetattr(fd, &options);
    cfsetispeed(&options, B9600);
    cfsetospeed(&options, B9600);
    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_oflag &= ~OPOST;  // 原始输出模式
    options.c_cc[VMIN] = 1;
    options.c_cc[VTIME] = 0;
    tcsetattr(fd, TCSANOW, &options);
    char buf[1024];
    while (1) {
        int n = read(fd, buf, sizeof(buf) - 1);
        if (n > 0) {
            buf[n] = '\0';
            printf("Received: %s", buf);
            write(fd, buf, n);  // 回显数据
        }
    }
    close(fd);
    return 0;
}

注意事项与调试技巧

  1. 权限问题:确保程序对串口设备有读写权限,可临时通过sudo运行或设置用户组权限。
  2. 波特率匹配:通信前务必确认两端设备波特率一致,否则数据可能乱码或丢失。
  3. 流控配置:若使用硬件流控(RTS/CTS),需在c_cflag中启用CRTSCTS标志;软件流控(XON/XOFF)则通过c_iflag设置。
  4. 调试工具:使用minicomscreen命令行工具测试串口是否正常工作,例如minicom -D /dev/ttyS0
  5. 多线程安全:在多线程环境中,需使用互斥锁保护串口文件描述符,避免并发读写冲突。
    开发者可以快速掌握Linux串口编程的核心方法,并根据实际需求调整参数和逻辑,串口通信虽然基础,但在物联网、嵌入式系统等领域仍具有不可替代的作用,深入理解其原理和实现方式对系统开发至关重要。
赞(0)
未经允许不得转载:好主机测评网 » Linux串口通信代码如何实现收发与配置参数?