如何在Yocto(Hardknott)嵌入式系统中禁用指定串口控制台并将其用作普通串口
你之前尝试用systemctl stop/disable命令没成功,大概率是因为没处理全依赖项(比如服务自动重启、内核启动参数还绑定了该端口为控制台)。下面一步步帮你搞定:
1. 彻底停止并禁用对应的serial-getty服务
首先,你之前的命令里写错了端口名(用了ttyS0但实际是ttymxc0),而且光stop/disable可能不够,还需要mask防止服务被其他进程唤醒:
先确认当前运行的serial-getty服务:
systemctl list-units | grep serial-getty你应该能看到
serial-getty@ttymxc0.service和serial-getty@ttymxc1.service停止目标服务:
systemctl stop serial-getty@ttymxc0.service禁用开机自动启动:
systemctl disable serial-getty@ttymxc0.service关键:mask服务,防止被其他系统进程自动拉起:
systemctl mask serial-getty@ttymxc0.service验证状态,确保服务处于inactive/masked状态:
systemctl status serial-getty@ttymxc0.service
2. 修改内核启动参数,移除该端口的console绑定
即使停了getty服务,内核如果还把ttymxc0设为控制台,系统还是会往这个端口输出日志,干扰串口通信。
查看当前内核启动参数:
cat /proc/cmdline你会看到类似
console=ttymxc0,115200 console=ttymxc1,115200 ...的内容修改启动参数(以U-Boot为例,Yocto嵌入式系统大多用U-Boot):
- 重启系统进入U-Boot命令行(通常按任意键打断启动)
- 设置新的bootargs,只保留
ttymxc1作为控制台:
注意:setenv bootargs 'console=ttymxc1,115200 root=/dev/mmcblk0p2 rootwait rw'root=/dev/mmcblk0p2要换成你系统实际的根分区设备 - 保存环境变量:
saveenv - 重启系统:
boot
如果你的系统用GRUB,修改/boot/grub/grub.cfg中的启动参数,移除ttymxc0的console项,然后更新GRUB配置。
3. 验证串口可用性
重启后,你可以用shell命令测试串口:
配置串口参数(以115200波特率、8N1为例):
stty -F /dev/ttymxc0 115200 cs8 -cstopb -parenb测试发送:
echo "Test serial communication" > /dev/ttymxc0另一端用串口工具连接
ttymxc0,应该能收到这条消息。测试接收:
cat /dev/ttymxc0从另一端发送数据,终端会打印出接收的内容。
如果遇到权限问题,把当前用户加入dialout组:
usermod -aG dialout your_username
重新登录后生效。
4. C代码操作串口示例
如果需要用C程序实现串口通信,这里有个简单的示例(配置115200 8N1,支持读写):
#include <stdio.h> #include <stdlib.h> #include <fcntl.h> #include <termios.h> #include <unistd.h> #include <string.h> int serial_open(const char *port, speed_t baud_rate) { int fd = open(port, O_RDWR | O_NOCTTY | O_NDELAY); if (fd == -1) { perror("Failed to open serial port"); return -1; } struct termios options; if (tcgetattr(fd, &options) != 0) { perror("Failed to get serial attributes"); close(fd); return -1; } // 设置波特率 cfsetispeed(&options, baud_rate); cfsetospeed(&options, baud_rate); // 配置8位数据位、无校验、1位停止位 options.c_cflag &= ~PARENB; options.c_cflag &= ~CSTOPB; options.c_cflag &= ~CSIZE; options.c_cflag |= CS8; // 禁用硬件流控,启用读取和本地模式 options.c_cflag &= ~CRTSCTS; options.c_cflag |= CREAD | CLOCAL; // 禁用规范模式、回显、信号 options.c_lflag &= ~ICANON; options.c_lflag &= ~ECHO; options.c_lflag &= ~ECHOE; options.c_lflag &= ~ISIG; // 禁用软件流控 options.c_iflag &= ~(IXON | IXOFF | IXANY); // 原始输出模式 options.c_oflag &= ~OPOST; // 设置接收超时:至少读1个字符,无超时 options.c_cc[VMIN] = 1; options.c_cc[VTIME] = 0; if (tcsetattr(fd, TCSANOW, &options) != 0) { perror("Failed to set serial attributes"); close(fd); return -1; } return fd; } int main() { const char *serial_port = "/dev/ttymxc0"; int fd = serial_open(serial_port, B115200); if (fd == -1) { return 1; } // 发送测试数据 const char *send_data = "Hello from C program!\n"; ssize_t bytes_written = write(fd, send_data, strlen(send_data)); if (bytes_written == -1) { perror("Failed to write to serial port"); close(fd); return 1; } printf("Sent %zd bytes: %s", bytes_written, send_data); // 接收数据 char recv_buf[256]; ssize_t bytes_read = read(fd, recv_buf, sizeof(recv_buf)-1); if (bytes_read > 0) { recv_buf[bytes_read] = '\0'; printf("Received %zd bytes: %s", bytes_read, recv_buf); } else if (bytes_read == -1) { perror("Failed to read from serial port"); } close(fd); return 0; }
编译命令:
gcc serial_comm.c -o serial_comm
运行程序:
./serial_comm
内容的提问来源于stack exchange,提问作者H2O

