如何将嵌入式串口打印信息重定向telnet/ssh界面

本文介绍了如何在嵌入式Linux系统中,将串口的调试信息实时重定向到远程telnet或ssh登录的终端界面,以方便查看程序的实时打印信息,同时避免因程序重启而破坏问题现场。

概述

在嵌入式Linux系统中,有时通过远程(telnet或者ssh)登录到现场设备,想看程序的实时打印的调试信息,需要将输出到串口的调试信息重定向到当前登录的终端界面上。

也可以将程序重新启动到当前终端界面,但是在程序出现问题时,如果重启程序,可能会破坏了问题现场,再查找问题就不好查找了。

下面是实现的代码,可以将输出到串口的日志信息,重定向到当前的telnet或者ssh界面上,是不是很神奇!

实现代码

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <unistd.h>

int main(int argc, char *argv[
当通过 **串口(UART)打印日志信息太快**,导致你 **无法输入命令或调试交互受阻** 时,这是一个非常常见的嵌入式开发问题。根本原因是:**日志输出持续占用串口通道,淹没用户输入机会**。 --- ## ✅ 问题本质分析 - 串口通常是 **半双工或全双工异步通信**,但终端工具(如 `minicom`、`putty`、`screen`、`Tera Term`)只能在一个窗口显示输出和接收输入。 - 当设备疯狂打印日志(比如每毫秒一条),你的键盘输入还没敲完,就被新的日志刷屏了。 - 结果:你看不到自己输入的内容,命令也发不上去。 --- ## ✅ 解决方案汇总(从易到难) ### ✅ 方案 1:【最推荐】使用不同串口分离“日志”与“交互” > 将系统分为两个 UART 接口: - **UART0**:专用于高速日志输出(接逻辑分析仪或只读终端) - **UART1**:专用于 Shell / 命令行交互(你用来输入命令) ```c // 示例(伪代码) init_uart0_for_logging(); // 日志走这里,狂打不停 init_uart1_for_shell(); // 用户命令走这里 while (1) { if (uart1_has_input()) { parse_and_exec_command(); } } ``` 📌 **优点**:彻底解决冲突 📌 **适用场景**:MCU 至少有两个 UART(如 STM32、ESP32、Linux 板卡等) --- ### ✅ 方案 2:动态控制日志级别(Log Level 控制) 在代码中加入日志等级机制,运行时可通过命令关闭/降低日志量。 #### 实现示例: ```c typedef enum { LOG_SILENT, LOG_ERROR, LOG_WARN, LOG_INFO, LOG_DEBUG, LOG_VERBOSE } log_level_t; log_level_t current_log_level = LOG_INFO; // 默认只打印 INFO 及以上 #define LOG_DEBUG(fmt, ...) \ do { \ if (current_log_level >= LOG_DEBUG) { \ printf("[DEBUG] " fmt "\n", ##__VA_ARGS__); \ } \ } while(0) #define LOG_INFO(fmt, ...) \ do { \ if (current_log_level >= LOG_INFO) { \ printf("[INFO] " fmt "\n", ##__VA_ARGS__); \ } \ } while(0) ``` #### 提供命令来调整日志等级: ```c void cmd_set_loglevel(int argc, char **argv) { if (argc < 2) { printf("Usage: loglevel <silent|error|warn|info|debug|verbose>\n"); return; } if (strcmp(argv[1], "silent") == 0) current_log_level = LOG_SILENT; else if (strcmp(argv[1], "error") == 0) current_log_level = LOG_ERROR; else if (strcmp(argv[1], "warn") == 0) current_log_level = LOG_WARN; else if (strcmp(argv[1], "info") == 0) current_log_level = LOG_INFO; else if (strcmp(argv[1], "debug") == 0) current_log_level = LOG_DEBUG; else if (strcmp(argv[1], "verbose") == 0) current_log_level = LOG_VERBOSE; else printf("Invalid level\n"); printf("Log level set to %d\n", current_log_level); } ``` 📌 使用方式: ``` > loglevel silent ← 关闭所有日志 [不再刷屏] > your_command_here ← 现在可以正常输入 > loglevel info ← 恢复部分日志 ``` --- ### ✅ 方案 3:添加“暂停日志”快捷键(Break Key 或特殊字符) 让设备监听一个特殊输入(例如连续按 3 次 `~` 或 `ESC`),进入“命令模式”,暂停日志输出。 #### 示例逻辑: ```c int break_count = 0; void uart_rx_handler(char c) { if (c == '~') { break_count++; if (break_count >= 3) { printf("\n*** LOG PAUSED. ENTER COMMAND MODE ***\n"); current_log_level = LOG_SILENT; // 暂停日志 enter_command_mode(); // 进入命令行等待 current_log_level = LOG_INFO; // 退出后恢复 break_count = 0; } } else { break_count = 0; } } ``` 📌 用户操作:快速敲 `~~~` → 进入命令模式,此时无日志干扰。 --- ### ✅ 方案 4:使用硬件流控(RTS/CTS) 如果你的串口支持 **硬件流控(Hardware Flow Control)**,可以让接收端(PC)告诉发送端(设备):“我现在忙,别发了”。 - PC 终端软件开启 RTS/CTS(如 Tera Term、SecureCRT) - 当终端缓冲区满时,自动拉高 CTS,设备停止发送 - 避免数据丢失,也能让你看清输入内容 🔧 配置方法(以 Tera Term 为例): - 打开串口设置 → Flow control → 选择 `RTS/CTS` 📌 要求:设备端必须支持流控引脚,并正确连接。 --- ### ✅ 方案 5:改用更高级的调试方式替代串口刷屏 | 替代方案 | 说明 | |--------|------| | **JTAG/SWD + RTT (Real Time Transfer)** | 使用 SEGGER J-Link + RTT,日志和输入完全独立,速度极快,推荐! | | **网络调试(Telnet / SSH / WebSocket)** | 设备联网后提供远程 shell,日志可重定向到文件,不影响命令行 | | **日志写入 Flash 或 SD 卡** | 不走串口,事后读取 | 📌 推荐组合:**RTT for logging + UART for fallback** --- ### ✅ 方案 6:优化日志本身(减少冗余输出) 很多性能问题是由于低效日志造成的: ❌ 错误做法: ```c while (1) { printf("loop running, x=%d, y=%d\n", x, y); // 每次都打印 } ``` ✅ 正确做法: ```c static int last_x = -1, last_y = -1; if (x != last_x || y != last_y) { LOG_DEBUG("x=%d, y=%d", x, y); last_x = x; last_y = y; } ``` 或者加时间间隔限制: ```c static uint32_t last_print = 0; if (millis() - last_print > 1000) { // 每秒最多一次 LOG_INFO("Status update..."); last_print = millis(); } ``` --- ## 🧩 总结:应对策略对比表 | 方法 | 是否推荐 | 适用场景 | 备注 | |------|----------|-----------|-------| | 分离串口(日志 vs 命令) | ⭐⭐⭐⭐⭐ | 多 UART 设备 | 最彻底解决方案 | | 动态日志等级控制 | ⭐⭐⭐⭐☆ | 所有嵌入式系统 | 必备功能 | | 快捷键暂停日志 | ⭐⭐⭐☆☆ | 交互式调试 | 易实现 | | 硬件流控 RTS/CTS | ⭐⭐⭐☆☆ | 支持流控的硬件 | 需接线正确 | | 使用 RTT / 网络调试 | ⭐⭐⭐⭐⭐ | 高级调试 | 效率最高 | | 减少日志频率 | ⭐⭐⭐⭐☆ | 所有情况 | 应该默认做 | ---
评论 4
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值