目录

1 什么是日志

2 RTT的移植与使用

1. 下载与移植

第一步、下载Jlink驱动

第二步、提取单片机上的RTT库

第三步、移植RTT

测试用例:

2. 虚拟终端的用法

a.实现分流

b.改变终端输出字体颜色

c.重定向

d.输出浮点数


1 什么是日志

日志索引用于记录日志在存储介质中的位置信息,断电日志存储区用于记录系统断电前的重要信息,日志存储区是日志信息的主体存储区域。

2 RTT的移植与使用

1. 下载与移植

第一步、下载Jlink驱动

SEGGER RTT是Jlink驱动里面的功能,要使用SEGGER RTT,就一定要下载Jlink 的驱动: 访问SEGGER的官网,在Jlink的下载页进行下载即可:

https://www.segger.com/downloads/jlink/

第二步、提取单片机上的RTT库

打开Jlink驱动的安装位置(默认为:C:\Program Files\SEGGER\JLink),不知道的话就右键打开文件位置去找

解压后我们会用到压缩包里面的这两个文件夹:

第三步、移植RTT

新建文件夹Middlewares->RTT,添加文件

然后添加组:

包含路径:

包含头文件:

进行初始化:

测试用例:
void SEGGER_RTT_Test(void)
{
    SEGGER_RTT_Init();                //初始化只需在单片机运行开始时调用一次即可
    uint32_t cycle = 1000;
    while (cycle--)
    {
        SEGGER_RTT_printf(0, "0123456789abcdefgh\r\n");
    }
}

为了更加优雅的使用,我们可以进行封装:

#ifndef _LOG_H_
#define _LOH_H_
#include "SEGGER_RTT.h"

#define LOG_DEBUG 1

#if LOG_DEBUG


#define LOG_PROTO(type,color,format,...)            \
        SEGGER_RTT_printf(0,"  %s%s"format"\r\n%s", \
                          color,                    \
                          type,                     \
                          ##__VA_ARGS__,            \
                          RTT_CTRL_RESET)

/* 清屏*/
#define LOG_CLEAR() SEGGER_RTT_WriteString(0, "  "RTT_CTRL_CLEAR)

/* 无颜色日志输出 */
#define LOG(format,...) LOG_PROTO("","",format,##__VA_ARGS__)

/* 有颜色格式日志输出 */
#define LOGI(format,...) LOG_PROTO("I: ", RTT_CTRL_TEXT_BRIGHT_GREEN , format, ##__VA_ARGS__)
#define LOGW(format,...) LOG_PROTO("W: ", RTT_CTRL_TEXT_BRIGHT_YELLOW, format, ##__VA_ARGS__)
#define LOGE(format,...) LOG_PROTO("E: ", RTT_CTRL_TEXT_BRIGHT_RED   , format, ##__VA_ARGS__)

#else
#define LOG_CLEAR()
#define LOG
#define LOGI
#define LOGW
#define LOGE

#endif

#endif // !_LOG_H_

用的时候先include “LOG.h”,然后这样用:

效果:

在viewer上查看

配置缓冲区的大小

2. 虚拟终端的用法

a.实现分流

b.改变终端输出字体颜色

c.重定向

d.输出浮点数

找到SEGGER_RTT_printf的实现

在SEGGER_RTT_vprintf的实现中加入输出浮点数的逻辑

    case 'f':
    case 'F': {
      float fv = (float)va_arg(*pParamList, double); // 从参数列表获取float(可变参数默认提升为double)
      unsigned int decimal_part;
      unsigned int precision = NumDigits; // 使用NumDigits作为小数精度(解析格式时的.n),默认0位
      
      // 处理负号
      if (fv < 0.0f) {
      _StoreChar(&BufferDesc, '-');
      fv = -fv; // 转为正数处理,简化后续逻辑
      }
      
      // 处理整数部分(提取小数点前的数字)
      int int_part = (int)fv;
      _PrintInt(&BufferDesc, int_part, 10u, 0u, FieldWidth, FormatFlags); // 整数部分不需要NumDigits(精度),传0
      
      // 处理小数部分(默认至少1位小数,若未指定精度则按1位处理)
      if (precision == 0u) {
      precision = 1u; // 若未指定精度(如%f),默认保留1位小数
      }
      _StoreChar(&BufferDesc, '.'); // 输出小数点
      
      // 计算小数部分:将float放大 precision 倍,取整数后取模(避免浮点误差)
      float decimal_f = fv - (float)int_part; // 提取小数部分(0 <= decimal_f < 1)
      // 生成10^precision(如precision=2则为100),用于放大小数部分
      unsigned int scale = 1u;
      for (unsigned int i = 0u; i < precision; i++) {
      scale *= 10u;
      }
      decimal_part = (unsigned int)(decimal_f * scale + 0.5f); // +0.5f 实现四舍五入
      decimal_part %= scale; // 确保不超出precision位(防止浮点误差导致的溢出)
      
      // 输出小数部分,不足precision位时补前导0(如0.5 → 0.50 当precision=2时)
      _PrintUnsigned(&BufferDesc, decimal_part, 10u, precision, precision, 0u); 
      break;
    }

测试:

3. SEGGER_RTT实现机制解析

好用的开源日志输出工具:SEGGER_RTT实现机制解析-CSDN博客

Logo

DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。

更多推荐