Память программы Arduino закончилась
У меня есть скетч Arduino, который я сделал, и у меня закончилась динамическая память на моем Arduino Nano. Как я могу уменьшить объем памяти, который занимает программа? (я не очень хорошо разбираюсь в этом)
PS: код здесь:
#include <SPI.h>
#include <SD.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
const int chipSelect = 4;
#define OLED_RESET 5
Adafruit_SSD1306 display(OLED_RESET);
#if (SSD1306_LCDHEIGHT != 64)
#error("Fix Height");
#endif
/********************************************/
#define CHARWIDTH 5
#define CHARHEIGHT 8
#define AXISWIDTH (2 + 1)
#define VISIBLEVALUEPIXELS (128 - AXISWIDTH)
#define NUMVALUES (2 * VISIBLEVALUEPIXELS)
#define TRIGGER_ENABLE_PIN 2
#define SCREEN_UPDATE_ENABLE_PIN 3
byte values[NUMVALUES];
int pos = 0;
int count = 0;
unsigned long readStartTime = 0;
int sampleRate = 1;
void displayln(const char* format, ...)
{
char buffer[32];
va_list args;
va_start(args, format);
vsprintf(buffer, format, args);
va_end(args);
int len = strlen(buffer);
for (uint8_t i = 0; i < len; i++) {
display.write(buffer[i]);
}
}
// Отрисовывает тики графика по вертикальной оси
void drawAxis()
{
// тики графика
for (int x = 0; x < 2; x++) {
display.drawPixel(x, 0, WHITE);
display.drawPixel(x, 13, WHITE);
display.drawPixel(x, 26, WHITE);
display.drawPixel(x, 38, WHITE);
display.drawPixel(x, 50, WHITE);
display.drawPixel(x, 63, WHITE);
}
}
// Рисует выборочные значения
void drawValues()
{
int start = 0;
if ( digitalRead(TRIGGER_ENABLE_PIN) ) {
// Находим первое вхождение нуля
for (int i = 0; i < NUMVALUES; i++) {
if ( values[i] == 0 ) {
// Теперь найдем следующее значение, отличное от нуля
for (; i < NUMVALUES; i++) {
if ( values[i] != 0 ) {
start = i;
break;
}
}
break;
}
}
// Если точка срабатывания не находится в пределах половины наших значений, мы
// недостаточно точек выборки для корректного отображения волны
if ( start >= VISIBLEVALUEPIXELS )
return;
}
for (int i = 0; i < VISIBLEVALUEPIXELS; i++) {
display.drawPixel(i + AXISWIDTH, 63 - (values[i + start]), WHITE);
}
}
// Показывает время, затраченное на выборку значений, отображаемых на экране
void drawFrameTime(unsigned long us)
{
display.setCursor(9 * CHARWIDTH, 7 * CHARHEIGHT - 2); // почти внизу, примерно по центру
displayln("%ld us", us);
}
/********************************************/
void setup() {
// Настраиваем отображение
display.begin(SSD1306_SWITCHCAPVCC, 0x3C); // Инициализация с адресом I2C 0x3D (для 128x64)
display.setTextColor(WHITE);
pinMode(TRIGGER_ENABLE_PIN, INPUT);
pinMode(SCREEN_UPDATE_ENABLE_PIN, INPUT);
// Открытие последовательной связи и ожидание открытия порта:
Serial.begin(9600);
while (!Serial) {
; // ждем подключения последовательного порта. Требуется только для родного порта USB
}
Serial.print("init start");
if (!SD.begin(chipSelect)) {
Serial.println("fail");
// больше ничего не делаем:
while (1);
}
Serial.println("init ok");
}
/********************************************/
void loop() {
// Если скоро начнется отбор проб, запишите время начала
if ( pos == 0 )
readStartTime = micros();
// Если это та итерация, для которой нам нужен образец, берем образец
if ( (++count) % sampleRate == 0 )
values[pos++] = analogRead(0) >> 4; // сдвиг вправо на 4 эффективно отображает диапазон 0-1023 в 0-63
// Если мы заполнили буфер сэмпла, отображаем результаты на экране
if ( pos >= NUMVALUES ) {
// Измеряем, сколько времени занял запуск
unsigned long totalSampleTime = (micros() - readStartTime) / 2; // Делим на 2, потому что мы берем в два раза больше образцов, чем показано на экране
if ( !digitalRead(SCREEN_UPDATE_ENABLE_PIN) ) {
// Отобразить данные на экране
display.clearDisplay();
drawAxis();
drawValues();
drawFrameTime(totalSampleTime);
display.display();
}
// Сброс значений для следующего запуска выборки
pos = 0;
count = 0;
}
String dataString = "";
// считываем три датчика и добавляем к строке:
for (int analogPin = 0; analogPin < 3; analogPin++) {
int sensor = analogRead(analogPin);
dataString += String(sensor);
dataString += ",";
}
// открываем файл. обратите внимание, что одновременно может быть открыт только один файл,
// так что вы должны закрыть это, прежде чем открывать другое.
File dataFile = SD.open("datalog.txt", FILE_WRITE);
// если файл доступен, пишем в него:
if (dataFile) {
dataFile.println(dataString);
dataFile.close();
// также печатать в последовательный порт:
Serial.println(dataString);
}
// если файл не открыт, выскакивает ошибка:
else {
Serial.println("error opening datalog.txt");
}
}
1 ответ
▲ 1
Несколько вещей, которые следует учитывать:
- Каждая переменная в вашей программе занимает память, старайтесь использовать наименьший тип данных (например, не используйте число с плавающей запятой, если вам нужно целое число).
- Удалить строки
- Сократите использование массива
- Уменьшите размер кода, используя функцию для избыточной задачи.
- Избегайте использования цифрового и аналогового красного/записи. Вместо этого используйте управление портами (ссылка здесь)
- Измените библиотеку, чтобы удалить из нее неиспользуемый код
- Используйте программатор ICSP вместо последовательного загрузчика
- Упростите свой код, чтобы уменьшить его размер.
Или просто...
Используйте другую плату, например, STM32 или более крупный чип ATmega с большим объемом ОЗУ и ПЗУ большего размера...
,
@P0pR0cK5
Смотрите также:
- Последовательная печать из флэш-памяти (F() macro, PROGMEM, sprintf_P, SPTR)
- Функция freeMemory() из библиотеки memoryfree не возвращает уменьшенное значение в arduino UNO
- Как функция/метод может определить, является ли передаваемый массив const PROGMEM (flash) или нет (RAM)?
- Считывание байтов из массива PROGMEM
- Чтение элемента вложенного массива из PROGMEM.
- Arduino записывает в память и автоматически выключается (через MOSFET)
- Мусорные значения в EEPROM. при записи больших значений
- Можно ли во время выполнения определить, объявлен ли указатель PROGMEM?
Не используйте
String
. Поместите строковые литералы во flash с помощьюF(...)
., @Majenko1. Где определяется VISIBLEVALUEPIXELS? Я получаю «неопределенную» ошибку от компилятора, когда пытаюсь скомпилировать ваш код. 2. Вы уверены, что вам не хватает памяти программ, а не памяти данных? Пожалуйста, покажите сообщение об ошибке. Это произошло во время компиляции или во время выполнения?, @JRobert
упс. я случайно закинул его раньше и забыл сохранить, @JustAnotherBitcoin
Сделанный. Теперь используйте приведенный выше код и скомпилируйте его. Причина, по которой раньше это не работало, заключается в том, что я переименовал VISIBLEVALUEPIXELS в visval., @JustAnotherBitcoin
Просто повторю точку зрения Дж. Роберта; Почему вы подозреваете, что память программы закончилась? не могли бы вы опубликовать сообщение об ошибке, которое вы получаете. Я также думаю, что у вас заканчивается SRAM, а не программа Flash., @sa_leinad
Просто пишет, что закончилась динамическая память., @JustAnotherBitcoin
Подсказка: вы составили бюджет памяти? Сколько памяти занимает каждая библиотека? Приблизительные цифры: Adafruit_SSD1306 1 КБ, SD 0,5 КБ и ваш эскиз 0,25 КБ+. Это оставляет менее 250 байт для других глобальных переменных, стека и кучи. И Arduino IDE выдаст предупреждение., @Mikael Patel
Какие у вас есть варианты? Купите Arduino с большим количеством SRAM (Arduino Mega). Сократите использование памяти с помощью Adafruit_SSD1306, реализовав собственную библиотеку, которой не требуется буфер размером 1 КБ. Перепишите SD так, чтобы вы использовали 512 Кбайт только при необходимости и т. д. Первым шагом является удаление всего ненужного использования SRAM, такого как статические строковые литералы (например, использование макроса F())., @Mikael Patel