Память заканчивается. Варианты решения.

AsNik
Offline
Зарегистрирован: 24.10.2020

Здравствуйте! Делаю для себя проект и дошел до:

Скетч использует 24518 байт (79%) памяти устройства. Всего доступно 30720 байт.
Глобальные переменные используют 1243 байт (60%) динамической памяти, оставляя 805 байт для локальных переменных. Максимум: 2048 байт.

Программа написана примерно на 50 процентов, ну и предполагаю что памяти флеш не хватит. да и оперативы тоже, ибо не все еще глобальные созданы....

Вариант перейти на мегу и подобные ей пока не рассматриваю. Одна из причин - ее нет, а наны есть.

По оптимизации кода уверен, что можно еще что-то сделать, но с моими познаниями что смог уже сделал. Ну может еще полтора килобайта смогу ужать. Как вариант убрать бутлоадер и еще полтора. Но так еще не делал, поэтому этот вариант на потом.

В коде нет ни String, ни Serial, флоат в одной единственной процедуре. Возможно(хотя это слово можно наверное убрать) неграмотно написан код. Память "забита" скорее всего LCD2004. Много строковых констант....  Еще вариант по сокращать строковые константы, но боюсь ими я много не освобожу...

везде, где возможно

lcd.setCursor(); lcd.print("Text");
lcd.setCursor(); lcd.print("Text");
lcd.setCursor(); lcd.print("Text");

Заменил на
void PrintText(const byte _col, const byte _row) {
lcd.setCursor(_col, _row); lcd.print("Text");
}

PrintText(0, 0); //ну и вызываю с разных мест

Исходник не выкладываю, хотя не секретный, не жалко, в 6 файлах под тысячу строк...

В общем вопрос такой: Решил программу разбить на два МК(нано). В одном только работа с экраном, а во втором основной алгоритм работы устройства. Соединить их думаю уже по Serial. Собс-но вопрос - имеет смысл моя идея. Никогда раньше не объединял ардуины для совместной работы. С чем мне придется столкнуться?

Komandir
Komandir аватар
Offline
Зарегистрирован: 18.08.2018

Без кода нам не ясно чем вы там память закакали ...

Соединить не проблема, только надо учесть что на стандартных платах аппаратный UART подключен к преобразователю USB-UART.

andycat
andycat аватар
Offline
Зарегистрирован: 07.09.2017

а где весь код программы?

AsNik
Offline
Зарегистрирован: 24.10.2020

Komandir пишет:

Соединить не проблема, только надо учесть что на стандартных платах аппаратный UART подключен к преобразователю USB-UART.

Уже делали такое?

Чем это грозит, то что они подключены (аппаратный с USB)?

 

Komandir
Komandir аватар
Offline
Зарегистрирован: 18.08.2018

Грозит тем что их сложно заюзать для обмена. Придётся либо дорожки резать (тогда при заливке скетча через загрузчик - паять перемычки) или использовать SoftawareSerial со своими заморочками ...

b707
Offline
Зарегистрирован: 26.05.2017

AsNik пишет:

В общем вопрос такой: Решил программу разбить на два МК(нано). В одном только работа с экраном, а во втором основной алгоритм работы устройства. Соединить их думаю уже по Serial. Собс-но вопрос - имеет смысл моя идея. Никогда раньше не объединял ардуины для совместной работы. С чем мне придется столкнуться?

ну это примерно как пытаться увезти бетонную плиту на двух "запорожцах" вместо одного грузовика.... :) эффективность этого решения примерно такая же :)

Разбив программу на 2 Нано - вы конечно вдвое увеличите память, но при этом получите массу нового для себя геморроя, связанного с обменом данными и координацией работы двух МК. И неизвестно, выиграете ли в сумме :)

AsNik
Offline
Зарегистрирован: 24.10.2020

Komandir пишет:

Грозит тем что их сложно заюзать для обмена. Придётся либо дорожки резать (тогда при заливке скетча через загрузчик - паять перемычки) или использовать SoftawareSerial со своими заморочками ...

т.е даже если я на обоих ардуинах в их программах(скечах) не буду использовать пины D0 и D1. (кроме как для соединения между собой). По отдельности их прошью,  и потом соединю проводами. В этом случае могут быть проблемы при передаче по UART между ними?

А какие проблемы? Связи не будет или будет нестабильна?

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

AsNik
Offline
Зарегистрирован: 24.10.2020

b707 пишет:

Согласен. Но с другой стороны интересно. Интересен сам вариант использования двух ардуин в единой задаче.

Может еще где пригодится такой опыт.

Нет, если затея бредовая, то конечно нет смысла заморачиваться...

В любом случае, если не по UART может еще как простенько связать две ардуины можно...?

b707
Offline
Зарегистрирован: 26.05.2017

AsNik пишет:

Но с другой стороны интересно. Интересен сам вариант использования двух ардуин в единой задаче.

если интересно - то другое дело.

Но с чисто практической точки зрения в вашем случае в разы правильнее купить Мегу

nik182
Offline
Зарегистрирован: 04.05.2015

