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缓存区中没有有效的字符

示例代码:

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

代码的下载链接: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));

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/214791.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

ImportError: cannot import name ‘metadata‘ from ‘importlib‘

yolov8 编译问题 ImportError: cannot import name ‘metadata’ from ‘importlib’ 将 from importlib import metadata 更改为 import importlib_metadata as metadata

canvas绘制单个圆和同心圆

代码实现&#xff1a; <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta http-equiv"X-UA-Compatible" content"IEedge"><meta name"viewport" content"widthdev…

【Java 基础】18 I/O流

文章目录 1.基本概念2.字节流3.字符流4.标准输入输出5.最佳实践 I/O流&#xff08;Input/Output 流&#xff09;是计算机程序中不可或缺的一部分&#xff0c; 往大了说所有的操作都是IO。Java 提供了强大而灵活的 I/O 框架&#xff0c;支持各种数据的 读取和 写入操作。 1.基…

网络安全--网络环境构成,系统的安全

2. 网络攻防环境 目标 了解攻防环境构成了解入侵检测系统&#xff08;平台&#xff09;的部署位置 2.1. 环境构成 2.1.1. 环境框图 一个基本的网络攻防实验环境包括&#xff1a;靶机、攻击机、入侵检测分析系统、网络连接四部分组成。 一个基础的网络攻防实验环境需要如下…

Mybatis 操作续集(结合上文)

当我们增加一个数据之后,如果我们想要获取它的 Id 进行别的操作,我们该如何获取 Id 呢? 用那个Options package com.example.mybatisdemo.mapper;import com.example.mybatisdemo.model.UserInfo; import org.apache.ibatis.annotations.*;import java.util.List;Mapper pub…

Leetcode刷题详解——乘积为正数的最长子数组长度

1. 题目链接&#xff1a;1567. 乘积为正数的最长子数组长度 2. 题目描述&#xff1a; 给你一个整数数组 nums &#xff0c;请你求出乘积为正数的最长子数组的长度。 一个数组的子数组是由原数组中零个或者更多个连续数字组成的数组。 请你返回乘积为正数的最长子数组长度。 示…

java面向对象 + 内存解析

这篇博客主要是重点讲解一些内存和一些规定的解释&#xff0c;对于定义我不会过多赘述&#xff0c;没有Java基础的话可以去翻看我之前的博客&#xff0c;学习完成之后再进行阅读。 面向对象可以说是Java中最重要的一部分了&#xff0c;这次复习我发现有几个点比较重要&#xf…

【Rust日报】2023-12-02 深度学习框架 Burn 发布 v0.11.0

深度学习框架 Burn 发布 v0.11.0 深度学习框架 Burn 发布 v0.11.0&#xff0c;新版本引入了自动内核融合&#xff08;Kernel Fusion&#xff09;功能&#xff0c;大大提升了访存密集型&#xff08;memory-bound&#xff09;操作的性能。同时宣布成立 Tracel AI (https://tracel…

深入理解 Kafka 集群搭建与管理

Apache Kafka 作为分布式流处理平台的核心&#xff0c;其集群搭建与管理是确保高可用性和高性能的关键。本文将深入研究 Kafka 集群的构建、配置、工作原理、节点角色以及一些高级管理策略&#xff0c;以助力读者更深层次地理解和灵活运用 Kafka 集群。 Kafka 集群基础 1 集群…

PHP开源问答网站平台源码系统 源码全部开源可二次开发 附带完整的搭建教程

目前&#xff0c;问答网站已经成为人们获取知识、交流思想的重要平台。然而&#xff0c;对于许多开发者来说&#xff0c;从头开始构建一个问答网站可能会面临各种挑战。今天&#xff0c;小编给大家介绍一款基于PHP的开源问答网站平台源码系统&#xff0c;它不仅源码全部开源&am…

HR看好的字符函数和字符串处理函数!!!

