Как уменьшить использование памяти в коде?
Я написал этот код для управления своей рождественской елкой. Он занимает большую часть памяти моего 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.
@Wes Summers, 👍1
Обсуждение1 ответ
Лучший ответ:
Помимо 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
.
- Глобальные переменные занимают много места в динамической памяти.
- Выделение памяти указателя в функции
- Запрос на помощь в сжатии кода и сохранении памяти
- Считывание байтов из массива PROGMEM
- Можете ли вы помочь мне сократить мой код?
- Почему Serial.print(1) требует на 228 байт больше программной памяти по сравнению с Serial.print((char)(48+1))?
- Использование памяти в аналоговом логгере библиотеки SdFat
- Как заставить компилятор гарантировать, что выделение памяти для локальных переменных не приведет к переполнению оперативной памяти во время выполнения?
Я вижу несколько целых чисел, которые можно было бы заменить на байты, чтобы сэкономить пару байтов. Помимо этого, похоже, вы используете библиотеки. Если вам нужно больше места, перейдите на процессор 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