J-Link RTT使用

Posted 无痕幽雨

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了J-Link RTT使用相关的知识,希望对你有一定的参考价值。

目录--点击可快速直达

写在前面

本文介绍了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缓存区中没有有效的字符

示例代码:

    int c;
    c = SEGGER_RTT_GetKey();
    if (c == 'q') {
        exit();
    }

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

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

示例代码:

   if (SEGGER_RTT_HasKey()) {
      int c = SEGGER_RTT_GetKey();
   }

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

例如:

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

ParameterMeaning
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

ValueMeaning
≥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);

代码的下载链接:RTT_Test.zip-其它代码类资源-CSDN下载 (工程包含了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 + 0x30;
		else
		{
			//_output[_output_length] = integer_buff / 10 % 10 + 0x30;
			_output[_output_length] = integer_buff / (unsigned long)pow(10, _length_buff - i - 1) % 10 + 0x30;
			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 + 0x30;
		else
		{
			_output[_output_length] = decimal_buff / (unsigned long)pow(10, _length_buff-i-1) % 10 + 0x30;
			decimal_buff = decimal_buff % (unsigned long)pow(10, _length_buff - i - 1);
		}
			
		_output_length++;
	}
	_output[_output_length] = 0x00;
	_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

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

Return Value

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

示例代码:

   float value = 3.1415;
   unsigned char length;
   SEGGER_RTT_printf(0,"value = %s \\n",out_float(value,4,&length));

标签: 调试备忘录

一、测试环境
1> 测试环境
系统:WIN7
MDK:keil v5.26
开发板:GD32F303C-EVAL
固件库:V1.0.2
FreeRTOS版本:V10.4.0
支持内核: ARM Cortex-M0/M0+/M1/M3/M4/M7/M23/M33 and Renesas RX100/200/600
更多详情可以参考官网:RTT
中文可以参考:仿真器代替串口打印
2> 找到JLINK驱动的安装目录。

 

解压后可以看到如下图所示文件,Example目录是参考的demo,RTT和Syscalls文件夹下就是移植所需要的文件

 

RTT目录内容:

 

Syscalls目录内容:

 

二、添加文件到工程
1> 在工程下新建一个文件夹,将上述中提到的文件放到这个文件夹中


2> 添加文件到工程

 

 

3> 添加头文件路径

 

————————————————
版权声明:本文为CSDN博主「笙歌君独忧」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/qq_23852045/article/details/108759582

三、测试使用
1>测试代码如下:

#include "gd32f30x.h"
#include "led.h"
#include "systick.h"
#include "timer.h"
#include <stdio.h>
#include "key.h"
#include "gpio.h"
#include "usart_shell.h"
#include "shell_port.h"
#include "gd25qxx.h"
#include <math.h>
#include <string.h>
#include "SEGGER_RTT.h"

#if 0
/* USER CODE BEGIN 0 */
int test(int i, char ch, char *str)
{
    printf("input int: %d, char: %c, string: %s\\r\\n", i, ch, str);
    
    return 0;
}

int func(int argc, char *agrv[])
{
    printf("%dparameter(s)\\r\\n", argc);
    for (char i = 1; i < argc; i++)
    {
        printf("%s\\r\\n", agrv[i]);
    }
        return 0;
}
SHELL_EXPORT_CMD(SHELL_CMD_PERMISSION(0)|SHELL_CMD_TYPE(SHELL_TYPE_CMD_MAIN), func, func, test2);

//导出到命令列表里
SHELL_EXPORT_CMD(SHELL_CMD_PERMISSION(0)|SHELL_CMD_TYPE(SHELL_TYPE_CMD_FUNC), test, test, test);

/* USER CODE END 0 */
#endif

volatile int _Cnt=0;
unsigned char *out_float(double value, unsigned char decimal_digit, unsigned char *output_length);
int main(void)
{
     float value = 3.1415;
   unsigned char length;
   
         
    delay_init();
    /*添加上行数据缓冲区,函数原型:
    int SEGGER_RTT_ConfigUpBuffer(unsigned BufferIndex, const char* sName, void* pBuffer, unsigned BufferSize, unsigned Flags) 
    若BufferIndex=0,RTT组件将使用默认的缓冲和大小,其大小由SEGGER_RTT_Conf.h中的BUFFER_SIZE_UP决定,所以使用这个缓存区0比较简单,
    令BufferIndex=0,pBuffer=NULL,BufferSize=NULL
    方向:MCU-->PC
    同理:SEGGER_RTT_ConfigDownBuffer,和它一样,仅仅方向不同,PC-->MCU
    */
  SEGGER_RTT_ConfigUpBuffer(0, NULL, NULL, 0, SEGGER_RTT_MODE_BLOCK_IF_FIFO_FULL);

    /*打印字符串函数*/
  SEGGER_RTT_WriteString(0, "SEGGER Real-Time-Terminal Sample\\r\\n\\r\\n");
  SEGGER_RTT_WriteString(0, "###### Testing SEGGER_printf() ######\\r\\n");
    SEGGER_RTT_WriteString(0, "###### 中文 ######\\r\\n");
    SEGGER_RTT_printf(0,"value = %s \\n",out_float(value,4,&length));
    /*与C库中printf类似,区别是不支持浮点数*/
  SEGGER_RTT_printf(0, "printf Test: %%c,         'S' : %c.\\r\\n", 'S');
  SEGGER_RTT_printf(0, "printf Test: %%5c,        'E' : %5c.\\r\\n", 'E');
  SEGGER_RTT_printf(0, "printf Test: %%-5c,       'G' : %-5c.\\r\\n", 'G');
  SEGGER_RTT_printf(0, "printf Test: %%5.3c,      'G' : %-5c.\\r\\n", 'G');
  SEGGER_RTT_printf(0, "printf Test: %%.3c,       'E' : %-5c.\\r\\n", 'E');
  SEGGER_RTT_printf(0, "printf Test: %%c,         'R' : %c.\\r\\n", 'R');

  SEGGER_RTT_printf(0, "printf Test: %%s,      \\"RTT\\" : %s.\\r\\n", "RTT");
  SEGGER_RTT_printf(0, "printf Test: %%s, \\"RTT\\\\r\\\\nRocks.\\" : %s.\\r\\n", "RTT\\r\\nRocks.");

  SEGGER_RTT_printf(0, "printf Test: %%u,       12345 : %u.\\r\\n", 12345);
  SEGGER_RTT_printf(0, "printf Test: %%+u,      12345 : %+u.\\r\\n", 12345);
  SEGGER_RTT_printf(0, "printf Test: %%.3u,     12345 : %.3u.\\r\\n", 12345);
  SEGGER_RTT_printf(0, "printf Test: %%.6u,     12345 : %.6u.\\r\\n", 12345);
  SEGGER_RTT_printf(0, "printf Test: %%6.3u,    12345 : %6.3u.\\r\\n", 12345);
  SEGGER_RTT_printf(0, "printf Test: %%8.6u,    12345 : %8.6u.\\r\\n", 12345);
  SEGGER_RTT_printf(0, "printf Test: %%08u,     12345 : %08u.\\r\\n", 12345);
  SEGGER_RTT_printf(0, "printf Test: %%08.6u,   12345 : %08.6u.\\r\\n", 12345);
  SEGGER_RTT_printf(0, "printf Test: %%0u,      12345 : %0u.\\r\\n", 12345);
  SEGGER_RTT_printf(0, "printf Test: %%-.6u,    12345 : %-.6u.\\r\\n", 12345);
  SEGGER_RTT_printf(0, "printf Test: %%-6.3u,   12345 : %-6.3u.\\r\\n", 12345);
  SEGGER_RTT_printf(0, "printf Test: %%-8.6u,   12345 : %-8.6u.\\r\\n", 12345);
  SEGGER_RTT_printf(0, "printf Test: %%-08u,    12345 : %-08u.\\r\\n", 12345);
  SEGGER_RTT_printf(0, "printf Test: %%-08.6u,  12345 : %-08.6u.\\r\\n", 12345);
  SEGGER_RTT_printf(0, "printf Test: %%-0u,     12345 : %-0u.\\r\\n", 12345);

  SEGGER_RTT_printf(0, "printf Test: %%u,      -12345 : %u.\\r\\n", -12345);
  SEGGER_RTT_printf(0, "printf Test: %%+u,     -12345 : %+u.\\r\\n", -12345);
  SEGGER_RTT_printf(0, "printf Test: %%.3u,    -12345 : %.3u.\\r\\n", -12345);
  SEGGER_RTT_printf(0, "printf Test: %%.6u,    -12345 : %.6u.\\r\\n", -12345);
  SEGGER_RTT_printf(0, "printf Test: %%6.3u,   -12345 : %6.3u.\\r\\n", -12345);
  SEGGER_RTT_printf(0, "printf Test: %%8.6u,   -12345 : %8.6u.\\r\\n", -12345);
  SEGGER_RTT_printf(0, "printf Test: %%08u,    -12345 : %08u.\\r\\n", -12345);
  SEGGER_RTT_printf(0, "printf Test: %%08.6u,  -12345 : %08.6u.\\r\\n", -12345);
  SEGGER_RTT_printf(0, "printf Test: %%0u,     -12345 : %0u.\\r\\n", -12345);
  SEGGER_RTT_printf(0, "printf Test: %%-.6u,   -12345 : %-.6u.\\r\\n", -12345);
  SEGGER_RTT_printf(0, "printf Test: %%-6.3u,  -12345 : %-6.3u.\\r\\n", -12345);
  SEGGER_RTT_printf(0, "printf Test: %%-8.6u,  -12345 : %-8.6u.\\r\\n", -12345);
  SEGGER_RTT_printf(0, "printf Test: %%-08u,   -12345 : %-08u.\\r\\n", -12345);
  SEGGER_RTT_printf(0, "printf Test: %%-08.6u, -12345 : %-08.6u.\\r\\n", -12345);
  SEGGER_RTT_printf(0, "printf Test: %%-0u,    -12345 : %-0u.\\r\\n", -12345);

  SEGGER_RTT_printf(0, "printf Test: %%d,      -12345 : %d.\\r\\n", -12345);
  SEGGER_RTT_printf(0, "printf Test: %%+d,     -12345 : %+d.\\r\\n", -12345);
  SEGGER_RTT_printf(0, "printf Test: %%.3d,    -12345 : %.3d.\\r\\n", -12345);
  SEGGER_RTT_printf(0, "printf Test: %%.6d,    -12345 : %.6d.\\r\\n", -12345);
  SEGGER_RTT_printf(0, "printf Test: %%6.3d,   -12345 : %6.3d.\\r\\n", -12345);
  SEGGER_RTT_printf(0, "printf Test: %%8.6d,   -12345 : %8.6d.\\r\\n", -12345);
  SEGGER_RTT_printf(0, "printf Test: %%08d,    -12345 : %08d.\\r\\n", -12345);
  SEGGER_RTT_printf(0, "printf Test: %%08.6d,  -12345 : %08.6d.\\r\\n", -12345);
  SEGGER_RTT_printf(0, "printf Test: %%0d,     -12345 : %0d.\\r\\n", -12345);
  SEGGER_RTT_printf(0, "printf Test: %%-.6d,   -12345 : %-.6d.\\r\\n", -12345);
  SEGGER_RTT_printf(0, "printf Test: %%-6.3d,  -12345 : %-6.3d.\\r\\n", -12345);
  SEGGER_RTT_printf(0, "printf Test: %%-8.6d,  -12345 : %-8.6d.\\r\\n", -12345);
  SEGGER_RTT_printf(0, "printf Test: %%-08d,   -12345 : %-08d.\\r\\n", -12345);
  SEGGER_RTT_printf(0, "printf Test: %%-08.6d, -12345 : %-08.6d.\\r\\n", -12345);
  SEGGER_RTT_printf(0, "printf Test: %%-0d,    -12345 : %-0d.\\r\\n", -12345);

  SEGGER_RTT_printf(0, "printf Test: %%x,      0x1234ABC : %x.\\r\\n", 0x1234ABC);
  SEGGER_RTT_printf(0, "printf Test: %%+x,     0x1234ABC : %+x.\\r\\n", 0x1234ABC);
  SEGGER_RTT_printf(0, "printf Test: %%.3x,    0x1234ABC : %.3x.\\r\\n", 0x1234ABC);
  SEGGER_RTT_printf(0, "printf Test: %%.6x,    0x1234ABC : %.6x.\\r\\n", 0x1234ABC);
  SEGGER_RTT_printf(0, "printf Test: %%6.3x,   0x1234ABC : %6.3x.\\r\\n", 0x1234ABC);
  SEGGER_RTT_printf(0, "printf Test: %%8.6x,   0x1234ABC : %8.6x.\\r\\n", 0x1234ABC);
  SEGGER_RTT_printf(0, "printf Test: %%08x,    0x1234ABC : %08x.\\r\\n", 0x1234ABC);
  SEGGER_RTT_printf(0, "printf Test: %%08.6x,  0x1234ABC : %08.6x.\\r\\n", 0x1234ABC);
  SEGGER_RTT_printf(0, "printf Test: %%0x,     0x1234ABC : %0x.\\r\\n", 0x1234ABC);
  SEGGER_RTT_printf(0, "printf Test: %%-.6x,   0x1234ABC : %-.6x.\\r\\n", 0x1234ABC);
  SEGGER_RTT_printf(0, "printf Test: %%-6.3x,  0x1234ABC : %-6.3x.\\r\\n", 0x1234ABC);
  SEGGER_RTT_printf(0, "printf Test: %%-8.6x,  0x1234ABC : %-8.6x.\\r\\n", 0x1234ABC);
  SEGGER_RTT_printf(0, "printf Test: %%-08x,   0x1234ABC : %-08x.\\r\\n", 0x1234ABC);
  SEGGER_RTT_printf(0, "printf Test: %%-08.6x, 0x1234ABC : %-08.6x.\\r\\n", 0x1234ABC);
  SEGGER_RTT_printf(0, "printf Test: %%-0x,    0x1234ABC : %-0x.\\r\\n", 0x1234ABC);

  SEGGER_RTT_printf(0, "printf Test: %%p,      &_Cnt      : %p.\\r\\n", &_Cnt);

  SEGGER_RTT_WriteString(0, "###### SEGGER_printf() Tests done. ######\\r\\n");
  do {
    _Cnt++;
        SEGGER_RTT_printf(0, "%d\\r\\n", _Cnt);
        delay_xms(100);
  } while (1);
}
/*
SEGGER_RTT_printf不支持浮点
这里引用网友写的一个浮点转字符的函数:
https://www.cnblogs.com/snowsad/p/12076740.html
Parameter:
Value                        Meaning
value                        想要打印的数据
decimal_digit        数字小数部分的位数
_output_length    输出字符串的长度

Return Value:
Value    Meaning
unsigned char*    返回一个字符串指针
*/
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 + 0x30;
        else
        {
            //_output[_output_length] = integer_buff / 10 % 10 + 0x30;
            _output[_output_length] = integer_buff / (unsigned long)pow(10, _length_buff - i - 1) % 10 + 0x30;
            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 + 0x30;
        else
        {
            _output[_output_length] = decimal_buff / (unsigned long)pow(10, _length_buff-i-1) % 10 + 0x30;
            decimal_buff = decimal_buff % (unsigned long)pow(10, _length_buff - i - 1);
        }
            
        _output_length++;
    }
    _output[_output_length] = 0x00;
    _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;
}



2>编译下载,重新上电,然后打开J-Link RTT Viewer,点击OK就可以看到输出结果,如果想仿真调试,需要先进入仿真状态,然后在点击OK。

3> 测试结果

4>将上面的代码编译,进入仿真,然后打开J-Link RTT Client软件,如下图,说明连接成功。

5>点击全速运行或单步调试就可以在窗口看到相应的打印信息。

6>client与viewer区别
client需要配合仿真使用,而viewer不需要。
client支持中文输出,而viewer不支持
四、输入测试
1>输入单个字符:
代码如下:

volatile int _Cnt;
volatile int _Delay;

static char r;
char acIn[20];
int ReadNum=0;
uint16_t i=0;
/*********************************************************************
*
*       main
*/
int main(void) {

      SEGGER_RTT_WriteString(0, "SEGGER Real-Time-Terminal Sample\\r\\n");
      SEGGER_RTT_ConfigUpBuffer(0, NULL, NULL, 0, SEGGER_RTT_MODE_NO_BLOCK_SKIP);
 
    while(1)
    {
        /*读取一个键值的第一种方式*/
        /*判断RTT的BUF缓冲区中是否有可用数据*/
        if(SEGGER_RTT_HasKey())
        {
                /*从RTT的BUF0的缓冲区内读取一个键值*/
              r = SEGGER_RTT_GetKey();
                if(r=='q')
                {
                    SEGGER_RTT_WriteString(0,"input :q\\r\\n");
                }
        }
        /*读取一个键值的第二种方式*/
//        do{
//            r = SEGGER_RTT_WaitKey();
//            SEGGER_RTT_printf(0,"input key is: %c\\r\\n",r);
//        }while(r != 'q');
//        SEGGER_RTT_printf(0,"host has been read q\\r\\n");
        

    }

}

