Arduino: printf / fprintf печатает знак вопроса вместо поплавка
у меня есть следующий код для 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 Вольт", но вместо этого, он печатает "? Вольт " (знак вопроса вместо фактического значения float). Если я пытаюсь отформатировать целое число, это отлично работает.
таким образом, в основном, если я заменю строку printf следующим, она будет работать правильно:
printf("%d Volts", 2); //prints correctly "2 Volts"
есть идеи, в чем проблема ?
4 ответов
GNU toolchain для AVRs (который входит в состав Arduino IDE) по умолчанию использует "минифицированную" версию стандартной библиотеки C, в которой, например, поддержка с плавающей запятой уменьшается/удаляется из отформатированных функций ввода-вывода (просто в порядке printf()
для установки в несколько кбайт длинного хранения чипа.)
Если вы хотите, чтобы это работало, вам нужно связать другую библиотеку, содержащую обычную версию 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-символ в int.
e.g I тип 65, и он печатает
У меня есть старый код, который может помочь, если вы хотите полностью избежать 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]='';
return i;
}
вы можете играть с ним и видеть, как он работает здесь: http://ideone.com/AtYxPQ