MCU:STM32F407VE
MDK:5.29
IAR:8.32
目录--点击可快速直达
目录
- 写在前面
- 什么是RTT?
- RTT的工作原理
- RTT的性能
- 快速使用教程
- 高级使用教程
- 附上测试代码
- 2019年12月27日更新--增加打印float的功能
写在前面
本文介绍了J-Link RTT的部分使用内容,很多地方参考和使用了J-Link的官方资料,有的地方可能翻译的不太准确,请见谅。
如果想了解更加准确详细的内容,请点此处。
什么是RTT?
RTT(Real Time Transfer)是一种用于嵌入式中与用户进行交互的技术,它结合了SWO和半主机的优点,具有极高的性能。
使用RTT可以从MCU非常快速输出调试信息和数据,且不影响MCU实时性。这个功能可以用于很多支持J-Link的设备和MCU,兼容性强。
RTT支持两个方向的多个通道,上到主机,下到目标,它可以用于不同的目的,为用户提供尽可能多的自由。默认实现每个方向使用一个通道,用于可打印终端输入和输出。
使用J-Link RTT Viewer,可用于“虚拟”终端,允许打印到多个窗口(例如,一个用于标准输出,一个对于错误输出,一个用于调试输出)。
RTT的工作原理
RTT在MCU的存储器中使用SEGGER RTT控制块结构管理数据读写。控制块对于每个可用的信道都在内存中包含了一个ID,通过J-Link或者环形缓冲结构区(链表)都可以通过ID找到对应的控制块。
可用信道的最大数目可以在编译时配置,并且每个缓冲区都可以在MCU运行时配置和使用。上下缓冲区可以分开处理。每个通道都可以配置为阻塞或非阻塞。
在阻塞模式下,应用程序将等待缓冲区写满,直到可以写入所有内存为止,这将导致应用程序处于阻塞状态,但可以防止数据丢失。
在非阻塞模式下,只会写入适合缓冲区的数据,或完全不写入缓冲区,其余的数据将被丢弃。这样即使没有连接调试器,也可以实时运行。开发人员不必创建特殊的调试版本,并且代码可以保留在发布应用程序中。
RTT的性能
RTT的性能明显高于其他任何用于将数据输出到主机PC的方式。平均一行文本可以在1微秒或更短的时间内输出。基本上相当于做一个memcopy()的时间。
RTT实现代码使用大约500字节的ROM和(n(通道数) * (24字节ID+24字节))的RAM。推荐的大小是1 kByte(上行信道)和16到32字节(下行信道),这取决于输入/输出的负载。
快速使用教程
1.首先安装J-Link的软件驱动。
2.安装完成后,打开J-Link的安装目录(开始->SEGGR->J-Link RTT Viewer->右键打开文件所在位置->然后继续右键打开文件所在位置->此时就是安装目录了),
找到如下路径SEGGER\JLink_V632f\Samples\RTT
,解压路径里面的压缩包SEGGER_RTT_V632f.zip
(不同的版本,V后面的数字可能不一样)。
3.将解压完的文件拷贝到代码工程目录中。
4.在项目工程中加入SEGGER_RTT_V632f\RTT
目录下的全部四个文件。工程添加文件方法请自行百度。
5.工程加入文件后,在想要用到RTT的文件中包含#include "SEGGER_RTT.h"
,然后直接调用SEGGER_RTT_printf()
就好了,
例如SEGGER_RTT_printf(0,"hello world!")
这个和C语言的printf的格式差不多,就是前面加了一个端口0
的参数。(详细信息请看高级使用教程)
6.然后点击开始->SEGGR->J-Link RTT Viewer,打开J-Link RTT Viewer 选择好你的芯片型号后,点击确认。
7.然后就能看到我们打印的内容了。
高级使用教程
1.部分函数介绍:
(1)void SEGGER_RTT_Init (void)
RTT初始化函数,应放于程序开始阶段。
(2)int SEGGER_RTT_GetKey (void);
从RTT终端获取一个按键字符。
Return Value
Value | Meaning |
---|---|
>=0 | 返回按键字符(0-255) |
< 0 | 缓存区中没有有效的字符 |
示例代码:
-
int c;
-
c
= SEGGER_RTT_GetKey();
-
if (c
=
=
'q') {
-
exit();
-
}
(3)int SEGGER_RTT_HasKey (void);
检测缓存区中是否还有字符。
Return Value
Value | Meaning |
---|---|
1 | 缓存区中至少有一个字符是有效的 |
0 | 缓存区中没有有效的字符 |
示例代码:
-
if (SEGGER_RTT_HasKey()) {
-
int c = SEGGER_RTT_GetKey();
-
}
(4)int SEGGER_RTT_printf (unsigned BufferIndex, const char * sFormat, …)
格式化输出字符串
Return Value
Value | Meaning |
---|---|
>=0 | 已经发送的字符数 |
< 0 | 发生错误 |
附加信息:
转换规范具有以下语法:
%[标志][字段宽度][.精度]转换指定程序
支持的标志:
-:在字段宽度内左对齐
+:始终打印有符号转换的符号扩展名
0:用0代替空格。使用“-”标志或精度时忽略
支持的转换说明符:
c:将参数打印为一个字符
d:将参数打印为有符号整数
u:将参数打印为无符号整数
x:将参数打印为十六进制整数
s:打印参数指向的字符串
p:将参数打印为8位十六进制整数。
ps.似乎官方没有给float类型格式化输出方式。
示例代码:
SEGGER_RTT_printf(0, "SEGGER RTT Sample. Uptime: %.10dms.", /*OS_Time*/ 890912);
同时,可以使用SEGGER_RTT_printf()
来设置字体颜色还背景颜色:
例如:
-
SEGGER_RTT_printf(
0,RTT_CTRL_BG_WHITE);
-
SEGGER_RTT_printf(
0,RTT_CTRL_TEXT_BLUE);
(5)void SEGGER_RTT_SetTerminal(char TerminalId);
设置虚拟终端ID。
Return Value
Parameter | Meaning |
---|---|
TerminalId | 虚拟终端的ID |
示例代码:
-
/
/
-
/
/
Send a
string
to terminal
1 which
is used
as
error out.
-
/
/
-
SEGGER_RTT_SetTerminal(
1);
/
/
Select terminal
1
-
SEGGER_RTT_WriteString(
0,
"ERROR: Buffer overflow");
-
SEGGER_RTT_SetTerminal(
0);
/
/
Reset
to
standard terminal
SEGGER_RTT_WriteString中的0参数,是通道号,不是终端号。
(6)int SEGGER_RTT_WaitKey (void);
检测缓存区中是否还有字符。
Return Value
Value | Meaning |
---|---|
≥0 | 等待返回一个按键值 |
示例代码:
-
int c
=
0;
-
do {
-
c
= SEGGER_RTT_WaitKey();
-
} while (c !
=
'c');
附上测试代码
-
/
*terminal
0:
if you press
any
key
in the keyboard ,terminal
0 will show the
key
value witch you press.
-
terminal
1: show the
date
-
terminal
2: show the
time
-
*
/
-
if (SEGGER_RTT_HasKey())
-
{
-
int c
= SEGGER_RTT_GetKey();
-
SEGGER_RTT_SetTerminal(
0);
-
SEGGER_RTT_
Write (
0,
&c,
1);
-
SEGGER_RTT_printf(
0,
"\n");
-
}
-
/
/
GET
DATA
-
HAL_RTC_GetTime(
&hrtc,
&_current_
time,RTC_
FORMAT_BIN);
-
/
/
GET
TIME
-
HAL_RTC_GetDate(
&hrtc,
&_current_
date,RTC_
FORMAT_BIN);
-
/
/Printf
-
SEGGER_RTT_SetTerminal(
1);
-
SEGGER_RTT_printf(
0,
"%d . %d . %d \n",_current_
date.Year,_current_
date.Month,_current_
date.
Date);
-
SEGGER_RTT_SetTerminal(
2);
-
SEGGER_RTT_printf(
0,
"%d : %d : %d \n\n",_current_
time.Hours,_current_
time.Minutes,_current_
time.Seconds);
代码的下载链接:https://download.csdn.net/download/xue745146527/12045381 (工程包含了Keil 和 IAR )
2019年12月27日更新--增加打印float的功能
因为官方的RTT View不能打印出float类型的数据,因此我简单写了个float转字符串的函数。
-
unsigned char
*out_float(double
value, unsigned char decimal_digit, unsigned char
*
output_
length)
-
{
-
unsigned char _
output[
20];
-
unsigned long integer;
-
unsigned long decimal;
-
unsigned char _
output_
length
=
0;
-
unsigned char _
length_buff
=
0;
-
static unsigned char
*
return_
pointer;
-
unsigned char signal_flag;
-
if (
value
<
0)
-
signal_flag
=
1;
-
else
-
signal_flag
=
0;
-
value
= fabs(
value);
-
integer
= (unsigned long)
value;
-
decimal
= (unsigned long)((
value
- integer)
* pow(
10, decimal_digit));
-
-
unsigned long integer_buff
= integer;
-
unsigned long decimal_buff
= decimal;
-
-
while (
1)
-
{
-
if (integer
/
10 !
=
0)
-
_
length_buff
+
+;
-
else
-
{
-
_
length_buff
+
+;
-
break;
-
}
-
integer
= integer
/
10;
-
}
-
for (int i
=
0; i
< _
length_buff; i
+
+)
-
{
-
if (i
=
= _
length_buff
-
1)
-
_
output[_
output_
length]
= integer_buff %
10
+
0x
30;
-
else
-
{
-
/
/_
output[_
output_
length]
= integer_buff
/
10 %
10
+
0x
30;
-
_
output[_
output_
length]
= integer_buff
/ (unsigned long)pow(
10, _
length_buff
- i
-
1) %
10
+
0x
30;
-
integer_buff
= integer_buff % (unsigned long)pow(
10, _
length_buff
- i
-
1);
-
/
/integer_buff
= integer_buff %
10;
-
}
-
_
output_
length
+
+;
-
}
-
_
output[_
output_
length]
=
'.';
-
_
output_
length
+
+;
-
_
length_buff
=
0;
-
while (
1)
-
{
-
if (decimal
/
10 !
=
0)
-
_
length_buff
+
+;
-
else
-
{
-
_
length_buff
+
+;
-
break;
-
}
-
decimal
= decimal
/
10;
-
}
-
for (int i
=
0; i
< _
length_buff; i
+
+)
-
{
-
if (i
=
= _
length_buff
-
1)
-
_
output[_
output_
length]
= decimal_buff %
10
+
0x
30;
-
else
-
{
-
_
output[_
output_
length]
= decimal_buff
/ (unsigned long)pow(
10, _
length_buff-i-
1) %
10
+
0x
30;
-
decimal_buff
= decimal_buff % (unsigned long)pow(
10, _
length_buff
- i
-
1);
-
}
-
-
_
output_
length
+
+;
-
}
-
_
output[_
output_
length]
=
0x
00;
-
_
output_
length
+
+;
-
return_
pointer
= (unsigned char
*)realloc(
return_
pointer,_
output_
length);
-
-
*
output_
length
= _
output_
length
-
1;
-
if (
return_
pointer
=
=
0)
-
return
0;
-
else
-
{
-
if (signal_flag
=
=
1)
-
{
-
return_
pointer[
0]
=
'-';
-
memcpy(
return_
pointer
+
1, _
output, _
output_
length);
-
}
-
else
-
memcpy(
return_
pointer, _
output, _
output_
length);
-
}
-
return
return_
pointer;
-
}
-
Parameter
Value | Meaning |
---|---|
value | 想要打印的数据 |
decimal_digit | 数字小数部分的位数 |
_output_length | 输出字符串的长度 |
Return Value
Value | Meaning |
---|---|
unsigned char* | 返回一个字符串指针 |
示例代码:
-
float
value
=
3.1415;
-
unsigned char
length;
-
SEGGER_RTT_printf(
0,
"value = %s \n",out_float(
value,
4,
&
length));