Создание форматированной строки (включая числа с плавающей запятой) в 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-символьной строки, пусть будет так.
@Bitbang3r, 👍8
Обсуждение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
Обычно для форматирования строк я бы предложил почтенный 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';
}
Можно использовать инициализацию типа 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
- Arduino Преобразование std:string в String
- Использование StringStream в скетче Arduino
- Чтение строки, разделенной запятыми
- Какова цель F() и FPSTR() в ESP8266WebServer -> FSBrowser?
- Утечка памяти, вызванная конкатенацией строк
- Каков наилучший способ преобразования std::string в строку?
- Чтение и запись в EEPROM
- Возможно ли, чтобы функция возвращала строку ИЛИ число, в зависимости от адреса
использовать функцию dtostrf(), @Juraj