【问题标题】:Arduino: printf/fprintf prints question mark instead of floatArduino:printf/fprintf 打印问号而不是浮点数
【发布时间】:2012-12-18 06:49:03
【问题描述】:

我有以下 Arduino 草图代码:

#include <LiquidCrystal.h>

LiquidCrystal lcd(12, 11, 5, 4, 3, 2);
static FILE lcdout = {0} ;

static int lcd_putchar(char ch, FILE* stream)
{
    lcd.write(ch) ;
    return (0) ;
}

void setup() {
  lcd.begin(16, 2);
  fdev_setup_stream (&lcdout, lcd_putchar, NULL, _FDEV_SETUP_WRITE);
}

void loop() 
{
  stdout = &lcdout;
  printf("%.2f Volts", 2.0);
}

问题出现在代码的最后一行。这应该打印出“2.00 Volts”,而是打印出“? Volts”(一个问号,而不是实际的浮点值)。如果我尝试格式化整数,这很好用。

所以基本上,如果我将 printf 行替换为以下内容,它将正常工作:

printf("%d Volts", 2); //prints correctly "2 Volts"

知道有什么问题吗?

【问题讨论】:

  • 一个无法处理浮点转换的愚蠢标准库?
  • 有趣的是,如果你只做一个 lcd.print(2.0) 它会打印出你想要的东西。不需要 sprintf 或任何其他。您可以使用可选的第二个参数指定小数点右边的位数。例如。 lcd.print(2,3) 会给你“2.000”。

标签: c arduino stdio printf


【解决方案1】:

如果您想完全避免 printf 并且只需要在小数点前后使用给定的数字进行打印,我有一些旧代码可能会有所帮助。此代码在 C 中编译,并且在 Arduino IDE 中也可以正常工作。几乎可以肯定,它可以用更少的 C++ 行来完成。 pow10 可以通过编程方式完成,但我正在使用的 C 版本不支持权力:

#include <stdio.h>

/*
Because lcd and serial don't support printf, and its very costly, and all we need
is simple formating with a certain number of digits and precision, this ftoa is enough.
If digits is negative, it will pad left.
*/
#define  BUF_LEN 20
char buf[BUF_LEN]; //need a buffer to hold formatted strings to send to LCD

int ftoa(char * str, float f, char digits, char precision) {
char i=0,k,l=0;
long a,c;
long pow10[10] = {1,10,100,1000,10000,100000,1000000,10000000,100000000,1000000000};
unsigned char b;
char decimal='.';

  if(digits>=10) {return 0;};
  // check for negative float
  if(f<0.0) {
    str[i++]='-';
    f*=-1;
    (0<digits?digits--:digits++);
    }
  a=(int)f; // extracting whole number
  f-=a; // extracting decimal part
  k = digits;
  // number of digits in whole number
  while(k>=0)   {
    c = pow10[k];
    c = a/c;
    if(c>0) { break; }
    k--;
    } // number of digits in whole number are k+1
  if (0<k && digits==k && c>10) { //overflow
    decimal = 'e';
    }
/*
extracting most significant digit i.e. right most digit , and concatenating    to string
obtained as quotient by dividing number by 10^k where k = (number of digit -1)
*/
  for(l=abs(k);l>=0;l--){
    c = pow10[l];
    b = a/c;
    str[i++]=(l&&!b?' ':b+48); //digit or pad
    a%=c;
    }
  if (precision) {str[i++] = decimal;};
/* extracting decimal digits till precision */
  if (0>precision) {k=0; precision=abs(precision);}
  for(l=0;l<precision;l++) {
    f*=10.0;
    b = (int)f; //math floor
    str[i++]=b+48; //48 is ASCII 0
    f-=(float)b;
    if (!k && 0==f) { break; } //nothing left, save chars.
    //won't work if there are any floating point errors.
    }
  str[i]='\0';
  return i;
  }

您可以使用它并在此处查看它的运行情况: http://ideone.com/AtYxPQ

【讨论】:

    【解决方案2】:

    我做了这个:

    unsigned char buffer[32];
    
    void setup() {
      serial.begin();
    }
    
    void loop() {
      if(serial.available()) {
        int size = serial.read(buffer);
        if (size!=0) {
          //serial.write((const uint8_t*)buffer, size);
          int bright = atoi((char *) buffer);
    
          //int final = ((unsigned int)buffer[0]);
    
          //int final = bright -'0';
          serial.write(bright);
          serial.write('\n');
        }
      }
      serial.poll();
    }
    

    现在当我通过 USB 发送一个 0-255 的值时,我得到一个 ascii 字符。 我应该找到一种将 ascii char 转换为 int 的方法。

    例如,我输入 65 并打印 A

    【讨论】:

      【解决方案3】:

      AVR 的 GNU 工具链(包含在 Arduino IDE 中)默认使用 C 标准库的“缩小”版本,例如,浮点支持从格式化的 I 中减少/取消/O 函数(只是为了让printf() 适合芯片的几 kBytes 长存储。)

      如果您想让它工作,您必须使用-Wl,-u,vfprintf -lprintf_flt 链接器标志再次链接另一个包含printf() 正常版本的库。

      【讨论】:

      • 所以当我链接我的代码时我必须提供这个链接器参数,或者我必须再次编译库并提供这个链接器参数?
      • @NicolaeSurdu 您不必重新编译库,您必须在链接自己的代码时提供这些标志。
      • 非常感谢您的支持!
      • 我不会说缩小。缩小意味着它具有所有功能,但代码已被混淆以节省空间。你的意思是代码已经通过删除它的一些功能来精简。
      【解决方案4】:

      来自avr-libcdocumentation

      如果需要包括浮点转换在内的全部功能,则应使用以下选项:

      -Wl,-u,vfprintf -lprintf_flt -l

      请注意,如果您的 MCU 不支持任何浮点运算,则应尽量避免浮点运算。浮点运算将在软件中完成,效率非常低,需要大量闪存。

      【讨论】:

      • 你甚至不需要-lprintf_min IIRC(我已经玩了一段时间了),libc.a 包含缩小的库。
      • @H2CO3 我删除了该行。我还认为,如果你不使用完整的printf_flt,那么printf 就没有任何浮点支持。
      • 是的,这就是我要说的。你总是会得到?
      猜你喜欢
      • 1970-01-01
      • 2021-08-11
      • 1970-01-01
      • 1970-01-01
      • 2018-09-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多