Arduino
Что использовать: статические или глобальные переменные
Давайте разберем тонкости использования глобальных и статических переменных в скетчах.
Начнем с примера. Рассмотрим простую задачу: нам нужно отправлять значение температуры с датчика. И, что важно, отправлять нужно только новое значение, если оно изменилось. Такой подход имеет преимущества: экономия трафика, упрощение логики на принимающей стороне. Скетч будет выглядеть примерно так:
Рассмотрим второй вариант реализации:
Разница в том, что для хранения последнего значения температуры мы используем статическую переменную. Что же такое статические переменные и чем они отличаются от обычных локальных переменных? Давайте обратимся к документации:
Ключевое слово static используется для создания переменных с областью видимости только в текущей функции. Однако, в отличии от локальных переменных, которые создаются и уничтожаются при каждом вызове функции, статические переменные остаются за пределами вызова функции, сохраняя свои значения между вызовами функции.
Переменные, объявленные как статические, будут создаваться и инициализироваться только при первом вызове функции.
Локальная область видимости
Обратите внимание на первый пример, в котором мы использовали глобальную переменную. Изменить ее значение можно из любой функции скетча. В приведенном примере менее 20 строчек кода и в нем трудно ошибиться, на деле же скетч будет сильно больше и есть много шансов допустить ошибку, перетерев значение глобальной переменной. Локальная же область видимости, во-первых, гарантирует, что значение переменной будет изменено только в текущей функции, а, во-вторых, позволит вынести этот функционал в отдельный класс или библиотеку, и переменная вообще не будет нам мешать.
Чище код
Когда мы читаем чужой или свой же код, написанный насколько лет назад, мы не помним всех его тонкостей. В коде могут полностью отсутствовать комментарии, а имена переменных могут быть не достаточно «говорящими», чтобы сразу понять, для чего эта переменная используется. И если мы видим, что переменная статическая, мы сразу будем знать, что ее значение не меняется нигде, кроме текущей функции. А также мы будем понимать, что ее не просто так объявили статической и она сохраняет какое-то значение между вызовами функции.
Код будет работать быстрее
Доступ к памяти со значением глобальной и локальной переменной, конечно, происходит с одинаковой скоростью. Однако компилятор, видя статическую переменную, понимает, что она принадлежит текущей функции, и может произвести некоторую оптимизацию. Например, может хранить переменную в регистре вызова функции. Не будем вдаваться в подробности, главное, что программа будет работать в некоторых случаях быстрее, и это уже неплохо. А с учетом остальных преимуществ, чаще используйте статические переменные, а не глобальные.
Типы данных, переменные

