MDK:5.29
IAR:8.32
目錄--點擊可快速直達
寫在前面
本文介紹了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 + 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
| 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));