注意,这种读取键值的方式,只支持Terminal0,打开J-Link RTT Viewer进行如下配置:

如果没有自动连接,可以按F2再次进行连接,F3为断开连接。
测试结果:


2> 输入多个字符串
测试代码:

volatile int _Cnt;
volatile int _Delay;

static char r;
char acIn[20];
int ReadNum=0;
uint16_t i=0;
/*********************************************************************
*
*       main
*/
int main(void) {

  SEGGER_RTT_WriteString(0, "SEGGER Real-Time-Terminal Sample\\r\\n");
  SEGGER_RTT_ConfigUpBuffer(0, NULL, NULL, 0, SEGGER_RTT_MODE_NO_BLOCK_SKIP);
 
    while(1)
    {
        /*判断RTT的BUF缓冲区中是否有可用数据*/
        if(SEGGER_RTT_HasKey())
        {
                /*从RTT的BUF0的缓冲区内读取一个键值*/
              ReadNum = SEGGER_RTT_Read(0,&acIn[0],sizeof(acIn));
                for(i=0;i<20;i++)
                {
                    if(0x0A != acIn[i])
                    {
                        ReadNum++;
                    }
                    else
                    {
                        break;
                    }
                }
                SEGGER_RTT_Write(0,acIn,ReadNum);
                ReadNum=0;
                memset(acIn,0,sizeof(acIn));
        }
    }

}