Обычно первые строки программы активно отъедают память, так как с ними к программе линкуются разные библиотеки. Если в конце программы в использовании новых библиотек нет нужды, то может получиться так, что сотня строк кода даст прирост программы на сотни три байт. Пробовать надо. У Вас ещё 6 кбайт кода свободно. Туда много чего можно впихнуть. У меня крутиться программа, у которой только 2 байта свободного флэша осталось. Что бы влезть, пришлось дигиталрид и дигиталрайт переписать на ассемблер. Это сэкономило сколько то байт и программа влезла. Так что часто есть путь упихнуть всё в один чип. Иногда надо чем то пожертвовать. Или брать более ёмкий корпус. Благо выбор большой.

DetSimen
DetSimen аватар
Offline
Зарегистрирован: 25.01.2017

Странна. У мня ООП код в 1000 строк в Нану влазиит со свистом. Думаю, что б туда еще прикрутить

AsNik
Offline
Зарегистрирован: 24.10.2020

DetSimen пишет:

Странна. У мня ООП код в 1000 строк в Нану влазиит со свистом. Думаю, что б туда еще прикрутить

:)

У меня некоторые переменные объявлены и "наполовину закомментированы", на дальнейшее развитие событий...

А сейчас дай думаю расскоментирую и гляну как у меня дела... Но был удивлен. Памяти стало почему-то больше... свободной.

Так:

enum TSensLocate {sens_ulica, sens1_kesson1, sens2_kesson1, /*podval, sens5, sens6*/ SENS_COUNT};
const char * SensTitle[SENS_COUNT] = {"Ulica", "Kes1Sens1", "Kes1Sens2", /*"Podval", "s5", "s6"*/};
Скетч использует 24518 байт (79%) памяти устройства. Всего доступно 30720 байт.
Глобальные переменные используют 1243 байт (60%) динамической памяти, оставляя 805 байт для локальных переменных. Максимум: 2048 байт.
 
А так:
enum TSensLocate {sens_ulica, sens1_kesson1, sens2_kesson1, podval, sens5, sens6,/**/ SENS_COUNT};
const char * SensTitle[SENS_COUNT] = {"Ulica", "Kes1Sens1", "Kes1Sens2", /*"Podval", "s5", "s6"*/};
Скетч использует 24472 байт (79%) памяти устройства. Всего доступно 30720 байт.
Глобальные переменные используют 1255 байт (61%) динамической памяти, оставляя 793 байт для локальных переменных. Максимум: 2048 байт.

В ОЗУ понятно они добавились, но почему с флеша ушли?)

v258
v258 аватар
Offline
Зарегистрирован: 25.05.2020

AsNik пишет:

В ОЗУ понятно они добавились, но почему с флеша ушли?)

Как они могли оттуда уйти, если их там не было? ))

AsNik
Offline
Зарегистрирован: 24.10.2020

v258 пишет:

AsNik пишет:

В ОЗУ понятно они добавились, но почему с флеша ушли?)

Как они могли оттуда уйти, если их там не было? ))

Не знаю.... Но размер флеша то изменился)

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

DetSimen пишет:

Странна. У мня ООП код в 1000 строк в Нану влазиит со свистом. Думаю, что б туда еще прикрутить

а вот если бы ты мог писать уложился в 500 строк )))

nik182
Offline
Зарегистрирован: 04.05.2015

Бывает что просто перестановка строк местами приводит к изменению размера во флэше. Лиинкер по другому располагает модули. Или ещё что. Так что надо пробовать. Слова - уже кончается! это не правильно. Надо всё собрать, попробовать, покрутить и только тогда за знанием на форум идти. А так гадать на хрустальном шаре что там у тебя не вмещается не продуктивно.

AsNik
Offline
Зарегистрирован: 24.10.2020

nik182 пишет:

Бывает что просто перестановка строк местами приводит к изменению размера во флэше. Лиинкер по другому располагает модули. Или ещё что. Так что надо пробовать.

Решил попробовать такой тест:

#include <Wire.h>
#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C lcd(0x27,20,4);

void setup(){
  lcd.init(); lcd.backlight();
}

void loop() {
 lcd.print("Test0"); //Скетч использует 3138 байт / Глобальные переменные используют 256 байт
//lcd.print("Test1"); //+22 Скетч использует 3160 байт/+6 Глобальные переменные используют 262 байт
//lcd.print("Test2"); //+22 Скетч использует 3182 байт/+6 Глобальные переменные используют 268 байт
//lcd.print("Test3"); //+22 Скетч использует 3204 байт/+6 Глобальные переменные используют 274 байт
//lcd.print("Test4"); //+22 Скетч использует 3226 байт/+6 Глобальные переменные используют 280 байт
//lcd.print("Test5"); //+22 Скетч использует 3248 байт/+6 Глобальные переменные используют 286 байт
//lcd.print("Test6"); //+22 Скетч использует 3270 байт/+6 Глобальные переменные используют 292 байт
//lcd.print("Test7"); //-16 Скетч использует 3254 байт/+6 Глобальные переменные используют 298 байт
//lcd.print("Test8"); //+14 Скетч использует 3268 байт/+6 Глобальные переменные используют 304 байт
//lcd.print("Test9"); //+14 Скетч использует 3282 байт/+6 Глобальные переменные используют 310 байт
//lcd.print("Test0"); //+8 Скетч использует 3290 байт/0 Глобальные переменные используют 310 байт
//lcd.print("Test1"); //+8 Скетч использует 3298 байт/0 Глобальные переменные используют 310 байт
//lcd.print("TEST2"); //+14 Скетч использует 3312 байт/+6 Глобальные переменные используют 316 байт
}

Действительно.  Если начать по одной строчке расскоментировать, то результаты интересные

Меня удивило, что "умный" компилятор помнит какие константы он уже использовал (Test0 и Test1)

Но +22, -16, +14 - как он там это считает))

А я давно обратил внимание, что когда пишу код, то размер прыгает то в одну, то в другую сторону, но как-то думал, что это от "другого" зависит, а тут вон оно что...

AsNik
Offline
Зарегистрирован: 24.10.2020

nik182 пишет:

А так гадать на хрустальном шаре что там у тебя не вмещается не продуктивно.

Да вопрос-то у меня в основном не в этом.... Если уж хочется на код посмотреть, то я могу его весь вывалить, но нужно?)

А так, по теме, уже посмотрел примеры использования связи двух ардуин по UART.... Буду смотреть пока в эту сторону.  Ибо то, что я накодил, и что еще нужно, вряд ли я уложу в 30 кил...

Komandir
Komandir аватар
Offline
Зарегистрирован: 18.08.2018

print("Test0"); 

в итоге Test0 будет и в коде и займет место в ОЗУ и так со всеми константами

AsNik
Offline
Зарегистрирован: 24.10.2020

Это верно. Но константы все равны(размер) а откуда 22, 16, 14, 8 ?

Вот в ОЗУ четко по 6 байт прибавляется для новых констант, это логично... А уже "имеющихся там" - ноль байт - Это умно) Не ожидал такого поведения со строковыми константами.... Но понятно, что Test2 и TEST2 это разные, поэтому для последнего +6 байт...

Может я и умещу(уместю) еще все))) Нужно только еще раз пробежаться по строковым константам

Komandir
Komandir аватар
Offline
Зарегистрирован: 18.08.2018

0x00 добавляется как конец строки

AsNik
Offline
Зарегистрирован: 24.10.2020

AsNik пишет:

 

#include <Wire.h>
#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C lcd(0x27,20,4);

void setup(){
  lcd.init(); lcd.backlight();
}

void loop() {
 lcd.print("Test0"); //Скетч использует 3138 байт / Глобальные переменные используют 256 байт
//lcd.print("Test1"); //+22 Скетч использует 3160 байт/+6 Глобальные переменные используют 262 байт
//lcd.print("Test2"); //+22 Скетч использует 3182 байт/+6 Глобальные переменные используют 268 байт
//lcd.print("Test3"); //+22 Скетч использует 3204 байт/+6 Глобальные переменные используют 274 байт
//lcd.print("Test4"); //+22 Скетч использует 3226 байт/+6 Глобальные переменные используют 280 байт
//lcd.print("Test5"); //+22 Скетч использует 3248 байт/+6 Глобальные переменные используют 286 байт
//lcd.print("Test6"); //+22 Скетч использует 3270 байт/+6 Глобальные переменные используют 292 байт
//lcd.print("Test7"); //-16 Скетч использует 3254 байт/+6 Глобальные переменные используют 298 байт
//lcd.print("Test8"); //+14 Скетч использует 3268 байт/+6 Глобальные переменные используют 304 байт
//lcd.print("Test9"); //+14 Скетч использует 3282 байт/+6 Глобальные переменные используют 310 байт
//lcd.print("Test0"); //+8 Скетч использует 3290 байт/0 Глобальные переменные используют 310 байт
//lcd.print("Test1"); //+8 Скетч использует 3298 байт/0 Глобальные переменные используют 310 байт
//lcd.print("TEST2"); //+14 Скетч использует 3312 байт/+6 Глобальные переменные используют 316 байт
}

Вот тест с макросом F()

#include <Wire.h>
#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C lcd(0x27, 20, 4);

void setup() {
  lcd.init(); lcd.backlight();
}

void loop() {
lcd.print(F("Test0")); //Скетч использует 3150 байт / Глобальные переменные используют 250 байт
lcd.print(F("Test1")); //+46 Скетч использует 3196 байт/0 Глобальные переменные используют 250 байт
lcd.print(F("Test2")); //+14 Скетч использует 3210 байт/0 Глобальные переменные используют 250 байт
lcd.print(F("Test3")); //+14 Скетч использует 3224 байт/0 Глобальные переменные используют 250 байт
lcd.print(F("Test4")); //+14 Скетч использует 3238 байт/0 Глобальные переменные используют 250 байт
lcd.print(F("Test5")); //+14 Скетч использует 3252 байт/0 Глобальные переменные используют 250 байт
lcd.print(F("Test6")); //+14 Скетч использует 3266 байт/0 Глобальные переменные используют 250 байт
lcd.print(F("Test7")); //+14 Скетч использует 3280 байт/0 Глобальные переменные используют 250 байт
lcd.print(F("Test8")); //+14 Скетч использует 3294 байт/0 Глобальные переменные используют 250 байт
lcd.print(F("Test9")); //+14 Скетч использует 3308 байт/0 Глобальные переменные используют 250 байт
lcd.print(F("Test0")); //+14 Скетч использует 3322 байт/0 Глобальные переменные используют 250 байт
lcd.print(F("Test1")); //+14 Скетч использует 3336 байт/0 Глобальные переменные используют 250 байт
lcd.print(F("TEST2")); //+14 Скетч использует 3350 байт/0 Глобальные переменные используют 250 байт
}

В данном случае одинаковые константы не учитываются, флеша используется на 18 байт больше, но экономится ОЗУ на 66 байт

AsNik
Offline
Зарегистрирован: 24.10.2020

Komandir пишет:

0x00 добавляется как конец строки

Это понятно. Про 6 байт в озу... пять символов и завершающий ноль...

А я про увеличение (но и в какой-то момент уменьшение) флеш памяти... Обратите внимание на +22, -16, +14

AsNik
Offline
Зарегистрирован: 24.10.2020

Исходя из этого, полагаю, что если в коде используются одинаковые строковые константы - то их лучше использовать без макроса F()

Komandir
Komandir аватар
Offline
Зарегистрирован: 18.08.2018

Просто надо одинаковые константы объявлять через const PROGMEM, а не пихать бездумно F() с одинаковым текстом ...

Вы тут байты экономите, где вы 50% обещанного кода собираетесь разпихать ???

AsNik
Offline
Зарегистрирован: 24.10.2020

Komandir пишет:

Просто надо одинаковые константы объявлять через const PROGMEM, а не пихать бездумно F() с одинаковым текстом ...

Возможно. Я попробовал версию одинаковых констант без F().... В итоге результат немного не тот, но это и правильно. В любом случае где то мы выигрываем, значит где-то проиграем... и с прогмем тоже самое будет...

AsNik
Offline
Зарегистрирован: 24.10.2020

Komandir пишет:

Вы тут байты экономите, где вы 50% обещанного кода собираетесь разпихать ???

:) Надеялся на чудо) Ну и про байты экономии - это в маленьких тестах.... На самом деле если пройтись по моей тысячи строк кода может и получится, как я уже в начале говорил, сэкономить килобайт.... 

Причем оперативы-то мне должно хватить...

Да нет, на самом деле я уже понимаю, что не умещу я программу, так и придется наверное делить ее на две ардуины...

Komandir
Komandir аватар
Offline
Зарегистрирован: 18.08.2018

Вы просто чего то намудрили ... Возьмите скетч Arduino transistor tester - в нем куча всего считается рисуется выводится и при этом он легко помещается в 32К...

AsNik
Offline
Зарегистрирован: 24.10.2020

https://create.arduino.cc/projecthub/plouc68000/ardutester-v1-13-the-arduino-uno-transistor-tester-dbafb4

Оно? Скачал, архив. Куча файлов. Открыл в ИДЕ... скомпилировал... Это какая-то шутка?

Скетч использует 26782 байт (87%) памяти устройства. Всего доступно 30720 байт.
Глобальные переменные используют 181 байт (8%) динамической памяти, оставляя 1867 байт для локальных переменных. Максимум: 2048 байт.
 
Там в одном первом(основном) файле почти 2500 строк... Куча оператор условной компиляции.... Для моего уровня этот исходник непонятен, но завтра попробую всеж разобраться..... почему там 181 байт оперативы только занято)
Komandir
Komandir аватар
Offline
Зарегистрирован: 18.08.2018
AsNik
Offline
Зарегистрирован: 24.10.2020

Komandir пишет:

Вы просто чего то намудрили ... Возьмите скетч Arduino transistor tester - в нем куча всего....

Я намудрил?))

Цитата:

http://arduino.ru/forum/proekty/transistor-tester-arduino

----------------------
Скетч использует 15190 байт (49%) памяти устройства. Всего доступно 30720 байт.
Глобальные переменные используют 387 байт (18%) динамической памяти, оставляя 1661 байт для локальных переменных. Максимум: 2048 байт.
----------------------

Вот где намудрили.... И это в хорошем смысле слова. Честно признаюсь, я там ничего не понял. Условной компиляцией никогда обширно не пользовался. Меня конечно очень сильно удивляет как так можно экономить ОЗУ, да и флеш тоже....  5000 строк кода.... Понятное дело не от количества строк кода зависит размер, но тем не менее и глобальных переменных достаточно, и строковых констант....дефайнов... и все равно добиться таких результатов, нужно от и до знать свое дело. Но с моим уровнем, а сейчас вообще редко выпадает случай посидеть вечером дома покодить для души... Нет, это я не смогу понять)

Если кто сможет на пальцах объяснить в чем суть в transistor-tester-arduino чем там так добились экономии. Может все дело в условной компиляции??? Вот реально, выкинуть бы все то что не попадает в компиляцию из этих пяти тыс. строк и посмотреть реальный исходник что там компилится....

Но молодцы, конечно, кто умеет так писать... Снимаю шляпу

AsNik
Offline
Зарегистрирован: 24.10.2020

У меня конечно "мильён" вопросов по данному скечу(хотя это уже не набросок)), но понимаю, что никто мне на них отвечать не будет, но..... Вот для чего так делается

.....

#define wait_about5ms() wait5ms()
....
....
#define  wait5ms()   delay(5)
....

Что бы запутать таких как я?

Komandir
Komandir аватар
Offline
Зарегистрирован: 18.08.2018

Так пишут программы под разные платы дисплеи условия ...

Раскомментировал нужные устройства, закомментировал ненужные и откомпилировал ...

AsNik
Offline
Зарегистрирован: 24.10.2020

Komandir пишет:

Так пишут программы под разные платы дисплеи условия ...

Раскомментировал нужные устройства, закомментировал ненужные и откомпилировал ...

Ну это и понятно... В итоге если сейчас убрать из этого скеча, все, что не нужно, допустим, для моей наны... Хотелось бы посмотреть что останется))

Ладно, я считаю, что данный пример мне мало чем поможет.... очень уж запутанно. А вот что-то подобное, но не для всех видов плат, а для одной.... я бы посмотрел. И еще беда с английским :(

wdrakula
wdrakula аватар
Offline
Зарегистрирован: 15.03.2016

ТС, дорогой! Я понимаю, что ты стесняешься привести свой код.Мы и правда не самые тактичные люди на свете! ;)), но не мог бы ты написать назначение кода, ну как бы ТЗ, где ТЗ - Техническое Задание, а не Точка Зрения. Тут многие люди писали много разного кода, я полагаю, что тебе сразу ответят, войдёт ли это в Нанку (на начальном уровне мастерства программиста).

wdrakula
wdrakula аватар
Offline
Зарегистрирован: 15.03.2016

AsNik пишет:

И еще беда с английским :(

Я очень добр в Шаббат и не стану сразу глумиться. Просто предупреждение - таких признаний на форумах по программированию и/или электронике следует избегать. Это те сферы знаний, в которых буквально всё происходит исключительно на аглицком. Часто случается, что после подобных признаний общение переходит в чистый глум и взаимное калометание, сорри. Мне и сейчас очень трудно себя сдерживать, но я стараюсь! ;))

AsNik
Offline
Зарегистрирован: 24.10.2020

Я не первый раз на форуме(ах) и знаю к чему могут привести такие высказывания. Но что есть, то есть. Я сказал честно. И когда читаю глум в других ветках, то иногда на стороне глумящихся, а иногда на стороне, над кем глумятся...

Хотите глумится - глумитесь. Просто нужно перед тем как глумится, оставаться человеком. Программирование - это мое хобби . Я неоднократно во всех своих вопросах это повторял и буду повторять. Не английский, ни языки программирования никогда и нигде не изучал основательно, но по мере возможности для себя дома... Но я всегда с уважением отношусь к советам, к примерам, ко всему что тоже с уважением... Еще раз, хотите глумится - глумитесь...

wdrakula пишет:

ТС, дорогой! Я понимаю, что ты стесняешься привести свой код.

Если хочешь, я, как и говорил выше могу выложить свой код...  Может быть даже меня носом ткнут, где я чего делаю не правильно. Я не столько стесняюсь кода, сколько понимаю, что никому в нем разбираться не захочется и вываливать несколько файлов сюда пока не вижу смысла.... тем более что ты уже собрался глумится;) Спасибо.

b707
Offline
Зарегистрирован: 26.05.2017

AsNik, вообще-то вас не просили показать код - а просили рассказать, в чем суть Вашего творения. Что за программу вы пишете и что еще собрались в нее добавить. что так уверены, что она в Нану не войдет.

Если вы даже этого не готовы сказать - то честно говоря я считаю дальнейшее обсуждение бессмысленным.

AsNik
Offline
Зарегистрирован: 24.10.2020

Хм.. Даже не знаю как кратко рассказать что, для чего и что будет... Шесть(максимум) сенсоров, 8 каналов и куча информации на LCD

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

Вот основной файл, где объявлены практически все глобальные переменные...

#include <LiquidCrystal_I2C.h>
#include "sav_button.h"

#define NO_DATA   9999          //Нет данных
#define NO_SUPP   9998          //Не поддерживается

//---------------------- PINS ---------------------------------

#define ENC_A   2               //ПинА энкодера
#define ENC_B   3               //ПинВ энкодера
#define ENC_SW  4               //Пин кнопки энкодера

//Входы датчиков
#define IND_1   5
#define IND_2   6
#define INA_1   15
#define INA_2   16

#define TESTPOWERPIN 8          // Для ТЕСТА Питание!!!!!!!!!!!!!!!!!!!!!!
//---------------------- END PINS -----------------------------

#define START_MENU 0            // 1 - при старте отображать меню, 0 - Отображать инфо экран датчика

//---------------------- СЕНСОРЫ ------------------------------
#include <iarduino_DHT.h>
#include <iarduino_AM2320.h>
#include <BME280I2C.h>
#include <Wire.h>


extern bool reading;    //Объявлена в файле Sensors

enum TPins {pin_I2C = 0, pin_IND1 = IND_1, pin_IND2 = IND_2, pin_INA1 = INA_1, pin_INA2 = INA_2};   //Возможно этот enum лишний
enum TSensStatus {ssOk = 0, ssReading, ssInit, ssNoSens, ssNoData, ssUnknownErr};
enum TSensorParam {spTemp, spHumi, spHumiABS, spPress};

enum TSensType {stDHT11, stDHT22, stAM, stBME, COUNT_TYPES};                    //Тип сенсора
const char * SensTypeStr[COUNT_TYPES] = {"<D11>", "<D22>", "<AM >", "<BME>"};   //Тип сенсора строка

//#define SENS_MAX   6            //Максимальное число подключаемых сенсоров
enum TSensLocate {sens_ulica, sens1_kesson1, sens2_kesson1, /*podval, sens5, sens6*/ SENS_COUNT};     //Размещение сенсора и индекс в массиве сенсоров. SENS_COUNT Кол-во подключенных сенсоров
const char * SensTitle[SENS_COUNT] = {"Ulica", "Kes1Sens1", "Kes1Sens2", /*"Podval", "s5", "s6"*/};   //Строковое описание сенсора. Макс 10 символов

struct TMaxMinTH {
  int t, h;
};

struct TSensorData {                    //Структура данных сенсора
  int T, tmpT, lastT;                   //Данные по температуре
  int H, tmpH, lastH;                   //Данные по влажности
  TMaxMinTH minT, maxT, minH, maxH;     //Данные по минимальной и максимальной температуре и влажности
  uint16_t P, tmpP, lastP, minP, maxP;  //Данные по давлению
};

struct TSensor {              //Структура сенсора
  void * sensor;                  //Указатель на сенсор
  byte sStatus;                   //Состояние сенсора. 0 - OK
  const bool isPressure;          //Поддержка у сенсора датчика атмосферного давления
  TSensType sensType;             //Тип сенсора
  TPins pinSens;              //Возможно это лишнее (избыточно TPins)
  TSensorData data;               //Данные сенсора
};

TSensor arSens [SENS_COUNT] = {                       //Массив сенсоров
  //{new iarduino_DHT(pin_IND1), ssInit, false, stDHT22, pin_IND1, {}}, //Убрать ТЕСТ
  {new BME280I2C, ssInit, true, stBME, pin_I2C, {}},                    //(sens_ulica) Сенсор улица
  {new iarduino_DHT(pin_IND1), ssInit, false, stDHT22, pin_IND1, {}},    //(sens1_kesson1)
  {new iarduino_DHT(pin_IND2), ssInit, false, stDHT11, pin_IND2, {}},    //(sens2_kesson1)
};

//-------------------------- end SENSORS ------------------------------

//------------------------ КАНАЛЫ ------------------------
#define CANNELS_COUNT 8
const char * CannelsTitle[CANNELS_COUNT] = {"Channel1", "Channel2", "Channel3", "Channel4", "Channel5", "Channel6", "Channel7", "Channel8"};      //Названия каналов макс 8 символов
struct Channel {                       //Данные канала
  //char chTitle[10];                  //Описание канала
  bool chEnable: 1;                    //Общее состояние канала
  bool chIsWork: 1;                    //Признак работы канала
  byte workCnt[3];                     //Счетчики срабатываний канала сегодня/вчера/позавчера
  uint32_t workTime;                   //Продолжительность работы канала, по завершению плюсуется к timesWork[0]
  uint32_t workTimes[3];               //Общее время работы канала сегодня/вчера/позавчера
  byte chError;                        // 0 = Ok, 1 - отсутствует, 2 - ошибка чтения.... в этом духе
};
Channel channels[CANNELS_COUNT];
//--------------------------------------------------------

// ------------------------ МЕНЮ -------------------------

struct TMenu {
  byte ItemCount;               //Кол-во итемов в меню
  byte ShowItemCount;           //Кол-во итемов отображаемых на экране. Может быть 2, 3, 4
  byte SelectItem;              //Выбранный пункт меню
  byte LastActiveItem;          //Активный пункт меню перед сменой меню
  byte LastTopItem;             //Верхний видимый пункт меню перед сменой меню
  const char **Items;           //Названия пунктов меню
};
TMenu *Menu;

const char *forMainMenu[] = {     //Названия пунктов главного меню
  "Info",
  "Sensors",
  "Channels",
  "Service"
};
TMenu MainMenu {sizeof(forMainMenu) / sizeof(forMainMenu[0]), 4, 0, 0, 0, forMainMenu};  //Главное меню

const char *forSensMenu[SENS_COUNT + 1] = {     //Названия пунктов меню сенсоров
  "Sens1",
  "Sens2",
  "Sens3",
  //"Sens4",
  //"Sens5",
  //"Sens6",
  "(Back)"
};
TMenu SensMenu {sizeof(forSensMenu) / sizeof(forSensMenu[0]), 3, 0, 0, 0, forSensMenu};   //Меню сенсоров

const char *forChannelsMenu[] = {     //Названия пунктов меню каналов
  "Chnl_1",
  "Chnl_2",
  "Chnl_3",
  "Chnl_4",
  "Chnl_5",
  "Chnl_6",
  "Chnl_7",
  "Chnl_8",
  "(Back)"
};
TMenu ChannelsMenu {sizeof(forChannelsMenu) / sizeof(forChannelsMenu[0]), 3, 0, 0, 0, forChannelsMenu};   //Меню каналов
//--------------------------------------------------------

//Экраны
bool isScreens = false;                               //true когда показаны экраны, а не меню
byte ScreenIndex, ScreenCount = 4;                    //Индекс текущего экрана, количество текущих экранов
byte InfoScreenIndex = 0, InfoScreenCount = 6;        //Индекс и кол-во информационных экранов
byte ServiceScreenIndex = 0, ServiceScreenCount = 3;  //.... сервисных экранов
byte SensScreenIndex = 0, SensScreenCount = 4;        //... экранов сенсоров
byte ChannelScreenIndex = 0, ChannelScreenCount = 3;  //.... экранов каналов

