使用printf函数通过串口能否输出彩色的调试信息

描述

前言

正常情况下,使用 printf 向串口打印调试信息,在串口调试工具界面只能看到一种颜色的字符,且使用不同的串口调试工具,字符默认的颜色都不一样。

如果你在 VSCode 上使用过 ESP-IDF 开发 ESP32 应用程序,你会发现其终端上输出的调试信息是五颜六色的,十分花哨。 而且不同类型的调试信息使用不同的颜色区分,能够快速地定位到程序中的问题,非常便捷实用。

那么我们使用 printf 函数通过串口能否输出彩色的调试信息呢? 答案是肯定的,只是需要一丢丢小技巧罢了。

ANSI 转义序列

在介绍如何打印彩色调试信息之前,我们先来了解一些背景知识 —— ANSI 转义序列。

我们将信息打印到终端上显示时,可以控制信息显示成粗体、斜体、下划线等形式,也可以控制字符显示不同的颜色。

例如执行如下代码,会在终端上显示红色 ---testing---:

printf("\\033[31m---testing---\\n");

为什么有些字符会被当做信息显示,有些字符会被当做命令处理? 其实这一切都归功于转义字符。

在C语言中,用反斜杠 "" 作为转义字符,正常情况下,"" 和 "n" 都是普通的字符,但是将这两个字符组合起来变成 "\\n" 的字符序列后,就表示换行符了。

在终端中也有类似的用法,只不过终端中的转义字符不是反斜杠 "" ,而是 "ESC"。 终端使用 "ESC" 作为转义字符,而 "ESC" 在 ASCII 表中的序号是 27,也就是 0x1b,因此终端中与 0x1b 组合起来的字符序列就会被转义成命令,不同的字符组合表示不同的终端命令,这些转义规则被规范化以后,就叫做 ANSI 转义序列(ANSI Escape Sequences), 主要用来控制终端上光标位置、颜色及其他选项。

ANSI 转义序列起始标志

ANSI 转义序列起始标志由两个字节组成,第一个字节是终端转义字符 "ESC" 也就是 0x1b,第二个字节的取值范围是0x40–0x5F(即 ASCII:@ A – Z [ \\ ] ^ _),也就是说 ANSI 转义序列的起始标志共有如下几种:

  • x1b@(ESC@)
  • x1bA(扫描)
  • x1b-(电调-)
  • x1bZ(ESCZ)
  • x1b[(ESC[)
  • x1b\\(ESC\\)
  • x1b](ESC])
  • x1b^(ESC^)
  • x1b_(ESC_)

上述那么多种起始标志,常见的起始标志就是 " x1b[ " ,其他的起始标志现在都很少用到了。

控制符起始标志 CSI

当 0x1b 与 "[" 组合时,就叫做控制符起始标志(Control Sequence Introducer),简称为 CSI ,其基本格式如下:

x1b[<code><tail>

code: 转义序列的具体内容,多个内容之间使用分号 ";" 隔开

tail : 转义序列结束标志,不同 tail 表示不同功能的序列

以 CSI 开头的转义序列有很多,不同的序列表示不同的终端指令,大致可以分为如下几类:

  • 字符渲染指令(SGR)
  • 光标移动指令
  • 清屏指令
  • 终端控制指令

字符渲染指令

字符渲指令(Select Graphic Rendition),简称为 SGR 。主要用于设置字符显示效果,其基本格式如下:

CSI编号

CSI:控制符起始标志 " 0x1b[ "

n :取值范围 0 ~ 107

m :转义序列结束标志,字母 m 作为结尾,表明是字符渲染序列

示例:

x1b[3m

n 的取值范围是 0 ~ 107,主要分为如下两类功能:

  • 字符样式控制
  • 字符颜色控制

n 的取值及说明:

n 功能 示例
0 重置/正常 x1b[0m 或 x1b[m
1 粗体或增加强度 x1b[1m
2 弱化(降低强度) x1b[2m
3 斜体 x1b[3m
4 下划线 x1b[4m
5 缓慢闪烁 ......
6 快速闪烁 ......
7 反显 ......
8 隐藏 ......
9 划除 ......
10 主要(默认)字体 ......
11–19 替代字体 ......
20 尖角体 ......
21 关闭粗体或双下划线 ......
22 正常颜色或强度 ......
23 非斜体、非尖角体 ......
24 关闭下划线 ......
25 关闭闪烁 ......
27 关闭反显 ......
28 关闭隐藏 ......
29 关闭划除 ......
30–37 设置前景色 ......
38 设置前景色 ......
39 默认前景色 ......
40–47 设置背景色 ......
48 设置背景色 ......
49 默认背景色 ......
51 Framed ......
52 Encircled ......
53 上划线 ......
54 Not framed or encircled ......
55 关闭上划线 ......
60 表意文字下划线或右边线 ......
61 表意文字双下划线或双右边线 ......
62 表意文字上划线或左边线 ......
63 表意文字双上划线或双左边线 ......
64 表意文字着重标志 ......
65 表意文字属性关闭 ......
90–97 设置明亮的前景色 ......
100–107 设置明亮的背景色 ......

有了上述这些背景知识,就足够搞懂串口输出彩色调试信息的原理了,关于 ANSI 转义序列的更多内容,感兴趣的小伙伴可以自行查阅。

串口输出彩色调试信息

在 《单片机 printf 重定向串口输出调试信息》这篇文章中介绍了如何使用 printf 通过串口输出调试信息,那么现在就在此基础上,再说说如何将输出的调试信息变成彩色的。

通过串口输出彩色调试信息有两个必要条件:

  • printf 参数列表中添加字符颜色控制相关的 ANSI转义序列
  • 接收串口数据的串口调试工具支持 ANSI 转义序列解析

回顾一下上面讲到的字符渲指令(SGR),其基本格式如下:

CSI n m

CSI:控制符起始标志 " 0x1b[ "

n :取值范围 0 ~ 107

m :转义序列结束标志,字母 m 作为结尾,表明是字符渲染序列

当我们想要输出不同颜色的字符时,将 n 替换成对应的数字即可,常见的颜色如下:

n 功能 示例
30 黑色 x1b[30m
31 红色 x1b[31m
32 绿色 x1b[32m
33 黄色 x1b[33m
34 蓝色 x1b[34m
35 品红 x1b[35m
36 青色 x1b[36m

使用 printf 打印 "Hello World" 代码如下:

printf("Hello World\\n");

打印不同的 "Hello World" 代码如下:

printf("\\x1b[31m" "Hello World\\n" "\\x1b[0m"); 
printf("\\x1b[32m" "Hello World\\n" "\\x1b[0m"); 
printf("\\x1b[33m" "Hello World\\n" "\\x1b[0m"); 
printf("\\x1b[34m" "Hello World\\n" "\\x1b[0m"); 
printf("\\x1b[35m" "Hello World\\n" "\\x1b[0m");
printf("\\x1b[36m" "Hello World\\n" "\\x1b[0m");

调试

注意事项

如果使用的串口调试工具不支持 ANSI 转义序列解析,那么接收到的串口数据会有部分乱码,而且只会使用工具默认的颜色显示信息:

调试

支持 ANSI 转义序列解析的串口调试工具才能正常显示彩色字符,推荐使用 MobaXterm 。

打开APP阅读更多精彩内容
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉

全部0条评论

快来发表一下你的评论吧 !

×
20
完善资料,
赚取积分