В ближайшее время нас будет интересовать только SRAM память, в которой хранятся переменные, именно о них дальше и пойдёт речь.
Двоичная система
В цифровом мире, к которому относится также микроконтроллер, информация хранится, преобразуется и передается в цифровом виде, то есть в виде нулей и единиц. Соответственно элементарная ячейка памяти, которая может запомнить 0 или 1, называется бит (bit). Таким образом мы плавно переходим к двоичной системе исчисления. Ну же, вспоминайте школьную информатику! Не вдаваясь в подробности “как это работает”, просто попробуем рассмотреть закономерность
| Двоичная | Десятичная |
| 0000 | 0 |
| 0001 | 1 |
| 0010 | 2 |
| 0011 | 3 |
| 0100 | 4 |
| 0101 | 5 |
| 0110 | 6 |
| 0111 | 7 |
| 1000 | 8 |
| 1001 | 9 |
| … | … |
| 10000 | 16 |
И так далее. Помимо закономерности увеличения разрядов и чисел есть ещё одна: приглядитесь к числам в двоичной системе со всеми нулями справа от единицы:
| 10 | 2 |
| 100 | 4 |
| 1000 | 8 |
| 10000 | 16 |
Именно, степень двойки! Именно на степенях двойки в цифровом мире завязано очень много. Чтобы получить количество десятичных чисел, которые могут быть закодированы заданным количеством бит, нужно возвести 2 в степень количества бит. Смотрим на таблицу выше и продолжаем:
И так далее. Сразу нужно запомнить, что в программировании счёт начинается с нуля, то есть 5ю битами мы можем закодировать десятичное число от 0 до 31, 8-ю битами – от 0 до 255, 10-ю битами – от 0 до 1023. Очень важно понять и запомнить это, дальше очень пригодится. Следующая по величине единица измерения в цифровом мире – байт (byte), состоит из 8 бит. Почему 8? Исторически сложилось, что шины первых микропроцессоров имели разрядность 8 бит, возможно поэтому это количество приняли за более старшую единицу памяти. Также 8 это 2 в степени 3, что очень символично и удобно. А ещё, для кодирования всех латинских букв, знаков препинания, математических знаков и просто символов (всех что на клавиатуре) раньше хватало 7-ми бит (128 символов), но потом их стало мало, и ввели дополнительный бит, восьмой. То есть 8 бит это также размер таблицы символов, которая называется ASCII. К ней мы вернёмся уже в этой главе. Так что вопрос почему в одном байте 8 бит четкого ответа не имеет, ведь бывает и 6-ти битный байт, и 9-ти битный… Но это исключения старых процессоров, в современных цифровых устройствах в одном байте обычно содержится 8 бит (на отличных от AVR архитектурах может быть иначе), что позволяет закодировать 256 десятичных чисел от 0 до 255 соответственно. Дальше вы уже точно знаете:
Двоичная система является родной для микроконтроллера, и для работы с отдельными битами существует целый ряд инструментов, о них мы поговорим в уроке о битовых операциях из раздела продвинутых уроков.
Другие системы исчисления
Данные в памяти микроконтроллера хранятся в двоичном представлении, но помимо него существуют и другие системы исчисления, в которых мы можем работать. Постарайтесь сразу запомнить и понять, что переводить числа из одной системы исчисления в другую не нужно, Ардуино абсолютно всё равно, в каком формате вы скармливаете значение переменной, они автоматически будут интерпретированы в двоичный вид. Разные системы исчисления введены в первую очередь для удобства программиста. Теперь по сути: ардуино поддерживает (да в целом другого и не нужно) четыре классических системы исчисления: двоичную, восьмеричную, десятичную и шестнадцатеричную. Да, и до неё добрались. Краткая напоминалка: 16-ричная система имеет 16 значений на один разряд, первые 10 как у десятичной, остальные – первые буквы латинского алфавита: 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, a, b, c, d, e, f. С десятичной системой всё просто, пишем числа так, как они выглядят. 10 это десять, 25 это двадцать пять, и так далее. Двоичная (Binary) имеет префикс 0b (ноль бэ) или B, то есть двоичное число 101 запишется как 0b101 ИЛИ B101. Восьмеричная (Octal) имеет префикс 0 (ноль), например 012. Шестнадцатеричная (hexadecimal) имеет префикс 0x (ноль икс), FF19 запишется как 0xFF19.
| Базис | Префикс | Пример | Особенности |
| 2 (двоичная) | B или 0b (ноль бэ) | B1101001 | цифры 0 и 1 |
| 8 (восьмеричная) | 0 (ноль) | 0175 | цифры 0 – 7 |
| 10 (десятичная) | нет | 100500 | цифры 0 – 9 |
| 16 (шестнадцатеричная) | 0x (ноль икс) | 0xFF21A | цифры 0-9, буквы A-F |
Основная фишка 16-ричной системы в том, что она позволяет записывать длинные десятиричные числа короче, например один байт (255) запишется как 0xFF, два байта (65 535) как 0xFFFF, а жуткие три байта (16 777 215) как 0xFFFFFF. Вы не представляете (или уже имеете представление), насколько удобно и понятно это позволяет работать с цветами и оттенками. Двоичная же система обычно используется для наглядного представления данных и низкоуровневых конфигураций различного железа. Например конфиг кодируется одним байтом, каждый бит в нём отвечает за отдельную настройку (вкл/выкл), и передав один байт вида 0b10110100 можно сразу кучу всего настроить, к этому мы вернёмся в уроке работа с регистрами из раздела продвинутых уроков. В документации по этому поводу пишут в стиле “первый бит отвечает за это, второй за то” и так далее.
Переменные
Переменная – это ячейка SRAM памяти, которая имеет своё уникальное название и хранит числа соответственно своему размеру. К переменной мы можем обратиться по её имени и получить значение, либо изменить его. Степень двойки преследует нас и дальше, ведь объём одной ячейки памяти в микроконтроллере тоже ей кратен:
Да, больше четырёх байт в ардуино (точнее в МК от AVR) уже не влезет, при использовании обычных типов данных. Для работы с разными диапазонами значений используются разные типы данных (переменных). По сути можно использовать 4 байта для хранения чего угодно, но это не оптимально. Это как знать, что вам нужно будет унести максимум 200 мл воды (меньше 1 байта), но вы всё равно берёте 19 литровую бутыль (2 байта). Или железнодорожную цистерну на 120 тонн (4 байта). Если хотите писать красивый и оптимальный код, используйте соответствующие типы данных. Кстати, вот они:
Типы данных
*Не встречал упоминания об этом в официальных источниках, но Ардуино (точнее компилятор) также поддерживает 64 битные числа, соответственно тип данных int64_t и uint64_t Максимальный размер всех типов данных хранится в константах, и его можно использовать в коде по надобности:
Есть ещё несколько нестандартных типов, которые иногда встречаются в чужом коде:
Объявление и инициализация переменных
Преобразование типов
Преобразование _cast (Pro)
Иногда можно встретить преобразование типов через оператор cast. Отличную статью можно глянуть на Хабре, а я кратко опишу 4 основных каста:
Как пользоваться: на примере предыдущего примера
Константы
Что такое константа понятно из её названия – что-то, значение чего мы можем только прочитать и не можем изменить. Задать (объявить) константу можно двумя способами:
Ещё пару слов о константах и переменных: если обычная переменная нигде не изменяется в процессе выполнения программы – компилятор может самостоятельно сделать её константой и она не займёт места в оперативной памяти, т.е. будет помещена во Flash.
Область видимости
Переменные, константы и другие типы данных (структуры и перечисления) имеют такое важное понятие, как область видимости. Она бывает
Глобальная
Глобальная переменная объявляется вне функций и доступна для чтения и записи в любом месте программы, в любой её функции.
Локальная
Локальная переменная живёт внутри функции или внутри любого блока кода, заключённого в < фигурные скобки >, доступна для чтения и записи только внутри него. При попытке обратиться к локальной переменной из другой функции (за пределами её < блока >) вы получите ошибку, потому что локальная переменная создаётся заново при выполнении содержащего её блока кода (или функции) и удаляется из памяти при завершении выполнения этого блока (или функции):
Важный момент: если имя локальной переменной совпадает с глобальной, то приоритет обращения по имени в функции отдаётся локальной переменной:
Формальная (параметр)
Формальная переменная, она же параметр, передаваемый в функцию, ведёт себя как обыкновенная локальная переменная, но появляется при немного других условиях: при вызове функции. Эту переменную можно читать и менять внутри её функции. Также читайте отдельный урок про функции.
Структуры (Pro)
Структура struct – очень интересный тип данных: это совокупность разнотипных переменных, объединённых одним именем. В некоторых случаях структуры позволяют очень сильно упростить написание кода, сделать его более логичным и легко модифицируемым. Тип данных структура объявляется вот по такой схеме:
Ярлык будет являться новым типом данных, и, используя этот ярлык, можно объявлять уже непосредственно саму структуру:
Также есть вариант объявления структуры без создания ярлыка, т.е. создаём структуру, не объявляя её как тип данных со своим именем.
Рассмотрим большой пример, где показано всё вышеописанное
Размер элемента структуры
Структуры позволяют делать одну очень интересную вещь для оптимизации памяти: указывать максимальный вес элемента в битах. Таким образом можно делать даже однобитные флаги (обычный bool / boolean занимает в памяти 8 бит). Делается это при помощи оператора двоеточие :
Вложенные структуры
Структуры также могут быть вложенными друг в друга, доступ к нужному элементу осуществляется так же при помощи оператора “точка”, смотрите простой пример:
Перечисления (Pro)
Перечисления ( enum – enumeration) – тип данных, представляющий собой набор именованных констант, нужен в первую очередь для удобства программиста. Сразу пример из опыта: допустим у нас есть переменная mode, отвечающая за номер режима работы устройства. Мы для себя запоминаем, какому значению переменной какой режим будет соответствовать, и где-нибудь себе записываем, например 0 – обычный режим, 1 – режим ожидания, 2 – режим настройки_1, 3 – режим настройки_2, 4 – калибровка, 5 – аварийный режим, ошибка. При написании или чтении программы часто придётся обращаться к этому списку, чтобы не запутаться. Можно сделать первый шаг по оптимизации: обозвать каждый режим при помощи дефайна:
Таким образом вместо цифры можно будет использовать понятные слова и ориентироваться в коде будет гораздо проще. Использование enum ещё немного упрощает эту конструкцию: перечисление позволяет создать переменную (по умолчанию типа int ), которая может принимать только те “названия”, которые для неё указаны. Это удобно тем, что в одной программе могут находиться разные хранители режимов с одинаковыми названиями, и в отличие от #define это не будет приводить к ошибкам. Объявление перечисления чем-то похоже на объявление структуры:
Таким образом мы объявили ярлык. Теперь, используя этот ярлык, можно объявить само перечисление:
Также как и у структур, можно объявить перечисление без создания ярлыка (зачем нам лишняя строчка?):
Созданное таким образом перечисление является переменной, которая может принимать указанные для неё имена, также с этими именами её можно сравнивать. Теперь самое главное: имена для программы являются числами, начиная с 0 и далее по порядку увеличиваясь на 1. В абстрактном примере выше имя1 равно 0, имя2 равно 1, имя3 равно 2, и так далее. Помимо указанных имён, перечислению можно приравнять и число напрямую, но как бы зачем. Рассмотрим пример!
Таким образом SET1 имеет значение 1, SET2 будет 2 и так далее по порядку.
Пользовательские типы (Pro)
В С++ (и на Ардуино) этого делать не нужно! Наоборот, typedef в этом применении может приводить к ошибкам. Например:
Пространство имён (Pro)
Пространство имён – очень удобная возможность языка, с её помощью можно разделить функции или переменные с одинаковыми именами друг от друга, то есть защитить свой набор данных инструментов от конфликтов имён с другими именами. “Именная область” определяется при помощи оператора namespace :
Чтобы использовать содержимое из пространства имён, нужно обратиться через его название и оператор разрешения области видимости ::
Более подробный пример:
И ниже по коду можно будет пользоваться содержимым пространства имён без обращения через имя::
Спецификаторы (Pro)
Помимо возможности сделать переменную константой при помощи спецификатора const у нас есть ещё несколько интересных инструментов по работе с переменной.
static
static – делает переменную (или константу) статичной. Что это значит? Статичная локальная Для начала вспомним, как работает обычная локальная переменная: при вызове функции локальная переменная создаётся заново и получает нулевое значение, если не указано иначе. Если локальная переменная объявлена как static – она будет хранить своё значение от вызова к вызову функции, то есть станет грубо говоря глобально-локальной. Пример:
Статическая локальная:
extern
extern – указывает компилятору, что переменная объявлена где-то в другом файле программы, и при компиляции он её найдёт и будет использовать. А если не найдёт – ошибки не будет. Например при помощи данного кода можно сбросить счётчик millis()
volatile
volatile – данный спецификатор указывает компилятору, что данную переменную не нужно оптимизировать и её значение может быть изменено откуда-то извне. Обычно переменные с таким спецификатором используются в обработчиках прерываний. Вычисления с такими переменными также не оптимизируются и занимают больше процессорного времени.
Видео
Arduino
Переменные
Существуют соглашения по именованию переменных. Имена переменных обычно начинаются со строчной буквы. Если имя состоит из одного слова, то оно целиком пишется строчными буквами (имена полностью из заглавных букв обычно используются для констант). Если же имя переменной состоит из нескольких слов, то принято либо разделять их символом подчеркивания, либо начинать каждое новое слово, кроме первого, с заглавной буквы:
Область видимости
От того, в какой части кода объявлена переменная, будет зависть то, в какой части кода эта переменная будет доступна. переменные делят на:
Рекомендуется как можно реже использовать глобальные переменные, так как их использование чаще приводит к ошибкам: значение переменной может быть случайно изменено в любой функции. Также при использовании локальных переменных код становится более понятным для восприятия.
static
Ключевое слово static используется для объявление локальных переменных, значение которых будет сохраняться между вызовами функции. Этим они отличаются от обычных локальных переменных, которые создаются при каждом вызове функции и уничтожаются при ее завершении.
Обратите внимание, что значением 10 будет также присвоено переменной только при ее инициализации.
volatile
Ключевое слово volatile используется для переменных, значение которых может быть изменено чем-то, находящимся вне секции кода. Например параллельным потоком. При использовании ключевого слова volatile компилятор будет брать значение переменной из ОЗУ, а не из регистра (временной ячейки памяти).
При программировании Arduino использовать volatile следует только в том случае, если вы используете прерывания. Причем, если переменная занимает больше 8 бит, при чтении ее значения прерывания должны быть отключены. Это связано с тем, что в arduino используется 8-ми битный микроконтроллер и он может за раз считать только 8 бит, а при чтении другая часть переменной уже может измениться.
Arduino.ru
Правильно использование static функций
Раз уж новички сюда не пишут, то я побуду новичком.
Пытаюсь для этого применить static функции. Сразу предупрежу, что функциональность приведённого ниже кода отсутствует. Это материал, схожий по структуре с реальным кодом, и иллюстрирующий проблему:
Если READY_TESTING определено, вызов waitToBMPReady() попадает в исходник и всё компилируется ОК.
Вопрос: как полагается делать правильно, чтобы компилятор не вываливал этот warning?
Ну так возьмите и waitToBMPReady() в #ifdef.
Так не компилируется, но если атрибут вперёд перенести, то компиляция проходит, предупреждений нет, однако. в полном соответствии с описанием » This attribute, attached to a function, means that code must be emitted for the function even if it appears that the function is not referenced. » жирнит результирующий код на размер невызываемых, но существующих функций.
Однако, как оказалось, рядом (https://gcc.gnu.org/onlinedocs/gcc/Common-Function-Attributes.html#Common-Function-Attributes) валяется аттрибут «unused»: » This attribute, attached to a function, means that the function is meant to be possibly unused. GCC does not produce a warning for this function. «. С ним, похоже, всё ОК.
Да не, я без претензий. По наводке понял, где покопать.
Кстати, оказывается gcc, за который IDE дёргает, понимает и такое:
Я не пользуюсь «unused» и любыми его «наколеночными» заменителями, а всегда честно исключаю дефайном.
То, что дефайнов много, так можно нужные функции компактно расположить (хоть в отдельном файле) и исключать чохом или сделать макрос для объявления функции и объявлять этим макросом (а дефайны в нём спрятаны).
Могу объяснить почему я не люблю «unused» и не пользуюсь отключением предупреждений в опциях компилятора. Есть несколько причин:
2. Компилятор и/или линкер обычно выбрасывают из кода ненужные вещи, но это а) зависит от их опций и б) может не сработать в сложных случаях. А зачем мне в коде неиспользуемые функции? Лучше я их дефайном исключу.
Static arduino что это
Ваша корзина пуста!
Привет друзья от geekmatic.in.ua! Пора заняться полезным делом и разобрать типы данных, представленные в Arduino IDE.
Перед использованием переменных, объектов и функций, мы должны сначала объявить их в тексте программы для того, чтобы компилятор отвел для них отдельное место в ячейках памяти. А для того, чтобы компилятор знал сколько места нужно отводить в памяти, нужно еще и указать типы этих данных при объявлении. Так же типы данных требуются компилятору для правильной интерпретации выражений над ними.
| Тип | Синоним | Байт | Диапазон |
| bool | boolean | 1 | false, true |
| byte | uint8_t | 1 | 0. 255 |
| char | 1 | -128. 127 | |
| unsigned char | 1 | 0. 255 | |
| int | short, int16_t | 2 | -32768. 32767 |
| unsigned int | word, uint16_t | 2 | 0. 65535 |
| long | int32_t | 4 | -2147483648. 2147483647 |
| unsigned long | uint32_t | 4 | 0. 4294967295 |
| float | double | 4 | -3.4028235E+38… 3.4028235E+38 |
| void | |||
| String() |
Так что погружаемся в дебри ардуиновских правил урезанного языка Си и да прибудет с нами мотивация! Обещаю в конце урока выделить самые необходимые типы создаваемых переменных. А пока начнем разбор по порядку с типа bool.
| Тип | Синоним | Байт | Диапазон |
| bool | boolean | 1 | false, true |
Тип данных bool используется для логических переменных, хранящих два возможных значения: true или false (правда или ложь). Такие переменные удобны для создания программных флажков или защелок, для хранения состояния дискретного входа. Для переменных, которые должны отвечать на вопрос типа да или нет, включен или выключен и подобных.
Здесь представлены примеры возможных вариантов объявления такой переменной и присвоения ей значений. Нам желательно запомнить, что все присваиваемые числа, больше нуля, будут переводить переменную типа bool в состояние true.
Булевскую переменную можно вставлять в функцию digitalWrite() для задания состояния дискретному выходу контроллера.
Так же удобно, как показано на примере, использовать булевскую переменную в условных операторах if. В первом примере условие сработает, если переменная в состоянии true, а во втором наоборот.
| Тип | Синоним | Байт | Диапазон |
| byte | uint8_t | 1 | 0. 255 |
Byte незаслуженно недооцененный начинающими программистами тип данных, который почему-то заменен типом int даже в большинстве примеров Arduino IDE. Он хорош тем, что занимает столько же места, сколько и один регистр памяти 8-битных контроллеров Arduino. 8 бит так же занимает и минимальный коммуникационный пакет данных в сети UART, I2C и других. LCD-индикаторы тоже принимают побайтные (8-битные) данные и команды. Поэтому тип byte незаменим при коммуникациях контроллера с различной умной периферией, при прямой работе с регистрами, а так же для хранения целых десятичных чисел в промежутке 0…255.
| Тип | Синоним | Байт | Диапазон |
| char | 1 | -128. 127 | |
| unsigned char | 1 | 0. 255 |
Unsigned char – тоже символьный тип данных, но он может хранить цифровые коды символов в диапазоне 0…255. Считается бесполезным. Неоднократно получал награду Золотой валенок.
Теперь посмотрим на саму таблицу ASCII.
Это таблица соответствия заложенных в компилятор символов и их десятичных цифровых кодов. До 32-го символа идут не читаемые символы. В примере мы использовали букву А. Вы можете попробовать найти здесь её цифровой код. А кириллицу кстати тут не найдёшь. Её буквы начинаются с кода 192 в расширенной таблице ASCII. О кириллице продолжим в конце урока.
| Тип | Синоним | Байт | Диапазон |
| int | short, int16_t | 2 | -32768. 32767 |
| unsigned int | word, uint16_t | 2 | 0. 65535 |
Int и unsigned int – самые популярные целочисленные типы. Они охватывают большой диапазон целых чисел, но занимают в два раза больше памяти чем тип byte. Переменная типа int занимает 16 бит. Unsigned int – тот же тип, только без знака. Он охватывает только положительные значения 0…65535. Эти два типа хорошо подходят например для хранения считанного значения аналогового входа.
| Тип | Синоним | Байт | Диапазон |
| long | int32_t | 4 | -2147483648. 2147483647 |
| unsigned long | uint32_t | 4 | 0. 4294967295 |
Типы long и unsigned long используются в тех случаях, когда не хватает размера int. Они тоже содержат целые числа, но, в отличии от int, занимают 32 бита памяти каждый. В переменных такого типа можно хранить например скорость UART-порта контроллера, номер телефона, количество миллисекунд. Такие большие числа в проектах встречаются не часто, но бывают.
| Тип | Синоним | Байт | Диапазон |
| float | double | 4 | -3.4028235E+38… 3.4028235E+38 |
Float – тип переменной с плавающей точкой или вещественного числа. Float позволяет получать и хранить значения данных с точностью до 6-7 знаков после запятой. Занимает 32 бита памяти. Применяется для хранения и отображения значения физических величин, результатов математических расчетов, аргументов математических формул, математических констант и так далее.
Обратите внимание на примеры, взятые из документации Arduino, по преобразованию целого числа int в вещественное float – тут есть свои нюансы.
Тип double на других платформах, позволяет получать значения чисел с точностью до 15 знаков после запятой, но у Arduino этот тип полностью аналогичен float.
| Тип | Синоним | Байт | Диапазон |
| void |
Тип void применим к функциям. Это тип-пустышка, который означает, что функция не возвращает никакого значения.
Здесь на примере для сравнения показана функция myfunc1, возвращающая значение типа int и три функции не возвращающие никакого значения, объявленные с типом void.
| Тип | Синоним | Байт | Диапазон |
| String() |
При объявлении типа String мы используем специальный класс для работы со строковыми данными. Он позволяет работать с длинными текстами, ограниченными только размерами памяти конкретного контроллера.
Текст присваивается переменной в двойных кавычках. А так же в Arduino IDE предусмотрена функция String(), которая преобразовывает значения различных типов переменных и констант в строку String. Вы видите примеры того, какие аргументы можно передавать функции String(). Интересно и то, что текст тут можно писать даже на кириллице.
Подробнее о строковых переменных будем говорить позднее.
А пока, напомним себе таблицу типов данных Arduino. Запоминать их все пока не обязательно, а ознакомиться не помешает. И, Чтобы новичков не сильно пугать, выполняя обещание, свожу самые используемые типы переменных в следующую упрощенную таблицу.
| Тип | Байт | Диапазон |
| int | 2 | -32768. 32767 |
| float | 4 | -3.4028235E+38… 3.4028235E+38 |
| String() |
Основные небольшие проекты можно строить всего на 3-х типах переменных, представленных в этой табличке. Без целочисленного int не обойдемся почти нигде. Для точных вычислений и представлений физических величин необходим тип с плавающей точкой. А текстовый String необходим для удобного вывода символов на LCD-индикаторы и в монитор порта.
Кому из вас трудно дается такая информация, просмотрите урок несколько раз. И спасибо за внимание! Всем вам желаю успехов и до новых встреч!

