串口原始模式是禁用终端行规程和信号处理的通信方式,确保read/write直接传递字节流;必须用cfmakeraw()或手动清除ICANON、ISIG、IXON、OPOST等标志并调用tcsetattr生效。

什么是串口原始模式,为什么必须禁用终端处理
在 Linux 嵌入式系统中,open("/dev/ttyS0", ...) 打开的串口默认挂载在终端(tty)子系统下,内核会按行规程(ICANON)处理输入,并响应 ^C、^Z、^\ 等特殊字符。这对交互式 shell 是必需的,但对嵌入式通信(如 Modbus、自定义协议、二进制帧)是灾难:任意字节都可能被丢弃、截断或触发信号。
原始模式(Raw Mode)本质是绕过所有行规程和输入/输出处理层,让 read() 和 write() 直接传递字节流——这才是串口通信该有的样子。
用 cfmakeraw() 设置原始模式最稳妥
cfmakeraw() 是 POSIX 标准函数,专为快速进入原始模式设计,它一次性清空所有易出错的标志位,比手写 cflag/iflag 更可靠。
关键点:
- 必须在
tcgetattr()读取当前属性后调用,不能直接传栈上未初始化的struct termios - 它不修改波特率、数据位等硬件参数,只重置处理逻辑,所以后续仍需用
cfsetispeed()/cfsetospeed()单独设速 - 调用后务必用
tcsetattr(fd, TCSANOW, &term)提交,否则无效
示例片段:
struct termios term;
if (tcgetattr(fd, &term) == -1) { /* error */ }
cfmakeraw(&term);
cfsetispeed(&term, B115200);
cfsetospeed(&term, B115200);
tcsetattr(fd, TCSANOW, &term);
手动清除 iflag 和 oflag 的常见漏项
如果不用 cfmakeraw()(比如需要微调某些标志),必须显式关掉以下几组:
Linux 安全审计工具,检查 SSH 配置、开放/监听端口、防火墙规则(ufw/iptables/nftables)、失败登录尝试、sudoers 权限...
-
term.c_iflag &= ~(IGNBRK | BRKINT | PARMRK | ISTRIP | INLCR | IGNCR | ICRNL | IXON)—— 特别注意IXON(软件流控),嵌入式设备常无 XON/XOFF 支持,不关会导致接收卡死 -
term.c_oflag &= ~OPOST—— 这是核心,关掉所有输出后处理(如\n→\r\n转换) -
term.c_lflag &= ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN)——ICANON(行缓冲)和ISIG(信号生成)是干扰主因 -
term.c_cflag &= ~CRTSCTS—— 若硬件不接 RTS/CTS 线,启用此位可能导致驱动等待握手而阻塞
验证是否真正生效的两个硬指标
光看代码不等于成功。必须实测:
- 发送
0x03(^C)到串口,你的进程不能收到SIGINT—— 否则ISIG没关干净 - 用
read(fd, buf, 1)逐字节读,连续发0x0d 0x0a 0x1b(回车、换行、ESC),read()必须原样返回这 3 字节,长度为 3 —— 若返回 1 或 2,说明ICRNL、IGNCR或INLCR还开着
嵌入式环境调试时,建议先用 stty -F /dev/ttyS0 -icanon -isig -ixon -opost 手动验证行为,再移植到代码里。很多问题其实出在没清掉 IXON 或漏了 tcsetattr() 的 TCSANOW 参数。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!










