Arduino-платформы вроде Uno, Nano или Pro Mini — отличные инструменты для создания прототипов и небольших проектов. Но у них есть одно важное ограничение — мало памяти. Например, классическая Arduino Uno располагает всего 2 КБ оперативной памяти (SRAM) и 32 КБ флеш-памяти (из которых около 0.5 КБ занимает загрузчик). В этом материале мы разберём, как экономить память на Arduino, не жертвуя функциональностью.
1. Понимай, какие типы памяти есть на Arduino
Прежде чем оптимизировать, нужно знать, с чем мы работаем. В Arduino (на базе AVR) есть три основные области памяти:
- Flash (программа) — для хранения кода. Обычно 32 КБ.
- SRAM — для хранения переменных во время выполнения. Обычно 2 КБ.
- EEPROM — энергонезависимая память (для хранения настроек). Обычно 1 КБ.
Чаще всего узким местом является SRAM. Именно её нужно оптимизировать.
2. Используй F() для строк
Каждая строка в кавычках ("Hello world") по умолчанию копируется из flash в SRAM при выполнении. Это быстро «съедает» оперативку.
Плохо:
Serial.println("Температура: ");
Хорошо:
Serial.println(F("Температура: "));
Макрос F() оставляет строку в flash-памяти, экономя драгоценные байты SRAM.
3. Избегай глобальных массивов, если можно
Большие массивы (int array[100]) сразу занимают SRAM. Если массивы нужны только временно, лучше объявлять их внутри функции, чтобы они удалялись после выхода из неё.
4. Выбирай компактные типы данных
По умолчанию int в Arduino — это 2 байта (на AVR). Если ты уверен, что переменная не превысит 255, используй byte или uint8_t.
| Название | Размер | Диапазон |
|---|---|---|
byte | 1 Байт | 0–255 |
int | 2 Байта | -32,768 до 32,767 |
long | 4 Байта | ±2 миллиарда |
Совет: Используй типы вроде uint8_t, int16_t — они явно указывают размер, что облегчает отладку и экономию.
5. Используй PROGMEM для хранения больших данных
Если тебе нужно хранить массивы строк, таблицы или изображения — можно положить их в flash-память с помощью PROGMEM.
Пример:
const char message[] PROGMEM = "Слишком длинное сообщение";
Чтобы считать строку из PROGMEM, нужно использовать специальные функции (pgm_read_byte, strcpy_P и др.).
6. Следи за динамическим выделением памяти (malloc / new)
Arduino плохо переносит фрагментацию памяти. Избегай malloc, new, String (объектов), особенно в цикле.
Плохо:
String s = "Hello " + String(value);
Хорошо:
char buffer[16];
sprintf(buffer, "Hello %d", value);
String — удобен, но создаёт фрагментацию SRAM, приводящую к нестабильной работе, особенно в долгосрочных проектах.
7. Очищай переменные, которые больше не нужны
Храни переменные как можно ближе к месту их использования. Лучше использовать локальные переменные внутри функций, чем глобальные.
8. Используй sizeof() и freeMemory() (библиотеки)
В процессе отладки можно использовать функции типа freeMemory() (например, из MemoryFree) — она покажет, сколько свободной SRAM осталось. Также sizeof() подскажет, сколько памяти занимает переменная или массив.
9. Минимизируй использование библиотек
Некоторые библиотеки занимают много памяти, даже если ты используешь только часть их функциональности. По возможности:
- Выбирай лёгкие аналоги.
- Изучи исходный код и убери неиспользуемые функции.
- Проверь, можно ли отключить отладку или
Serial.print().
Итоги
Arduino — это искусство компромиссов. При проектировании важно учитывать ограниченные ресурсы и писать эффективный, экономный код. Следуя этим советам, ты сможешь выжать максимум даже из самой маленькой платы и избежать проблем с зависаниями и нестабильностью.