Память программы 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

Обсуждение

Не используйте String. Поместите строковые литералы во flash с помощью F(...)., @Majenko

1. Где определяется 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


1 ответ


1

Несколько вещей, которые следует учитывать:

  • Каждая переменная в вашей программе занимает память, старайтесь использовать наименьший тип данных (например, не используйте число с плавающей запятой, если вам нужно целое число).
  • Удалить строки
  • Сократите использование массива
  • Уменьшите размер кода, используя функцию для избыточной задачи.
  • Избегайте использования цифрового и аналогового красного/записи. Вместо этого используйте управление портами (ссылка здесь)
  • Измените библиотеку, чтобы удалить из нее неиспользуемый код
  • Используйте программатор ICSP вместо последовательного загрузчика
  • Упростите свой код, чтобы уменьшить его размер.

Или просто...

Используйте другую плату, например, STM32 или более крупный чип ATmega с большим объемом ОЗУ и ПЗУ большего размера...

,