这种方式支持多个Terminal,打开J-Link RTT Viewer进行如下配置:

测试结果:


五、使用小技巧
可以使用多个Terminal终端来输出不同的内容,比如终端0输出打印信息,终端1输出错误信息,J-Link RTT Viewer最多支持16个终端。
另外,还可以配置字体不同的打印颜色,方便识别,这个要远比串口好用的多。
测试代码如下:

static void _Delay(int period) 
{
    int i = 100000*period;
    do { ; } while (i--);
}
int main(void) 
{
    int cnt=0;
    while(1)
    {
        SEGGER_RTT_SetTerminal(1);
        SEGGER_RTT_WriteString(0,RTT_CTRL_RESET"Red: "\\
                                                        RTT_CTRL_TEXT_RED"This text is red."\\
                                                        RTT_CTRL_TEXT_BLACK""\\
                                                        RTT_CTRL_BG_BRIGHT_GREEN"This background is green."\\
                                                        RTT_CTRL_RESET"Normal text again.\\r\\n");
        _Delay(200);
        cnt++;
        SEGGER_RTT_SetTerminal(0);
        SEGGER_RTT_WriteString(0,RTT_CTRL_RESET"Terminal:\\r\\n");
        SEGGER_RTT_printf(0,"%sCounter:%s%d\\r\\n",RTT_CTRL_RESET,RTT_CTRL_TEXT_YELLOW,cnt);
        if(cnt > 5)
        {
            SEGGER_RTT_TerminalOut(0,RTT_CTRL_TEXT_RED"Counter overflow!\\r\\n");
            cnt=0;
        }
    }
    return 0;
}

