Создание форматированной строки (включая числа с плавающей запятой) в Arduino-совместимом C++

Я использую Mega2560 и универсальный OLED-дисплей SSD1306 с библиотекой Adafruit_SSD1306 (и, соответственно, Adafruit_gfx).

Мне нужно вывести на дисплей набор значений с плавающей запятой (от 30,0 до 99,9) с точностью до одного десятичного знака. Загвоздка в том, что в библиотеке Adafruit нет метода printf(), только тот, который принимает одну готовую к печати строку.

Вот (очевидно, не Arduino) Java-подобный пример того, что я пытаюсь сделать:

String foo = String.format("%.1f, %.1f\%", temp1, hum1);
// «дисплей» — это мой экземпляр Adafruit_SSD1306
display.print(foo);

Итак... как я могу сделать что-то подобное в Arduino-совместимом C(++)?

Примечание: для этой конкретной программы у меня есть (условно говоря) оперативная память для сжигания, поэтому мне действительно все равно, какая библиотека, которую я использую для создания форматированных строк, особенно эффективна (пока она не протекает). Если он хочет использовать 4 КБ ОЗУ и 80 КБ флэш-памяти для форматирования 20-символьной строки, пусть будет так.

, 👍8

Обсуждение

использовать функцию dtostrf(), @Juraj


3 ответа


3

Класс Adafruit_GFX имеет два метода с именами print() и println(). Они ведут себя точно так же, как Serial.print() и Serial.println(). В частности, при печати числа с плавающей запятой вы можете предоставить второй аргумент, указывающий количество десятичных разрядов, которое вы хотите после десятичная точка:

display.print(temp1, 1);  // 1 цифра после запятой
display.print(", ");
display.print(hum1, 1);  // то же самое
display.print("%");

Предыстория: причина, по которой эти методы ведут себя так же, Serial заключается в том, что оба Adafruit_GFX и HardwareSerial наследуют их. из виртуального класса Print .

,

это не идеально для выровненных по правому краю чисел с плавающей запятой на ЖК-дисплее, @Juraj

@Юрай: Верно. Однако формат, используемый ОП в его вопросе ("%.1f, %.1f\%"), не выполняет никакого выравнивания. Таким образом, я предположил, что выравнивание не является обязательным требованием., @Edgar Bonet


4

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

Я полагаю, что где-то в Интернете есть версия с плавающей точкой, которую можно каким-то образом установить, хотя я никогда не рассматривал возможность этого.

Вместо этого вам нужно выполнить форматирование float вручную. Все остальное можно сделать с помощью snprintf, но числа с плавающей запятой нужно делать отдельно.

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

float myVal = 23.49173783;
char *buffer[10]; // Достаточно места для цифр, которые вы хотите, и больше, чтобы быть в безопасности
dtostrf(myVal, 9, 1, buffer);

Первое число в списке параметров — это количество символов, которое вы хотите иметь в выводе, включая . и любой предшествующий -. Любые лишние символы дополняются пробелом. Второе число - это количество знаков после запятой. Если первое число отрицательное, значение выравнивается по левому краю. Если он положительный, он выровнен по правому краю. Таким образом, приведенный выше код даст вам:

〿〿〿〿〿23.5␀

(Примечание: я использую для обозначения символа пробела.) Если вы использовали -9, вы получите:

23.5〿〿〿〿〿␀

Конечно, вы можете передать эту созданную строку в другую строку, используя snprintf и заполнитель %s.

char buf2[32];
snprintf(buf2, 32, "The temperature is: %s\r\n", buffer);

buf2 ⇒ "The temperature is: 23.5〿〿〿〿〿"

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

char *space = strchr(buffer, ' ');
if (space != NULL) {
    *space = '\0';
}
,

0

Можно использовать инициализацию типа String() для преобразования любого числа, включая float, в String. Например, чтобы преобразовать 3.14159, просто введите ⤵︎

float num = 3.14159
String str1 = String(num, 1) // 3.1
String str2 = String(num, 2) // 3.14
String str3 = String(num, 3) // 3.141

Справа от запятой указано количество знаков после запятой, которое должно быть в строковом результате. У него много функций, но это одна из перегрузок. Вы можете увидеть их здесь!

Чтобы увидеть, как этот код работает с скетчем .ino, посетите этот репозиторий GitHub. https://github.com/aeonSolutions/aeonlabs-ESP32-C-Base-Firmware-Libraries

,