引言
要搞清楚结构体termios的c_iflag
字段的BRKINT选项和IGNBRK选项的含义,首先要搞清楚BREAK信号的含义。其实当你搞清楚BREAK信号后,结构体termios的c_iflag
字段的BRKINT选项和IGNBRK选项的含义你也就自然知道了。
1. 什么是 BREAK 信号?
在串口通信(UART)中,BREAK 信号 指的是 发送端保持 TXD 低电平超过一帧完整字符的时间(一帧完整字符通常为8位数据位+1位校验位+1位停止位,共10位),BREAK 信号通常用于:
- 通信错误检测
- 终端控制
- 复位设备
- 同步设备状态
示意图(不含校验位):
正常传输:
Start | Data bits | Stop
------|------------|------0 | 10101010 | 1 (1帧字符)BREAK 信号:
Start | 低电平持续时间 |
------|----------------|------0 | 低电平 | 低电平
2. BREAK 信号的特性
- BREAK 信号 = TX 线一直保持低电平
- 持续时间至少要大于 1 帧字符传输的时间
- 不会被解释为正常数据
- 可用于特殊控制用途,如复位、唤醒、错误通知等
3. BREAK 信号的用途
① 终端控制(TTY 设备)
- Linux TTY 设备收到 BREAK 时,可触发 SIGINT(中断信号) 终止前台进程。
- 相关
termios
选项:BRKINT
(如果启用,则 BREAK 会触发SIGINT
)。IGNBRK
(如果启用,则忽略 BREAK 信号)。
② 设备复位
某些设备(如 Modbus 从机、某些 GPS 设备)会在收到 BREAK 后执行复位。
③ 调制解调器通信
- 传统调制解调器(Modem)使用 BREAK 作为特殊指令,如退出数据模式、进入命令模式。
④ 通信错误检测
- 串口通信通常有校验(如奇偶校验),但如果线路出现严重干扰,设备可能发送 BREAK 作为错误指示。
4. BREAK 信号的处理方式
单独介绍选项值IGNBRK
和BRKINT
不同操作系统和硬件会有不同的 BREAK 处理方式,通常可以通过 termios
结构体的 c_iflag
选项来配置。
c_iflag 选项 | 含义 |
---|---|
IGNBRK | 忽略 BREAK 信号,不传递给应用程序 |
BRKINT | 启用 BREAK,BREAK 触发 SIGINT 终止进程 |
PARMRK | 在 奇偶校验启用 时,将 BREAK 作为 \377\0\0 发送给用户 |
示例:
struct termios options;
tcgetattr(fd, &options);// 让 BREAK 触发 SIGINT
options.c_iflag |= BRKINT;// 设置新属性
tcsetattr(fd, TCSANOW, &options);
选项值IGNBRK
和BRKINT
组合使用的效果
IGNBRK | BRKINT | 处理方式 |
---|---|---|
1(启用) | 0(禁用) | 直接忽略 BREAK 信号,不通知用户空间 |
1(启用) | 1(启用) | 直接忽略 BREAK 信号,不触发 SIGINT |
0(禁用) | 0(禁用) | BREAK 被视为 空字符 (0x00 ) 传递给用户 |
0(禁用) | 1(启用) | BREAK 触发 SIGINT (终止进程) |
5. 发送 BREAK 信号
在 Linux 上,tcsendbreak(fd, duration)
用于 主动发送 BREAK 信号。
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <termios.h>int main() {int fd = open("/dev/ttyS0", O_RDWR | O_NOCTTY);if (fd == -1) {perror("open");return -1;}// 发送 BREAK 信号,持续时间为 0(默认 250~500ms)tcsendbreak(fd, 0);close(fd);return 0;
}
duration = 0
:发送 默认长度(250~500ms)的 BREAK。duration > 0
:发送 特定长度 的 BREAK(非 POSIX 标准,仅部分系统支持)。
6. 检测 BREAK 信号
在应用程序中,可以通过 read()
检测是否接收到 BREAK,但大多数情况下,内核会转换 BREAK 为 SIGINT
,因此不需要手动读取。
如果要检测 BREAK 而不让它触发 SIGINT
,可以:
struct termios options;
tcgetattr(fd, &options);
options.c_iflag &= ~BRKINT; // 禁止 BREAK 触发 SIGINT
tcsetattr(fd, TCSANOW, &options);
然后在 read()
中读取数据,如果 PARMRK
使能,BREAK 会作为 \377\0\0
传输。
7. 物理层行为
波特率 | 1 帧字符时间(按10位字符来算) | BREAK 最小持续时间 |
---|---|---|
115200 | 86.8 µs | ≥ 87 µs |
9600 | 1.04 ms | ≥ 1.04 ms |
2400 | 4.17 ms | ≥ 4.17 ms |
例如,在 9600 bps 下,BREAK 必须至少 保持低电平 1.04 ms 才会被识别。
8. 相关 Linux 命令
stty
命令查看和设置 BREAK 处理方式
stty -F /dev/ttyS0 -a # 查看当前串口设置
stty -F /dev/ttyS0 brkint # 使能 BREAK 触发 SIGINT
stty -F /dev/ttyS0 -brkint # 禁止 BREAK 触发 SIGINT
- 手动发送 BREAK
echo -e "\x00" > /dev/ttyS0 # 可能不会产生 BREAK
stty -F /dev/ttyS0 sendbreak # 发送 BREAK 信号
总结
- BREAK 信号 = TX 线保持低电平超过 1 个字符时间。
- 用途:设备复位、终端控制(
SIGINT
)、调制解调器控制、错误检测等。 - Linux 处理方式:
IGNBRK
:忽略 BREAKBRKINT
:BREAK 触发SIGINT
tcsendbreak(fd, duration)
主动发送 BREAK
- 应用场景:
- 串口调试时可用 BREAK 触发设备复位
- TTY 终端可用 BREAK 中断进程
- 工业设备可能使用 BREAK 作为特殊信号