测试结果:

这个是所有终端的信息,不过这个颜色是和我们想要测试的不同的,不过信息是正确的。

这里可以看出Terminal0, Terminal1这两个终端既是我们设置的颜色的输出。
————————————————
版权声明:本文为CSDN博主「笙歌君独忧」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/qq_23852045/article/details/108759582

RTT打印中文乱码的解决方法

例如下方例程,1秒打印一次数据。

if (D1s.arrived == 0x01)
{
    D1s.arrived = 0x00;
    SEGGER_RTT_printf(0, "D1s.arrived \\n"); //调试通用
    SEGGER_RTT_printf(0, "1秒到\\n"); //调试通用
}

如下图所示,RTT Viewer窗口显示的中文出现乱码。


解决方法一:
先打开RTT Viewer,再打开RTT Client 即可。

 

解决方法二:
完全卸载所有的J-Link软件,再安装。(注意:其他版本的也要卸载)

 

目前使用一年多,推荐版本JLink_Windows_V663d.exe


解决方法三:待补充。
————————————————
版权声明:本文为CSDN博主「辉夜星辰」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/weixin_37787043/article/details/112224654

 

 

以上是关于J-Link RTT使用的主要内容,如果未能解决你的问题,请参考以下文章

J-Link RTT使用

J-Link的RTT功能实践

STM32打印log--使用J-Link RTT Viewer

《嵌入式 - 嵌入式大杂烩》详解J-Link RTT打印

J-Link RTT库和CmBacktrace库使用总结

嵌入式芯片调试神器-J-Link RTT详解