硬汉嵌入式论坛

 找回密码
 立即注册
查看: 1942|回复: 6
收起左侧

[SEGGER RTT] 添加SEGGER_RTT_printf的浮点数打印

[复制链接]

2

主题

7

回帖

13

积分

新手上路

积分
13
发表于 2024-8-16 18:24:01 | 显示全部楼层 |阅读模式
SEGGER_RTT_vprintf函数中添加代码如下:

[C] 纯文本查看 复制代码
case 'f':
      case 'F':
      {
        float fv = (float)va_arg(*pParamList, double); // Retrieves the input floating point value

        v = (int)fv;                                                         // Take the positive integer part
        _PrintInt(&BufferDesc, v, 10u, FieldWidth, FieldWidth, FormatFlags); // According to an integer

        if ((NumDigits == 0) || (NumDigits > 6)) // 最高打印6位小数
          NumDigits = 6;

        _StoreChar(&BufferDesc, '.'); // Display decimal point
        unsigned int powN = _pow(10, NumDigits);

        fv = fv - v;            // 取小数部分
        fv = fv < 0 ? -fv : fv; // 取小数的绝对值
        fv *= powN;             // 根据显示精度取整
        v = (int)(fv);
        if (fv - v >= 0.5f) // 四舍五入
          v += 1;

        _PrintUnsigned(&BufferDesc, (unsigned)v, 10u, NumDigits, FieldWidth, FormatFlags | FORMAT_FLAG_LEFT_JUSTIFY | FORMAT_FLAG_PAD_ZERO); // Display three decimal places
      }
break;



其中依赖的函数与数组:
[C] 纯文本查看 复制代码
static unsigned int _powBuf[] = {1, 10, 100, 1000, 10000, 100000, 1000000};
/*********************************************************************
 *
 *       _pow
 */
static unsigned int _pow(unsigned char base, unsigned char index)
{
  (void)base;
  if (index <= 6)
    return _powBuf[index];
  else
    return 1;
}


测试浮点的代码:
[C] 纯文本查看 复制代码
    float data_float = 1234.12595f;
    double data_double = 1234.12595f;

    float short_pi = 3.14f;
    float pi = 3.1415926535f;

    SEGGER_RTT_printf(0, "data_float = %.0f\n", data_float);
    SEGGER_RTT_printf(0, "data_float = %.1f\n", data_float);
    SEGGER_RTT_printf(0, "data_float = %.2f\n", data_float);
    SEGGER_RTT_printf(0, "data_float = %.3f\n", data_float);
    SEGGER_RTT_printf(0, "data_float = %.4f\n", data_float);
    SEGGER_RTT_printf(0, "data_float = %.5f\n", data_float);
    SEGGER_RTT_printf(0, "data_float = %.6f\n", data_float);
    SEGGER_RTT_printf(0, "data_float = %.7f\n", data_float);
    SEGGER_RTT_printf(0, "-data_float = %f\n", -data_float);
    SEGGER_RTT_printf(0, "-data_float = %03.5f\n", -data_float);
    SEGGER_RTT_printf(0, "-data_float = %6.5lf\n", -data_float);

    SEGGER_RTT_printf(0, "data_double = %.0lf\n", data_double);
    SEGGER_RTT_printf(0, "data_double = %.1lf\n", data_double);
    SEGGER_RTT_printf(0, "data_double = %.2lf\n", data_double);
    SEGGER_RTT_printf(0, "data_double = %.3lf\n", data_double);
    SEGGER_RTT_printf(0, "data_double = %.4lf\n", data_double);
    SEGGER_RTT_printf(0, "data_double = %.5lf\n", data_double);
    SEGGER_RTT_printf(0, "data_double = %.6lf\n", data_double);
    SEGGER_RTT_printf(0, "data_double = %.7lf\n", data_double);
    SEGGER_RTT_printf(0, "-data_double = %lf\n", -data_double);
    SEGGER_RTT_printf(0, "-data_double = %03.5lf\n", -data_double);
    SEGGER_RTT_printf(0, "-data_double = %6.5lf\n", -data_double);

    SEGGER_RTT_printf(0, "pi = %f\n", short_pi);
    SEGGER_RTT_printf(0, "pi = %f\n", pi);


打印效果:
111.png

对比电脑端C语言的效果:
222.png

占用的flash大小:
增加前: 333.png
增加后: 444.png
flash占用2964Bytes,约2.9KB。

