【问题标题】:STM32L1 snprintf usage to convert float to stringSTM32L1 snprintf使用float转字符串
【发布时间】:2021-06-20 10:19:09
【问题描述】:

我在 STM32 上将 float 转换为 str 时遇到问题, 我有两个简单的函数来打印 Int 和 Float Int 工作正常,但浮点打印导致程序崩溃

void LCD_PrintInt(int value) {
    char str[8];
    sprintf(str, "%d", value);
    LCD_Print(str);
}

void LCD_PrintFloat(float value, uint8_t length) {
    char str[length];
    snprintf(str, length + 1, "%f", value);
    LCD_Print(str);
}

LCD_PrintFloat(99.9, 4); <- crash
LCD_Print("99.9"); <- works fine

我正在使用 STM32CubeIDE 并设置 -u _printf_float 链接器标志 我究竟做错了什么?浮点运算(在STM32上)是正确的方法吗?

【问题讨论】:

    标签: floating-point type-conversion stm32


    【解决方案1】:

    对于“%d”,您至少需要 12 个字符,您只允许 8 个。

    在“%f”的情况下,你需要 10 个,但你只分配了 4 个,然后你告诉 snprintf 你已经分配了 5 个。

    您需要 10 的原因是“99.900000”加上一个空终止符(printf 默认使用 6 个小数位)。如果只需要一位小数,则需要使用“%.1f”。

    无论你想要多少个地方,你都必须告诉函数有多少字节是真正可用的。当您为空终止符添加一个时,您还必须将其添加到缓冲区的大小,而不仅仅是函数参数。

    [编辑] 我错过了更大的问题是%f 需要一个双精度类型的参数,但您传递的是一个浮点数。如果您使用 -Wall 打开警告,它会告诉您这一点。

    【讨论】:

    • void LCD_PrintFloat(float value) { char str[10]; snprintf(str, 10, "%f", value); LCD_Print(str); } 我分配了 10 或 11 但仍然程序崩溃
    • 哪个编译器和设置?
    • gcc -mcpu=cortex-m3 -std=gnu11 -g3 -DUSE_HAL_DRIVER -DSTM32L151xBA -DDEBUG -c -I../Core/Inc -I../Drivers/STM32L1xx_HAL_Driver/Inc -I. ./Drivers/STM32L1xx_HAL_Driver/Inc/Legacy -I../Drivers/CMSIS/Device/ST/STM32L1xx/Include -I../Drivers/CMSIS/Include -O0 -ffunction-sections -fdata-sections -Wall -fstack-用法 --specs=nano.specs -mfloat-abi=soft -mthumb
    • 在 C 中,... 函数的 float 参数被提升为 double-Wall 是个好主意,但在这里并没有什么不同。但也许 STM32 不符合 C 标准。
    • STM32 是硬件。它不能合规或不合规。我怀疑(尽管他没有说)OP 正在使用或多或少兼容的 newlib C 库。
    【解决方案2】:

    我做错了什么?

    关闭 1

    不要告诉snprintf() 有比实际可用空间更多的空间。这会导致 OP 经历的未定义行为 (UB)。

    char str[length];
    // snprintf(str, length + 1, "%f", value);  // One too many
    snprintf(str, length, "%f", value);
    

    最好使用适合所有float 的格式和缓冲区大小。我建议使用指数格式,例如:%a%g%e
    "%e" 示例:

    //                     -   d   .  dddddddd  e   -  E...E \0
    #define FLT_TEXT_SIZE (1 + 1 + 1 +    8   + 1 + 1 + 5   + 1)
    char str[FLT_TEXT_SIZE];
    snprintf(str, sizeof str, "%.*e", FLT_DECIMAL_DIG-1, value);
    

    我怀疑 OP 的 snprintf() 不能很好地处理缓冲区太小的情况。使用充足的缓冲区。

    【讨论】:

    • #include &lt;float.h&gt; void LCD_PrintFloat(float value) { char str[FLT_TEXT_SIZE]; snprintf(str, sizeof str, "%.*e", FLT_DECIMAL_DIG-1, value); LCD_Print(str); } 仍然导致程序崩溃
    • @dmvs 我怀疑 snprintf() 本身或其与 FP 一起使用会导致问题,可能不喜欢数学库。祝你好运
    • 我应该使用另一种方式将float转换为str吗?使用我的 LCD_print()
    • @dmvs 你在数学库中链接吗?
    • 链接器命令gcc -lm如果我不明白我很抱歉,但我是STM32的新手
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-07-25
    • 2016-07-31
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多