J-Link RTT的使用(原理 + 教程 + 应用 + 代码)

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

ValueMeaning
>=0返回按键字符(0-255)
< 0缓存区中没有有效的字符

示例代码:


   
   
  1. int c;
  2. c = SEGGER_RTT_GetKey();
  3. if (c = = 'q') {
  4. exit();
  5. }

(3)int SEGGER_RTT_HasKey (void);检测缓存区中是否还有字符。
Return Value

ValueMeaning
1缓存区中至少有一个字符是有效的
0缓存区中没有有效的字符

示例代码:


   
   
  1. if (SEGGER_RTT_HasKey()) {
  2. int c = SEGGER_RTT_GetKey();
  3. }

(4)int SEGGER_RTT_printf (unsigned BufferIndex, const char * sFormat, …)格式化输出字符串
Return Value

ValueMeaning
>=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()来设置字体颜色还背景颜色:

例如:


   
   
  1. SEGGER_RTT_printf( 0,RTT_CTRL_BG_WHITE);
  2. SEGGER_RTT_printf( 0,RTT_CTRL_TEXT_BLUE);

(5)void SEGGER_RTT_SetTerminal(char TerminalId);设置虚拟终端ID。
Return Value

ParameterMeaning
TerminalId虚拟终端的ID

示例代码:


   
   
  1. / /
  2. / / Send a string to terminal 1 which is used as error out.
  3. / /
  4. SEGGER_RTT_SetTerminal( 1); / / Select terminal 1
  5. SEGGER_RTT_WriteString( 0, "ERROR: Buffer overflow");
  6. SEGGER_RTT_SetTerminal( 0); / / Reset to standard terminal

SEGGER_RTT_WriteString中的0参数,是通道号,不是终端号。


(6)int SEGGER_RTT_WaitKey (void);检测缓存区中是否还有字符。
Return Value

ValueMeaning
≥0等待返回一个按键值

示例代码:


   
   
  1. int c = 0;
  2. do {
  3. c = SEGGER_RTT_WaitKey();
  4. } while (c ! = 'c');

附上测试代码


   
   
  1. / *terminal 0: if you press any key in the keyboard ,terminal 0 will show the key value witch you press.
  2. terminal 1: show the date
  3. terminal 2: show the time
  4. * /
  5. if (SEGGER_RTT_HasKey())
  6. {
  7. int c = SEGGER_RTT_GetKey();
  8. SEGGER_RTT_SetTerminal( 0);
  9. SEGGER_RTT_ Write ( 0, &c, 1);
  10. SEGGER_RTT_printf( 0, "\n");
  11. }
  12. / / GET DATA
  13. HAL_RTC_GetTime( &hrtc, &_current_ time,RTC_ FORMAT_BIN);
  14. / / GET TIME
  15. HAL_RTC_GetDate( &hrtc, &_current_ date,RTC_ FORMAT_BIN);
  16. / /Printf
  17. SEGGER_RTT_SetTerminal( 1);
  18. SEGGER_RTT_printf( 0, "%d . %d . %d \n",_current_ date.Year,_current_ date.Month,_current_ date. Date);
  19. SEGGER_RTT_SetTerminal( 2);
  20. 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转字符串的函数。


   
   
  1. unsigned char *out_float(double value, unsigned char decimal_digit, unsigned char * output_ length)
  2. {
  3. unsigned char _ output[ 20];
  4. unsigned long integer;
  5. unsigned long decimal;
  6. unsigned char _ output_ length = 0;
  7. unsigned char _ length_buff = 0;
  8. static unsigned char * return_ pointer;
  9. unsigned char signal_flag;
  10. if ( value < 0)
  11. signal_flag = 1;
  12. else
  13. signal_flag = 0;
  14. value = fabs( value);
  15. integer = (unsigned long) value;
  16. decimal = (unsigned long)(( value - integer) * pow( 10, decimal_digit));
  17. unsigned long integer_buff = integer;
  18. unsigned long decimal_buff = decimal;
  19. while ( 1)
  20. {
  21. if (integer / 10 ! = 0)
  22. _ length_buff + +;
  23. else
  24. {
  25. _ length_buff + +;
  26. break;
  27. }
  28. integer = integer / 10;
  29. }
  30. for (int i = 0; i < _ length_buff; i + +)
  31. {
  32. if (i = = _ length_buff - 1)
  33. _ output[_ output_ length] = integer_buff % 10 + 0x 30;
  34. else
  35. {
  36. / /_ output[_ output_ length] = integer_buff / 10 % 10 + 0x 30;
  37. _ output[_ output_ length] = integer_buff / (unsigned long)pow( 10, _ length_buff - i - 1) % 10 + 0x 30;
  38. integer_buff = integer_buff % (unsigned long)pow( 10, _ length_buff - i - 1);
  39. / /integer_buff = integer_buff % 10;
  40. }
  41. _ output_ length + +;
  42. }
  43. _ output[_ output_ length] = '.';
  44. _ output_ length + +;
  45. _ length_buff = 0;
  46. while ( 1)
  47. {
  48. if (decimal / 10 ! = 0)
  49. _ length_buff + +;
  50. else
  51. {
  52. _ length_buff + +;
  53. break;
  54. }
  55. decimal = decimal / 10;
  56. }
  57. for (int i = 0; i < _ length_buff; i + +)
  58. {
  59. if (i = = _ length_buff - 1)
  60. _ output[_ output_ length] = decimal_buff % 10 + 0x 30;
  61. else
  62. {
  63. _ output[_ output_ length] = decimal_buff / (unsigned long)pow( 10, _ length_buff-i- 1) % 10 + 0x 30;
  64. decimal_buff = decimal_buff % (unsigned long)pow( 10, _ length_buff - i - 1);
  65. }
  66. _ output_ length + +;
  67. }
  68. _ output[_ output_ length] = 0x 00;
  69. _ output_ length + +;
  70. return_ pointer = (unsigned char *)realloc( return_ pointer,_ output_ length);
  71. * output_ length = _ output_ length - 1;
  72. if ( return_ pointer = = 0)
  73. return 0;
  74. else
  75. {
  76. if (signal_flag = = 1)
  77. {
  78. return_ pointer[ 0] = '-';
  79. memcpy( return_ pointer + 1, _ output, _ output_ length);
  80. }
  81. else
  82. memcpy( return_ pointer, _ output, _ output_ length);
  83. }
  84. return return_ pointer;
  85. }

Parameter

ValueMeaning
value想要打印的数据
decimal_digit数字小数部分的位数
_output_length输出字符串的长度

Return Value

ValueMeaning
unsigned char*返回一个字符串指针

示例代码:


   
   
  1. float value = 3.1415
  2. unsigned char length;
  3. SEGGER_RTT_printf( 0, "value = %s \n",out_float( value, 4, & length));
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值