TCFSETISPEED函数如何正确设置C语言输入波特率?

99ANYc3cd6
预计阅读时长 21 分钟
位置: 首页 C语言 正文

这是一个在 Linux/Unix 系统中进行串口通信时非常重要的函数。

c语言 tcfsetispeed
(图片来源网络,侵删)

函数概述

tcfsetispeed 函数用于设置终端输入(接收)线路的速度,也就是波特率。

  • 头文件: <termios.h>
  • 函数原型:
    int tcfsetispeed(struct termios *termios_p, speed_t speed);
  • 功能: 修改 termios_p 指向的 termios 结构体中的输入波特率部分。
  • 返回值:
    • 成功时返回 0
    • 失败时返回 -1,并设置 errno 来指示具体的错误。

参数详解

  1. struct termios *termios_p

    • 这是一个指向 termios 结构体的指针。termios 结构体是 POSIX 标准中定义的,用于描述终端的 I/O 特性。
    • 在使用 tcfsetispeed 之前,你通常需要先通过 tcgetattr() 函数获取当前终端的设置,并将其保存在一个 termios 结构体变量中。
    • tcfsetispeed 不会直接修改终端,而是修改这个内存中的结构体,之后你需要调用 tcsetattr() 函数,将修改后的设置应用到实际的终端设备上。
  2. speed_t speed

    • 这是一个 speed_t 类型的值,代表你想要设置的波特率。
    • 你不能直接使用数字(如 9600),而应该使用 <termios.h> 中定义的,这些宏通常以 B 开头。
    • 常见的波特率宏有:
      • B0: 0 波特率(挂断)
      • B50: 50 bps
      • B75: 75 bps
      • B110: 110 bps
      • B134: 134.5 bps
      • B150: 150 bps
      • B200: 200 bps
      • B300: 300 bps
      • B600: 600 bps
      • B1200: 1200 bps
      • B1800: 1800 bps
      • B2400: 2400 bps
      • B4800: 4800 bps
      • B9600: 9600 bps (最常用)
      • B19200: 19200 bps
      • B38400: 38400 bps
      • B57600: 57600 bps
      • B115200: 115200 bps (非常常用)
      • B230400: 230400 bps
      • ... 等等,具体取决于你的系统和内核支持。

工作流程(典型用法)

要配置一个串口,通常需要遵循以下步骤:

c语言 tcfsetispeed
(图片来源网络,侵删)
  1. 获取当前设置: 使用 tcgetattr() 读取串口的当前配置,并存入 struct termios 结构体。
  2. 修改设置: 修改 struct termios 结构体中的各个字段,包括波特率、数据位、停止位、校验位等。
  3. 应用设置: 使用 tcsetattr() 将修改后的配置写入串口,使其立即生效。
  4. 通信: 使用 read()write() 进行数据的收发。
  5. 恢复设置 (可选): 程序退出前,可以再次使用 tcgetattr()tcsetattr() 恢复串口到原始状态。

tcgetattr()tcsetattr() 函数也需要 <termios.h><unistd.h> 头文件。


完整示例代码

