JLink RTT功能介绍和使用

前言

在学习嵌入式开发以及参与RoboMaster的过程中,调试一直是一件繁琐而又不得不去做的事。

初学的时候,我们学习过UART串口,但在实际使用中,串口的速率实在捉襟见肘,并且在发送过快时,前面的数据尚未发出,后面的数据又接踵而至,不仅数据没发出来,少量接收到的数据也完全损坏不能使用。

除此以外,部分开发版根本没有预留用来调试的串口,在这种情况下调试更是一种折磨。此刻我们迫切地希望有工具能解决这个问题,而这个工具就是RTT(Real Time Transfer)

RTT的介绍

RTTSEGGER公司开发的一种技术,它允许在嵌入式应用程序中进行系统监控和交互式用户输入/输出。

相对于其他方案,RTT的优势很大:

  • 无需额外的接口,仅仅使用最基础的SWDIOSWCLK便能使用。
  • 速度十分快,几乎没有任何性能开销,因为其工作方式就是读写内存。
  • 双向通信,主机与MCU之间可以互相收发数据。
  • 多通道支持

RTT的原理就是RTT库在RAM中创建了一个名为SEGGER RTT Control Block的控制块结构。在发送和读取数据时,本质上是对这块区域进行写和读。

RTT的使用

RTT库的导入

首先我们需要到JLink驱动的安装目录下的Samples文件夹中,在我的电脑上,这一路径为C:\Program Files\SEGGER\JLink\Samples

在这个文件夹内部,有一个名为RTT的文件夹。新版的JLink驱动中没有这个文件夹,可以卸载然后安装旧版驱动来使用。

RTT文件夹中有一个压缩包,解压,然后将其中的Config文件夹和RTT文件夹复制到自己的项目下,并添加到项目资源。此时便可以使用了。

RTT库的用法

在需要使用到RTT的地方,导入SEGGER_RTT.h。在调用RTTAPI时,其会自动检测RTT是否初始化并进行初始化,所以不用显性的调用SEGGER_RTT_Init函数进行初始化。

发送

RTT一共有三种向终端发送数据的方式,分别为SEGGER_RTT_WriteSEGGER_RTT_WriteStringSEGGER_RTT_printf

说是发送其实并不准确,实际上是将数据写入到上行缓冲区。

如同函数名,这三者分别为将字节、字符串、以及格式化字符串写入到缓冲区。示例代码如下:

1
2
3
4
uint8_t bytes[] = "Hello, World from SEGGER_RTT_Write!\n";
SEGGER_RTT_Write(0, bytes, strlen(bytes));
SEGGER_RTT_WriteString(0, "Hello, World from SEGGER_RTT_WriteString!\n");
SEGGER_RTT_printf(0, "Hello, World from SEGGER_RTT_printf on %d/%d/%d!\n", year, month, day);

将数据写入到缓冲区后,主机会读取缓冲区数据。

添加printf对浮点数的输出支持

RTT库提供的SEGGER_RTT_printf函数默认并不支持浮点数,我们可以手动为其加上相关支持。

我们在库文件中找到SEGGER_RTT_printf.c文件。在其中的SEGGER_RTT_vprintf函数中的switch-case语句块的末尾,加上如下代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
case 'f':
case 'F':{
float fv;
fv = (float)va_arg(*pParamList, double);

// 输出负号
if (fv < 0) _StoreChar(&BufferDesc, '-');

v = abs((int)fv);

_PrintInt(&BufferDesc, v, 10u, NumDigits, FieldWidth, FormatFlags); // 输出整数部分
_StoreChar(&BufferDesc, '.'); // 小数点

// 输出小数部分(3位小数)
// 若需要修改小数位数,修改下面`1000`和`3`这两个常数即可。
// 例如修改为两位小数,只需要将`1000`改为`10^2`=`100`,将`3`改为`2`即可。
v = abs((int)(fv * 1000));
v = v % 1000;
_PrintInt(&BufferDesc, v, 10u, 3, FieldWidth, FormatFlags);

break;
}
带有颜色的字符串输出

接收

接收和发送类似,也存在一个下行缓冲区。与接收相关的函数分别为SEGGER_RTT_Read()SEGGER_RTT_HasKey()SEGGER_RTT_GetKey()

如同函数名,其作用分别为将下行缓冲区的数据读入、检测下行缓冲区是否有数据以及获取其中的一位数据。
可以从下面的两个例子中了解其用法。

1
2
3
4
5
6
char acIn[4];
unsigned NumBytes = sizeof(acIn);
NumBytes = SEGGER_RTT_Read(0, &acIn[0], NumBytes); // SEGGER_RTT_Read函数的返回值为缓冲区中的有效位数。
if (NumBytes) {
AnalyzeInput(acIn);
}
1
2
3
if (SEGGER_RTT_HasKey()) {
int c = SEGGER_RTT_GetKey();
}

终端切换

其他


JLink RTT功能介绍和使用
https://blog.faneter.top/2026/03/04/JLink-RTT功能介绍和使用/
作者
Faneter
发布于
2026年3月4日
许可协议