stty(set teletype)命令用于配置和显示终端设备的参数设置,包括波特率、数据位、停止位、奇偶校验等串口通信参数,以及终端输入输出行为控制。
stty主要用于配置终端设备:
stty [选项] [设置] [设备]
# 常用选项
-a, --all # 以可读格式显示所有设置
-g, --save # 以stty可读格式显示当前设置
-F, --file=设备 # 打开指定设备而不是stdin
--help # 显示帮助信息
--version # 显示版本信息
# 示例
stty -a # 显示所有当前终端设置
stty -g # 以stty格式显示设置(可用于保存和恢复)
stty sane # 恢复终端到合理设置
stty 9600 cs8 -cstopb -parenb # 设置串口参数
# 1. 查看当前终端的所有设置(最常用)
stty -a
# 输出示例:
# speed 38400 baud; rows 24; columns 80; line = 0;
# intr = ^C; quit = ^\; erase = ^?; kill = ^U; eof = ^D; eol = M-^?; eol2 = M-^?; swtch = M-^?;
# start = ^Q; stop = ^S; susp = ^Z; rprnt = ^R; werase = ^W; lnext = ^V; discard = ^O;
# min = 1; time = 0;
# -parenb -parodd -cmspar cs8 -hupcl -cstopb cread -clocal -crtscts
# -ignbrk -brkint -ignpar -parmrk -inpck -istrip -inlcr -igncr icrnl ixon -ixoff -iuclc -ixany
# imaxbel iutf8
# opost -olcuc -ocrnl onlcr -onocr -onlret -ofill -ofdel nl0 cr0 tab0 bs0 vt0 ff0
# isig icanon iexten echo echoe echok -echonl -noflsh -xcase -tostop -echoprt echoctl echoke
# 2. 以stty可读格式显示(用于保存和恢复)
stty -g
# 输出类似:5500:5:1cb:8a3b:3:1c:7f:15:4:0:0:0:11:13:1a:0:12:f:17:16:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0
# 3. 查看特定设置
stty speed # 查看波特率
stty rows # 查看行数
stty columns # 查看列数
stty size # 查看行数和列数
# 4. 查看特定设备设置
stty -F /dev/ttyS0 -a # 查看串口设备设置
stty -F /dev/ttyUSB0 -a # 查看USB串口设置
| 设置 | 说明 | 示例 |
|---|---|---|
rows N |
设置终端行数 | stty rows 48 |
cols N |
设置终端列数 | stty cols 132 |
size |
显示终端尺寸(行×列) | stty size |
echo |
启用字符回显 | stty echo |
-echo |
禁用字符回显(用于密码输入) | stty -echo |
icanon |
启用规范模式(行缓冲) | stty icanon |
-icanon |
禁用规范模式(字符模式) | stty -icanon |
raw |
原始模式(无处理) | stty raw |
-raw |
禁用原始模式 | stty -raw |
cooked |
启用规范处理(默认) | stty cooked |
# 1. 设置波特率(常见值:300, 1200, 2400, 4800, 9600, 19200, 38400, 57600, 115200)
stty -F /dev/ttyS0 9600 # 设置串口0为9600波特率
stty -F /dev/ttyUSB0 115200 # 设置USB串口为115200波特率
# 2. 设置数据位(5, 6, 7, 8)
stty -F /dev/ttyS0 cs7 # 7位数据位
stty -F /dev/ttyS0 cs8 # 8位数据位(默认)
# 3. 设置停止位(1或2)
stty -F /dev/ttyS0 -cstopb # 1个停止位
stty -F /dev/ttyS0 cstopb # 2个停止位
# 4. 设置奇偶校验
stty -F /dev/ttyS0 -parenb # 无校验(默认)
stty -F /dev/ttyS0 parenb # 启用奇偶校验
stty -F /dev/ttyS0 parodd # 奇校验
stty -F /dev/ttyS0 -parodd # 偶校验
# 5. 设置硬件流控
stty -F /dev/ttyS0 crtscts # 启用RTS/CTS流控
stty -F /dev/ttyS0 -crtscts # 禁用硬件流控
# 6. 设置软件流控
stty -F /dev/ttyS0 ixon ixoff # 启用XON/XOFF流控
stty -F /dev/ttyS0 -ixon -ixoff # 禁用软件流控
# 7. 综合设置示例
# 8位数据位,1个停止位,无校验,115200波特率
stty -F /dev/ttyS0 115200 cs8 -cstopb -parenb
# 7位数据位,2个停止位,偶校验,9600波特率
stty -F /dev/ttyS0 9600 cs7 cstopb parenb -parodd
# 8位数据位,1个停止位,无校验,硬件流控,19200波特率
stty -F /dev/ttyS0 19200 cs8 -cstopb -parenb crtscts
| 控制字符 | 默认值 | 说明 | 设置示例 |
|---|---|---|---|
intr |
^C (Ctrl+C) | 中断信号 | stty intr ^X |
quit |
^\ (Ctrl+\) | 退出信号 | stty quit ^Q |
erase |
^? (Backspace) | 删除前一个字符 | stty erase ^H |
kill |
^U (Ctrl+U) | 删除整行 | stty kill ^K |
eof |
^D (Ctrl+D) | 文件结束 | stty eof ^E |
start |
^Q (Ctrl+Q) | 恢复输出 | stty start ^S |
stop |
^S (Ctrl+S) | 暂停输出 | stty stop ^T |
susp |
^Z (Ctrl+Z) | 挂起进程 | stty susp ^Y |
rprnt |
^R (Ctrl+R) | 重绘当前行 | stty rprnt ^L |
werase |
^W (Ctrl+W) | 删除前一个单词 | stty werase ^B |
lnext |
^V (Ctrl+V) | 输入下一个字符的字面值 | stty lnext ^N |
# 1. 保存和恢复终端设置
# 保存当前设置
SAVED_SETTINGS=$(stty -g)
echo "当前设置已保存"
# 修改设置
stty -echo icanon
# 恢复原始设置
stty "$SAVED_SETTINGS"
echo "设置已恢复"
# 2. 密码输入(不显示输入)
echo -n "请输入密码: "
stty -echo
read PASSWORD
stty echo
echo -e "\n密码已接收"
# 3. 实时按键检测(无回车)
echo "按任意键继续..."
stty -icanon -echo
KEY=$(dd bs=1 count=1 2>/dev/null)
stty icanon echo
echo "你按下了: $KEY"
# 4. 设置串口并读取数据
# 配置串口
stty -F /dev/ttyUSB0 9600 cs8 -cstopb -parenb
# 读取串口数据
cat /dev/ttyUSB0
# 或使用
cat < /dev/ttyUSB0
# 5. 向串口发送数据
echo "AT" > /dev/ttyUSB0
echo -e "AT\r\n" > /dev/ttyUSB0
# 6. 双向串口通信
# 配置串口
stty -F /dev/ttyUSB0 115200 cs8 -cstopb -parenb
# 在一个终端读取
cat /dev/ttyUSB0
# 在另一个终端写入
echo "HELLO" > /dev/ttyUSB0
# 7. 检查串口是否可用
if [ -c /dev/ttyUSB0 ]; then
echo "串口设备存在"
stty -F /dev/ttyUSB0 -a
else
echo "串口设备不存在"
fi
# 8. 设置终端为原始模式(用于串口终端)
stty -F /dev/ttyS0 raw
stty -F /dev/ttyS0 -echo
#!/bin/bash
# 串口通信脚本
# 文件名:serial_communication.sh
SERIAL_PORT="/dev/ttyUSB0"
BAUD_RATE="115200"
LOG_FILE="/tmp/serial.log"
# 检查串口设备
if [ ! -c "$SERIAL_PORT" ]; then
echo "错误: 串口设备 $SERIAL_PORT 不存在"
exit 1
fi
# 配置串口
echo "配置串口 $SERIAL_PORT 为 $BAUD_RATE 波特率..."
stty -F "$SERIAL_PORT" $BAUD_RATE cs8 -cstopb -parenb -crtscts
# 显示当前设置
echo "当前串口设置:"
stty -F "$SERIAL_PORT" -a | head -5
# 清理旧日志
> "$LOG_FILE"
# 读取串口数据的函数
read_serial() {
echo "开始读取串口数据(按Ctrl+C停止)..."
echo "数据将保存到: $LOG_FILE"
echo "==============================" > "$LOG_FILE"
echo "串口日志 - $(date)" >> "$LOG_FILE"
echo "==============================" >> "$LOG_FILE"
# 设置终端为原始模式
stty -F "$SERIAL_PORT" raw -echo
# 读取数据并记录
while true; do
# 读取一行或超时
if read -t 5 -r LINE < "$SERIAL_PORT"; then
TIMESTAMP=$(date "+%Y-%m-%d %H:%M:%S")
echo "[$TIMESTAMP] $LINE" | tee -a "$LOG_FILE"
fi
done
}
# 发送数据的函数
send_serial() {
local message="$1"
echo "发送: $message"
echo -e "$message\r\n" > "$SERIAL_PORT"
sleep 0.5
}
# 菜单
show_menu() {
echo ""
echo "=== 串口通信菜单 ==="
echo "1. 开始读取串口数据"
echo "2. 发送AT命令"
echo "3. 发送自定义命令"
echo "4. 查看日志"
echo "5. 重新配置串口"
echo "6. 退出"
echo -n "请选择 [1-6]: "
}
# 主循环
while true; do
show_menu
read -r CHOICE
case $CHOICE in
1)
read_serial &
READ_PID=$!
echo "读取进程PID: $READ_PID"
echo "按回车键返回菜单"
read -r
kill $READ_PID 2>/dev/null
;;
2)
send_serial "AT"
send_serial "ATI"
send_serial "AT+CGMR"
;;
3)
echo -n "请输入要发送的命令: "
read -r CMD
send_serial "$CMD"
;;
4)
echo "=== 最近日志 ==="
tail -20 "$LOG_FILE"
;;
5)
echo -n "请输入波特率 [9600, 115200, 等]: "
read -r NEW_BAUD
stty -F "$SERIAL_PORT" "$NEW_BAUD" cs8 -cstopb -parenb
echo "串口已重新配置为 $NEW_BAUD 波特率"
;;
6)
echo "退出..."
exit 0
;;
*)
echo "无效选择"
;;
esac
done
#!/bin/bash
# 终端配置管理脚本
# 文件名:terminal_manager.sh
CONFIG_FILE="$HOME/.terminal_config"
BACKUP_FILE="$HOME/.terminal_config.backup"
# 保存当前配置
save_config() {
echo "保存当前终端配置..."
stty -g > "$CONFIG_FILE"
echo "配置已保存到: $CONFIG_FILE"
# 同时创建备份
cp "$CONFIG_FILE" "$BACKUP_FILE"
echo "备份已创建: $BACKUP_FILE"
}
# 恢复配置
restore_config() {
if [ -f "$CONFIG_FILE" ]; then
echo "恢复终端配置..."
stty "$(cat "$CONFIG_FILE")"
echo "配置已恢复"
else
echo "错误: 配置文件不存在"
fi
}
# 恢复默认设置
restore_default() {
echo "恢复默认终端设置..."
stty sane
echo "默认设置已恢复"
}
# 配置特殊字符
setup_special_chars() {
echo "配置特殊字符..."
# 保存原始设置
OLD_INTR=$(stty -a | grep -o "intr = .[^;]*" | cut -d= -f2 | tr -d ' ')
# 设置新的特殊字符
stty intr ^X # Ctrl+X 代替 Ctrl+C
stty quit ^Q # Ctrl+Q 代替 Ctrl+\
stty erase ^H # Ctrl+H 代替 Backspace
stty kill ^K # Ctrl+K 代替 Ctrl+U
stty eof ^E # Ctrl+E 代替 Ctrl+D
echo "特殊字符已配置:"
echo " 中断: Ctrl+X (原: $OLD_INTR)"
echo " 退出: Ctrl+Q"
echo " 删除: Ctrl+H"
echo " 清行: Ctrl+K"
echo " 结束: Ctrl+E"
}
# 配置串口模式
setup_serial_mode() {
echo "配置串口终端模式..."
# 禁用回显和规范模式
stty -echo -icanon
# 设置原始模式
stty raw
# 禁用软件流控
stty -ixon -ixoff
echo "串口模式已启用:"
echo " - 无回显"
echo " - 原始模式"
echo " - 无流控"
}
# 显示当前设置
show_current() {
echo "=== 当前终端设置 ==="
echo "尺寸: $(stty size)"
echo "波特率: $(stty speed)"
echo -e "\n特殊字符:"
stty -a | grep -E "intr|quit|erase|kill|eof" | sed 's/^/ /'
echo -e "\n模式设置:"
stty -a | grep -E "echo|icanon|raw" | head -3 | sed 's/^/ /'
}
# 菜单
show_menu() {
echo ""
echo "=== 终端配置管理器 ==="
echo "1. 显示当前设置"
echo "2. 保存当前配置"
echo "3. 恢复保存的配置"
echo "4. 恢复默认设置"
echo "5. 配置特殊字符"
echo "6. 配置串口模式"
echo "7. 测试串口终端"
echo "8. 退出"
echo -n "请选择 [1-8]: "
}
# 测试串口终端
test_serial_terminal() {
echo "测试串口终端..."
echo "按 Ctrl+X 中断测试"
# 设置测试模式
stty -echo -icanon
echo -n "输入字符测试 (输入 'q' 退出): "
while true; do
# 读取单个字符
CHAR=$(dd bs=1 count=1 2>/dev/null)
# 检查退出条件
if [ "$CHAR" = "q" ]; then
break
fi
echo -n "$CHAR"
done
# 恢复设置
stty echo icanon
echo -e "\n测试结束"
}
# 主循环
while true; do
show_menu
read -r CHOICE
case $CHOICE in
1) show_current ;;
2) save_config ;;
3) restore_config ;;
4) restore_default ;;
5) setup_special_chars ;;
6) setup_serial_mode ;;
7) test_serial_terminal ;;
8)
echo "退出..."
exit 0
;;
*)
echo "无效选择"
;;
esac
done
#!/bin/bash
# 串口设备自动检测和配置
# 文件名:auto_detect_serial.sh
LOG_FILE="/var/log/serial_detection.log"
CONFIG_DIR="/etc/serial_configs"
# 创建配置目录
mkdir -p "$CONFIG_DIR"
# 日志函数
log() {
echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1" | tee -a "$LOG_FILE"
}
# 检测串口设备
detect_serial_devices() {
log "开始检测串口设备..."
# 查找所有串口设备
SERIAL_DEVICES=$(find /dev -name "ttyS*" -o -name "ttyUSB*" -o -name "ttyACM*" 2>/dev/null | sort)
if [ -z "$SERIAL_DEVICES" ]; then
log "未找到串口设备"
return 1
fi
log "找到以下串口设备:"
echo "$SERIAL_DEVICES" | while read -r DEVICE; do
if [ -c "$DEVICE" ]; then
log " $DEVICE"
fi
done
echo "$SERIAL_DEVICES"
}
# 测试串口设备
test_serial_device() {
local device="$1"
local baud_rates="9600 19200 38400 57600 115200"
log "测试设备: $device"
# 检查设备权限
if [ ! -r "$device" ] || [ ! -w "$device" ]; then
log " 警告: 设备 $device 权限不足"
sudo chmod 666 "$device" 2>/dev/null
if [ $? -ne 0 ]; then
log " 错误: 无法设置设备权限"
return 1
fi
fi
# 尝试不同波特率
for baud in $baud_rates; do
log " 测试波特率: $baud"
# 保存原始设置
OLD_SETTINGS=$(stty -F "$device" -g 2>/dev/null)
# 设置新参数
stty -F "$device" "$baud" cs8 -cstopb -parenb -crtscts -ixon -ixoff 2>/dev/null
if [ $? -eq 0 ]; then
# 发送测试命令
echo -e "AT\r\n" > "$device" 2>/dev/null
# 尝试读取响应(超时1秒)
timeout 1 cat "$device" 2>/dev/null | head -5 > "/tmp/serial_test_$$"
if [ -s "/tmp/serial_test_$$" ]; then
log " 成功: $baud 波特率工作正常"
log " 响应: $(cat "/tmp/serial_test_$$" | tr '\n' ' ')"
# 保存配置
save_serial_config "$device" "$baud"
# 恢复原始设置
if [ -n "$OLD_SETTINGS" ]; then
stty -F "$device" "$OLD_SETTINGS" 2>/dev/null
fi
rm -f "/tmp/serial_test_$$"
return 0
fi
fi
# 恢复原始设置
if [ -n "$OLD_SETTINGS" ]; then
stty -F "$device" "$OLD_SETTINGS" 2>/dev/null
fi
done
log " 失败: 未找到可用的波特率"
rm -f "/tmp/serial_test_$$"
return 1
}
# 保存串口配置
save_serial_config() {
local device="$1"
local baud="$2"
local config_file="$CONFIG_DIR/$(basename "$device").conf"
cat > "$config_file" << EOF
# 串口配置
# 设备: $device
# 检测时间: $(date)
# 推荐波特率: $baud
DEVICE="$device"
BAUD_RATE="$baud"
DATA_BITS="8"
STOP_BITS="1"
PARITY="none"
FLOW_CONTROL="none"
# 配置命令
stty -F "\$DEVICE" "\$BAUD_RATE" cs\$DATA_BITS -cstopb -parenb -crtscts -ixon -ixoff
# 使用示例
# 读取数据: cat "\$DEVICE"
# 发送数据: echo "命令" > "\$DEVICE"
EOF
log " 配置已保存: $config_file"
}
# 生成使用脚本
generate_usage_script() {
local script_file="/usr/local/bin/serial_manager"
cat > "$script_file" << 'EOF'
#!/bin/bash
# 串口设备管理器
# 自动生成的脚本
CONFIG_DIR="/etc/serial_configs"
show_help() {
echo "串口设备管理器"
echo "用法: $0 [选项]"
echo ""
echo "选项:"
echo " list 列出所有已配置的串口设备"
echo " config 配置指定设备"
echo " read 从指定设备读取数据"
echo " write 向指定设备写入数据"
echo " monitor 监控指定设备"
echo " help 显示此帮助信息"
}
list_devices() {
echo "已配置的串口设备:"
find "$CONFIG_DIR" -name "*.conf" -type f | while read -r config; do
device=$(grep "^DEVICE=" "$config" | cut -d'"' -f2)
baud=$(grep "^BAUD_RATE=" "$config" | cut -d'"' -f2)
echo " $device ($baud baud) - $config"
done
}
# 主程序
case "$1" in
list)
list_devices
;;
*)
show_help
;;
esac
EOF
chmod +x "$script_file"
log "使用脚本已生成: $script_file"
}
# 主函数
main() {
log "=== 串口设备自动检测开始 ==="
# 检测设备
DEVICES=$(detect_serial_devices)
if [ -z "$DEVICES" ]; then
log "没有找到可用的串口设备"
exit 1
fi
# 测试每个设备
WORKING_DEVICES=0
echo "$DEVICES" | while read -r DEVICE; do
if test_serial_device "$DEVICE"; then
WORKING_DEVICES=$((WORKING_DEVICES + 1))
fi
done
log "检测完成: 找到 $WORKING_DEVICES 个可用的串口设备"
# 生成使用脚本
generate_usage_script
log "=== 检测完成 ==="
log "详细日志: $LOG_FILE"
log "配置文件目录: $CONFIG_DIR"
}
# 执行主函数
main
# 错误:stty: /dev/ttyUSB0: Permission denied
# 原因:当前用户没有串口设备的读写权限
# 解决方案:
# 1. 使用sudo运行命令
sudo stty -F /dev/ttyUSB0 9600
# 2. 将用户添加到dialout组(推荐)
sudo usermod -a -G dialout $USER
# 注销重新登录生效
# 3. 修改设备权限(临时)
sudo chmod 666 /dev/ttyUSB0
# 4. 创建udev规则(永久)
sudo vi /etc/udev/rules.d/99-serial.rules
# 添加:
# SUBSYSTEM=="tty", ATTRS{idVendor}=="xxxx", ATTRS{idProduct}=="xxxx", MODE="0666"
# 或
# SUBSYSTEM=="tty", GROUP="dialout", MODE="0660"
# 重新加载udev规则
sudo udevadm control --reload-rules
sudo udevadm trigger
# 5. 检查当前权限
ls -la /dev/ttyUSB0
# 输出:crw-rw---- 1 root dialout 188, 0 Jan 1 12:00 /dev/ttyUSB0
# 问题:串口通信数据乱码或无法收到数据
# 原因:波特率、数据位、停止位、校验位不匹配
# 解决方案:
# 1. 检查设备两端的参数是否一致
# 两端必须使用相同的:波特率、数据位、停止位、校验位、流控
# 2. 尝试不同的波特率
for baud in 9600 19200 38400 57600 115200; do
echo "测试 $baud 波特率..."
stty -F /dev/ttyUSB0 $baud cs8 -cstopb -parenb
echo "AT" > /dev/ttyUSB0
sleep 0.1
done
# 3. 检查硬件连接
# 确保TX/RX交叉连接,GND连接
# 4. 使用minicom或screen测试
sudo apt-get install minicom
sudo minicom -D /dev/ttyUSB0 -b 9600
# 或使用screen
sudo screen /dev/ttyUSB0 9600
# 退出screen: Ctrl+A, 然后按K,然后按Y
# 5. 检查缓冲区设置
stty -F /dev/ttyUSB0 -icanon min 1 time 0
# 或使用原始模式
stty -F /dev/ttyUSB0 raw
# 6. 检查流控设置
# 禁用所有流控
stty -F /dev/ttyUSB0 -crtscts -ixon -ixoff
# 问题:终端显示异常,按键无反应
# 原因:stty设置不当导致终端进入异常状态
# 解决方案:
# 1. 恢复终端到合理状态(最常用)
stty sane
# 2. 重置所有设置
reset
# 或
tput reset
# 3. 如果键盘无响应,尝试:
# 先按Ctrl+J(换行),然后输入:
stty echo icanon
# 4. 恢复特殊字符默认值
stty intr ^C
stty quit ^\
stty erase ^?
stty kill ^U
stty eof ^D
# 5. 启用回显
stty echo
# 6. 退出原始模式
stty -raw
stty cooked
# 7. 如果完全无响应,尝试:
# 关闭当前终端,打开新终端
# 或使用SSH重新连接
# 错误:stty: /dev/ttyS0: No such device or address
# 原因:串口设备不存在或驱动程序未加载
# 解决方案:
# 1. 检查设备是否存在
ls -la /dev/ttyS* /dev/ttyUSB* /dev/ttyACM*
# 2. 检查内核模块
lsmod | grep -E "serial|usbserial|ftdi_sio|pl2303"
# 3. 加载串口驱动
sudo modprobe serial
sudo modprobe usbserial
sudo modprobe ftdi_sio # FTDI芯片
sudo modprobe pl2303 # Prolific芯片
sudo modprobe ch341 # CH341芯片
# 4. 检查dmesg日志
dmesg | grep -i tty
dmesg | grep -i usb
# 5. 重新插拔USB串口设备
# 查看插拔前后的dmesg输出
# 6. 检查虚拟串口
# 创建虚拟串口对
sudo socat -d -d pty,raw,echo=0 pty,raw,echo=0
# 会输出类似:/dev/pts/2 和 /dev/pts/3
# 7. 使用其他设备名
# 有些系统使用:
# /dev/ttyACM0 (CDC ACM设备)
# /dev/ttyXRUSB0 (Exar设备)
# /dev/ttyO0 (OMAP UART)
stty -a - 显示所有设置stty -g - 以stty格式显示stty size - 显示终端尺寸stty speed - 显示波特率stty sane - 恢复合理设置stty -echo - 禁用回显stty raw - 原始模式stty 9600 cs8 - 串口设置# 标准串口配置
stty -F /dev/ttyUSB0 9600 cs8 -cstopb -parenb -crtscts
# 原始模式串口通信
stty -F /dev/ttyS0 raw -echo
cat /dev/ttyS0
stty -g保存当前设置,便于恢复stty sane快速恢复混乱的终端dialout组避免权限问题stty -echo后记得恢复,否则看不到输入screen或minicom更可靠