How to format strings without the String class
I often recommend avoiding the String class in Arduino programs, but I never took the time to show you the alternatives. In this article, I’ll teach you how to format complex strings without the String class. What do I mean by that? You know, this kind of things:
What’s the problem with the String class?
But why should we avoid the String class? As I explained in a previous article, heap fragmentation is a major concern in embedded programming. To prevent fragmentation, you should always allocate blocks of the same size, or better, don’t use the heap at all.
The problem with the String class is that it forces you to use the heap and allocates blocks of variables size. Use several String instances in your program, and soon, the RAM is full of holes like Swiss cheese.
Back to basics
So how can we get rid of the String class? We’ll take some distance with C++ for a moment and get back to plain old C. As you probably know, we can use any C feature in C++, and that what we’re going to do in this article: we’ll formats strings as C programmers do.
First, let’s look at how the C language models strings. In C, a string is a contiguous sequence of characters ended by a 0. We call this last byte the “terminator” because it marks the end of the sequence. The picture below shows how the bytes of the string “hello” are laid out in RAM.
Keep this picture in mind because every time you write a string literal, this is exactly what goes in memory, whether you use the String class or not. Indeed, the String class is just a fancy wrapper on top of a C string. Everything you can do with the String class, you can also do with a C string, even if it’s usually more complicated.
String formatting in C
If you’ve done any C programming, you probably used the printf() function, which writes things to the terminal. printf() is the equivalent of Arduino’s Serial.print() .
The major difference between printf() and Serial.print() is that, before passing the things you want to write, you must tell printf() the type of those things. For example, suppose you have a float that contains the weight of something, and you want to display it. On Arduino you would write:
In C, you would write:
As you see, we need to pass an extra argument that specifies the type. In this case, %f means that we are passing a floating-point value. We’ll see more examples in a moment, but first, let me explain how this relates to strings.
Storing the result
As you know, Serial.print() sends information to the serial port but doesn’t store it. Similarly, printf() sends information to the terminal but doesn’t store anything. To save the result of in a string, we need to use another function called sprintf() . This function takes the destination string as an additional argument. The destination comes first in the argument list, before the format and before the values you want to write.
If we go back to our previous example, to store the string on Arduino you would probably write:
In C, you would write;
As you can see, the C version is a little more verbose. In addition to calling sprintf() , we need to allocate the sequence of characters. In this case, we used a simple char array large enough to store the string with the terminator.
Now you can see a major difference between the two approaches: the Arduino version uses a String , which allocates the right number of bytes in the heap, whereas the C version allocates a fixed number of bytes in the stack.
You probably worry about the overhead caused by the unused bytes in the array. You’re right, there can be up to 14 unused bytes in the array, but this is nothing compared to what you loose from the heap management data and from the heap fragmentation. Moreover, this is a local variable, so we’ll reclaim the memory as soon as it gets out of scope.
Buffer overflows
No, I’m not worried about the memory overhead, but I’m seriously concerned about buffer overflows. What happens if you’ve been too cheap when allocating the string and the actual content is longer than expected. I’ll tell you what happens: bad things! sprintf() is not aware of the capacity of the destination buffer, so it continues to write as if nothing happened.
In practice, it overrides the bytes that follow the buffer in RAM. For example, if there is an integer variable stored just after the buffer, the value of this variable will change. This is what we call a buffer overflow, and it’s a real security issue. Not only a buffer overflow may crash your program, but it also allows hackers to modify the memory of your process and change its behavior.
To protect your program against buffer overflows, you must use another variant of printf() , called snprintf() , which supports an additional parameter to specify the capacity of the destination buffer. Here it is in action:
As you can see, we pass the size of the buffer as the second parameter of snprintf() ; I used the literal 16 , but we could use sizeof(s) instead.
Placeholders
We saw how we could use snprintf() to convert a float to a string, is that all we can do? Of course not, that was just an introduction; snprintf() is very flexible as we’ll see now.
First, let’s see how we can put this float in a sentence. Imagine we want to generate the string «weight =
From the programmer’s point of view, this line of code is OK: it does the job and is fairly readable. However, from the processor standpoint, this line of code is horrible: it requires 4 allocations in the heap and possibly several memory duplications. That’s way too much work for such a simple task.
Now, let’s see how we would write the same line with snprintf() :
The syntax is a bit more clunky, but as soon as you get used to it (and every C programmer got used to it before you), it reads fairly well too. As you can see, the %f that was our complete format specification is now a placeholder for the value.
If you want to format your number in a certain way, you can say so in the format string. For example, if you want four digits after the decimal point, you can write:
As a reminder, this is how you would do with the String class:
Which one is the most readable now?
Other types
I think you get the idea; let’s talk about other value types. Remember that you must adapt the format specifier to the type of the value. %f was only for floats; for other types, you must use other specifiers like %i , %h , or %s . The table below summarizes the most common format specifiers:
Format | Type |
---|---|
%c | char |
%i | int |
%u | unsigned |
%f | float * |
%s | string |
*: not supported by the Arduino Core for AVR
You can find the complete list on Wikipedia. There is also a shorter version in Appendix B of the K&R book, which I recommend.
Mixing types
Of course, we can use several placeholders when we have several values. Suppose we want to create the string »
As you see, we use the %s format for the string and %i for the integer. In this case, I assumed the string was a const char* . Indeed, snprintf() is a C function, so it knows nothing about C++ objects, it only supports C strings. If instead, we have a String object, we would have to get the pointer to the internal C string, like that:
Also, notice the order of the arguments: the values appear in the same order as the placeholders. This is a constraint imposed by printf functions: the arguments must be in the same order as the placeholders in the format string.
Format string errors
What happens if you pass the arguments in the wrong order? For %i , it’s not so bad, snprintf() would treat name as an integer instead of a string. In practice, it would print the address of the string in decimal. Things get way worse for the %s because snprintf() would treat the integer as a string: it would look at the bytes at the address specified in the integer and print them until it finds the terminator. In practice, this would print garbage in the destination buffer.
Here too, we have a potential security issue. If there is a mismatch between the format specifier and the types of the arguments, the program may disclose information that an attacker could exploit. For example, it could display the value of a pointer value, or even reveal the complete content of the RAM.
Fortunately, the compiler is your friend: it issues a warning when it detects a mismatch in a printf-like function. That’s yet another reason why you should never ignore warnings.
Because this verification is done by the compiler, it can only work if the format string is available at compile-time. In other words, it only works if you pass a constant as the format string. Remember this: Never use a variable as the format string, always use a constant.
In particular, never ever use a string that comes from user input as the format string because it would be an easy target for the aspiring hacker. When I say “a user input,” I mean anything that comes from the outside of the code, including configuration files and HTTP requests or responses. Ignoring this commandment would open the door to a format string attack.
The Holy Grail
Before we say goodbye, I’ll like to present my all-time favorite function of the whole Arduino ecosystem. It’s snprintf_P() , but I call it “the holy grail” because it’s a hidden treasure that does everything one would want. It is identical to snprintf() except that it reads the format string from the Flash memory, and therefore reduces the RAM consumption. See it in action here:
Note that I used the PSTR() macro instead of F() because snprintf_P() expects a regular char pointer and not a const __FlashStringHelper* .
Conclusion
I’ll conclude this article with my usual advice: stop using the String class.
Start today. Replace instances one after the other. Soon your program will become more reliable because it won’t rely on the status of the heap to run correctly.
Getting rid of the String class is a step forward in making your code portable. By avoiding Arduino specific classes and sticking with standard functions, you allow your code to be compiled for other platforms. For example, you could decide to run some parts of your program on your development machine for testing.
And for the very few situations where you must use a String , for example, if a library forces you to use this class (and there are quite a few), use the 8 tips I showed in my previous article.
A blog for Arduino developers who want to write good C++ code. Neither a beginner site nor an expert site, it’s something in between.
ОБОРУДОВАНИЕ
ТЕХНОЛОГИИ
РАЗРАБОТКИ
Блог технической поддержки моих разработок
Урок 30. Текстовые строки в Ардуино. Конвертирование данных в строки и наоборот. Класс String.
В уроке рассказываю о текстовых строках в Ардуино, о классе String, о преобразовании различных типов данных в текстовые строки и об обратной операции — преобразовании строк в числа.
Собирался разрабатывать драйвер шагового двигателя с управлением от компьютера, но столкнулся с необходимой для разработки темой, которую мы еще не изучали. Поэтому на один урок я отвлекусь от шаговых двигателей и расскажу о текстовых строках и операциях с ними.
Текстовые строки в Ардуино.
Текстовая строка это массив символов, завершающийся специальным символом – признаком конца строки. Признак необходим для того, чтобы функции работы со строками определяли, где заканчиваются символы строки и не считывали лишние данные, не принадлежащие ей.
В Ардуино признаком конца строки является число 0, в текстовом виде ‘\0’. При объявлении строковых переменных в некоторых случаях необходимо явно указывать признак конца строки, а в некоторых он формируется по умолчанию.
Способы объявления и инициализации текстовых строк.
Объявлен символьный массив определенного размера. При заполнении его символами необходимо позаботиться о записи в конце строки байта со значением 0 – признака окончания строки.
Объявлен массив и присвоено значение элементам. В конце строки компилятор прибавит признак конца строки автоматически.
То же самое, только завершающий признак мы объявили явно.
char myStr4 [ ] = “Start”;
Массив инициализирован строковой константой. Компилятор автоматически задаст размер массива и добавит завершающий символ.
char myStr5 [6 ] = “Start”;
То же самое, только размер массива указан явно.
char myStr 6[20 ] = “Start”;
Можно явно указать больший размер массива, например, если он будет использован для строк разной длины.
- Строковые константы объявляются внутри двойных кавычек ( ”Start” ).
- Отдельные символы задаются внутри одинарных ( ‘S’ ).
Длинные строки допускают объявление в таком виде:
char myStr7 [] = “Текстовая строка может быть”
“ объявлена”
“ таким образом”;
Ничего не мешает задавать массивы строк. Поскольку сами строки являются массивами, массивы строк будут двумерными массивами.
Массивы строк объявляют как массив указателей. Это связано с тем, что строки могут иметь разную длину, и приходится резервировать двумерный массив данных, рассчитанный на самую длинную строку. А указатели требуют одинаковое количество ячеек памяти.
Управляющие символы.
В текстовых строках могут содержаться не только текстовые символы, но и управляющие. Управляющие символы не отображаются на экране в графическом виде. Они используются для управления передачей данных и выводом на экран. Таких символов несколько десятков. Я выделю наиболее важные.
Код символа в HEX (DEC) | Название | Обозначение | |
0 (0) | Конец строки | \0 | Признак конца строки |
0D (13) | Возврат каретки | \r | Перемещает курсор в крайнюю левую позицию |
0A (10) | Перевод строки | \n | Перемещает курсор на одну строку вниз |
Для того чтобы вывести текст с новой строки необходимо использовать символы ‘\r’ и ‘\n’.
Простая программа, демонстрирующая использование управляющих символов для печати с новой строки.
// управляющие символы
void setup() <
Serial.begin(9600); // скорость 9600
>
void loop() <
Serial.println(«\r\n Begin \r\n next string»
«\r\n 3 empty strings \r\n\r\n\r\n»); // вывод сообщения в нескольких строках
delay(1000);
>
На экране монитора последовательного порта увидим:
Часто управляющие символы ‘\r’ и ‘\n’ применяют для завершения команды в символьном виде, например AT команды. Такой способ управления будем использовать в следующем уроке для драйвера шагового двигателя.
Конвертирование различных типов данных Ардуино в текстовую строку.
Задача преобразования различных типов данных в символьный вид и наоборот возникает:
- при выводе данных на дисплей или индикаторы;
- передаче данных на другие устройства, например компьютер;
- некоторые электронные компоненты требуют обмена данными с помощью AT команд в символьном виде, например GSM модемы, WiFi модули и т.п.
Существует достаточно много способов для решения этой задачи. Я подробно опишу несколько из них, на мой взгляд, самых удачных.
Конвертирование данных в строку через встроенные функции классов ввода-вывода.
Самый удобный, предпочтительный способ преобразования данных в символьный вид. Многие библиотеки ввода-вывода имеют функции преобразования данных в текстовый формат.
Если необходимо передавать данные через последовательный порт, почему бы не воспользоваться стандартными функциями класса Serial (урок 12).
Преобразование | Функция класса Sreial | |
int в DEC текст | print(int d) | Преобразует переменную int в строку с десятичным представлением числа |
int в DEC текст | print(int d, DEC) | Преобразует переменную int в строку с десятичным представлением числа |
int в HEX текст | print(int d, HEX) | Преобразует переменную int в строку с шестнадцатеричным представлением числа |
int в OCT текст | print(int d, OCT) | Преобразует переменную int в строку с восьмеричным представлением числа |
int в BIN текст | print(int d, BIN) | Преобразует переменную int в строку с двоичным представлением числа |
float в текст | print(float d) | Преобразует переменную float в строку с двумя знаками после запятой |
float в текст | print(float d, N) | Преобразует переменную float в строку с N знаками после запятой |
Например, конвертирование числа int в строку будет выглядеть так.
Преобразование переменной float в строку можно выполнить так.
Преобразование будет выполнено при передаче данных на другое устройство. Функции класса Serial подробно описаны в уроке 12.
Для вывода данных на LCD дисплей с помощью библиотеки LiquidCristal, можно использовать метод print с такими же параметрами.
Конвертирование целочисленных данных в строку через функции itoa, ltoa, ultoa.
Функции простые, позволяют конвертировать числа целых форматов в текстовую строку.
itoa (int data, char* string, int radix); // преобразование int
ltoa (long data, char* string, int radix); // преобразование long
ultoa (unsigned long data, char* string, int radix); // преобразование unsigned long
- data – это конвертируемая переменная;
- char* string – указатель на строку (имя массива);
- radix – система исчисления результата в строке:
- 10 для DEC;
- 8 для OCT;
- 16 для HEX;
- 2 для BIN.
Например, конвертирование переменой x типа int в строку myStr1 можно сделать так.
itoa(x, myStr1, 10); // в десятичном виде
itoa(x, myStr1, 8); // в восьмеричном виде
itoa(x, myStr1, 16); // в шестнадцатеричном виде
itoa(x, myStr1, 2); // в двоичном виде
Вот программа для проверки работы этих функций.
// проверка преобразования числа в текстовую строку
int x=0; // переменная, которая выводится
char myStr[20]; // текстовый массив
void loop() <
// подготовка буфера строки
for (int i=0; i заполнение пробелами
myStr[18]=’\r’; // возврат каретки
myStr[19]=’\n’; // перевод строки
// преобразование переменной int x
itoa(x, myStr, 10); // int -> DEC
//itoa(x, myStr, 8); // int -> OCT
//itoa(x, myStr, 16); // int -> HEX
//itoa(x, myStr, 2); // int -> BIN
// преобразование переменной long x
//ltoa(x, myStr, 10); // long -> DEC
//ltoa(x, myStr, 8); // long -> OCT
//ltoa(x, myStr, 16); // long -> HEX
//ltoa(x, myStr, 2); // long -> BIN
// преобразование переменной unsigned long x
//ultoa(x, myStr, 10); // long -> DEC
//ultoa(x, myStr, 8); // long -> OCT
//ultoa(x, myStr, 16); // long -> HEX
//ultoa(x, myStr, 2); // long -> BIN
В цикле каждые 0,5 секунд происходит:
- Текстовая строка myStr заполняется пробелами, в конце добавляются управляющие символы возврат каретки и перевод строки.
- Переменная x конвертируется одной из функцией. Результат оказывается в буфере myStr.
- Функция Serial.write(myStr, 20); передает через последовательный порт 20 байтов массива myStr в виде байтов.
- Прибавляется 1 к переменной x.
Чтобы проверить нужную функцию необходимо освободить ее от признака комментарий. Я проверил все.
Для вывода чисел с плавающей запятой можно опять предложить метод из урока 20.
Конвертирование данных в строку с помощью функции sprintf.
Это самый удобный, универсальный метод. Недостаток такого способа заключается в том, что функция sprintf просто пожирает ресурсы микроконтроллера. В критичных по времени и объему памяти приложениях ее лучше не применять.
sprint это функция форматированного вывода. Ее широко используют в приложениях на компьютерах. Она дает самые широкие возможности для преобразования данных в строку. Но в системе Ардуино sprintf не поддерживает формат чисел с плавающей запятой.
int sprintf( char *string, const char *format , argument1, argument2 . )
Функция возвращает число преобразованных символов. В случае ошибки возвращает число – 1.
- argument – это переменные, которые необходимо преобразовать;
- format – управляющая строка:
% [флаг] [ширина] тип_формата
Флаг и ширина — необязательные поля.
Тип формата | Тип выходных данных |
c | Символ |
s | Символьная строка |
d, i | Целое десятичное число |
u | Целое без знаковое десятичное число |
o | Целое восьмеричное число |
x | Целое шестнадцатеричное число |
Знак | Действие |
— | Выравнивание результата влево |
+ | Выводит знак числа |
Пробел | Выводит знак пробел перед положительными числами |
0 | Заполняет поле 0 |
Ширина – минимальный размер поля для вывода символов. Если длина числа меньше, то добавляются пробелы. Если перед шириной стоит 0, то добавляются нули.
На примерах из таблицы все должно быть понятно.
int x= 125; int y= 34;
Функция | Выведет в myStr |
sprintf(myStr2,»%d»,x ); | 125 |
sprintf(myStr2,»%5d»,x ); | 125 |
sprintf(myStr2,»%05d»,x ); | 00125 |
sprintf(myStr2,»%+05d»,x ); | +00125 |
sprintf(myStr2,»Цикл %d закончен»,x ); | Цикл 125 закончен |
sprintf(myStr2,»Цикл %d закончен y= %d»,x,y ); | Цикл 125 закончен y= 34 |
sprintf(myStr2,»%o»,x ); | 175 |
sprintf(myStr2,»%x»,x ); | 7d |
Можете загрузить следующую программу и проверить работу sprintf в реальном контроллере Ардуино.
// проверка преобразования числа в текстовую строку
// с помощью sprintf
int x=0; // переменная, которая выводится
char myStr[20]; // текстовый массив
void loop() <
// подготовка буфера строки
for (int i=0; i заполнение пробелами
myStr[18]=’\r’; // возврат каретки
myStr[19]=’\n’; // перевод строки
// преобразование переменной int x в строку
sprintf(myStr,»%d»,x ); // int -> DEC
//sprintf(myStr,»%5d»,x ); // int -> DEC
//sprintf(myStr,»%05d»,x ); // int -> DEC
//sprintf(myStr,»%+05d»,x ); // int -> DEC
//sprintf(myStr,»Cycle %d is over»,x ); // int -> DEC с текстом
//sprintf(myStr,»%o»,x ); // int -> OCT
//sprintf(myStr,»%x»,x ); // int -> HEX
Конвертирование данных типа float в текстовую строку.
Самый простой способ преобразования float в текстовую строку – использование функции dtostrf.
char* dtostrf(double data, signed char width, unsigned char prec, char *string)
- data – это конвертируемая переменная;
- width – число значащих разрядов;
- prec – число разрядов после запятой;
- char* string – указатель на строку (имя массива).
float x= 12.728;
dtostrf(x, 2, 3, myStr3); // выводим в строку myStr3 2 разряда до, 3 разряда после запятой
Вот программа для проверки такого способа.
// проверка преобразования числа в текстовую строку
// с помощью dtostrf
float x=0; // переменная, которая выводится
char myStr[20]; // текстовый массив
void loop() <
// подготовка буфера строки
for (int i=0; i заполнение пробелами
myStr[18]=’\r’; // возврат каретки
myStr[19]=’\n’; // перевод строки
// преобразование переменной float x в строку
dtostrf(x, 2, 3, myStr);
Serial.write(myStr, 20);
x+= 0.01;
delay(500);
>
У меня работает.
Конвертирование текстовой строки в различные типы данных.
В следующем разделе речь идет об обратном преобразовании – текстовой строки в число.
Преобразование строки в данные с помощью функций atoi, atol, atof.
Хороший, удобный метод. Функции простые, имеют вид:
int atoi(const char* string); // преобразование в int
long atol(const char* string); // преобразование в long
double atof(const char* string); // преобразование в float
В качестве аргумента функций указывается указатель на строку с числом в десятичном виде. Возвращают – конвертированное значение числа.
Например, преобразование строки myStr4 в переменную x типа int будет выглядеть так.
Для чисел с плавающей запятой.
Вот программа проверки atoi и atol.
// проверка преобразования текстовой строки в число
// с помощью atoi
char myStr[]= «123»; // текстовый массив
void loop() <
Serial.println(atoi(myStr)); // преобразование строки в int
//Serial.println(atol(myStr)); // преобразование строки в long
delay(1000);
>
А в этой программе я проверил работу atof.
// проверка преобразования текстовой строки в число
// с помощью atof
char myStr[]= «123.456»; // текстовый массив
void loop() <
Serial.println(atof(myStr),3); // преобразование строки в float
delay(1000);
>
Конвертирование текстовой строки в числа с помощью функции sscanf.
Функция является обратной функцией для sprintf с такими же недостатками и достоинствами. Но она позволяет конвертировать числа в восьмеричном и шестнадцатеричном форматах. Тип float эта функция на Ардуино не поддерживает.
int sscanf( char *string, const char *format , address1, address2 . )
Все аргументы и форматы такие же, как у sprintf. Только указываются адреса переменных ( address1, address2 . ).
Конвертирование строки myStr5 в переменную x типа int будет выглядеть так.
int x;
sscanf(myStr5,»%d», &x); // для десятичных чисел
sscanf(myStr5,»%o», &x); // для восьмеричных чисел
sscanf(myStr5,»%x», &x); // для шестнадцатеричных чисел
Вот скетч проверки функции для целочисленных операций.
// проверка преобразования текстовой строки в число
// с помощью sscanf
int x;
char myStr[]= «123»; // текстовый массив
void loop() <
sscanf(myStr,»%d», &x);
Serial.println(x); // преобразование строки в int
delay(1000);
>
Класс String Ардуино.
В Ардуино существует класс String. Он предоставляет более широкие возможности для работы с текстовыми строками.
Надо четко различать:
- char myStr [ ] = “Start”; — строка символов, т.е. массив типа char с завершающим признаком в конце;
- String MyStr = Start”; — экземпляр класса String.
Принято имена текстовых строк начинать как обычные переменные с маленькой буквы ( myStr ), а экземпляры String – с большой буквы ( MyStr ).
Экземпляры класса String занимают больше памяти, медленнее обрабатываются, но зато они позволяют расширять , объединять строки, производить поиск, замену символов и многое другое. Пользоваться текстовыми строками или классом String – решать Вам. В оптимальных по ресурсам приложениях лучше использовать строки.
Несколько основных функций класса String.
Я опишу только минимум функций, необходимых для работы с классом String.
String()
Конструктор, создает экземпляр класса String. Объект типа String может быть создан из разных типов данных:
String MyStr1 = «Start»; // инициализация строковой константы
String MyStr2 = String(‘d’); // преобразование символа в объект String
String MyStr3 = String(«Start»); // преобразование строковой константы в объект String
String MyStr4 = String(MyStr1 + » in 10 sec»); // конкатенация двух строк
String MyStr5 = String(67); // использование целочисленной константы
String MyStr6 = String(analogRead(1), DEC); // использование int с основанием 10
String MyStr7 = String(346, BIN); // использование int с основанием 2
String MyStr8 = String(89, HEX); // использование int с основанием 16
String MyStr9 = String(millis(), DEC); // использование long с основанием системы счисления
При создании объекта из числа, сформированная строка будет содержать ASCII (символьное) представление числа. По умолчанию используется десятичная система счисления, но можно указать другую. Т.е. функция String может осуществлять преобразование целочисленных данных в текстовую строку.
toCharArray(*buf, length)
Копирует текст экземпляра класса String в указанный массив.
- buf – указатель на массив;
- length – количество символов.
MyStr.toCharArray(myStr, 10); // копируем 10 символов в массив myStr
int length()
Функция возвращает длину строки String в символах без учета завершающего признака нуля.
int len =MyStr.length(); // получаем длину строки MyStr
long toInt()
Функция преобразовывает объект String в целое число.
int x = MyStr.toInt(); // конвертирование строки MyStr в int
Конвертирование данных в строку String.
Для целочисленных форматов все очень просто.
String MyStr;
int x;
MyStr= String(x, DEC); // для десятичных чисел
MyStr= String(x, HEX); // для шестнадцатеричных чисел
MyStr= String(x, BIN); // для двоичных чисел
Программа для проверки.
// проверка преобразования числа в String
int x=0; // переменная, которая выводится
String MyStr;
MyStr= String(x, DEC); // int -> DEC
//MyStr= String(x, HEX); // int -> HEX
//MyStr= String(x, BIN); // int -> BIN
Для плавающей запятой надо использовать функцию dtostrf(). С помощью нее получить строку-массив, а затем занести ее в объект String.
float x=2.789;
String MyStr;
char myStr8[10];
dtostrf(x, 2, 3, myStr8); // выводим в строку myStr8 2 разряда до, 3 разряда после запятой
MyStr = myStr8;
Программа для проверки преобразования float.
// проверка преобразования числа в String
float x=0; // переменная, которая выводится
String MyStr;
char myStr[10];
dtostrf(x, 2, 3, myStr); // выводим в строку myStr 2 разряда до, 3 разряда после запятой
MyStr = myStr;
Serial.println(MyStr);
x += 0.01;
delay(500);
>
Конвертирование строки String в различные типы данных.
Для целых чисел используем функцию toInt().
String MyStr = «123»;
int x = MyStr.toInt();
// проверка преобразования String в число
// с помощью toInt
String MyStr = «123»;
void loop() <
Serial.println(MyStr.toInt()); // преобразование строки в int
delay(1000);
>
Для плавающей запятой.
Получим данные из объекта String в массив и выполним преобразование функцией atof().
String MyStr = «34.123»;
char myStr8[10];
MyStr.toCharArray(myStr8, MyStr.length()); // копирование String в массив myStr8
float x = atof(myStr8); // преобразование в float
Программа для проверки.
// проверка преобразования String в число
// с помощью toInt
String MyStr = «34.123»;
char myStr[10];
Я привел достаточно много различных способов преобразования данных в строки и наоборот. Выбирайте, придумывайте свои.