Как уменьшить использование памяти в коде?

Я написал этот код для управления своей рождественской елкой. Он занимает большую часть памяти моего Arduino Uno:

Sketch uses 31822 bytes (98%) of program storage space. Maximum is 32256 bytes.
Global variables use 1882 bytes (91%) of dynamic memory, leaving 166 bytes for local variables. Maximum is 2048 bytes.
Low memory available, stability problems may occur.

Кто-нибудь знает, как можно уменьшить использование памяти?

Код:

#include <SPI.h>
#include <SdFat.h>
#include <SdFatUtil.h>
#include <SFEMP3Shield.h>

#define TREEONE 3
#define TREETWO 4
#define TREETHREE 5
#define TREEFOUR 10

SdFat sd;
SFEMP3Shield MP3player;

const uint8_t volume = 10; // Громкость MP3-плеера 0=макс., 255=самая низкая (выкл.)
//10 для подвала 50 для тестирования

const uint16_t monoMode = 1;

int song = 3;
int num = 0;
int count = 0;

//помещаем сюда массивы
byte arrayTree[] = {17,16,9,8,3,2,5,4,17,16,9,8,3, ...etc };

void setup() {
  initSD();
  initMP3Player();

  pinMode(TREEONE, OUTPUT);
  pinMode(TREETWO, OUTPUT);
  pinMode(TREETHREE, OUTPUT);
  pinMode(TREEFOUR, OUTPUT);

  digitalWrite(TREEONE, HIGH);
  digitalWrite(TREETWO, HIGH);
  digitalWrite(TREETHREE, HIGH);
  digitalWrite(TREEFOUR, HIGH);
}

void loop() {
  if(!MP3player.isPlaying()){
    MP3player.playTrack(song);
    MetallicaChristmas();
  }
}

void initSD() {
  if(!sd.begin(SD_SEL, SPI_HALF_SPEED)) 
    sd.initErrorHalt();
  if(!sd.chdir("/")) 
    sd.errorHalt("sd.chdir");
}

void initMP3Player() {
  uint8_t result = MP3player.begin();
  MP3player.setVolume(volume, volume);
  MP3player.setMonoMode(monoMode);
}

void treeFunc() {
    //задержка(arrayTimes[i]);
    num = arrayTree[count];

    //ДЕРЕВООДИН
    if(num>15){
      if((num%2)==0){
        digitalWrite(TREEONE,HIGH);
      }else{
        digitalWrite(TREEONE,LOW);
      }
    }
    //ДЕРЕВОДВА
    if((num%16)>7){
      if((num%2)==0){
        digitalWrite(TREETWO,HIGH);
      }else{
        digitalWrite(TREETWO,LOW);
      }
    }
    //ТРИ ДЕРЕВА
    if((num%8)>3){
      if((num%2)==0){
        digitalWrite(TREETHREE,HIGH);
      }else{
        digitalWrite(TREETHREE,LOW);
      }
    }
    //ДЕРЕВОЧЕТЫРЕ
    if((num%4)>1){
      if((num%2)==0){
        digitalWrite(TREEFOUR,HIGH);
      }else{
        digitalWrite(TREEFOUR,LOW);
      }
    }
  count = count + 1;
}

void MetallicaChristmas()
{
  //событие 1
  delay(670);
  treeFunc();
  delay(248);
  treeFunc();
  //событие 2
  delay(116);
  treeFunc();
  delay(248);
  treeFunc();
  //событие 3
  delay(100);
  treeFunc();
  delay(248);
  treeFunc();
  //событие 4
  delay(132);
  treeFunc();
  delay(248);
  treeFunc();
  //событие 5
  delay(125);
  treeFunc();
  delay(248);
  treeFunc();
  //событие 6

  ...etc.

, 👍1

Обсуждение

Я вижу несколько целых чисел, которые можно было бы заменить на байты, чтобы сэкономить пару байтов. Помимо этого, похоже, вы используете библиотеки. Если вам нужно больше места, перейдите на процессор 1284P. 128 КБ флэш-памяти, 16 КБ SRAM. Я предлагаю платы в нескольких форм-факторах, ваш код будет перенесен вместе с надстройкой MightyCore в Arduino IDE. https://www.crossroadsfencing.com/BobuinoRev17, @CrossRoads

Покажите пожалуйста полный эскиз. Какова длина массива arrayTree? Каждое второе число на 1 меньше предыдущего? Как долго действует функция MetallicaChristmas? Существует меньшая библиотека sdfat, но я не знаю, совместима ли она с SFEMP3Shield. Прочтите о PROGMEM и структуре., @Jot

Я думаю, что если вы сохраните задержки в массиве, как ArrayTree. И используйте [PROGMEM](https://www.arduino.cc/reference/en/language/variables/utilities/progmem/) в обоих массивах, ваш код станет меньше и будет использовать меньше динамической памяти. А также облегчить чтение/поддержание., @Gerben

Без полного эскиза мы не сможем скомпилировать его самостоятельно, чтобы увидеть, насколько далеко мы сможем снизить использование памяти., @Jot

О, вот оно: https://arduinoprosto.ru/q/60109/problem-with-mp3-shield-and-function-calling-combination, @Jot


1 ответ


Лучший ответ:

3

Помимо PROGMEM (как описано в комментариях), вы можете добиться еще нескольких преимуществ:

  • Вызов функции требует больших затрат (занимает много места для кода), а вы выполняете их МНОГО!

    • Повторяющиеся вызовы delay(), за которыми следует treeFunc(), являются расточительными. Ваша закомментированная строка

      //delay(arrayTimes[i]);
      

      похоже, вы собирались поступить правильно, поэтому я бы восстановил это (использовал count вместо i) и поместил delay() числа в новом массиве int arrayTimes[].

      PROGMEM и этот массив тоже, конечно!

    • Сделав это, вы можете удалить все вызовы delay(). У вас не останется ничего, кроме повторных вызовов treefunc(), которые вы можете заменить одним циклом:

      for (count=0;count<sizeof(arrayTree);++count) {
         treeFunc();
      } // for
      

      Не забудьте избавиться от строки count = count + 1; из treeFunc() — теперь она находится в for цикл.

  • Также дорого обходится вызов одной и той же функции дважды, но с разными параметрами в обеих частях if в treeFunc(). Вместо:

    if (<condition>) {
       Function(1);
    } // if
    else {
       Function(0);
    } // else
    

    вместо этого вы можете сделать:

    Function(<condition>);
    

    Чтобы это работало, вам нужно знать, что HIGH имеет значение 1, а LOW имеет значение 0 - и что условие true имеет значение 1, а условие false имеет значение 0.< /п>

    Итак, вам нужно немного изменить if():

    digitalWrite(THREEONE, (num%2)>0);
    
  • Наконец, оператор mod % сам по себе очень дорог, поскольку фактически представляет собой деление, а чип Arduino не знает, как делить, поэтому для этого используется следующий код: большой. Но код, который вы написали, использует двоичную арифметику, которую Arduino может выполнять мгновенно — вам просто нужно написать ее как таковую.

    • Вместо (num%2)>0 используйте num & B0001.
    • Вместо (num%4)>1 используйте num & B0010.
    • Вместо (num%8)>3 используйте num & B0100.
    • Вместо (num%16)>7 используйте num & B1000.

Возможно, вы скопировали часть этого кода откуда-то еще, и хотя он работает, он не очень эффективен. Написание кода, как указано выше, значительно уменьшит размер вашего кода, заменяя повторяющиеся вызовы гораздо меньшими массивами PROGMEM.

,