Linux shell中设置串口参数
在Linux shell中,可以使用多种工具和命令来配置串口参数,主要包括stty、setserial和ioctl系统调用。
1. 使用stty命令
stty是最常用的终端配置工具,可以设置串口参数。
基本语法
bash
stty -F <设备文件> <参数>
常用参数设置
设置波特率
bash
# 设置波特率为115200
stty -F /dev/ttyS0 115200
# 设置波特率为9600
stty -F /dev/ttyUSB0 9600
设置数据位、停止位、校验位
bash
# 8位数据位,1位停止位,无校验
stty -F /dev/ttyS0 cs8 -cstopb -parenb
# 7位数据位,1位停止位,偶校验
stty -F /dev/ttyS0 cs7 -cstopb parenb -parodd
# 7位数据位,2位停止位,奇校验
stty -F /dev/ttyS0 cs7 cstopb parenb parodd
设置流控制
bash
# 启用硬件流控制(RTS/CTS)
stty -F /dev/ttyS0 crtscts
# 禁用硬件流控制
stty -F /dev/ttyS0 -crtscts
# 启用软件流控制(XON/XOFF)
stty -F /dev/ttyS0 ixon ixoff
# 禁用软件流控制
stty -F /dev/ttyS0 -ixon -ixoff
其他重要设置
bash
# 设置原始模式(禁用所有处理)
stty -F /dev/ttyS0 raw
# 设置规范模式(启用行编辑)
stty -F /dev/ttyS0 -raw
# 禁用回显
stty -F /dev/ttyS0 -echo
# 启用回显
stty -F /dev/ttyS0 echo
# 设置最小读取字符数和超时(非规范模式)
stty -F /dev/ttyS0 min 0 time 10 # 0个字符,1秒超时
stty -F /dev/ttyS0 min 1 time 0 # 至少1个字符,无超时
查看当前设置
bash
# 查看所有设置
stty -F /dev/ttyS0 -a
# 查看特定设置
stty -F /dev/ttyS0
完整配置示例
bash
#!/bin/bash
# 配置串口为115200波特率,8N1,无流控制,原始模式
SERIAL_PORT="/dev/ttyUSB0"
BAUDRATE="115200"
# 配置基本参数
stty -F $SERIAL_PORT $BAUDRATE cs8 -cstopb -parenb
stty -F $SERIAL_PORT -crtscts -ixon -ixoff
# 设置原始模式,禁用回显
stty -F $SERIAL_PORT raw -echo
# 设置非阻塞读取
stty -F $SERIAL_PORT -icanon min 0 time 0
echo "串口 $SERIAL_PORT 已配置为 $BAUDRATE 8N1"
2. 使用setserial命令
setserial用于设置串口硬件参数,通常需要root权限。
基本语法
bash
setserial <设备文件> [参数]
常用参数
bash
# 查看串口信息
setserial -g /dev/ttyS[0-3]
# 设置UART类型
setserial /dev/ttyS0 uart 16550A
# 设置I/O端口地址
setserial /dev/ttyS0 port 0x3f8
# 设置IRQ
setserial /dev/ttyS0 irq 4
# 设置自动配置
setserial /dev/ttyS0 autoconfig
# 保存设置
setserial /dev/ttyS0 -a
3. 使用ioctl系统调用(C程序)
通过C程序直接调用ioctl系统调用设置串口参数。
示例程序
c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <termios.h>
#include <errno.h>
#include <string.h>
int set_serial_port(const char *port, speed_t baudrate) {
int fd;
struct termios options;
// 打开串口
fd = open(port, O_RDWR | O_NOCTTY | O_NDELAY);
if (fd < 0) {
perror("无法打开串口");
return -1;
}
// 获取当前设置
if (tcgetattr(fd, &options) < 0) {
perror("获取串口设置失败");
close(fd);
return -1;
}
// 设置输入输出波特率
cfsetispeed(&options, baudrate);
cfsetospeed(&options, baudrate);
// 8N1设置
options.c_cflag &= ~CSIZE;
options.c_cflag |= CS8;
options.c_cflag &= ~PARENB;
options.c_cflag &= ~CSTOPB;
// 无硬件流控制
options.c_cflag &= ~CRTSCTS;
// 启用接收器,忽略调制解调器状态
options.c_cflag |= (CLOCAL | CREAD);
// 原始输入
options.c_iflag &= ~(IGNBRK | BRKINT | PARMRK | ISTRIP
| INLCR | IGNCR | ICRNL | IXON);
// 原始输出
options.c_oflag = 0;
// 无本地处理
options.c_lflag = 0;
// 非规范模式,立即返回
options.c_cc[VTIME] = 0;
options.c_cc[VMIN] = 0;
// 应用设置
if (tcsetattr(fd, TCSANOW, &options) < 0) {
perror("设置串口参数失败");
close(fd);
return -1;
}
// 清空缓冲区
tcflush(fd, TCIOFLUSH);
return fd;
}
4. 使用Python(pyserial库)
python
#!/usr/bin/env python3
import serial
import serial.tools.list_ports
# 配置串口参数
ser = serial.Serial(
port='/dev/ttyUSB0', # 串口设备
baudrate=115200, # 波特率
bytesize=serial.EIGHTBITS, # 数据位:8
parity=serial.PARITY_NONE, # 校验位:无
stopbits=serial.STOPBITS_ONE, # 停止位:1
timeout=1, # 读取超时(秒)
xonxoff=False, # 软件流控制
rtscts=False, # 硬件流控制
dsrdtr=False # DSR/DTR流控制
)
# 或者逐个设置
ser = serial.Serial()
ser.port = '/dev/ttyS0'
ser.baudrate = 9600
ser.bytesize = serial.SEVENBITS
ser.parity = serial.PARITY_EVEN
ser.stopbits = serial.STOPBITS_TWO
ser.timeout = 0.5
ser.xonxoff = True
ser.rtscts = False
ser.open()
# 列出可用串口
ports = serial.tools.list_ports.comports()
for port in ports:
print(f"{port.device}: {port.description}")
5. Shell脚本示例
完整的串口配置脚本
bash
#!/bin/bash
# serial_config.sh
# 配置参数
PORT=${1:-"/dev/ttyUSB0"}
BAUD=${2:-115200}
DATABITS=${3:-8}
PARITY=${4:-"none"}
STOPBITS=${5:-1}
FLOW=${6:-"none"}
# 校验位映射
case $PARITY in
"none") PARITY_FLAGS="-parenb" ;;
"odd") PARITY_FLAGS="parenb parodd" ;;
"even") PARITY_FLAGS="parenb -parodd" ;;
*) echo "无效的校验位: $PARITY"; exit 1 ;;
esac
# 数据位映射
case $DATABITS in
5) DATABIT_FLAGS="cs5" ;;
6) DATABIT_FLAGS="cs6" ;;
7) DATABIT_FLAGS="cs7" ;;
8) DATABIT_FLAGS="cs8" ;;
*) echo "无效的数据位: $DATABITS"; exit 1 ;;
esac
# 停止位映射
if [ "$STOPBITS" = "2" ]; then
STOPBIT_FLAGS="cstopb"
else
STOPBIT_FLAGS="-cstopb"
fi
# 流控制映射
case $FLOW in
"none") FLOW_FLAGS="-crtscts -ixon -ixoff" ;;
"hardware") FLOW_FLAGS="crtscts -ixon -ixoff" ;;
"software") FLOW_FLAGS="-crtscts ixon ixoff" ;;
*) echo "无效的流控制: $FLOW"; exit 1 ;;
esac
# 检查设备是否存在
if [ ! -c "$PORT" ]; then
echo "错误: 设备 $PORT 不存在"
exit 1
fi
# 应用设置
echo "配置串口 $PORT:"
echo " 波特率: $BAUD"
echo " 数据位: $DATABITS"
echo " 校验位: $PARITY"
echo " 停止位: $STOPBITS"
echo " 流控制: $FLOW"
stty -F $PORT $BAUD $DATABIT_FLAGS $STOPBIT_FLAGS $PARITY_FLAGS $FLOW_FLAGS raw -echo -icanon
# 验证设置
echo -e "\n当前设置:"
stty -F $PORT -a | grep -E "speed|cs[0-9]|parenb|parodd|cstopb|crtscts|ixon|ixoff"
# 设置权限(可选)
# sudo chmod 666 $PORT
交互式串口配置脚本
bash
#!/bin/bash
# interactive_serial_config.sh
# 列出可用串口
echo "可用串口:"
ls /dev/ttyS* /dev/ttyUSB* /dev/ttyACM* 2>/dev/null
# 选择串口
read -p "输入串口设备: " PORT
# 选择波特率
echo "常用波特率:"
echo "1) 9600"
echo "2) 19200"
echo "3) 38400"
echo "4) 57600"
echo "5) 115200"
echo "6) 230400"
echo "7) 自定义"
read -p "选择波特率 [1-7]: " BAUD_CHOICE
case $BAUD_CHOICE in
1) BAUD=9600 ;;
2) BAUD=19200 ;;
3) BAUD=38400 ;;
4) BAUD=57600 ;;
5) BAUD=115200 ;;
6) BAUD=230400 ;;
7) read -p "输入自定义波特率: " BAUD ;;
*) BAUD=115200 ;;
esac
# 应用配置
stty -F $PORT $BAUD cs8 -cstopb -parenb -crtscts raw -echo
echo "串口 $PORT 已配置为 $BAUD 8N1"
echo "按Ctrl+C退出"
# 简单终端
cat $PORT &
CAT_PID=$!
trap "kill $CAT_PID 2>/dev/null" EXIT
while true; do
read -p "> " INPUT
echo -e "$INPUT" > $PORT
done
6. 其他实用命令
查看串口信息
bash
# 查看所有串口设备
dmesg | grep tty
# 查看串口详细信息
udevadm info -a -n /dev/ttyS0
# 查看串口驱动信息
cat /proc/tty/driver/serial
设置权限
bash
# 添加用户到dialout组
sudo usermod -a -G dialout $USER
# 临时更改权限
sudo chmod 666 /dev/ttyUSB0
# 永久设置udev规则
echo 'KERNEL=="ttyUSB*", MODE="0666"' | sudo tee /etc/udev/rules.d/50-usb-serial.rules
sudo udevadm control --reload-rules
测试串口
bash
# 发送测试数据
echo "test" > /dev/ttyS0
# 接收数据(显示十六进制)
cat -v < /dev/ttyS0
# 十六进制转储
od -x < /dev/ttyS0
# 使用screen作为简单终端
screen /dev/ttyS0 115200
7. 常见问题解决
权限问题
bash
# 检查当前用户组
groups
# 添加用户到dialout组
sudo gpasswd -a $USER dialout
# 需要重新登录生效
设备忙问题
bash
# 查看占用进程
lsof /dev/ttyS0
# 强制释放设备
fuser -k /dev/ttyS0
保存和恢复设置
bash
# 保存当前设置
stty -F /dev/ttyS0 -g > serial_settings.txt
# 恢复设置
stty -F /dev/ttyS0 $(cat serial_settings.txt)
这些shell命令和脚本提供了灵活的方式来配置Linux串口参数,可以根据具体需求进行组合和调整。