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

(图片来源网络,侵删)
函数概述
tcfsetispeed 函数用于设置终端输入(接收)线路的速度,也就是波特率。
- 头文件:
<termios.h> - 函数原型:
int tcfsetispeed(struct termios *termios_p, speed_t speed);
- 功能: 修改
termios_p指向的termios结构体中的输入波特率部分。 - 返回值:
- 成功时返回
0。 - 失败时返回
-1,并设置errno来指示具体的错误。
- 成功时返回
参数详解
-
struct termios *termios_p- 这是一个指向
termios结构体的指针。termios结构体是 POSIX 标准中定义的,用于描述终端的 I/O 特性。 - 在使用
tcfsetispeed之前,你通常需要先通过tcgetattr()函数获取当前终端的设置,并将其保存在一个termios结构体变量中。 tcfsetispeed不会直接修改终端,而是修改这个内存中的结构体,之后你需要调用tcsetattr()函数,将修改后的设置应用到实际的终端设备上。
- 这是一个指向
-
speed_t speed- 这是一个
speed_t类型的值,代表你想要设置的波特率。 - 你不能直接使用数字(如
9600),而应该使用<termios.h>中定义的宏,这些宏通常以B开头。 - 常见的波特率宏有:
B0: 0 波特率(挂断)B50: 50 bpsB75: 75 bpsB110: 110 bpsB134: 134.5 bpsB150: 150 bpsB200: 200 bpsB300: 300 bpsB600: 600 bpsB1200: 1200 bpsB1800: 1800 bpsB2400: 2400 bpsB4800: 4800 bpsB9600: 9600 bps (最常用)B19200: 19200 bpsB38400: 38400 bpsB57600: 57600 bpsB115200: 115200 bps (非常常用)B230400: 230400 bps- ... 等等,具体取决于你的系统和内核支持。
- 这是一个
工作流程(典型用法)
要配置一个串口,通常需要遵循以下步骤:

(图片来源网络,侵删)
- 获取当前设置: 使用
tcgetattr()读取串口的当前配置,并存入struct termios结构体。 - 修改设置: 修改
struct termios结构体中的各个字段,包括波特率、数据位、停止位、校验位等。 - 应用设置: 使用
tcsetattr()将修改后的配置写入串口,使其立即生效。 - 通信: 使用
read()和write()进行数据的收发。 - 恢复设置 (可选): 程序退出前,可以再次使用
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 的使用更为广泛,被认为是更可移植的写法,在实际开发中,推荐使用 cfsetispeed 和 cfsetospeed。

(图片来源网络,侵删)
常见错误
Permission denied: 没有权限访问串口设备,通常需要使用sudo运行你的程序,或者将当前用户添加到dialout组(在 Debian/Ubuntu 等系统上)。sudo usermod -a -G dialout $USER # 修改后需要重新登录或重启才能生效
No such file or directory: 设备路径错误(如/dev/ttyUSB0不存在)或设备未连接。Invalid argument: 传递给tcfsetispeed的speed值不是有效的宏(如B9600),或者你的内核不支持该波特率。Device or resource busy: 另一个程序已经打开了该串口设备,串口设备一次只能被一个程序以独占方式打开。
tcfsetispeed 是配置串口输入波特率的核心函数,它本身不直接与硬件交互,而是修改内存中的 termios 配置结构体,真正的配置生效需要通过 tcsetattr() 完成,在使用时,请务必记住:
- 包含正确的头文件
<termios.h>。 - 使用预定义的宏(如
B115200)来设置波特率,而不是硬编码数字。 - 理解它与
tcgetattr和tcsetattr的配合使用流程。 - 考虑使用更通用的
cfsetispeed作为替代。
