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

发布者:beta12最新更新时间:2021-09-07 来源: eefocus关键字:J-Link  RTT 手机看文章 扫描二维码
随时随地手机看文章

什么是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->右键打开文件所在位置->然后继续右键打开文件所在位置->此时就是安装目录了),

找到如下路径SEGGERJLink_V632fSamplesRTT,解压路径里面的压缩包SEGGER_RTT_V632f.zip(不同的版本,V后面的数字可能不一样)。

3.将解压完的文件拷贝到代码工程目录中。

4.在项目工程中加入SEGGER_RTT_V632fRTT目录下的全部四个文件。工程添加文件方法请自行百度。

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();
    }123456

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

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

示例代码:

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

(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 nn",_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 + 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));


关键字:J-Link  RTT 引用地址: J-Link RTT的使用(原理 + 教程 + 应用 + 代码)

上一篇:示波器分析485波形图
下一篇:STM32G0系列通过HAL库读取CPUID

推荐阅读最新更新时间:2024-11-08 06:16

【ARM】使用J-Link下载u-boot到Mini2440开发板
#1各种引导系统介绍 ##1.1 bios 1 BIOS是英文 Basic Input Output System 的缩略语,直译过来后中文名称就是 基本输入输出系统 。其实,它是一组固化到计算机内主板上一个ROM芯片上的程序,它保存着计算机最重要的基本输入输出的程序、系统设置信息、开机后自检程序和系统自启动程序。 其主要功能是为计算机提供最底层的、最直接的硬件设置和控制。 ##1.2 Grub 2 GNU GRUB(GRand Unified Bootloader简称“GRUB”)是一个来自GNU项目的多操作系统启动程序。GRUB是多启动规范的实现,它允许用户可以在计算机内同时拥有多个操作系统,并在计算机启动时选择希望运行的
[单片机]
【ARM】使用<font color='red'>J-Link</font>下载u-boot到Mini2440开发板
小广播
推荐内容
设计资源 培训 开发板 精华推荐

最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

换一换 更多 相关热搜器件

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved