Overfow dynamic memory
- Войдите на сайт для отправки комментариев
Втр, 06/10/2015 - 14:33
Добрый день.
Думаю не я первый, кто сталкнулся с данной проблемой.
Я сделал скетч, он работает. Спасибо форумчанам. Провел тестирование, все гуд. Но как обычно возникло желание немного приукрасить. К тому же у меня есть OLED дисплей.
И того:
Ардуино нано + TLC5940 + DALLAS-DS18B20 и + OLED дисплей 0.96''
И вот, только вставил в начале:
#include <OLED_I2C.h> // Подключение библиотеки для дисплея
OLED myOLED(SDA, SCL, 8);
Сразу при компилляции получил:
Sketch uses 12 680 bytes (41%) of program storage space. Maximum is 30 720 bytes.
Global variables use 2 227 bytes (108%) of dynamic memory, leaving -179 bytes for local variables. Maximum is 2 048 bytes.
Попытки урезать количество переменных, которые я использую особо не помогли. Поэтому видимо все динамическую память занимают переменные в библиотеке.
Есть какой-либо не сильно сложный все же уместиться в выделенную память?
Уместиться-то можно, но это потребует некоторого программирования. Вы готовы? Если готовы - дерзайте. Если нужны советы, так хоть скетч покажите.
Вот скетч с внесенными стоками
// "Недорогой контроллер на Ардуино нано + TLC5940 + DALLAS-DS18B20" // шести канальный контроллер, 12-bit шим // Комплектация: Arduino nano, RTC-modul, TLC5940, DALLAS-DS18B20. // перед началом компиляции откройте монитор порта в правом верхнем углу окна программы #include <OLED_I2C.h> // Подключение библиотеки для дисплея OLED myOLED(SDA, SCL, 8); #include "Tlc5940.h" #include <OneWire.h> OneWire ds(5); // Температурный сенсор DALLAS-DS18B20 подключен к D5 #include <DS1307.h> DS1307 rtc(A0, A1); //RTC-модуль подключен к: SDA - > A0, SCL -> A1 Time t; int ventpin = 6; // управление вентилятором осуществляется с D6 byte tic[6][5]; unsigned long Value[6]; unsigned long Array[6][6]; unsigned long Event[6][3]; float power = 100; // общая мощность освещения [0 - 100] unsigned long time_all; unsigned long last_time_all; byte temp = 0; unsigned long level; // значение уровня канала в цикле периода (рассвет, закат) void setup() { Serial.begin ( 115200 ); // Указвать скорость на которой работает Ваш COM-порт Tlc.init(); Tlc.clear(); pinMode (ventpin, OUTPUT); rtc.halt(false); /* MONDEY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY Три строчки ниже необходимо раскомментировать (убрать двойную дробь) при стартовой загрузки программы. Сразу после первой загрузки, нужно закомментировать данные строки и обращаться к этой процедуре в случае сбоя в работе часов. RTC-модуль запомнит время. */ // rtc.setDOW(SUNDAY); // изменить день недели. примеры указаны на четыре строчки выше // rtc.setTime(11, 41, 0); // время // rtc.setDate(13, 9, 2015); // дата // Настройки светильника: <время восхода>, <продолжительность рассвета>, <мощность канала в течении "дня">, <время заката>, <продолжительность заката> // первый канал Array[0][0] = 540; // начало рассвета первого канала в минутах. например: 10:00 записывается как <600> (в минутах) Array[0][1] = 630; // конец рассвета первого канала. например: 11:15 записывается как <675> (в минутах) Array[0][2] = 1020; // начало заката первого канала. например: 20:50 записывается как <1250> (в минутах) Array[0][3] = 1080; // окончание заката первого канала. например: 21:50 записывается как <1310> (в минутах) Array[0][4] = 100; // мощность первого канала в процентах в течении "дня" (в процентах). не может быть больше 100 Array[0][5] = 0; // инвертор драйвера. Имеет значения 0 и 1. 0 - прямая логика, 1 - обратная логика // второй канал Array[1][0] = 585; // начало рассвета второго канала в минутах. например: 10:00 записывается как <600> (в минутах) Array[1][1] = 600; // конец рассвета второго канала. например: 11:15 записывается как <675> (в минутах) Array[1][2] = 1030; // начало заката второго канала. например: 20:50 записывается как <1250> (в минутах) Array[1][3] = 1080; // окончание заката второго канала. например: 21:50 записывается как <1310> (в минутах) Array[1][4] = 100; // мощность второго канала в процентах в течении "дня" (в процентах). не может быть больше 100 Array[1][5] = 0; // инвертор драйвера. Имеет значения 0 и 1. 0 - прямая логика, 1 - обратная логика // третий канал Array[2][0] = 590; // начало рассвета тертьего канала в минутах. например: 10:00 записывается как <600> (в минутах) Array[2][1] = 600; // конец рассвета тертьего канала. например: 11:15 записывается как <675> (в минутах) Array[2][2] = 1040; // начало заката тертьего канала. например: 20:50 записывается как <1250> (в минутах) Array[2][3] = 1080; // окончание заката тертьего канала. например: 21:50 записывается как <1310> (в минутах) Array[2][4] = 100; // мощность тертьего канала в процентах в течении "дня" (в процентах). не может быть больше 100 Array[2][5] = 0; // инвертор драйвера. Имеет значения 0 и 1. 0 - прямая логика, 1 - обратная логика // четвертый канал Array[3][0] = 555; // начало рассвета четвертого канала в минутах. например: 10:00 записывается как <600> (в минутах) Array[3][1] = 600; // конец рассвета четвертого канала. например: 11:15 записывается как <675> (в минутах) Array[3][2] = 1050; // начало заката четвертого канала. например: 20:50 записывается как <1250> (в минутах) Array[3][3] = 1080; // окончание заката четвертого канала. например: 21:50 записывается как <1310> (в минутах) Array[3][4] = 100; // мощность четвертого канала в процентах в течении "дня" (в процентах). не может быть больше 100 Array[3][5] = 0; // инвертор драйвера. Имеет значения 0 и 1. 0 - прямая логика, 1 - обратная логика // пятый канал Array[4][0] = 560; // начало рассвета пятого канала в минутах. например: 10:00 записывается как <600> (в минутах) Array[4][1] = 570; // конец рассвета пятого канала. например: 11:15 записывается как <675> (в минутах) Array[4][2] = 1060; // начало заката пятого канала. например: 20:50 записывается как <1250> (в минутах) Array[4][3] = 1080; // окончание заката пятого канала. например: 21:50 записывается как <1310> (в минутах) Array[4][4] = 100; // мощность пятого канала в процентах в течении "дня" (в процентах). не может быть больше 100 Array[4][5] = 0; // инвертор драйвера. Имеет значения 0 и 1. 0 - прямая логика, 1 - обратная логика // шестой канал Array[5][0] = 565; // начало рассвета шестого канала в минутах. например: 10:00 записывается как <600> (в минутах) Array[5][1] = 570; // конец рассвета шестого канала. например: 11:15 записывается как <675> (в минутах) Array[5][2] = 1070; // начало заката шестого канала. например: 20:50 записывается как <1250> (в минутах) Array[5][3] = 1080; // окончание заката шестого канала. например: 21:50 записывается как <1310> (в минутах) Array[5][4] = 100; // мощность шестого канала в процентах в течении "дня" (в процентах). не может быть больше 100 Array[5][5] = 0; // инвертор драйвера. Имеет значения 0 и 1. 0 - прямая логика, 1 - обратная логика // Перевод массива в секунды for (int q=0; q<6; q++) { for (int w=0; w<4; w++) { Array[q][w] = Array[q][w] * 60; } } // Сброс суточного массива for (int q=0; q<6; q++) { for (int w=0; w<5; w++) { tic[q][w] = 0; } } // Вывод проверочной стартовой таблицы Serial.println ( "" );Serial.println ( "" ); Serial.print ( " Time: " ); Serial.print ( rtc.getTimeStr() ); Serial.println ( " <- Check this after reset." );Serial.println ( "" ); Serial.println ( " Chanal : Sanrise : Day : Sanset : Night : Led chanal: Inverse" ); for (int q=0; q<6; q++) { Serial.print ( " PWM" ); Serial.print ( q+1 ); for (int w=0; w<5; w++) { Serial.print ( " : " ); if (w < 4) { if ( ( Array[q][w]/3600 ) < 10) {Serial.print ( "0" ); Serial.print ( Array[q][w]/3600 ); } else {Serial.print ( Array[q][w]/3600 );} Serial.print ( ":" ); if ((( Array[q][w]-((Array[q][w]/3600)*3600))/60) < 10) {Serial.print ( "0" );Serial.print (( Array[q][w]-((Array[q][w]/3600)*3600))/60 ); } else {Serial.print (( Array[q][w]-((Array[q][w]/3600)*3600))/60 );} } else { if (Array[q][w] < 100) {Serial.print ( " ");} Serial.print ( Array[q][w]);Serial.print ( "%");Serial.print ( " : "); Serial.print ( Array[q][w+1]); } } Serial.println ( "" ); } Serial.println ( "-------------------------------------------------" ); // Проверка корректности ввода исходных данных for (int q=0; q<6; q++) {if (Array[q][4] >= 86400) {Array[q][4] = 86399; Serial.print ( "Error, check PWM" ); Serial.print ( q+1 ); Serial.println ( ", fixed the end of the sunset to 24:00" );}} for (int q=0; q<6; q++) {if (Array[q][5] >= 101) {Array[q][5] = 100; Serial.print ( "Error, check PWM" ); Serial.print ( q+1 ); Serial.println ( ", fixed the power led to 100%" ); }} for (int q=0; q<6; q++) { for (int w=0; w<3; w++) { if ( Array[q][w] > Array[q][w+1] ) {Serial.print ( "Error, check PWM" ); Serial.print ( q+1 ); Serial.println ( ", not continuity sanrise and sanset. Controller will not work correctly. Check setup. " ); } } } Serial.print ( " All powerful LEDs: " ); Serial.print ( power ); Serial.println ( "%" ); Serial.println ( " In service. OK." ); // Изменение мощности из процентов в значение for (int q=0; q<6; q++) { Value[q] = map (Array[q][4], 0, 100, 0, 4095) * (power/ 100); } } void loop() { // Константы температуры float tmin = 26.00; // минитальное значение на датчике, при достижении которого запускается вентилятор. Указывается значение в градусах. Например: "32", означает 32градуса цельсия float tmax = 31.00; // максимальное значение на датчике, служит для плавного увеличения скорости вращения вентилятора. Указывается значение в градусах. Например: "36", означает 36градуса цельсия. На превышающих значениях вентилятор работает на 100% мощности // Блок программы работающий с температурным датчиком и вентилятором byte i; byte present = 0; byte type_s; byte data[12]; byte addr[8]; float celsius; ds.search(addr); ds.reset(); ds.select(addr); ds.write(0x44, 1); ds.reset(); present = ds.reset(); ds.select(addr); ds.write(0xBE); for ( i = 0; i < 9; i++) { data[i] = ds.read(); } int16_t raw = (data[1] << 8) | data[0]; if (type_s) { raw = raw << 3; // if (data[7] == 0x10) { raw = (raw & 0xFFF0) + 12 - data[6]; } } else { byte cfg = (data[4] & 0x60); if (cfg == 0x00) raw = raw & ~7; else if (cfg == 0x20) raw = raw & ~3; else if (cfg == 0x40) raw = raw & ~1; } celsius = (float)raw / 16.0; if (temp == 0) { Serial.print(" Temperature = "); Serial.print(celsius); Serial.println(" Celsius \n "); temp = 1;} if ( tmin > celsius ) analogWrite (ventpin, 0); if ( tmin <= celsius && tmax >= celsius ) analogWrite (ventpin, map(celsius, tmin , tmax, 0, 255)); if ( tmax < celsius) analogWrite (ventpin,255); // конец блока температуры t = rtc.getTime(); int long h = t.hour; int long m = t.min; int long s = t.sec; time_all = ( (h * 3600)+(m * 60)+ s ); // Сброс состояния контроллера на новый день. if (time_all < last_time_all) { // Сброс суточного массива for (int q=0; q<6; q++) { for (int w=0; w<5; w++) { tic[q][w] = 0; } } } last_time_all = time_all; // Контроллер for (int q=0; q<6; q++) { if (time_all >= 0 && time_all <= Array[q][0] && tic[q][0] == 0) { if (Array[q][5]==0)Tlc.set (q, 0); if (Array[q][5]==1)Tlc.set (q, 4095); tic[q][0] = 1; Serial.print ( rtc.getTimeStr() );Serial.print ( " PWM:" );Serial.print ( q+1 ); Serial.println ( " - mon" ); } if (time_all >= Array[q][0] && time_all <= Array[q][1] ) { if (tic[q][1] == 0){Event[q][0] = (time_all - Array[q][0])*1000; Event[q][1] = ((Array[q][1]-Array[q][0])*1000); Event[q][2] = millis(); Serial.print ( rtc.getTimeStr() );Serial.print ( " PWM:" );Serial.print ( q+1 ); Serial.println ( " - on" ); tic[q][1] = 1;} level = (((float)millis() - Event[q][2]+Event[q][0])*Value[q])/(Event[q][1]); if(level <= 0) level = 0; if(level >= Value[q]) level = Value[q]; if (Array[q][5]==0)Tlc.set (q, level); if (Array[q][5]==1)Tlc.set (q, 4095-level); } if (time_all >= Array[q][1] && time_all <= Array[q][2] && tic[q][2] == 0) { if (Array[q][5]==0)Tlc.set (q, Value[q]); if (Array[q][5]==1)Tlc.set (q, 4095-Value[q]); tic[q][2] = 1 ; Serial.print ( rtc.getTimeStr() );Serial.print ( " PWM:" );Serial.print ( q+1 ); Serial.println ( " - day " ); } if (time_all >= Array[q][2] && time_all <= Array[q][3] ) { if (tic[q][3] == 0){ Event[q][0] = (time_all - Array[q][2])*1000; Event[q][1] = ((Array[q][3]-Array[q][2])*1000); Event[q][2] = millis(); Serial.print ( rtc.getTimeStr() );Serial.print ( " PWM:" );Serial.print ( q+1 ); Serial.println ( " - off" ); tic[q][3] = 1;} level = (((float)millis() - Event[q][2]+Event[q][0])*Value[q])/(Event[q][1]); if(level <= 0) level = 0; if(level >= Value[q]) level = Value[q]; if (Array[q][5]==0)Tlc.set (q, 4095-level); // Закат сделан по принципу рассвета. if (Array[q][5]==1)Tlc.set (q, level); // Разница в этих двух строках. } if (time_all >= Array[q][3] && time_all <= 86399 && tic[q][4] == 0) { if (Array[q][5]==0)Tlc.set (q, 4095-Value[q]); if (Array[q][5]==1)Tlc.set (q, Value[q]); tic[q][4] = 1 ; Serial.print ( rtc.getTimeStr() );Serial.print ( " PWM:" );Serial.print ( q+1 ); Serial.println ( " - nig" ); } } Tlc.update(); }Да что за вирус такой? Зачем лепить RTC на A0 и A1?
Мало аппаратного TWI на A5 и A4?
Все строки в FLASH!
Serial.print ( F(" All powerful LEDs: " ));И да, для OLED надо много памяти, если тебе не надо рисовать на экране, то замени его на текстовый дисплей 20x4 например.
Не вникал в программу, но заметил, что сплошь и рядом используется тип данных unsigned long да еще и в двумерных массивах. А это по 4 байта на каждое значение. Уверены, что unsigned int никак не обойтись?
В том то и дело, что хочу нарисовать уровни с их значениями.
Не вникал в программу, но заметил, что сплошь и рядом используется тип данных unsigned long да еще и в двумерных массивах. А это по 4 байта на каждое значение. Уверены, что unsigned int никак не обойтись?
К сожалению не обойтись. В скетче считается все в миллисекундах. Значения очень большие.
Да, и все попытки как то ужать мои переменные не очень сильно влияют на общий объем.
К сожалению не обойтись
Ну это как еще посмотреть. Даже переменная ventpin определена как int, а там типа byte хватит с огромным запасом. А еще лучше в #define ее закатать. Она же в программе не вычисляется.
Ну и о строках уже говорили. Одна только фраза " Chanal : Sanrise : Day : Sanset : Night : Led chanal: Inverse" занимает почти половину недостающей памяти.
И его в лонг???
К сожалению не обойтись
Ну это как еще посмотреть. Даже переменная ventpin определена как int, а там типа byte хватит с огромным запасом. А еще лучше в #define ее закатать. Она же в программе не вычисляется.
Ну и о строках уже говорили. Одна только фраза " Chanal : Sanrise : Day : Sanset : Night : Led chanal: Inverse" занимает почти половину недостающей памяти.
Эта строка " Chanal : Sanrise : Day : Sanset : Night : Led chanal: Inverse" занимает не динамическую память, а память скетча, а тут проблем нет...
В военное время cos(0) может достигать 4, а булевые переменные хранить вообще никакой памяти не хватит.
Эта строка " Chanal : Sanrise : Day : Sanset : Night : Led chanal: Inverse" занимает не динамическую память, а память скетча, а тут проблем нет...
Да ладно...
void setup() { Serial.begin(9600); Serial.print(" Chanal : Sanrise : Day : Sanset : Night : Led chanal: Inverse"); } void loop() { }Sketch uses 1 810 bytes (5%) of program storage space. Maximum is 30 720 bytes.
Global variables use 264 bytes (12%) of dynamic memory, leaving 1 784 bytes for local variables. Maximum is 2 048 bytes.
void setup() { Serial.begin(9600); Serial.print(F(" Chanal : Sanrise : Day : Sanset : Night : Led chanal: Inverse")); } void loop() { }Sketch uses 1 836 bytes (5%) of program storage space. Maximum is 30 720 bytes.
Global variables use 182 bytes (8%) of dynamic memory, leaving 1 866 bytes for local variables. Maximum is 2 048 bytes.
Array, Value просятся во флеш, поскольку не меняются. Возможно еще что то. Пусть не так уж и много, но всё таки.
Про сообщения во флеш уже сказали.
Уже этого будет немало. В смысле освободится немало.
sinnpriest,
главный отжиратель памяти у Вас массив scrbuf[1024], объявленный в классе OLED. Он кушает ровно половину всего, что у Вас есть.
От него можно избавиться, хотя для этого потребуется немного переделать библиотеку. Такая переделка потребует навыков программиста среднего уровня. Не выше, но и не ниже - не ахти какая сложность, но и не для "чайников".
Как избавиться:
Библиотека устроена так: все изменения пишутся не напрямую на экран а в этот самый массив-буфер. Затем, когда Вы вызываете функцию update, она тупо копирует весь буфер в эран.
Можно переписать так, чтобы необходимые Вам изменения не накапливались в буфере, а писались на экран напрямую. Тогда надобность в буфере (как и в функции update) отпадёт вовсе и Вы спокойно освободите этот килобайт.
Т.е. я бы на Вашем емсте, переписал бы эту библиотеку на новое место как "свою" и правил бы. В итоге получилась бы новая бибилиотека, которая этот огромный буфер не использует.
Ну и мелочёвкой (типа "константы в progmem") о которой Вам тут уже многие писали пренебрагать тоже не стоит.
В моменты, когда недостающей памяти счет идет на байты, эти байты и надо ловить на всем. А тут поле непаханное для оптимизации. Про ventpin я уже говорил, туда же tmin и tmax. Вобщем, есть где развернуться.
Эта строка " Chanal : Sanrise : Day : Sanset : Night : Led chanal: Inverse" занимает не динамическую память, а память скетча, а тут проблем нет...
Да ладно...
void setup() { Serial.begin(9600); Serial.print(" Chanal : Sanrise : Day : Sanset : Night : Led chanal: Inverse"); } void loop() { }Sketch uses 1 810 bytes (5%) of program storage space. Maximum is 30 720 bytes.
Global variables use 264 bytes (12%) of dynamic memory, leaving 1 784 bytes for local variables. Maximum is 2 048 bytes.
void setup() { Serial.begin(9600); Serial.print(F(" Chanal : Sanrise : Day : Sanset : Night : Led chanal: Inverse")); } void loop() { }Sketch uses 1 836 bytes (5%) of program storage space. Maximum is 30 720 bytes.
Global variables use 182 bytes (8%) of dynamic memory, leaving 1 866 bytes for local variables. Maximum is 2 048 bytes.
Афигеть!!! Спасибо!!! ))) Да, я плохо в этом разбираюсь (
Я только этим Serial.print(F(".... освободил себе память до 85%...
ЕвгенийП верно поставил диагноз, но предложил слишком радикальный метод лечения.
Не обязательно самому переписывать библиотеку, достаточно найти такую, которая не использует буфер. Например, мою, которая выложена в теме "Кириллица на дисплее или что я делаю не так".
Правда, отказ от буфера накладывает довольно жесткие ограничения на то, что можно нарисовать, а что - нет. Но тут уж либо-либо. Библиотеки дисплея, не имеющие буфера, как правило, рассчитаны на то, что дисплей занимает далеко не центральное место в конструкции, а играет лишь вспомогательную роль.
PS. Кстати, переписал основные функции библиотеки, после чего она стала работать в 2-3 раза быстрее. На днях выложу новую версию.