本篇会加入个人的所谓‘鱼式疯言’❤️❤️❤️鱼式疯言:❤️❤️❤️此疯言非彼疯言,而是理解过并总结出来通俗易懂的大白话,我会尽可能的在每个概念后插入鱼式疯言,帮助大家理解的&#xff0c;可能说的不是那么严谨.但小编初心是能让更多人能接受我们这个概念 前言 在本篇…

基于maobox-gl 纯前端绘制全球色斑图

基于maobox-gl.js、turf.js 绘制全球色斑图绘制 1、准备全球的某一类的点位数据&#xff0c;可以使用turf.js 随机生成点&#xff0c;并点数据赋properties属性 let points turf.randomPoint(30, { bbox: [-180, -90, 180, 90]}); let interpolateOptions {gridType: "…

如何在线给官网搭建一个帮助文档?

在数字化时代&#xff0c;帮助文档已成为官网不可或缺的一部分。然而&#xff0c;传统的帮助文档往往只是简单地罗列问题和答案&#xff0c;缺乏互动性和用户体验。那么&#xff0c;如何在线给官网搭建一个富有创意且用户友好的帮助文档呢&#xff1f; | 一、打造沉浸式体验 传…

Google Chrome访问出现 NET::ERR_CERT_INVALID

Google Chrome访问出现 NET::ERR_CERT_INVALID然后访问不了当前网站&#xff0c;这个是由于证书失效了&#xff0c;临时解决方式是&#xff1a; 第一种方案&#xff1a; 在Chrome提示“您的连接不是私密连接”页面的空白区域点击一下&#xff0c;然后输入“thisisunsafe”(页…

逻辑漏洞测试靶场实验

任务一&#xff1a; 突破功能限制漏洞&#xff0c;要求突破查询按钮disabled限制&#xff0c;获取编号&#xff1a;110010的查询内容&#xff08;弹框中的flag&#xff09; 任务二&#xff1a;用户信息泄露漏洞&#xff0c;通过回显信息&#xff0c;以暴力破解法方式猜测系统中…

Shell循环:expect(二)

expect实战&#xff1a;公钥推送 一、准备工作&#xff1a;安装expect&#xff0c;装备公钥 二、通过shell循环判断主机在线 #!/bin/bash #脚本编写 #创建一个IP地址文件 >ip.txt #使用for循环ping测试主机是否在线 for i in {3..254} do{ip192.168.151.$iping -c1 -W…

docker搭建rabbitmq、配置延迟队列插件

docker搭建rabbitmq、配置延迟队列插件 消息队列的作用&#xff1a;消峰、解耦、异步 rabbitmq安装 查询 [rootlocalhost ~]# docker search rabbitmq安装 [rootlocalhost ~]# docker pull rabbitmq准备工作 创建文件夹&#xff1a;/usr/local/software/rabbitmq/data 运…

【设计模式-4.3】行为型——责任链模式

说明&#xff1a;本文介绍设计模式中行为型设计模式中的&#xff0c;责任链模式&#xff1b; 审批流程 责任链模式属于行为型设计模式&#xff0c;关注于对象的行为。责任链模式非常典型的案例&#xff0c;就是审批流程的实现。如一个报销单的审批流程&#xff0c;根据报销单…

Android CardView基础使用

目录 一、CardView 1.1 导入material库 1.2 属性 二、使用(效果) 2.1 圆角卡片效果 2.2 阴影卡片效果 2.3 背景 2.3.1 设置卡片背景(app:cardBackgroundColor) 2.3.2 内嵌布局&#xff0c;给布局设置背景色 2.4 进阶版 2.4.1 带透明度 2.4.2 无透明度 一、CardView 顾名…

麒麟系统添加环境变量

环境变量添加方法 方法一&#xff1a;用户主目录下的.profile或.bashrc文件&#xff08;推荐&#xff09; 登录到你的用户&#xff08;非root&#xff09;&#xff0c;在终端输入&#xff1a; sudo vim ~/.profile 或者 sudo vim ~/.bashrc 翻到该文件最后&#xff0c…