( Задачу не представляю возможности в кратце рассказать здесь, а у себя в голове эта задача четкая, но не маленькая ;)
Так не бывает.
Изложение задачи на бумаге - это не пустая формальность, а единственный способ уложиться в конечные сроки, аппаратные и финансовые ресурсы, т.к. именно четкая формулировка задачи позволяет оперативно отсекать все лишнее.
Upd. Вот, кстати, и вырисовался конкретный совет: начните с четкого и подробного изложения задачи на бумаге (в текстовом файле). Это - первый шаг к тому, чтобы все, что надо, влезло. Т.е. надо начинать не с исходника, а немного раньше.
В общем вопрос такой: Решил программу разбить на два МК(нано). В одном только работа с экраном, а во втором основной алгоритм работы устройства. Соединить их думаю уже по Serial. Собс-но вопрос - имеет смысл моя идея. Никогда раньше не объединял ардуины для совместной работы. С чем мне придется столкнуться?
Но сейчас мне интересен ответ про стратегическую ошибку в коде.
Я очень хочу показать код, но не для стеба, а для того, что бы понять что я делаю не так... Но пока я вижу, что кому-то просто хочется поугарать)
Согласен. Но это больше подходит для профессионального решения, а не...
Отличие тут есть. Когда ты проф, то ты точно знаешь, что тебе надо и что у тебя будет. А тут ставишь себе задачу, пока ее решаешь, оказывается что так вообще нельзя и начинаешь все с нуля... новая задача и... примерно так. Но это не мое основное занятие. Я понимаю, что форум больше на профессионалов расчитан, а любителей тут не любят).
Нет смысла отвечать абстрактно на вопросы экономии памяти. В этом русле у нас беседы не будет. Просто по причине очень разных "весовых категорий". Тебе кажется, что есть универсальные приемы, нужные тебе, а их нет. Нужно просто сразу писать правильный код.
Поэтому показывай, чем забил память. Иначе решай свои задачи сам. Прости за жесткость, но беседа ни-о-чем уже немного надоела.
Ты жеманничаешь, как пожилая куртизанка. Доставай уже свой ...код! ;)))))
И вот этот код забил всю память? Приведи под катом компилируемый вариант, чтобы я собрать мог. Просто слей всё в один файл и под кат его. Именно чтобы мне в два движения собрать.
Оценка беглая - нормально. У нас тут есть люди из Делфи вышедшие - по неймингу переменных видны за километр! ;)) Это как раз очень достойная привычка, тут только похвалить можно!
Ошибка та, что по кусочку было видно. Попытка писать для МК, как для ПК. То есть заложенная в код универсальность аж до выбора типа датчиков. В таком виде в МК - по крайней мере в Нану - почти нереально.
Если ты разрабатываешь полукоммерческий проект, в котором планируется настройка параметров пользователями без квалификации, то придется пойти одним из двух путей:
1. Выбрать другой МК, в котором будет достаточно дури для ран-тайм переключения датчиков и изменения настроек.
2. Удобный генератор прошивки, по параметрам и выведенный разъем ISCP для перешивки. В прочем можно и через USB, хоть это и варварство.
--------------------
Про системы МК в проекте.
Что CAN, что RS-485 прекрасно подойдут для организации связи на короткие расстояния в условиях промышленных помех. Их для этого и создавали. На судах, вот прям Больших Железных Пароходах, RS-485 называется NMEA-0183, а CAN - NMEA-2000. И этими шинами соединяются все датчики, экраны, эхолоты, радары и черт-знает что на десятки метров по судну.
Реализация на RS-485 будет чутка подешевле, но очень желательно не использовать Нано, из-зи USB трансивера на контактах UART. ТО есть взять Мини, если вот прям охуительно нужен atmega328. Для 485 потребуется трансивер MAX485 - 50 руб на Али. Модуль занимает UART, что понятно.
Реализация CAN - чуть сложнее и чуть дороже. Модуль MCP2515 содержит и контроллер и трансивер CAN в одном флаконе. И встроенный терминатор, то есть вообще полный сервис ;). Стоит примерно 200р на Али. Занимает SPI.
На 485 реализация шины - программная, как понятно из протокола. Менее устойчива к сбоям. CAN - само-собой уже "мерседес", по сравнения с "запорожцем"-485. Но в твоей задаче разделение на функциональные блоки просматривается очень натянутым.
В теории, если рассматривать более гибкую и очччч-чень масштабируемую систему, то можно делать такие модули (на КАН или на 485)
1. модуль сенсоров, либо автоопределяет либо получает от Центра Управления (ЦУ) типы сенсоров, период опроса, номера контактов. Передает данные сенсоров.
2.Модуль каналов управления - настраиваются каналы, возможно с контролем цепи и датчиками тока потребления.
3. Модуль GUI - тут ясно, экран и кнопки/джойстик/энкодер. Настраиваются типы сообщений.
4. Ну и модуль ЦУ ;))) - Кольцо Всевластия! ;))
------------------------
Ты заикнулся про I2C - это внутрисхемеая шина, не предназначена для соединения модулей вне одной платы, или хотя бы одного корпуса ;).
DHT11, DHT22, AM2320 в сущности один и тот же датчик с одним и тем же протоколом. Достаточно выбрать один получше и не тащить в код саппорт всего.
Много строк в интерфейсе, даже повторяющиеся есть. Достаточно в PROGMEM залепить их и пользоваться указателем. Плюс - сократить число вариаций написания.
Вообще нисколько.... так, для себя и в качестве тренировки мозга. Раньше по молодости увлекался программированием на делфи.... но тоже было просто хобби. Моя деятельность(работа) с этим никогда не была связана.
DHT11, DHT22, AM2320 в сущности один и тот же датчик с одним и тем же протоколом. Достаточно выбрать один получше и не тащить в код саппорт всего.
Ну плюс/минус (больше плюс) - согласен. Тем более текущая либа сама определяет тип датчика.
sadman41 пишет:
Много строк в интерфейсе, даже повторяющиеся есть. Достаточно в PROGMEM залепить их и пользоваться указателем. Плюс - сократить число вариаций написания.
У меня пока этот шаг в запасе. Просто, ну сколько я высвобожу, около килобайта....
Экспериментировал с F() и "одинаковыми" константами, результат не очень... туда сюда прыгает размер.
А мне хочется и ОЗУ освободить и флеш не занимать) ...шутка
На snprintf_p легко заменяются все подобные гроздья: PrintTextLCD(0, 0, "Sens"); PrintColon(); Print_Space(); PrintTextLCD(SensTitle[sens_ulica]); Шаблон для snprintf_p так же закладывается в progmem достаточно просто. Тем более, что всякие printf-ы в коде есть и они уже отожрали свой кусок.
Если не сложно, можно какойнить пример по этому делу? Если я суть пойму, я разберусь...
Тогда и правда перестань валять дурака! Закажи Мегу, в форм факторе mini pro вот такую:
На ней достаточно всего и форма удобная. У меня такая сейчас отопителем на Кемпере управляет:
датчики темпераруры и NTC и Далласы, датчик оборотов двигателя продувки камеры сгорания, датчик 220, датчик тока основного вентилятора, термопредохранители, ионный датчик пламени. Каналы управления: и ТЭНы на 220 и искра поджига и клапаны газа, ШИМ на вентилятор и ШИМ на продувку. ГУИ на Некстионе. И все это включено 10 сентября и более не выключается до сих пор. ;))) То есть и в дороге и на рыбалке и сейчас стоит на зиму укрыт, но не слита вода пока, отопление в нем работает. Это очень хороший контроллер - Честное слово! ;)
==================================
А на Нанках детям гирлянду на НГ сделаешь на лампочках WS2811. Ну или какой диммер для дома для семьи! Не пропадут.
Обязательно.... и без шуток. Давно уже на нее гляжу.... И как назло сейчас цены на всю эту электронику немного скаканули :( ...Но пока всеж потренирую мозг на нане... (или нанах)
Поясню: я сижу на кухне, за компом, за спиной стоит ректификационная колонна, за которой я предпочитаю следить. На колонне автоматика, но мерные щелчки клапана отбора действуют на меня умиротворяюще! ;)))
Следовательно я привязан к кухне на несколько часов. Если тебе надо, чтобы я посмотрел на код - сделай мне удобно, если тебе не надо, то у меня есть анекдоты и порнуха в сети ...и котеги, конечно!;)))
Библиотеки не нужно, если у тебя нет привязки к особенной версии. (Её не должно быть в нормальном коде)
-----------------
Ну и конечно нужно предупредить, что через несколько часов результат работы колонны будет подвергнут вдумчивому тестированию, несовместимому с оценкой программного кода. ;)
Правильно ли я сделал? Указатели, ...я в них путаюсь(
И вопрос еще. Тут получается мне нужно помнить какой индекс у строки. Мне сразу увиделся вариант добавить enum типа (strTemp, strHumi ...) и вызывать PrintTextIndex(strTemp). Но это опять расход памяти... Или не парится и вызывать по индексу?
А напрямую нельзя обратится к string_0 (переименовав ее например strTemp т.е.:
Посмотрел. Просто ужасно много кода, написанного по ПК-шному. Все универсальности нужно выкидывать. Поток примитивов вида "печать стрелки" и подобное - убирать в константы.
Это вечная болезнь разработчика из мира ПК - делаем не решение, а сразу универсальный инструмент для будущих решений. Не нужно писать библиотеку для всех меню в мире, а сделать одно меню! (как в анекдоте про математика и физика: "Видел одну козу, черную сверху"). Так вот нужно "одну козу" и черную только сверху, аналогия понятна? Вся эта куча "универсальностей" и забила память.
Программистски - очень хорошо. Все в декомпозиции, все случаи разобраны, состояния прописаны. Одно плохо - на весь этот тюнинг зоопарка не хватает.
И я бы еще советовал иную парадигму кода. Сам поток управления у тебя тоже ПК-шный немного.
Вот такая структура общей автоматики на МК, если использована парадигма "бесконечный цикл" - единственная принятая в Ардуино:
1. Чтение сенсоров, формирование сообщений от сенсоров.
2. ГУИ. Независимый модуль, общается сообщениями. ГУИ получает сообщения от основного потока и изменяет экран, читает ХИДы и изменяет экран и формирует сообщения для основного потока.
3. Чтение очереди входящих сообщений, установка флагов действий.
4. Исполнение действий по флагам, Действия могут быть многошаговые, например разгон/торможение привода и т.п. Тогда формируются промежуточные флаги и параметры развития действия.
---------------------------
Не нужно "отрисовывать" значения температур и влажностей. На этапе разбора сообщений, если что нужно - формируй сообщение для ГУИ. Ты получил данные с сенсора, проверил изменение температуры (к примеру) если есть - сформировал мессадж для ГУИ "Новая строка в поле ххх". Таким образом ГУИ проще и код не дублируется - например вызовы СетКурсор. У тебя есть номера полей ГУИ, все остальное - внутри объекта. Не строй экран в коде! Все экраны напиши константами с темплейтами - код уменьшится в разы. Подстановки вместо темплейтов их значений делаются стандартными строковыми функциями.
Кнопки, энкодеры и другие ХИДы - не должны быть вообще видны вне ГУИ. Зачем они там? На событие от ХИДа меняется экран и формируется мессадж в ЦУ.
Вот так причешешь постепенно, глядишь и память освободится.
========================
Конкретно как я пишу нужно сказать. Я выше общий вариант привел, каждый программист думает по-своему.
У меня так:
1. чтение из гуи;
2. чтение сенсоров;
3. действия;
4. Передача в ГУИ.
Этап переработки сообщений во флаги я делаю одновременно с чтением сообщений и сенсоров.
К моему стыду, я не все понял из сказанного #75 :( Не программист я, просто маленький любитель.... многие термины мне непонятны.
Но суть понял. Универсальность - да. Была такая задумка. И это я еще от много чего отказался. Но все равно не уместил...)
Попробую лишнего по убирать, сделать константы в PROGMEM (здесь ниже очередной пример, разбираюсь с ПРОГМЕМ)
Цитата:
ГУИ. Независимый модуль, общается сообщениями.
Как такое делается? Конкретно по значениям с датчиков - у меня вроде как, так и делается. Обновляются данные на экране только когда изменились(считались) данные... Но повторяюсь, я в связи с низкими знаниями программирования МК, может чего понимаю не так...
у меня экраны обновляются только если произошло событие от энкодера или считались очередные данные с сенсоров...
3 и 4 пункт на очереди. Ну если в третьем не обращать внимание на сообщения. Что в понятиях МК - сообщения? Или это мне нужно придумать архитектуру сообщений типа как в винде. Утрированно. Тогда мне нужно перечеркивать этот проект и начинать заново.
Не нужно "отрисовывать" значения температур и влажностей. На этапе разбора сообщений, если что нужно - формируй сообщение для ГУИ. Ты получил данные с сенсора, проверил изменение температуры (к примеру) если есть - сформировал мессадж для ГУИ "Новая строка в поле ххх". Таким образом ГУИ проще и код не дублируется - например вызовы СетКурсор. У тебя есть номера полей ГУИ,
Скорее всего это структура(архитектура, логика) программы должна быть для этого. Тем не менее разные экраны все равно придется рисовать, что бы потом в поля вставлять данные. Хотя у меня именно так и происходит
UpdateScreen(bool) вот от bool и зависит - полностью экран перерисовываем или только данные
И можно ли считать UpdateScreen(bool) - тем самым сообщением для ГУИ?
Таким образом ГУИ проще и код не дублируется - например вызовы СетКурсор. У тебя есть номера полей ГУИ, все остальное - внутри объекта. Не строй экран в коде! Все экраны напиши константами с темплейтами - код уменьшится в разы.
Как бы на разных экранах одни и теже данные в разных местах... Ну да - это получается избыточно. Если бы посмотрели это в устройстве, то поняли бы о чем я...
Цитата:
Подстановки вместо темплейтов их значений делаются стандартными строковыми функциями.
типа ("Temp: %d ", t) ? ....Хм, а константу хранить PROGMEM Line1 = "Temp: %d " . Надо попробовать. Точно!!!
Цитата:
Кнопки, энкодеры и другие ХИДы - не должны быть вообще видны вне ГУИ. Зачем они там? На событие от ХИДа меняется экран и формируется мессадж в ЦУ.
Вроде стараюсь к этому, но не всегда пока получается. Спасибо за помощь!!
Но есть один нюанс. У меня в случае ошибки на месте где были цифры, выводятся строки... Это получается нужно делать два шаблона для одной строки или все данный конвертировать в строку используя в шаблоне %s
Вот когда на меге заработает будешь оптимизировать.
Тут вступит в силу парадокс HDD... сколько бы не было все равно мало
А что это за парадокс такой?
У меня 1Тб диск (под систему 128Гб SSD) и ещё один на 1Тб под бэкап системы и данных. Так вот, для понимания, тот что под бэкап - заполнен на 60%. И это с учетом того, что на первом диске фильмов много. Старых, но хороших. Жаль удалять. Ещё со времён торрентов (когда скорости были по 128кб/с).
ЗЫ: диски эти у меня уже лет 6-8 трудятся, сигейты. Данные со старого перенёс и все. Ну и свежие прибавляются по немного. Литература в основном.
Во времена, когда зародился этот парадокс, таких аббревиатур как SSD не было и про такие объемы как 1 Тб просто даже и не думали, не то что не мечтали). При имеющемся в системнике 4Гб HDD думали, что если заменить на 32 Гб, то все туда поместится, но поимевши 32 Гб, все повторялось...
Второй день экспериментирую, но не с кодом ...пока, а с файлами. Решил сначала код разбить еще на файлы (в том числе *.h)
После моих действий компилятор(может линкер) начали ругаться... Методом отката до рабочего состояния я пришел к тому, что ошибка появляется сразу после одного единственного изменения в (рабочем/компилируемом) коде и структуре файлов, а именно - два файла sav_button.cpp и sav_button.h перенес в подкатолог myLib и строчку подключения в коде изменил с #include "sav_button.h" на #include "myLib/sav_button.h"
В итоге:
exit status 1
Ошибка компиляции для платы Arduino Nano.
IDE 1.8.10
Нельзя "личные/локальные" библиотеки проекта в отдельную папку?
При компиляции последние две строки в логе IDE (внизу):
exit status 1
Ошибка компиляции для платы Arduino Nano.
Еще обратил внимание, что если в пути использовать \ - то строка не подсвечивается (синтаксис) , но если слеши поменять на /, то срабатывает подсветка, но результат тот же.
Уже проект перенес поближе к началу...
#include "E:/TMP_Climat/myLib/sav_button.h" (строка с обратными слешами, подсвечивается зеленым
А так #include "E:\TMP_Climat\myLib\sav_button.h" - в IDE она черным цветом.
но если намеренно указать неверный путь, например: #include "E:/TMP_Climat/NOmyLib/sav_button.h"
то:
exit status 1
E:/TMP_Climat/NOmyLib/sav_button.h: No such file or directory
Оказывается (получилось что-то найти в инете, пару веток даже на этом форуме) есть такая непонятная проблема с IDE, подкаталогами и #include... Ок. Верну пока в корень проекта. Но если будут у кого какие решения/мысли - делитесь)
Если файлов меньше сотни, к примеру, то даже визуально никаких проблем нет если они в корне располагаются. А если ещё и называть файлы понятно - то и вопросов не возникнет. Зачем в подкаталоги перемещать?
Понятно, что удобнее, но с ардуино это «такое себе удобство».
У меня всё работает, подгружает нужные файлы из подкаталога скетча:
Ну ненаююю... Может версию нужно обновить до 14, у меня 1.8.10
Хотя я пробовал и 2.0.0 (то еще г...) тоже самое (или не тоже, ну скомпилить не получилось)
А вот если каталог src назвать, то ОК.
BOOM пишет:
Зачем в подкаталоги перемещать?
Понятно, что удобнее, но с ардуино это «такое себе удобство».
Я уже понял, что IDE вообще не рассчитана на "серьезные вещи" с разбиением проекта на файлы, причем ошибки начинает выдавать странные и непонятно по какому принципу. Перенес один кусок кода из одного ino в другой а ошибку выдал:
Возвращаю на место, все компилится... В общем странное поведение...(
Я читал сейчас и про include, заодно узнал про import - почему им не пользуются? Я так понял, это сделали чтоб в библиотеках не делали #pragma once и более длинную версию защиты от повторного использования библиотеки....
Вопрос, можно повредить загрузчик какими либо(неправильными) действиями из прошивки? Ардуина вроде как в полуживом состоянии.. При загрузке начинает загружаться и в середине стопарится и начинает ребутится... Мог я своими экспериментами с PROGMEM и работай (неправильной) с указателями убить ардуину/загрузчик? Ну т.е. теоретически это возможно? Ничего хитрого я не делал... пытался в функцию чтения из прогмем передать массив... Вот в эту:
Хотелось бы вместе с _i передавать туда и ссылку на string_table... но что-то у меня пошло не так и ардуина сдохла...
Еще пару штук есть, но ...теперь боюсь) Ну и если убил загрузчик, то ....читаю как прошить optiboot. Одну ардуину буду в качестве программатора делать.. и ей пробовать восстановить дохлую. Если конечно это я убил загрузчик...
ЕМНИП, ПЗУ имеет ограниченное число перезаписей, меньшее чем флеш-память. ПЗУ что-то около тысячи перезаписей, а флеш около 10 тысяч. Если у вас старая Ардуина, могли израсходовать ресурс перезаписей. Поэтому многие используют эмуляторы. Либо не используют ПЗУ )
У меня ардуина первая с 16-го года. Чувствует себя хорошо, несмотря на все издевательства. Остальные горели только от повышенного напряжения. Штуки три лежат в качестве массогабаритных моделей.
( Задачу не представляю возможности в кратце рассказать здесь, а у себя в голове эта задача четкая, но не маленькая ;)
Изложение задачи на бумаге - это не пустая формальность, а единственный способ уложиться в конечные сроки, аппаратные и финансовые ресурсы, т.к. именно четкая формулировка задачи позволяет оперативно отсекать все лишнее.
Upd. Вот, кстати, и вырисовался конкретный совет: начните с четкого и подробного изложения задачи на бумаге (в текстовом файле). Это - первый шаг к тому, чтобы все, что надо, влезло. Т.е. надо начинать не с исходника, а немного раньше.
Изначально вопрос темы был такой:
В общем вопрос такой: Решил программу разбить на два МК(нано). В одном только работа с экраном, а во втором основной алгоритм работы устройства. Соединить их думаю уже по Serial. Собс-но вопрос - имеет смысл моя идея. Никогда раньше не объединял ардуины для совместной работы. С чем мне придется столкнуться?
Но сейчас мне интересен ответ про стратегическую ошибку в коде.
Я очень хочу показать код, но не для стеба, а для того, что бы понять что я делаю не так... Но пока я вижу, что кому-то просто хочется поугарать)
#51
Согласен. Но это больше подходит для профессионального решения, а не...
Отличие тут есть. Когда ты проф, то ты точно знаешь, что тебе надо и что у тебя будет. А тут ставишь себе задачу, пока ее решаешь, оказывается что так вообще нельзя и начинаешь все с нуля... новая задача и... примерно так. Но это не мое основное занятие. Я понимаю, что форум больше на профессионалов расчитан, а любителей тут не любят).
Нет смысла отвечать абстрактно на вопросы экономии памяти. В этом русле у нас беседы не будет. Просто по причине очень разных "весовых категорий". Тебе кажется, что есть универсальные приемы, нужные тебе, а их нет. Нужно просто сразу писать правильный код.
Поэтому показывай, чем забил память. Иначе решай свои задачи сам. Прости за жесткость, но беседа ни-о-чем уже немного надоела.
Ты жеманничаешь, как пожилая куртизанка. Доставай уже свой ...код! ;)))))
И вот этот код забил всю память? Приведи под катом компилируемый вариант, чтобы я собрать мог. Просто слей всё в один файл и под кат его. Именно чтобы мне в два движения собрать.
Оценка беглая - нормально. У нас тут есть люди из Делфи вышедшие - по неймингу переменных видны за километр! ;)) Это как раз очень достойная привычка, тут только похвалить можно!
Ошибка та, что по кусочку было видно. Попытка писать для МК, как для ПК. То есть заложенная в код универсальность аж до выбора типа датчиков. В таком виде в МК - по крайней мере в Нану - почти нереально.
Если ты разрабатываешь полукоммерческий проект, в котором планируется настройка параметров пользователями без квалификации, то придется пойти одним из двух путей:
1. Выбрать другой МК, в котором будет достаточно дури для ран-тайм переключения датчиков и изменения настроек.
2. Удобный генератор прошивки, по параметрам и выведенный разъем ISCP для перешивки. В прочем можно и через USB, хоть это и варварство.
--------------------
Про системы МК в проекте.
Что CAN, что RS-485 прекрасно подойдут для организации связи на короткие расстояния в условиях промышленных помех. Их для этого и создавали. На судах, вот прям Больших Железных Пароходах, RS-485 называется NMEA-0183, а CAN - NMEA-2000. И этими шинами соединяются все датчики, экраны, эхолоты, радары и черт-знает что на десятки метров по судну.
Реализация на RS-485 будет чутка подешевле, но очень желательно не использовать Нано, из-зи USB трансивера на контактах UART. ТО есть взять Мини, если вот прям охуительно нужен atmega328. Для 485 потребуется трансивер MAX485 - 50 руб на Али. Модуль занимает UART, что понятно.
Реализация CAN - чуть сложнее и чуть дороже. Модуль MCP2515 содержит и контроллер и трансивер CAN в одном флаконе. И встроенный терминатор, то есть вообще полный сервис ;). Стоит примерно 200р на Али. Занимает SPI.
На 485 реализация шины - программная, как понятно из протокола. Менее устойчива к сбоям. CAN - само-собой уже "мерседес", по сравнения с "запорожцем"-485. Но в твоей задаче разделение на функциональные блоки просматривается очень натянутым.
В теории, если рассматривать более гибкую и очччч-чень масштабируемую систему, то можно делать такие модули (на КАН или на 485)
1. модуль сенсоров, либо автоопределяет либо получает от Центра Управления (ЦУ) типы сенсоров, период опроса, номера контактов. Передает данные сенсоров.
2.Модуль каналов управления - настраиваются каналы, возможно с контролем цепи и датчиками тока потребления.
3. Модуль GUI - тут ясно, экран и кнопки/джойстик/энкодер. Настраиваются типы сообщений.
4. Ну и модуль ЦУ ;))) - Кольцо Всевластия! ;))
------------------------
Ты заикнулся про I2C - это внутрисхемеая шина, не предназначена для соединения модулей вне одной платы, или хотя бы одного корпуса ;).
DHT11, DHT22, AM2320 в сущности один и тот же датчик с одним и тем же протоколом. Достаточно выбрать один получше и не тащить в код саппорт всего.
Много строк в интерфейсе, даже повторяющиеся есть. Достаточно в PROGMEM залепить их и пользоваться указателем. Плюс - сократить число вариаций написания.
Приведи под катом компилируемый вариант, чтобы я собрать мог. Просто слей всё в один файл и под кат его. Именно чтобы мне в два движения собрать.
Так это же нужно и библиотеки.... Просто слить свой и сюда выложить смогу, но без либ.... надо?
Если ты разрабатываешь полукоммерческий проект
Вообще нисколько.... так, для себя и в качестве тренировки мозга. Раньше по молодости увлекался программированием на делфи.... но тоже было просто хобби. Моя деятельность(работа) с этим никогда не была связана.
У нас тут есть люди из Делфи вышедшие - по неймингу переменных видны за километр! ;))
Мною уважаемый дед ...например)
На snprintf_p легко заменяются все подобные гроздья: PrintTextLCD(0, 0, "Sens"); PrintColon(); Print_Space(); PrintTextLCD(SensTitle[sens_ulica]);
Шаблон для snprintf_p так же закладывается в progmem достаточно просто. Тем более, что всякие printf-ы в коде есть и они уже отожрали свой кусок.
Ну плюс/минус (больше плюс) - согласен. Тем более текущая либа сама определяет тип датчика.
У меня пока этот шаг в запасе. Просто, ну сколько я высвобожу, около килобайта....
Экспериментировал с F() и "одинаковыми" константами, результат не очень... туда сюда прыгает размер.
А мне хочется и ОЗУ освободить и флеш не занимать) ...шутка
Если не сложно, можно какойнить пример по этому делу? Если я суть пойму, я разберусь...
F() интересен только если строки разные. На одинаковых он экономии не даст, даже будет плюсовать. А вот char progmem поможет.
Если ты разрабатываешь полукоммерческий проект
Вообще нисколько.... так, для себя
Тогда и правда перестань валять дурака! Закажи Мегу, в форм факторе mini pro вот такую:
На ней достаточно всего и форма удобная. У меня такая сейчас отопителем на Кемпере управляет:
датчики темпераруры и NTC и Далласы, датчик оборотов двигателя продувки камеры сгорания, датчик 220, датчик тока основного вентилятора, термопредохранители, ионный датчик пламени. Каналы управления: и ТЭНы на 220 и искра поджига и клапаны газа, ШИМ на вентилятор и ШИМ на продувку. ГУИ на Некстионе. И все это включено 10 сентября и более не выключается до сих пор. ;))) То есть и в дороге и на рыбалке и сейчас стоит на зиму укрыт, но не слита вода пока, отопление в нем работает. Это очень хороший контроллер - Честное слово! ;)
==================================
А на Нанках детям гирлянду на НГ сделаешь на лампочках WS2811. Ну или какой диммер для дома для семьи! Не пропадут.
Если не сложно, можно какойнить пример по этому делу? Если я суть пойму, я разберусь...
Тут должно быть:
http://arduino.ru/forum/programmirovanie/progmem-tricks
Нашел пример использования:
Нормальный пример? (немного исправил)
Закажи Мегу, в форм факторе mini pro вот такую:
Обязательно.... и без шуток. Давно уже на нее гляжу.... И как назло сейчас цены на всю эту электронику немного скаканули :( ...Но пока всеж потренирую мозг на нане... (или нанах)
Если не сложно, можно какойнить пример по этому делу? Если я суть пойму, я разберусь...
Спасибо.
Мне?? ;))
Поясню: я сижу на кухне, за компом, за спиной стоит ректификационная колонна, за которой я предпочитаю следить. На колонне автоматика, но мерные щелчки клапана отбора действуют на меня умиротворяюще! ;)))
Следовательно я привязан к кухне на несколько часов. Если тебе надо, чтобы я посмотрел на код - сделай мне удобно, если тебе не надо, то у меня есть анекдоты и порнуха в сети ...и котеги, конечно!;)))
Библиотеки не нужно, если у тебя нет привязки к особенной версии. (Её не должно быть в нормальном коде)
-----------------
Ну и конечно нужно предупредить, что через несколько часов результат работы колонны будет подвергнут вдумчивому тестированию, несовместимому с оценкой программного кода. ;)
Нашел пример использования:
Сделал так:
Правильно ли я сделал? Указатели, ...я в них путаюсь(
И вопрос еще. Тут получается мне нужно помнить какой индекс у строки. Мне сразу увиделся вариант добавить enum типа (strTemp, strHumi ...) и вызывать PrintTextIndex(strTemp). Но это опять расход памяти... Или не парится и вызывать по индексу?
А напрямую нельзя обратится к string_0 (переименовав ее например strTemp т.е.:
const char strTemp[] PROGMEM = "Temp";)?
Мне?? ;))
Ок. Сейчас слеплю
Так, ну вот в таком виде у меня скомпилировалось:
...
Посмотрел. Просто ужасно много кода, написанного по ПК-шному. Все универсальности нужно выкидывать. Поток примитивов вида "печать стрелки" и подобное - убирать в константы.
Это вечная болезнь разработчика из мира ПК - делаем не решение, а сразу универсальный инструмент для будущих решений. Не нужно писать библиотеку для всех меню в мире, а сделать одно меню! (как в анекдоте про математика и физика: "Видел одну козу, черную сверху"). Так вот нужно "одну козу" и черную только сверху, аналогия понятна? Вся эта куча "универсальностей" и забила память.
Программистски - очень хорошо. Все в декомпозиции, все случаи разобраны, состояния прописаны. Одно плохо - на весь этот тюнинг зоопарка не хватает.
Универсальный инструмент == другой контроллер. Нано - решать КОНКРЕТНУЮ задачу. Одну. Черную - сверху. ;))
И я бы еще советовал иную парадигму кода. Сам поток управления у тебя тоже ПК-шный немного.
Вот такая структура общей автоматики на МК, если использована парадигма "бесконечный цикл" - единственная принятая в Ардуино:
1. Чтение сенсоров, формирование сообщений от сенсоров.
2. ГУИ. Независимый модуль, общается сообщениями. ГУИ получает сообщения от основного потока и изменяет экран, читает ХИДы и изменяет экран и формирует сообщения для основного потока.
3. Чтение очереди входящих сообщений, установка флагов действий.
4. Исполнение действий по флагам, Действия могут быть многошаговые, например разгон/торможение привода и т.п. Тогда формируются промежуточные флаги и параметры развития действия.
---------------------------
Не нужно "отрисовывать" значения температур и влажностей. На этапе разбора сообщений, если что нужно - формируй сообщение для ГУИ. Ты получил данные с сенсора, проверил изменение температуры (к примеру) если есть - сформировал мессадж для ГУИ "Новая строка в поле ххх". Таким образом ГУИ проще и код не дублируется - например вызовы СетКурсор. У тебя есть номера полей ГУИ, все остальное - внутри объекта. Не строй экран в коде! Все экраны напиши константами с темплейтами - код уменьшится в разы. Подстановки вместо темплейтов их значений делаются стандартными строковыми функциями.
Кнопки, энкодеры и другие ХИДы - не должны быть вообще видны вне ГУИ. Зачем они там? На событие от ХИДа меняется экран и формируется мессадж в ЦУ.
Вот так причешешь постепенно, глядишь и память освободится.
========================
Конкретно как я пишу нужно сказать. Я выше общий вариант привел, каждый программист думает по-своему.
У меня так:
1. чтение из гуи;
2. чтение сенсоров;
3. действия;
4. Передача в ГУИ.
Этап переработки сообщений во флаги я делаю одновременно с чтением сообщений и сенсоров.
К моему стыду, я не все понял из сказанного #75 :( Не программист я, просто маленький любитель.... многие термины мне непонятны.
Но суть понял. Универсальность - да. Была такая задумка. И это я еще от много чего отказался. Но все равно не уместил...)
Попробую лишнего по убирать, сделать константы в PROGMEM (здесь ниже очередной пример, разбираюсь с ПРОГМЕМ)
Как такое делается? Конкретно по значениям с датчиков - у меня вроде как, так и делается. Обновляются данные на экране только когда изменились(считались) данные... Но повторяюсь, я в связи с низкими знаниями программирования МК, может чего понимаю не так...
у меня экраны обновляются только если произошло событие от энкодера или считались очередные данные с сенсоров...
3 и 4 пункт на очереди. Ну если в третьем не обращать внимание на сообщения. Что в понятиях МК - сообщения? Или это мне нужно придумать архитектуру сообщений типа как в винде. Утрированно. Тогда мне нужно перечеркивать этот проект и начинать заново.
Такими темпами я его долго буду делать))
Вот экспериментирую с ПРОГМЕМ:
Где-то (в транзистортестере) подсмотрел как вытаскивать строки из флеша напрямую без массива (вопрос выше задавал)
Не нужно "отрисовывать" значения температур и влажностей. На этапе разбора сообщений, если что нужно - формируй сообщение для ГУИ. Ты получил данные с сенсора, проверил изменение температуры (к примеру) если есть - сформировал мессадж для ГУИ "Новая строка в поле ххх". Таким образом ГУИ проще и код не дублируется - например вызовы СетКурсор. У тебя есть номера полей ГУИ,
Скорее всего это структура(архитектура, логика) программы должна быть для этого. Тем не менее разные экраны все равно придется рисовать, что бы потом в поля вставлять данные. Хотя у меня именно так и происходит
UpdateScreen(bool) вот от bool и зависит - полностью экран перерисовываем или только данные
И можно ли считать UpdateScreen(bool) - тем самым сообщением для ГУИ?
Как бы на разных экранах одни и теже данные в разных местах... Ну да - это получается избыточно. Если бы посмотрели это в устройстве, то поняли бы о чем я...
типа ("Temp: %d ", t) ? ....Хм, а константу хранить PROGMEM Line1 = "Temp: %d " . Надо попробовать. Точно!!!
Вроде стараюсь к этому, но не всегда пока получается. Спасибо за помощь!!
типа ("Temp: %d ", t) ? ....Хм, а константу хранить PROGMEM Line1 = "Temp: %d " . Надо попробовать. Точно!!!
Обрадовался... Сделал даже вот такой тест:
Но есть один нюанс. У меня в случае ошибки на месте где были цифры, выводятся строки... Это получается нужно делать два шаблона для одной строки или все данный конвертировать в строку используя в шаблоне %s
для строк из прогмем - шаблон %S, большая буква
S
S - Similar to the %ss
format, except the pointer is expected to point to a program-memory (ROM) string instead of a RAM string.Тут вступит в силу парадокс HDD... сколько бы не было все равно мало
А что это за парадокс такой?
У меня 1Тб диск (под систему 128Гб SSD) и ещё один на 1Тб под бэкап системы и данных. Так вот, для понимания, тот что под бэкап - заполнен на 60%. И это с учетом того, что на первом диске фильмов много. Старых, но хороших. Жаль удалять. Ещё со времён торрентов (когда скорости были по 128кб/с).
ЗЫ: диски эти у меня уже лет 6-8 трудятся, сигейты. Данные со старого перенёс и все. Ну и свежие прибавляются по немного. Литература в основном.
А что это за парадокс такой?
У меня 1Тб диск (под систему 128Гб SSD)
Во времена, когда зародился этот парадокс, таких аббревиатур как SSD не было и про такие объемы как 1 Тб просто даже и не думали, не то что не мечтали). При имеющемся в системнике 4Гб HDD думали, что если заменить на 32 Гб, то все туда поместится, но поимевши 32 Гб, все повторялось...
Как вариант, в случае если нужно вывести данные не подходящие по шаблону, то просто вывести их по setCursor'у поверх шаблона...
Нормальный пример? (немного исправил)
Спасибо. Сейчас буду экспериментировать, пробовать, придумывать, может и перепишу все(почти все) заново...
Второй день экспериментирую, но не с кодом ...пока, а с файлами. Решил сначала код разбить еще на файлы (в том числе *.h)
После моих действий компилятор(может линкер) начали ругаться... Методом отката до рабочего состояния я пришел к тому, что ошибка появляется сразу после одного единственного изменения в (рабочем/компилируемом) коде и структуре файлов, а именно - два файла sav_button.cpp и sav_button.h перенес в подкатолог myLib и строчку подключения в коде изменил с #include "sav_button.h" на #include "myLib/sav_button.h"
В итоге:
IDE 1.8.10
С чем-то похожим сталкивался. Пришел к выводу, что работает только при указании полного пути.
С полным путем конечно не удобно, но сейчас попробую... в принципе если про это знать и помнить), то жить можно
Но в моем случае #include "E:\ELECTRONICS\MYPROJECT\MK\ARDUINO\SKETCHS\ASMClimat\ClimateControl2\TMP\myLib\sav_button.h" - не помогло :(
Что значит "не помогло"? Не включается указанный файл или не компилируются *.cpp файлы?
Что значит "не помогло"?
При компиляции последние две строки в логе IDE (внизу):
Еще обратил внимание, что если в пути использовать \ - то строка не подсвечивается (синтаксис) , но если слеши поменять на /, то срабатывает подсветка, но результат тот же.
Уже проект перенес поближе к началу...
#include "E:/TMP_Climat/myLib/sav_button.h" (строка с обратными слешами, подсвечивается зеленым
А так #include "E:\TMP_Climat\myLib\sav_button.h" - в IDE она черным цветом.
но если намеренно указать неверный путь, например: #include "E:/TMP_Climat/NOmyLib/sav_button.h"
то:
Оказывается (получилось что-то найти в инете, пару веток даже на этом форуме) есть такая непонятная проблема с IDE, подкаталогами и #include... Ок. Верну пока в корень проекта. Но если будут у кого какие решения/мысли - делитесь)
Свои cpp и h можно складывать в projectdir/src/...
AsNik а что с уровнем оптимизации компилятора ?
Может надо ему явно указать #pragma GCC optimize ("Os") или #pragma GCC optimize ("O3") и он уменьшит код ???
Быстрая проверка показала, что похоже вот этот вариант работает. Спасибо. Буду пробовать еще...
AsNik а что с уровнем оптимизации компилятора ?
Может надо ему явно указать #pragma GCC optimize ("Os") или #pragma GCC optimize ("O3") и он уменьшит код ???
К сожалению моих знаний не хватило что бы понять о чем речь.... почитаю в инете, может разберусь...
У меня всё работает, подгружает нужные файлы из подкаталога скетча:
Если файлов меньше сотни, к примеру, то даже визуально никаких проблем нет если они в корне располагаются. А если ещё и называть файлы понятно - то и вопросов не возникнет. Зачем в подкаталоги перемещать?
Понятно, что удобнее, но с ардуино это «такое себе удобство».
У меня всё работает, подгружает нужные файлы из подкаталога скетча:
Ну ненаююю... Может версию нужно обновить до 14, у меня 1.8.10
Хотя я пробовал и 2.0.0 (то еще г...) тоже самое (или не тоже, ну скомпилить не получилось)
А вот если каталог src назвать, то ОК.
Зачем в подкаталоги перемещать?
Понятно, что удобнее, но с ардуино это «такое себе удобство».
Я уже понял, что IDE вообще не рассчитана на "серьезные вещи" с разбиением проекта на файлы, причем ошибки начинает выдавать странные и непонятно по какому принципу. Перенес один кусок кода из одного ino в другой а ошибку выдал:
exit status 1
Возвращаю на место, все компилится... В общем странное поведение...(
Я читал сейчас и про include, заодно узнал про import - почему им не пользуются? Я так понял, это сделали чтоб в библиотеках не делали #pragma once и более длинную версию защиты от повторного использования библиотеки....
Сдохла ардуина? Не выдержала моих перепрошивок(
Вопрос, можно повредить загрузчик какими либо(неправильными) действиями из прошивки? Ардуина вроде как в полуживом состоянии.. При загрузке начинает загружаться и в середине стопарится и начинает ребутится... Мог я своими экспериментами с PROGMEM и работай (неправильной) с указателями убить ардуину/загрузчик? Ну т.е. теоретически это возможно? Ничего хитрого я не делал... пытался в функцию чтения из прогмем передать массив... Вот в эту:
Хотелось бы вместе с _i передавать туда и ссылку на string_table... но что-то у меня пошло не так и ардуина сдохла...
Еще пару штук есть, но ...теперь боюсь) Ну и если убил загрузчик, то ....читаю как прошить optiboot. Одну ардуину буду в качестве программатора делать.. и ей пробовать восстановить дохлую. Если конечно это я убил загрузчик...
ЕМНИП, ПЗУ имеет ограниченное число перезаписей, меньшее чем флеш-память. ПЗУ что-то около тысячи перезаписей, а флеш около 10 тысяч. Если у вас старая Ардуина, могли израсходовать ресурс перезаписей. Поэтому многие используют эмуляторы. Либо не используют ПЗУ )
У меня ардуина первая с 16-го года. Чувствует себя хорошо, несмотря на все издевательства. Остальные горели только от повышенного напряжения. Штуки три лежат в качестве массогабаритных моделей.