存在的问题:
1. %.0f 处理的不好,正确逻辑应该不打印小数,这里打印了六位最高精度。
原因是想尽量减少修改,如果想正确处理这部分逻辑,需要判断"."的时候添加标志位。而且应该也没什么人打浮点数不打小数吧。

2. double 的精度不够。
555.png
可以看到float的精度符合预期,但是double的精度与float相同。比较奇怪的是电脑端的c语言也是一样。

最后吐槽一下CubeIDE:
本来没想在这里添加浮点支持的,但是神奇的CubelIDE使能了-u _printf_float后,flash神奇的增加了十几KB,各位有兴趣的话可以试试。


评分

参与人数 1金币 +100 收起 理由
eric2013 + 100 很给力!

查看全部评分

回复

使用道具 举报

2

主题

7

回帖

13

积分

新手上路

积分
13
 楼主| 发表于 2024-8-16 18:29:11 | 显示全部楼层
这个浮点打印的精度最高只到六位小数,如果需要增加的话,需要修改第一段代码中的最大值限制,以及第二个计算十次方函数的数组也要对应添加变量。
这份代码的尺寸是我能做到的最小尺寸了,希望有大佬优化一下
回复

使用道具 举报

2

主题

22

回帖

28

积分

新手上路

积分
28
发表于 2024-8-17 09:55:54 | 显示全部楼层
这里有个NIT的printf的实现,好像还不错,https://github.com/mpaland/printf
回复

使用道具 举报

1万

主题

7万

回帖

11万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
115434
QQ
发表于 2024-8-17 10:40:32 | 显示全部楼层
谢谢楼主分享。
回复

使用道具 举报

2

主题

7

回帖

13

积分

新手上路

积分
13
 楼主| 发表于 2024-8-20 10:39:45 | 显示全部楼层
zouhp 发表于 2024-8-17 09:55
这里有个NIT的printf的实现,好像还不错,https://github.com/mpaland/printf

测试过了,使用这个的vsnprintf,比我写的大了接近10k。但是比CubeIDE的-u _printf_float小了接近8k。
这个确实更标准、通用一些。
回复

使用道具 举报

4

主题

178

回帖

190

积分

初级会员

积分
190
发表于 2024-11-17 21:49:45 | 显示全部楼层
还有优化之处,比如
short_pi = 3.14;
printf("pi = %-7.3fA\n", short_pi);
printf("pi = %07.3fA\n", short_pi);  
printf("pi = %10.3fA\n", short_pi);  
上面添加的代码,这些和C库的打印出来都不对
回复

使用道具 举报

0

主题

7

回帖

7

积分

新手上路

积分
7
发表于 2025-4-1 19:45:48 | 显示全部楼层
有一点小小的问题,当浮点数在(-1,0)之间时,打印出的数字没有负号。
稍微优化了一下,如果有问题,欢迎各位大佬指正。
[C] 纯文本查看 复制代码
case 'f':
case 'F':
{
    float fv = (float)va_arg(*pParamList, double); // Retrieves the input floating point value
    int sign = fv < 0 ? -1 : 1; // 记录符号
    fv = fv < 0 ? -fv : fv; // 取绝对值

    int v = (int)fv;                                                         // Take the positive integer part
    if (sign == -1) {
        _StoreChar(&BufferDesc, '-'); // 如果是负数,先输出负号
    }
    _PrintInt(&BufferDesc, v, 10u, FieldWidth, FieldWidth, FormatFlags); // According to an integer

    if ((Precision == 0) || (Precision > 6)) // 最高打印6位小数
        Precision = 6;

    _StoreChar(&BufferDesc, '.'); // Display decimal point
    unsigned int powN = _pow(10, Precision);

    fv = fv - v;            // 取小数部分
    fv *= powN;             // 根据显示精度取整
    v = (int)(fv);
    if (fv - v >= 0.5f) // 四舍五入
        v += 1;

    _PrintUnsigned(&BufferDesc, (unsigned)v, 10u, Precision, FieldWidth, FormatFlags | FORMAT_FLAG_LEFT_JUSTIFY | FORMAT_FLAG_PAD_ZERO); // Display three decimal places
}
break;
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|小黑屋|Archiver|手机版|硬汉嵌入式论坛

GMT+8, 2025-4-25 21:45 , Processed in 0.290282 second(s), 29 queries .

Powered by Discuz! X3.4 Licensed

Copyright © 2001-2023, Tencent Cloud.

快速回复 返回顶部 返回列表