【问题标题】:Arduino Reading floating point numbers with sscanfArduino 使用 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++ 库的支持非常有限

标签: c++ arduino arduino-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 pagesscanf()家庭功能:

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

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

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

      d

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

      您必须改用%x

      x

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

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

      【讨论】:

      • @P__J__ 你能解释一下吗?
      • @Jabberwocky 看看我的回答
      • 你看过这个问题的原始版本吗?格式使用%d 而不是%x 所以rt 为0,因为第一次转换失败。你描述的不是不符合的行为。嵌入式系统中的浮点数通常需要额外的链接标志。但是添加这些标志不会使原始代码成为 IMO。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2016-01-03
      • 2021-11-08
      • 1970-01-01
      • 2014-04-01
      • 1970-01-01
      • 1970-01-01
      • 2016-08-19
      相关资源
      最近更新 更多