LiquidCrystal_I2C lcd(0x27, 20, 4);
SButton swEnc(ENC_SW, 10, 50, 1000);

byte gradus[8] = {B00010, B00101, B00010, B00000, B00000, B00000, B00000, B00000};    //Символ градуса
//byte slesh[8]  = {B00000, B10000, B01000, B00100, B00010, B00001, B00000, B00000};    //Символ обратного слеша;
byte arup[8]   = {B00100, B01110, B10101, B00100, B00100, B00000, B00000, B00000};    //Стрелка вверх
byte ardown[8] = {B00000, B00000, B00000, B00100, B00100, B10101, B01110, B00100};    //Стрелка вниз

void Print_Space(const byte _cnt = 1);

// ==================== ISR обработка прерываний ========================
volatile bool f_isrA = false;
volatile char encTick = 0;
void isrA() {
  f_isrA = true;
}

void isrB() {
  if (f_isrA) {        //Если было Прерывание Энодера A
    f_isrA = false;
    digitalRead(ENC_A) == digitalRead(ENC_B) ? encTick = 1 : encTick = -1;
  }
}
// ========================================= END ISR ====================================

void setup() {
  attachInterrupt(0, isrA, FALLING);    // прерывание на 2 пине! A у энка
  attachInterrupt(1, isrB, FALLING);    // прерывание на 3 пине! B у энка

  Wire.begin();
  static_cast<BME280I2C*>(arSens[0].sensor)->begin();
  swEnc.begin();
  lcd.init(); lcd.backlight();
  lcd.createChar(1, gradus);

  Menu = &MainMenu;
  if (START_MENU) UpdateMenu(true);
  else {
    Menu->SelectItem = 1;
    isScreens = true;
    ScreenIndex = InfoScreenIndex;
    ScreenCount = InfoScreenCount;
    UpdateScreens(true);
  }

  for (byte n = 0; n < SENS_COUNT; ++n) SetSensorStatus(n, ssInit); //Инициализация датчиков
  ResetMinMaxDay();

  //убрать. для теста
  channels[0].workCnt[0] = 9;
  channels[6].workCnt[0] = 79;
  channels[7].workCnt[0] = 253;
  channels[2].chIsWork = true;
  channels[7].chIsWork = true;

  pinMode(TESTPOWERPIN, OUTPUT);
}

void loop() {
  readEnc();
  readSens();
}

SBUTTON_CLICK CorrectButtonClick() {
  static bool fclick = false;         //Сделали клик кнопкой, а обрабатывается при отпускании кнопки
  switch (swEnc.Loop()) {
    case SB_DOWNED:
      break;
    case SB_CLICK:
      fclick = true;
      return SB_NONE;
      break;
    case SB_LONG_CLICK:
      fclick = false;
      return SB_LONG_CLICK;
    case SB_RELEASE:
      if (!fclick) break;
      fclick = false;
      return SB_CLICK;
      break;
    case SB_NONE:
      break;
  }
  return SB_NONE;
}

void readEnc() {
  bool isR = encTick == 1;    //Энкодер повернули вправо
  bool isL = encTick == -1;   //Энкодер повернули влево
  encTick = 0;
  if (!isScreens) CalckMenu(isR, isL, CorrectButtonClick());
  else CalckScreens(isR, isL, CorrectButtonClick());
}

Наверное я много хочу от наны ( Или просто реально все не правильно делаю (

За код... конечно немного стыдно, но я не говорю, что я крутой программер на си.... Но на данный момент код еще ужасен тем, что я пытаюсь его оптимизировать, и некоторые моменты могут быть просто ужасными. Ну и комментарии - это отдельная песня)

И вообще уже есть желание забросить его) Ну т.е. откатится немного назад, перед началом оптимизации и попробовать распихать по двум ардуинам.

wdrakula
wdrakula аватар
Offline
Зарегистрирован: 15.03.2016

Ох. Партизан Боснюк! ;). Ни слова не сказал супостатам!
Дорогой! Нужно разоблачаться перед Партией! А то недолго и билет на стол положить!

MaksVV
Offline
Зарегистрирован: 06.08.2015

ТС , возьми мегу, не сношай мозг. Опыт придет позже , будешь на нане собирать . В таком длинном коде кроме проблем с не влезанием еще стопицот ошибок будет , которые придется искать . а так хоть одной проблемой меньше . Вот когда на меге заработает будешь оптимизировать. Ты пишешь меги нет, а что это такая проблема ее купить ?

AsNik
Offline
Зарегистрирован: 24.10.2020

Я могу даже старенький ПК для этого выделить), все равно валяется... и написать программу на делфи.... Хотя и делфи-то уже забыл, лет пятнадцать не писал... А вот на мегу пока средств лишних нет. Да и задача не в том, что бы просто сделать данный девайс, а с... со спортивным интересом. Я думаю, что мою задачу можно и в нану уложить. И у меня два варианта решения. (Оба полезные) Оптимизация кода и разделение одного устройства на два. С первым, я так понял у меня есть проблема ( .... Ну а второй почему бы и нет?

По кусочку исходника если кто что скажет полезного и поучительного, рад почитать. Спасибо всем.

wdrakula
wdrakula аватар
Offline
Зарегистрирован: 15.03.2016

Да поставь же ты задачу, наконец!!! Сенсоры, каналы, экраны, my ass!!!

Дискутировать без кода или хотя бы задачи - бред. По стилю кусочка видна стратегическая ошибка, но она может иметь или не имеет последствий. Напиши простым языком, что именно ты строишь.
Ну и вишенкой - почти 100%, что в Нанку это влезает. ;)
И в довесок просто про всякую домашнюю автоматику: Нано для макета части идеи, в боевое применение потом все собрать в Мегу. Это уже просто совет.

