Arduino 使用 sscanf 读取浮点数

Posted

技术标签:

【中文标题】Arduino 使用 sscanf 读取浮点数【英文标题】:Arduino Reading floating point numbers with sscanf 【发布时间】:2019-11-21 13:12:45 【问题描述】:

我正在尝试使用 sscanf() 读取数字,但我使用双变量没有成功,但可以读取 int

双重示例

//double var reading not working 
    const char KBuffer[80] = "0x3:2.1:2.1:2.1";

    int rt;
    double p,i,d;
    int n = sscanf(KBuffer, "%x:%lf:%lf:%lf", &rt, &p, &i, &d);

    Serial.println();
    Serial.print("rt "); Serial.print(rt);
    Serial.print(" P ");Serial.print(p);
    Serial.print(" i ");Serial.print(i);
    Serial.print(" d ");Serial.print(d);

// 输出 rt 3 P 0.00 i ovf d 0.00

整数示例

// int reading working ok
    const char KBuffer[80] = "0x3:2:2:2";

    int rt;
    int p,i,d;
    int n = sscanf(KBuffer, "%x:%d:%d:%d", &rt, &p, &i, &d);

    Serial.println();
    Serial.print("rt "); Serial.print(rt);
    Serial.print(" P ");Serial.print(p);
    Serial.print(" i ");Serial.print(i);
    Serial.print(" d ");Serial.print(d);
 // output
rt 3 P 2 i 2 i 2 

所以知道做错了什么

当我在 c++ 在线编译器上运行时相同的代码,例如:https://onlinegdb.com/ryS8zfE3r

我得到了正确的结果

【问题讨论】:

"%d:%lf:%lf:%lf" -> "%x:%lf:%lf:%lf" @Jabberwocky 恐怕还不够 @Jabberwocky 我更新了它,有点错误但问题是一样的 @SamVarshavchik Arduino 语言是具有 C++ 语法和非标准库的 C++ 编译器。 @AnttiHaapala 它是没有 90% 的 C++ 的 C++ 变体 - 对标准 C++ 库的支持非常有限 【参考方案1】:

即使第一次转换顺利,arduino scanf 也不会读取浮点数,printf 也不会打印它们。 scanf 和 printf 系列函数默认不支持浮点数。

第一个问题很容易排序:int n = sscanf(KBuffer, "0x%x:%d:%d:%d", &rt, &p, &i, &d); 第二个需要通过添加-Wl,-u,vfscanf -lscanf_flt -lm 来更改编译器(或链接器)选项,但 irt 会增加大约 15kb 的图像大小。

在安装板库的目录中的hardware/tools/avr/doc/avr-libc/group__avr__stdio.html 中阅读更多信息

【讨论】:

【参考方案2】:

花了一段时间后,我得出结论,sscanf 无法处理浮点/双精度值,因此为了解决通过串行通信输入浮点数的问题,我采用了另一种方法,分享它可能会对某人有所帮助

void setup() 
Serial.begin(9600);


void loop() 
char KBuffer[80] = "c:0x3;p:2.12;i:2.15;d:2.17";

bool top_pid_input = false;

// Read each command pair
char* command = strtok(KBuffer, ";");
while (command != NULL)
  
//  Serial.print(command);
    // Split the command in two values
    char* separator = strchr(command, ':');
    if (separator != 0)
    
       // Actually split the string in 2: replace ':' with 0
      *separator = 0;

        // string
         if(strcmp(command, "c") == 0 )
            top_pid_input = true;
            Serial.println();Serial.print(" command: ");Serial.print(command);
            ++separator;
            Serial.print(separator);
         else if(top_pid_input && strcmp(command, "p") == 0 )
            Serial.println();Serial.print(" p: ");Serial.print(command);
            ++separator;
            Serial.print(separator);        
        else if(top_pid_input && strcmp(command, "i") == 0 )
            Serial.println();Serial.print(" i: ");Serial.print(command);
            ++separator;
            Serial.print(separator);          
        else if(top_pid_input && strcmp(command, "d") == 0 )
            Serial.println();Serial.print(" d: ");Serial.print(command);
            ++separator;
            Serial.print(separator);         
        

     // convert char to float 
     top_kd = atof(separator);  

    
    // Find the next command in input string
    command = strtok(0, ";");




delay(300000);

【讨论】:

【参考方案3】:

编辑:问题已被编辑,因此此答案不再相关。

根据man pages对scanf()家庭功能:

返回值 这些函数返回输入项的数量 成功匹配和分配,可以少于提供的 在早期匹配失败的情况下,甚至为零。

您应该检查代码中的返回值n,以查看转换是否失败。

这里,第一次转换失败:%d 无法读取十六进制数字。再次从手册页:

d

匹配一个可选的有符号十进制整数;下一个指针必须是 一个指向 int 的指针。

您必须改用%x

x

匹配一个无符号的十六进制整数;下一个指针必须是 指向无符号整数的指针。

因为第一次转换失败,所以其他的转换都没有执行。

【讨论】:

@P__J__ 你能解释一下吗? @Jabberwocky 看看我的回答 你看过这个问题的原始版本吗?格式使用%d 而不是%x 所以rt 为0,因为第一次转换失败。你描述的不是不符合的行为。嵌入式系统中的浮点数通常需要额外的链接标志。但是添加这些标志不会使原始代码成为 IMO。

以上是关于Arduino 使用 sscanf 读取浮点数的主要内容,如果未能解决你的问题,请参考以下文章

arduino怎么写小数吗

批处理文件:从 .csv 文件中读取浮点值

ValueError:无法将字符串转换为浮点数:使用 matplotlib、arduino 和 pyqt5 时

Arduino对串口接收到的数据处理以及对整数或者浮点数数据进行提取

TCL:变量存储一个代表浮点数的十六进制值,如何将它作为浮点数显示在屏幕上?

汇编浮点指令