SEGGER RTT printf 的移植和浮点数处理

本文档详细介绍了如何在STM32项目中移植并配置SEGGER RTT库,以实现浮点数打印和彩色日志输出。首先从安装目录获取RTT源代码并将其添加到项目中,然后修改SEGGER_RTT_Config.h裁剪内存和启用浮点数支持。接着,修改SEGGER_RTT_printf.c以处理浮点数,并在用户层封装宏定义,提供方便的日志输出接口。在测试过程中,发现并解决了浮点数负数打印丢失的问题。此外,还记录了在RT1052上移植时遇到的显示问题及解决方法,包括查找SEGGER_RTT.o的.bss段地址并在RTT Viewer中配置。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1. 从安装目录下找到RTT源代码

C:\Program Files\SEGGER\JLink\Samples\RTT

将压缩包解压,解压后目录如下

在这里插入图片描述

将RTT中源代码拷贝至项目工程中

在这里插入图片描述

2. 修改配置和源代码

  1. SEGGER_RTT_Config.h 中可根据需要裁剪内存占用大小,和是否启动LOCK和UNLOCK, 并添加浮点数支持的宏定义

    //! 浮点数的支持(需要420 BYTE的flash空间)
    #ifndef SEGGER_RTT_PRINT_FLOAT_ENABLE
        #define SEGGER_RTT_PRINT_FLOAT_ENABLE                 (1)
    #endif
    
  2. 如何支持浮点数打印,修改SEGGER_RTT_printf.c

  3. 调用关系SEGGER_RTT_printf–>SEGGER_RTT_vprintf, 固在SEGGER_RTT_vprintf中添加如下代码

    int SEGGER_RTT_vprintf(unsigned BufferIndex, const char * sFormat, va_list * pParamList) {
      char c;
      SEGGER_RTT_PRINTF_DESC BufferDesc;
      int v;
      unsigned NumDigits;
      unsigned FormatFlags;
      unsigned FieldWidth;
      char acBuffer[SEGGER_RTT_PRINTF_BUFFER_SIZE];
    
      BufferDesc.pBuffer        = acBuffer;
      BufferDesc.BufferSize     = SEGGER_RTT_PRINTF_BUFFER_SIZE;
      BufferDesc.Cnt            = 0u;
      BufferDesc.RTTBufferIndex = BufferIndex;
      BufferDesc.ReturnValue    = 0;
    
      do {
        c = *sFormat;
        sFormat++;
        if (c == 0u) {
          break;
        }
        if (c == '%') {
          //
          // Filter out flags
          //
          FormatFlags = 0u;
          v = 1;
          do {
            c = *sFormat;
            switch (c) {
            case '-': FormatFlags |= FORMAT_FLAG_LEFT_JUSTIFY; sFormat++; break;
            case '0': FormatFlags |= FORMAT_FLAG_PAD_ZERO;     sFormat++; break;
            case '+': FormatFlags |= FORMAT_FLAG_PRINT_SIGN;   sFormat++; break;
            case '#': FormatFlags |= FORMAT_FLAG_ALTERNATE;    sFormat++; break;
            default:  v = 0; break;
            }
          } while (v);
          //
          // filter out field with
          //
          FieldWidth = 0u;
          do {
            c = *sFormat;
            if ((c < '0') || (c > '9')) {
              break;
            }
            sFormat++;
            FieldWidth = (FieldWidth * 10u) + ((unsigned)c - '0');
          } while (1);
    
          //
          // Filter out precision (number of digits to display)
          //
          NumDigits = 0u;
          c = *sFormat;
          if (c == '.') {
            sFormat++;
            do {
              c = *sFormat;
              if ((c < '0') || (c > '9')) {
                break;
              }
              sFormat++;
              NumDigits = NumDigits * 10u + ((unsigned)c - '0');
            } while (1);
          }
          //
          // Filter out length modifier
          //
          c = *sFormat;
          do {
            if ((c == 'l') || (c == 'h')) {
              sFormat++;
              c = *sFormat;
            } else {
              break;
            }
          } while (1);
          //
          // Handle specifiers
          //
          switch (c) {
    		...
    
    //! ============================================================
            //! 支持浮点数  
    #if (SEGGER_RTT_PRINT_FLOAT_ENABLE != 0)	
            case 'f':
            case 'F':
            {
                float fv;
                fv = (float)va_arg(*pParamList, double);    //取出输入的浮点数值
                
    			if(fv < 0) _StoreChar(&BufferDesc, '-');          // 判断正负,用来显示负号
                
                v = abs((int)fv);                                //取整数部分
    
                _PrintInt(&BufferDesc, v, 10u, NumDigits, FieldWidth, FormatFlags); //显示整数
                _StoreChar(&BufferDesc, '.');                                        //显示小数点
    
                v = abs((int)(fv * 1000));               
                v = v % 1000;
                _PrintInt(&BufferDesc, v, 10u, 3, FieldWidth, FormatFlags);          //显示小数点后三位
            }
            break;
    #endif	
    //! ============================================================
    
          default:
            break;
          }
          sFormat++;
        } else {
          _StoreChar(&BufferDesc, c);
        }
      } while (BufferDesc.ReturnValue >= 0);
        
        ...
    }
    

