Arduino 使用 sscanf 读取浮点数

Arduino Reading floating point numbers with sscanf

我正在尝试使用 sscanf() 读取数字,但我使用 double vars 没有成功,但可以读取 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

我得到了正确的结果

编辑:问题已被编辑,所以这个答案不再相关。

根据 man pagesscanf() 族函数:

Return value These functions return the number of input items successfully matched and assigned, which can be fewer than provided for, or even zero in the event of an early matching failure.

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

此处,第一次转换失败:%d无法读取十六进制数。再次来自手册页:

d

Matches an optionally signed decimal integer; the next pointer must be a pointer to int.

您必须使用 %x 来代替:

x

Matches an unsigned hexadecimal integer; the next pointer must be a pointer to unsigned int.

由于第一次转换失败,其他的转换都没有进行。

即使第一次转换顺利,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 中的板库安装目录中阅读更多内容

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

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);
}