下面的示例代码演示了如何打开一个串口设备(如 /dev/ttyS0/dev/ttyUSB0),并使用 tcfsetispeed 将其输入波特率设置为 115200

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <termios.h> // 包含 tcfsetispeed 的头文件
#define DEVICE "/dev/ttyUSB0" // 修改为你的串口设备名
int main() {
    int fd;
    struct termios options;
    // 1. 打开串口设备
    // O_RDWR: 读写模式
    // O_NOCTTY: 不将此设备作为终端控制设备
    // O_NDELAY: 非阻塞模式(可选)
    fd = open(DEVICE, O_RDWR | O_NOCTTY | O_NDELAY);
    if (fd < 0) {
        perror("Error opening serial port");
        return -1;
    }
    printf("Serial port %s opened successfully.\n", DEVICE);
    // 2. 获取当前串口设置
    if (tcgetattr(fd, &options) != 0) {
        perror("Error getting serial attributes");
        close(fd);
        return -1;
    }
    // 3. 修改波特率
    // 设置输入波特率
    if (tcfsetispeed(&options, B115200) != 0) {
        perror("Error setting input speed");
        close(fd);
        return -1;
    }
    // 输入和输出波特率设置为相同的值
    // 设置输出波特率
    if (tcsetattr(fd, TCSANOW, &options) != 0) { // tcsetattr 会同时设置输入和输出波特率
        perror("Error setting output speed");
        close(fd);
        return -1;
    }
    // 注意:上面的写法中,tcsetattr 会同时更新输入和输出波特率。
    // 更严谨的写法是分别设置输入和输出,然后再一次性应用。
    // 但通常我们希望两者一致,所以可以这样写:
    cfsetispeed(&options, B115200); // 推荐使用 cfsetispeed,它更通用
    cfsetospeed(&options, B115200); // 推荐使用 cfsetospeed
    // 应用所有设置
    if (tcsetattr(fd, TCSANOW, &options) != 0) {
        perror("Error applying serial attributes");
        close(fd);
        return -1;
    }
    printf("Baud rate set to 115200 successfully.\n");
    // (可选) 设置其他参数,如数据位、停止位、校验位等
    options.c_cflag &= ~CSIZE; // 清除数据位设置
    options.c_cflag |= CS8;    // 设置为8位数据位
    options.c_cflag &= ~PARENB; // 无校验位
    options.c_cflag &= ~CSTOPB; // 1位停止位
    options.c_cflag |= (CLOCAL | CREAD); // 忽略调制解调器控制线,启用接收
    // 应用所有新设置
    if (tcsetattr(fd, TCSANOW, &options) != 0) {
        perror("Error applying serial attributes (part 2)");
        close(fd);
        return -1;
    }
    printf("Other serial attributes (8N1) set successfully.\n");
    // 4. 简单的读写测试
    char write_buf[] = "Hello Serial Port!\n";
    char read_buf[256];
    // 写入数据
    int bytes_written = write(fd, write_buf, strlen(write_buf));
    if (bytes_written < 0) {
        perror("Error writing to serial port");
    } else {
        printf("Wrote %d bytes: %s", bytes_written, write_buf);
    }
    // 等待一小会儿,让另一端有机会响应
    usleep(500000); // 等待0.5秒
    // 读取数据
    int bytes_read = read(fd, read_buf, sizeof(read_buf) - 1);
    if (bytes_read < 0) {
        perror("Error reading from serial port");
    } else {
        read_buf[bytes_read] = '\0'; // 确保字符串以 null 
        printf("Read %d bytes: %s\n", bytes_read, read_buf);
    }
    // 5. 关闭串口
    close(fd);
    printf("Serial port closed.\n");
    return 0;
}

tcfsetispeed vs. cfsetispeed

你可能会在代码中看到 cfsetispeed 函数,这两个函数功能几乎完全相同,但有一个细微差别:

  • tcfsetispeed(termios_p, speed): 是 POSIX.1 标准中定义的函数,名字中的 "t" 代表 "terminal"。
  • cfsetispeed(termios_p, speed): 是一个更古老的 System V 接口,名字中的 "c" 代表 "control"。

在现代 Linux 系统中,这两个函数通常都被实现为完全相同的宏或内联函数,行为没有区别。cfsetispeed 的使用更为广泛,被认为是更可移植的写法,在实际开发中,推荐使用 cfsetispeedcfsetospeed

c语言 tcfsetispeed
(图片来源网络,侵删)

常见错误

  1. Permission denied: 没有权限访问串口设备,通常需要使用 sudo 运行你的程序,或者将当前用户添加到 dialout 组(在 Debian/Ubuntu 等系统上)。
    sudo usermod -a -G dialout $USER
    # 修改后需要重新登录或重启才能生效
  2. No such file or directory: 设备路径错误(如 /dev/ttyUSB0 不存在)或设备未连接。
  3. Invalid argument: 传递给 tcfsetispeedspeed 值不是有效的宏(如 B9600),或者你的内核不支持该波特率。
  4. Device or resource busy: 另一个程序已经打开了该串口设备,串口设备一次只能被一个程序以独占方式打开。

tcfsetispeed 是配置串口输入波特率的核心函数,它本身不直接与硬件交互,而是修改内存中的 termios 配置结构体,真正的配置生效需要通过 tcsetattr() 完成,在使用时,请务必记住:

  • 包含正确的头文件 <termios.h>
  • 使用预定义的宏(如 B115200)来设置波特率,而不是硬编码数字。
  • 理解它与 tcgetattrtcsetattr 的配合使用流程。
  • 考虑使用更通用的 cfsetispeed 作为替代。
-- 展开阅读全文 --
头像
dede如何彻底删除数据库中的冗余文件?
« 上一篇 2025-12-20
dede模板PC与手机端不同步怎么办?
下一篇 » 2025-12-20

相关文章

取消
微信二维码
支付宝二维码

目录[+]