AsNik
Offline
Зарегистрирован: 24.10.2020

MaksVV пишет:
Вот когда на меге заработает будешь оптимизировать.

Тут вступит в силу парадокс HDD... сколько бы не было все равно мало

AsNik
Offline
Зарегистрирован: 24.10.2020

wdrakula пишет:
Да поставь же ты задачу, наконец!!!

Я не представляю возможным как мне поставить задачу :( Вопрос в теме про варианты решения был как бы общим. Т.е. варианты такие: убрать веские типы (float, string...) Serial.. Баласт между ПРОГМЕМ, F() и ОЗУ.... Разделение устройства на части.... Условная компиляция - но в данном, моем, случае я ее не рассматриваю...

Потому, как делаю под одну плату, но.... Есть вариант прикрутить все же эту условную, и я попробовал. Например выкинуть из кода либы и работу с сенсорами, которые физически не подключены, но возможность в коде предусмотрена. Например все датчики будут BME, тогда код других датчиков не компилировать, но тут нужно будет перепрошивать, если вдруг что поменяется... И не так уж и много освобождается места от выключения датчиков... я уже проверил это.

wdrakula пишет:
Дискутировать без кода или хотя бы задачи - бред. По стилю кусочка видна стратегическая ошибка, но она может иметь или не имеет последствий.

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

wdrakula пишет:
Напиши простым языком, что именно ты строишь.

Да ничего особенного. Контроль за температурой и влажностью. Сенсоры мерят, а каналы включают нагрузку, типа обогрев и вентиляция.... все как у всех и ничего необычного.... Но тут дело не в этом. Я даже не дошел до основных алгоритмов работы устройства, а память уже подходит к концу... Сейчас в устройстве только реализована отрисовка почти(но еще не всё:)) всего что нужно на LCD и чтение сенсоров...

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

Жаль что памяти не хватает не только в камнях, но и в моей балванке, которая на плечах.... Многие вещи, которые в прошлом году делал, уже за лето забыл как)

wdrakula пишет:
Ну и вишенкой - почти 100%, что в Нанку это влезает. ;)

Добавил немного оптимизма;)

wdrakula пишет:
И в довесок просто про всякую домашнюю автоматику: Нано для макета части идеи, в боевое применение потом все собрать в Мегу. Это уже просто совет.

 Спасибо. Верно. Вот тут я думаю как раз нужен опыт объединения МК (типа сети, может CAN) для решения ими одной (или несколько) целей...

andriano
andriano аватар
Offline
Зарегистрирован: 20.06.2015

AsNik пишет:

А вот на мегу пока средств лишних нет.

Нет, ну если нет средств даже на расходники, тогда следует выбрать хобби подешевле. 

Цитата:

Да и задача не в том, что бы просто сделать данный девайс, а с... со спортивным интересом.

Спортивный интерес  и обращение на форум за советом, вроде как, вещи взаимоисключающие. Нет?

 

PS. Если есть старенький комп, который можно приспособить к задаче, может имеет смысл делить задачу не на две Ардуины, а на комп и Ардуину: ресурсоемкую часть оставить компу, а работу с периферией возложить на Ардуину?

andriano
andriano аватар
Offline
Зарегистрирован: 20.06.2015

AsNik пишет:

MaksVV пишет:
Вот когда на меге заработает будешь оптимизировать.

Тут вступит в силу парадокс HDD... сколько бы не было все равно мало

Это исключительно от неумения планировать.

Т.е. проблема имеет не аппаратный, а психологический характер.

AsNik
Offline
Зарегистрирован: 24.10.2020

andriano пишет:

Т.е. проблема имеет не аппаратный, а психологический характер.

Даже не отрицаю, но это факт)

andriano
andriano аватар
Offline
Зарегистрирован: 20.06.2015

AsNik пишет:

Я не представляю возможным как мне поставить задачу...

Сэр искренне полагает, что можно решить задачу, не имея никаких представлений о том, в чем эта задача заключается?

 

Ds. Задача никогда не будет решена. Даже на кластере из 1000 суперкомпьютеров.

AsNik
Offline
Зарегистрирован: 24.10.2020

andriano пишет:

Нет, ну если нет средств даже на расходники, тогда следует выбрать хобби подешевле. 

Их и не будет. Если раскидываться ими на право и на лево... У меня есть другие МК. Я знаю, что если куплю Мегу, то либо сделаю на ней, а другие будут валятся, либо и ее положу в угол, а сделаю по другому...

Поэтому покупка меги пока не рассматривается именно для этого устройства, но в целом.... может.

AsNik
Offline
Зарегистрирован: 24.10.2020

andriano пишет:

Сэр искренне полагает, что можно решить задачу, не имея никаких представлений о том, в чем эта задача заключается?

Вот не люблю эту печатную беседу....( Задачу не представляю возможности в кратце рассказать здесь, а у себя в голове эта задача четкая, но не маленькая ;)