Ошибка при загрузке скетча // Недостаточно памяти, программа может работать нестабильно.
- Войдите на сайт для отправки комментариев
Пнд, 07/05/2018 - 18:55
Помогите пожалуйста решить проблему. При загрузке скетча пишет:
Скетч использует 10894 байт (75%) памяти устройства. Всего доступно 14336 байт.Глобальные переменные используют 1000 байт (97%) динамической памяти, оставляя 24 байт для локальных переменных. Максимум: 1024 байт.
Недостаточно памяти, программа может работать нестабильно.
Произошла ошибка при загрузке скетча.
Вот текст скетча (скетч написан не мной):
/* Модифицировано под дисплей 1602 klykov.net vk.com/ms262 instagram.com/klykovnet Блок электроники для крутого моддинга вашего ПК, возможности: - Вывод основных параметров железа на внешний LCD дисплей - Температура: CPU, GPU, материнская плата, самый горячий HDD - Уровень загрузки: CPU, GPU, RAM, видеопамять - Графики изменения вышеперечисленных параметров по времени Программа HardwareMonitorPlus https://github.com/AlexGyver/PCdisplay - Запустить OpenHardwareMonitor.exe - Options/Serial/Run - запуск соединения с Ардуиной - Options/Serial/Config - настройка параметров работы - PORT address - адрес порта, куда подключена Ардуина - TEMP source - источник показаний температуры (процессор, видеокарта, максимум проц+видео, датчик 1, датчик 2) Что идёт в порт: 0-CPU temp, 1-GPU temp, 2-mother temp, 3-max HDD temp, 4-CPU load, 5-GPU load, 6-RAM use, 7-GPU memory use, */ // ------------------------ НАСТРОЙКИ ---------------------------- #define DRIVER_VERSION 1 // 0 - маркировка драйвера кончается на 4АТ, 1 - на 4Т // ------------------------ НАСТРОЙКИ ---------------------------- // ----------------------- ПИНЫ --------------------------- #define BTN1 A3 // первая кнопка #define BTN2 A2 // вторая кнопка // ----------------------- ПИНЫ --------------------------- // -------------------- БИБЛИОТЕКИ --------------------- #include <string.h> // библиотека расширенной работы со строками #include <Wire.h> // библиотека для соединения #include <LiquidCrystal_I2C.h> // библтотека дислея #include <TimerOne.h> // библиотека таймера // -------------------- БИБЛИОТЕКИ --------------------- // -------- АВТОВЫБОР ОПРЕДЕЛЕНИЯ ДИСПЛЕЯ------------- // Если кончается на 4Т - это 0х27. Если на 4АТ - 0х3f #if (DRIVER_VERSION) LiquidCrystal_I2C lcd(0x27, 16, 2); #else LiquidCrystal_I2C lcd(0x27, 16, 2); #endif // -------- АВТОВЫБОР ОПРЕДЕЛЕНИЯ ДИСПЛЕЯ------------- #define printByte(args) write(args); #define TEMPERATURE_PRECISION 9 // стартовый логотип byte logo0[8] = {0b00011, 0b00110, 0b01110, 0b11111, 0b11011, 0b11001, 0b00000, 0b00000}; byte logo1[8] = {0b10000, 0b00001, 0b00001, 0b00001, 0b00000, 0b10001, 0b11011, 0b11111}; byte logo2[8] = {0b11100, 0b11000, 0b10001, 0b11011, 0b11111, 0b11100, 0b00000, 0b00000}; byte logo3[8] = {0b00000, 0b00001, 0b00011, 0b00111, 0b01101, 0b00111, 0b00010, 0b00000}; byte logo4[8] = {0b11111, 0b11111, 0b11011, 0b10001, 0b00000, 0b00000, 0b00000, 0b00000}; byte logo5[8] = {0b00000, 0b10000, 0b11000, 0b11100, 0b11110, 0b11100, 0b01000, 0b00000}; // значок градуса!!!! lcd.write(223); byte degree[8] = {0b11100, 0b10100, 0b11100, 0b00000, 0b00000, 0b00000, 0b00000, 0b00000}; // правый край полосы загрузки byte right_empty[8] = {0b11111, 0b00001, 0b00001, 0b00001, 0b00001, 0b00001, 0b00001, 0b11111}; // левый край полосы загрузки byte left_empty[8] = {0b11111, 0b10000, 0b10000, 0b10000, 0b10000, 0b10000, 0b10000, 0b11111}; // центр полосы загрузки byte center_empty[8] = {0b11111, 0b00000, 0b00000, 0b00000, 0b00000, 0b00000, 0b00000, 0b11111}; // блоки для построения графиков byte row8[8] = {0b11111, 0b11111, 0b11111, 0b11111, 0b11111, 0b11111, 0b11111, 0b11111}; byte row7[8] = {0b00000, 0b11111, 0b11111, 0b11111, 0b11111, 0b11111, 0b11111, 0b11111}; byte row6[8] = {0b00000, 0b00000, 0b11111, 0b11111, 0b11111, 0b11111, 0b11111, 0b11111}; byte row5[8] = {0b00000, 0b00000, 0b00000, 0b11111, 0b11111, 0b11111, 0b11111, 0b11111}; byte row4[8] = {0b00000, 0b00000, 0b00000, 0b00000, 0b11111, 0b11111, 0b11111, 0b11111}; byte row3[8] = {0b00000, 0b00000, 0b00000, 0b00000, 0b00000, 0b11111, 0b11111, 0b11111}; byte row2[8] = {0b00000, 0b00000, 0b00000, 0b00000, 0b00000, 0b00000, 0b11111, 0b11111}; byte row1[8] = {0b00000, 0b00000, 0b00000, 0b00000, 0b00000, 0b00000, 0b00000, 0b11111}; char inData[82]; // массив входных значений (СИМВОЛЫ) int PCdata[20]; // массив численных значений показаний с компьютера byte PLOTmem[6][16]; // массив для хранения данных для построения графика (16 значений для 6 параметров) byte blocks, halfs; byte index = 0; int display_mode = 6; String string_convert; unsigned long timeout, uptime_timer, plot_timer; boolean lightState, reDraw_flag = 1, updateDisplay_flag, updateTemp_flag, timeOut_flag = 1; int duty, LEDcolor; int k, b, R, G, B, Rf, Gf, Bf; byte mainTemp; byte lines[] = {4, 5, 7, 6}; byte plotLines[] = {0, 1, 4, 5, 6, 7}; // 0-CPU temp, 1-GPU temp, 2-CPU load, 3-GPU load, 4-RAM load, 5-GPU memory String perc; unsigned long sec, mins, hrs; byte temp1, temp2; boolean btn1_sig, btn2_sig, btn1_flag, btn2_flag; // Названия для легенды графиков const char plot_0[] = "CPU"; const char plot_1[] = "GPU"; const char plot_2[] = "RAM"; const char plot_3[] = "temp"; const char plot_4[] = "load"; const char plot_5[] = "mem"; // названия ниже должны совпадать с массивами сверху и идти по порядку! static const char *plotNames0[] = { plot_0, plot_1, plot_0, plot_1, plot_2, plot_1 }; static const char *plotNames1[] = { plot_3, plot_3, plot_4, plot_4, plot_4, plot_5 }; // 0-CPU temp, 1-GPU temp, 2-CPU load, 3-GPU load, 4-RAM load, 5-GPU memory void setup() { Serial.begin(9600); pinMode(BTN1, INPUT_PULLUP); pinMode(BTN2, INPUT_PULLUP); // инициализация дисплея lcd.init(); lcd.backlight(); lcd.clear(); // очистить дисплей show_logo(); // показать логотип delay(2000); lcd.clear(); // очистить дисплей show_logo2(); // показать логотип } // ------------------------------ ОСНОВНОЙ ЦИКЛ ------------------------------- void loop() { parsing(); // парсим строки с компьютера updatePlot(); // обновляем массив данных графика dutyCalculate(); // посчитать скважность для вентиляторов buttonsTick(); // опрос кнопок и смена режимов updateDisplay(); // обновить показания на дисплее timeoutTick(); // проверка таймаута } // ------------------------------ ОСНОВНОЙ ЦИКЛ ------------------------------- void buttonsTick() { btn1_sig = !digitalRead(BTN1); btn2_sig = !digitalRead(BTN2); if (btn1_sig && !btn1_flag) { display_mode++; reDraw_flag = 1; if (display_mode > 9) display_mode = 0; btn1_flag = 1; } if (!btn1_sig && btn1_flag) { btn1_flag = 0; } if (btn2_sig && !btn2_flag) { display_mode--; reDraw_flag = 1; if (display_mode < 0) display_mode = 9; btn2_flag = 1; } if (!btn2_sig && btn2_flag) { btn2_flag = 0; } } void dutyCalculate() { if (PCdata[12] == 1) // если стоит галочка ManualFAN duty = PCdata[14]; // скважность равна установленной ползунком else { // если нет switch (PCdata[18]) { case 0: mainTemp = PCdata[0]; // взять опорную температуру как CPU break; case 1: mainTemp = PCdata[1]; // взять опорную температуру как GPU break; case 2: mainTemp = max(PCdata[0], PCdata[1]); // взять опорную температуру как максимум CPU и GPU break; case 3: mainTemp = temp1; break; case 4: mainTemp = temp2; break; } duty = map(mainTemp, PCdata[11], PCdata[10], PCdata[9], PCdata[8]); duty = constrain(duty, PCdata[9], PCdata[8]); } } void parsing() { while (Serial.available() > 0) { char aChar = Serial.read(); if (aChar != 'E') { inData[index] = aChar; index++; inData[index] = '\0'; } else { char *p = inData; char *str; index = 0; String value = ""; while ((str = strtok_r(p, ";", &p)) != NULL) { string_convert = str; PCdata[index] = string_convert.toInt(); index++; } index = 0; updateDisplay_flag = 1; updateTemp_flag = 1; } if (!timeOut_flag) { // если связь была потеряна, но восстановилась } timeout = millis(); timeOut_flag = 1; } } void updatePlot() { if ((millis() - plot_timer) > (PCdata[17] * 1000)) { for (int i = 0; i < 6; i++) { // для каждой строки параметров for (int j = 0; j < 15; j++) { // каждый столбец параметров (кроме последнего) PLOTmem[i][j] = PLOTmem[i][j + 1]; // сдвинуть весь массив на шаг ВЛЕВО } } for (int i = 0; i < 6; i++) { // запомнить общее число полосок графика в ПОСЛЕДНИЙ элемент массива PLOTmem[i][15] = PCdata[plotLines[i]]; } plot_timer = millis(); } } void updateDisplay() { if (updateDisplay_flag) { if (reDraw_flag) { lcd.clear(); switch (display_mode) { case 0: case 1: case 2: case 3: case 4: case 5: draw_plot_symb(); break; case 6: draw_labels_11(); break; case 7: draw_labels_12(); break; case 8: draw_labels_21(); break; case 9: draw_labels_22(); break; } reDraw_flag = 0; } switch (display_mode) { case 0: case 1: case 2: case 3: case 4: case 5: draw_plot(); break; case 6: draw_stats_11(); break; case 7: draw_stats_12(); break; case 8: draw_stats_21(); break; case 9: draw_stats_22(); break; case 50: debug(); break; } updateDisplay_flag = 0; } } void draw_stats_11() { lcd.setCursor(4, 0); lcd.print(PCdata[0]); lcd.write(223); lcd.setCursor(13, 0); lcd.print(PCdata[4]); if (PCdata[4] < 10) perc = "% "; else if (PCdata[4] < 100) perc = "%"; else perc = ""; lcd.print(perc); lcd.setCursor(4, 1); lcd.print(PCdata[1]); lcd.write(223); lcd.setCursor(13, 1); lcd.print(PCdata[5]); if (PCdata[5] < 10) perc = "% "; else if (PCdata[5] < 100) perc = "%"; else perc = ""; lcd.print(perc); for (int i = 0; i < 2; i++) { byte line = ceil(PCdata[lines[i]] / 16); lcd.setCursor(7, i); if (line == 0) lcd.printByte(1) else lcd.printByte(4); for (int n = 1; n < 5; n++) { if (n < line) lcd.printByte(4); if (n >= line) lcd.printByte(2); } if (line == 6) lcd.printByte(4) else lcd.printByte(3); } } void draw_stats_12() { lcd.setCursor(13, 0); lcd.print(PCdata[7]); if (PCdata[7] < 10) perc = "% "; else if (PCdata[7] < 100) perc = "%"; else perc = ""; lcd.print(perc); lcd.setCursor(13, 1); lcd.print(PCdata[6]); if (PCdata[6] < 10) perc = "% "; else if (PCdata[6] < 100) perc = "%"; else perc = ""; lcd.print(perc); for (int i = 0; i < 2; i++) { byte line = ceil(PCdata[lines[i + 2]] / 16); lcd.setCursor(7, i); if (line == 0) lcd.printByte(1) else lcd.printByte(4); for (int n = 1; n < 5; n++) { if (n < line) lcd.printByte(4); if (n >= line) lcd.printByte(2); } if (line == 6) lcd.printByte(4) else lcd.printByte(3); } } void draw_stats_21() { lcd.setCursor(13, 0); lcd.print(duty); if ((duty) < 10) perc = "% "; else if ((duty) < 100) perc = "%"; else perc = ""; lcd.print(perc); lcd.setCursor(3, 1); lcd.print(temp1); lcd.write(223); lcd.setCursor(11, 1); lcd.print(temp2); lcd.write(223); byte line = ceil(duty / 16); lcd.setCursor(6, 0); if (line == 0) lcd.printByte(1) else lcd.printByte(4); for (int n = 1; n < 5; n++) { if (n < line) lcd.printByte(4); if (n >= line) lcd.printByte(2); } if (line == 6) lcd.printByte(4) else lcd.printByte(3); } void draw_stats_22() { lcd.setCursor(2, 0); lcd.print(PCdata[2]); lcd.write(223); lcd.setCursor(10, 0); lcd.print(PCdata[3]); lcd.write(223); lcd.setCursor(7, 1); sec = (long)(millis() - uptime_timer) / 1000; hrs = floor((sec / 3600)); mins = floor(sec - (hrs * 3600)) / 60; sec = sec - (hrs * 3600 + mins * 60); if (hrs < 10) lcd.print(0); lcd.print(hrs); lcd.print(":"); if (mins < 10) lcd.print(0); lcd.print(mins); lcd.print(":"); if (sec < 10) lcd.print(0); lcd.print(sec); } void draw_labels_11() { lcd.createChar(0, degree); lcd.createChar(1, left_empty); lcd.createChar(2, center_empty); lcd.createChar(3, right_empty); lcd.createChar(4, row8); lcd.setCursor(0, 0); lcd.print("CPU:"); lcd.setCursor(0, 1); lcd.print("GPU:"); } void draw_labels_12() { lcd.createChar(0, degree); lcd.createChar(1, left_empty); lcd.createChar(2, center_empty); lcd.createChar(3, right_empty); lcd.createChar(4, row8); lcd.setCursor(0, 0); lcd.print("GPUmem:"); lcd.setCursor(0, 1); lcd.print("RAMuse:"); } void draw_labels_21() { lcd.createChar(0, degree); lcd.createChar(1, left_empty); lcd.createChar(2, center_empty); lcd.createChar(3, right_empty); lcd.createChar(4, row8); lcd.setCursor(0, 0); lcd.print("FANsp:"); lcd.setCursor(0, 1); lcd.print("T1: "); lcd.setCursor(8, 1); lcd.print("T2:"); } void draw_labels_22() { lcd.createChar(0, degree); lcd.createChar(1, left_empty); lcd.createChar(2, center_empty); lcd.createChar(3, right_empty); lcd.createChar(4, row8); lcd.setCursor(0, 0); lcd.print("M:"); lcd.setCursor(7, 0); lcd.print("HM:"); lcd.setCursor(0, 1); lcd.print("UPTIME:"); } void draw_legend() { byte data = PCdata[plotLines[display_mode]]; lcd.setCursor(10, 0); lcd.print(data); if (display_mode > 1) { if (data < 10) perc = "% "; else if (data < 100) perc = "%"; else { perc = ""; } lcd.print(perc); } else { if (data < 10) { lcd.write(223); lcd.print(" "); } else if (data < 100) { lcd.write(223); lcd.print(" "); } else { lcd.write(223); } } } void draw_plot() { draw_legend(); lcd.setCursor(0, 1); for (int i = 0; i < 16; i++) { lcd.printByte(constrain(map(PLOTmem[display_mode][i], 0, 100, 0, 7), 0, 7)); } } void draw_plot_symb() { lcd.createChar(0, row1); lcd.createChar(1, row2); lcd.createChar(2, row3); lcd.createChar(3, row4); lcd.createChar(4, row5); lcd.createChar(5, row6); lcd.createChar(6, row7); lcd.createChar(7, row8); lcd.setCursor(0, 0); lcd.print(plotNames0[display_mode]); lcd.setCursor(3, 0); lcd.print(plotNames1[display_mode]); lcd.print(": "); } void timeoutTick() { if ((millis() - timeout > 5000) && timeOut_flag) { lcd.clear(); lcd.setCursor(3, 0); lcd.print("CONNECTION"); lcd.setCursor(5, 1); lcd.print("FAILED"); timeOut_flag = 0; reDraw_flag = 1; } } void show_logo() { lcd.createChar(0, logo0); lcd.createChar(1, logo1); lcd.createChar(2, logo2); lcd.createChar(3, logo3); lcd.createChar(4, logo4); lcd.createChar(5, logo5); lcd.setCursor(0, 0); lcd.printByte(0); lcd.printByte(1); lcd.printByte(2); lcd.setCursor(0, 1); lcd.printByte(3); lcd.printByte(4); lcd.printByte(5); lcd.setCursor(4, 0); lcd.print("AlexGyver"); lcd.setCursor(4, 1); lcd.print("Technologies"); } void show_logo2() { lcd.setCursor(1, 0); lcd.print("modified by"); lcd.setCursor(5, 1); lcd.print("klykov.net"); } void debug() { lcd.clear(); lcd.setCursor(0, 0); for (int j = 0; j < 5; j++) { lcd.print(PCdata[j]); lcd.print(" "); } lcd.setCursor(0, 1); for (int j = 6; j < 10; j++) { lcd.print(PCdata[j]); lcd.print(" "); } lcd.setCursor(0, 2); for (int j = 10; j < 15; j++) { lcd.print(PCdata[j]); lcd.print(" "); } lcd.setCursor(0, 3); for (int j = 15; j < 18; j++) { lcd.print(PCdata[j]); lcd.print(" "); } }
ЗАРАНЕЕ СПАСИБО!!! <3
Какую проблему-то решить? Памяти допаять вам в МК что ли?
Помогите пожалуйста решить проблему.
А проблема-то есть? Она работает или нет? Ну, мало памяти, но может хватает? Вы уж толком говорите.
А так - какие проблемы? Сокращать память, как я понимаю для Вас не вариант, ну тогда берите Мегу - туда влезет.
Фигня все это, у меня один скетч при 90 % стабильно уж пару месяцев работает, зависит от самого скетча, количества вызовов процедур (стек), количества сторонних библиотек и ещё кучи причин.
https://forum.arduino.cc/index.php?topic=428015.0
Вряд ли будет работать, стоит переходить на иной камень. Мой ХШ подсказывает, что сама программа отожрет в худшем случае около 10 байт со стека. Но, в ней активно работает lcd.print(), который есть наследник как и Serial.print() от всего стека классов stream, а там жрется не так уж и мало, вот сколько точно уже не помню, но вряд ли меньше 14 байт. Там тучно есть около 9 вложенных вызовов "друг в друга", из-за чего и делал свою часть библиотеки - аналога работы с LCD, а это явно уже 18 байт стека как миниум, без локальных переменных.
ТС, даже интересно, работает стабильно или куда? :)
На Arduino 1.8.5 для Nano_V3 cкетч использует 10818 байт (35%) памяти устройства. Всего доступно30720 байт.Глобальные переменные используют 1000 байт (48%) динамической памяти, оставляя 1048 байт для локальных переменных. Максимум: 2048 байт.
Может это наведет Вас на правильную мысль. :-)
и Serial.print()
я наверное что то не понимаю в этой жизни....зачем в готовом реальном устройстве используется вывод текстовых сообщений в UART?
обычно удаляю все информационные сообщения когда скетч полностью оттестирован.
Вместо массивов row1-row8 можно генерировать програмно один массив на 8 байт с нужным символом в данный момент. Экономия в 56 байт обеспечена.