Arduino: printf / fprintf печатает знак вопроса вместо float

У меня есть следующий код для эскиза Arduino:

#include  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» (знак вопроса вместо фактического значения поплавка). Если я попытаюсь форматировать целое число, это отлично работает.

Поэтому в основном, если я заменю строку printf следующим образом, она будет работать правильно:

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

Любая идея, в чем проблема?

Инструментальная привязка GNU для AVR (которая входит в состав Arduino IDE) по умолчанию использует «минированную» версию стандартной библиотеки C, в которой, например, поддержка с плавающей запятой уменьшается / отбирается от форматированных функций ввода / вывода (только для того, чтобы printf() вписывался в несколько kBytes долгое время хранения чипа.)

Если вы хотите, чтобы это сработало, вам нужно связать еще одну библиотеку, содержащую обычную версию printf() , с помощью -Wl,-u,vfprintf -lprintf_flt .

Из документации avr-libc :

Если требуется полная функциональность, включая конверсии с плавающей запятой, следует использовать следующие параметры:

-Wl,-u,vfprintf -lprintf_flt -l

Обратите внимание, что если ваш MCU не поддерживает поддержку с плавающей запятой, вы должны полностью отказаться от операций с плавающей запятой. Операции с плавающей запятой будут выполняться в программном обеспечении, которое очень неэффективно и требует много флэш-памяти.

Я сделал это:

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

и теперь я получаю символ ascii, когда я посылаю значение от 0 до 255 через USB. Я должен найти способ преобразования ascii char в int.

например, тип 65, и он печатает A

У меня есть старый код, который может помочь, если вы хотите полностью отказаться от printf и просто нужно печатать с заданным числом цифр до и после десятичного числа. Этот код компилируется на C и отлично работает в среде Arduino. Это почти наверняка можно было сделать в меньшем количестве строк на C ++. Pow10 можно было сделать программно, но полномочия не поддерживались в версии CI, которая работала с:

 #include  /* 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=0) { c = pow10[k]; c = a/c; if(c>0) { break; } k--; } // number of digits in whole number are k+1 if (010) { //overflow decimal = 'e'; } /* extracting most significant digit ie 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 в #include  /* 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=0) { c = pow10[k]; c = a/c; if(c>0) { break; } k--; } // number of digits in whole number are k+1 if (010) { //overflow decimal = 'e'; } /* extracting most significant digit ie 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 

Вы можете играть с ним и посмотреть, как он работает здесь: http://ideone.com/AtYxPQ