3. 用户层封装, 在头文件中实现如下代码

//! 调试输出配置
#define RTT_DBG_ENABLE          (1)

#if RTT_DBG_ENABLE
    #include "SEGGER_RTT.h"
	/* 初始化调试模块 */
    #define DEBUG_INIT()    SEGGER_RTT_Init()
    /* RTT 终端号 */
    #define RTT_DBG_PORT        0
    #define LOG_PROTO(type,color,format,...)                        \
            SEGGER_RTT_printf(RTT_DBG_PORT,"%s%s"format"\r\n%s",    \
                            color,                                  \
                            type,                                   \
                            ##__VA_ARGS__,                          \
                            RTT_CTRL_RESET)
    /* 清屏*/
    #define log_clear()     SEGGER_RTT_WriteString(RTT_DBG_PORT, "  "RTT_CTRL_CLEAR)
    /* 无颜色日志输出 */
    #define log_debug(format,...)   LOG_PROTO("D:","",format,##__VA_ARGS__)
    /* 有颜色格式日志输出 */
    #define log_info(format,...)    LOG_PROTO("I:", RTT_CTRL_TEXT_BRIGHT_GREEN , format, ##__VA_ARGS__)
    #define log_warn(format,...)    LOG_PROTO("W:", RTT_CTRL_TEXT_BRIGHT_YELLOW, format, ##__VA_ARGS__)
    #define log_error(format,...)   LOG_PROTO("E:", RTT_CTRL_TEXT_BRIGHT_RED   , format, ##__VA_ARGS__)

#else
    #define DEBUG_INIT()
    #define log_clear()
    #define log_debug
    #define log_info
    #define log_warn
    #define log_error
#endif

4. 测试

在这里插入图片描述

在这里插入图片描述

这样浮点数打印以及日志颜色都能使用了,注意:浮点数只能打印两位,如需要更多则修改源码即可

20221114修改:之前打印-0.03之类小于0的小数,负号会丢失,固重新修改了下打印浮点机制,现已正常

参考链接1:用VS Code开发STM32(四)——增加SEGGER RTT日志输出支持
参考链接2:给SEGGER RTT的 SEGGER_RTT_printf() 函数添加浮点显示功能

补充:
  1. 移植到rt1052上遇到的问题和解决
    a. 移植到rt1052上后发现显示不出来,然后网上搜到了这个文章:https://blog.youkuaiyun.com/qq_31860135/article/details/128135539
    b. 然后从map文件中找到了segger_rtt.o的.bss端地址(即rtt上传至rtt viewer工具的缓冲数组)
    map中的rtt数组地址
    c. 然后修改rtt viewer工具配置
    rtt工程配置
    d. 最终正常的显示效果
    正常显示效果
    2. 问题分析
    a. 尝试使用了6.98e版本的rtt viewer,发现可以自动检测到,直接显示(无需手动设置地址)
    b. 对比两个版本设置差异: 不同版本的配置差异
    c. 最终发现7.88e版本找不到具体的型号了,只有系列类型;而6.98e还可已找到对应的型号,所有6.98e可以直接自动检测,而7.88e需要手动输入地址
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值