Класс-процессы и Программа Blink Bottom
- Войдите на сайт для отправки комментариев
Пт, 29/07/2016 - 21:24
Это просто демонстрация еще одного инструмента(приема). Вообщем светодиод на выв 13 мигает, а выв 2 включают 0/ выключают 1 это мигание. Все организовано с помощью класс-процессов. Что означет, что можно одновременно организовать 6 таких пар. Причем мигать светодиоды могут с разной частотой.
https://yadi.sk/d/pXeze5_XtkRbP
код на яндекс диске.
// Класс-процесс Вспышка class qw_blink { public: qw_blink(int pin);// конструктор с таймингом по умолчанию qw_blink(int pin,unsigned long span);// конструктор c установкой тайминга void on(); // включить мигание void off();// прекратить мигание void go(); // драйвер blink private: unsigned long span;// интервал гашения или включения unsigned long future;// время сменить состояние гашения или включения int pin;// номер вывода boolean state;// состояние светодиода boolean blinks;// 0 - нет мигания/ 1- мигание }; qw_blink::qw_blink(int pin){ // конструктор с таймингом по умолчанию // общая часть this->span = 500;// тайминг 0.5 сек future = span+millis(); // индивидуальная часть this->pin = pin; pinMode(pin, OUTPUT); blinks = 1; // миганиe включить state = 0; digitalWrite(pin, state); } qw_blink::qw_blink(int pin,unsigned long span){ // конструктор c установкой тайминга // общая часть this->span = span/2; future = span+millis(); // индивидуальная часть this->pin = pin; pinMode(pin, OUTPUT); blinks = 1; // миганиe включить state = 0; digitalWrite(pin, state); } void qw_blink::on(){ // включить мигание blinks = 1; } void qw_blink::off(){// прекратить мигание blinks = 0; } void qw_blink::go(){ // общая часть if (millis() < future) return; future = span+millis(); // индивидуальная часть if (blinks == 0) state = 0; else state = ! state ; digitalWrite(pin, state); } // Класс-процесс "мигалка-кнопка" // (вывод)-(кнопка)-(земля) // подтягивающий резистор подключен программно // 1 -не нажата / 0 - нажата class qw_blink_bottom { public: qw_blink_bottom(int pin,qw_blink * BLINK);// конструктор qw_blink_bottom с таймингом по умолчанию qw_blink_bottom(unsigned long span,int pin,qw_blink * BLINK);// конструктор qw_blink_bottom void go();// драйвер qw_blink_bottom qw_blink * BLINK; // ссылка на нужного представителя qw_blink private: unsigned long span;// интервал сообщения unsigned long future;// время следующего сообщения int pin; // нога для подключения аналог кнопок boolean state;// состояние кнопки 1 -не нажата / 0 - нажата }; qw_blink_bottom::qw_blink_bottom(int pin,qw_blink * BLINK){ // конструктор qw_blink_bottom // общая часть this->span = 5;// тайминг 5 миллисек future = span+millis(); // индивидуальная часть this->pin = pin; pinMode(pin, INPUT); state = digitalRead(pin); this->BLINK = BLINK; } qw_blink_bottom::qw_blink_bottom(unsigned long span,int pin,qw_blink * BLINK){ // конструктор qw_blink_bottom // общая часть this->span = span; future = span+millis(); // индивидуальная часть this->pin = pin; pinMode(pin, INPUT); digitalWrite (pin, HIGH); // включить подтягивающий резистор state = digitalRead(pin); this->BLINK = BLINK; } void qw_blink_bottom::go(){ // драйвер qw_blink_bottom // общая часть if (millis() < future) return; future = span+millis(); // индивидуальная часть state = digitalRead(pin); if (state == 0) BLINK->on(); else BLINK->off(); } // ===== Программа ======= // объявить класс объекты qw_blink VD1(13); // класс-процесс мигание светодиода на выв. 13 qw_blink_bottom SB1(2, & VD1); // класс-процесс включение (выключение) мигания светодиода на выв. 2 void setup() { } void loop() { // подключить драйвера VD1.go(); SB1.go(); }
Ну а это пример Мультивибратора , частота мигания светодиода задается потенциометром на выв А0.
Разумеется на одной Ардуине можно собрать до 6 независимых мультивибраторов.По числу аналоговых входов.
http://yadi.sk/d/mS_0LnSJtkh97
Светодиод на 110 строк, с возможностью адресации 65536 пинов, но без защиты от переполнения - это круто!
Ссылка здесь http://www.anekdot.ru/id/-10050884/
Это я к тому. Что если горе программист залезет в исходник, то все защиты уйдут по боку. А вот утяжелять код ради защиты, так я деньги на кодинге не зарабатываю.
Светодиод на 110 строк, с возможностью адресации 65536 пинов, но без защиты от переполнения - это круто!
У меня есть имхо по этому поводу: просто сейчас у ТС такой период: классовая горячка. Когда хочется всё и вся сделать классами, библиотеками, универсальными решениями. Это одновременно и хорошо, и плохо. Хорошо - потому что обучает мыслить архитектурно. Плохо - потому что обучает мыслить архитектурно там, где этого - не надо.
Как показывает опыт - это проходит, всему своё время.
с помощью класс-процессов.
«Не следует привлекать новые сущности без крайней на то необходимости» (Уильям Оккам)
Точно. Вот только моя задача это не мигать светодиодом. А отработать технологию создания драйверов. Разумеется для себя. Вот я привел здесь 2 программы. Сколько вам времени понадобится, что бы совместить 2 разнородные программы. А вот эти программы я совместил за 5 минут. Загрузите и посмотрите.
«Не следует привлекать новые сущности без крайней на то необходимости» (Уильям Оккам)
А что делать. Если в классах помимо переменных и методов появились ПРОЦЕССЫ. Тут приходится приводить новые понятия. Другое дело что это понятие уже занято.
А что делать. Если ...
Что делать? Изучить предмет и пользоваться общепринятой терминологией. Если, конечно, хотите, чтобы Вас понимали.
Что делать? Изучить предмет и пользоваться общепринятой терминологией. Если, конечно, хотите, чтобы Вас понимали.
Ну пока предмет есть, а вот общепринятой терминологии для этого предмета нет. Вот я этот предмет и изучаю.
Перефразировка из В. И. Ленина: "Учиться настоящему делу военным образом!"
И чего прицепились к ТС. Код он выложил очень даже неплохой. По крайней мере не хуже чем 90% осталього кода начинающих.
И его .go() это именно процес, я усебя их так и называю Process(). А то что нет хендла и креатпроцесса - ну так не винда ж. А по сути это именно процесс, т.к. важен не один вызов .go() а непрерывная последовательность вызовов.
Драйвером этот класс я бы не стал называть.
В целом подход верный, ООП попустит и совсем хороше будит.
По коду.
Два конструктора не нужно достаточно так qw_blink(int pin,unsigned long span=500);
Если решили играть с ООП - почему два класса есть, а иерархии нет. Нужен родитель, наследование...
Про millis(). Ну так, как у вас, её используют большинство. Но учитывая что Вы в начале большого пути и правильно смотрите на вещи - мой совет. Делайте так.
И так в каждом проекте. А в либах экстерном цепляйте LoopTime и не используете millis(). Это кривовато архитектурно, но зато очень хороше по размеру кода, скорости, мерзопакостным плавающим бага и в отладке. Кроме того для времени до минуты long int не нужен, хватит и int - мелочь, но экономит.
У меня не совсем класс. Я больше стороник считать что у меня ПРОЦЕСС получился.
Если бы Си поддерживал это , то код был таким.
Так что никакого наследования в принципе быть не может. А то что я 2 процесса сделал, так это 1 ) отработка взаимодествий двух изначально независимых процессов 2) просто так решение было проще 1 процесс мигает светодиодом. А 2-й опрашивает вывод и в случае если кнопка нажата, отключает светодиод, но процесс идет. Замечание у процессов даже тайминги могут не совпадать.
Ну пока предмет есть, а вот общепринятой терминологии для этого предмета нет. Вот я этот предмет и изучаю.
Более правильно будет так: "предмет есть, а вот общепринятой терминологии для этого предмета
нетя не знаю. Вот яэтот предметиизучаюколхозю самогонную терминологию, поскольку изучать лень " :))))У меня не совсем класс. Я больше стороник считать что у меня ПРОЦЕСС получился.
Если бы Си поддерживал это , то код был таким.
Ну раз уж мы юзаем ключевое слово class - то это уже С++, а не С, это, что называется, раз. Два - в С++ требуемое вами решается стотыщью разных способов. Лично я, если подумать - сходу выбрал бы шаблонную реализацию, немножко секса, зато потом красота.
Тот же секс только в профиль. Я не показываю стотыщь способов решать проблему. Я объясняю как решить этим способом.
Я объясняю как решить этим способом.
Спасибо. Будем знать.
Вот это класика такого подхода. Мигать 12 светодиодами, каждый мигает со своей частотой
http://yadi.sk/d/HdcfkT5Otm884
Давно хотел высказаться. Заранее прошу прощение у автора топика за отступление от темы!
Регулярно просматриваю форум... ЕвгенийП (и такие же товарищи как Он, Светилы этого форума и вобще просто молодцы по жизни))) ), я вижу, Вы походу неплохо разбиратесь "во всем этом нелёгком деле", но... Я вот понимаю, когда Вы гнобите народ, который не хочет разбираться и просит помочь в вовпросе, котором им самим приложить хоть какое-то усилие лень ( это я про "новичков" на форуме). Но, когда Вы начинаете носатить более менее толковых и имеющих желание разобраться, поделиться какими-то навыками, порой пускай даже поначалу быдлокодом ( это не относится к автору этой статьи!), то это уже перебор. Форум создан чтобы помогать друг другу, а не отбивать желание и мотивацию учиться! У Вас же всё наоборот. Лучше дайте людям направление правильное ( что почитать, где посмотреть, просто сами разжуйте, если есть желание). Почему у "буржуев" народ относится иначе?! Сколько читаю англоязычные форумы такого не вижу. У нас же всё иначе...
P.S. Сам являюсь быдлокодером, копипастером и т .д., но с большим желание разбираться и изучать начиная с осонов, чем постоянно и занимаюсь. Разводить срач не хочу, поэтому просто оставлю это тут и не более того. (т.е. ответа не жду и сам того желаю))...просто для размышления )
spa-sam,
наверное, я в чём-то неправ, раз Вы так это поняли. Но, видит Бог, я вовсе не хотел как-то принижать ТС, просто попросил его пользоваться общепринятой терминологией и не придумывать свою. Ладно, постараюсь быть повнимательнее в выборе выражений.
И чем оно лучше привычной классики?
На данный момент я вижу, что "новая" классика проигрывает "старой" по объему исходного кода, объему результирующего исполняемого кода, аппетитам к ОЗУ и скоростью выполнения. Собственно, по всем важным параметрам и проигрывает. И где тут плюсы нового подхода?
В невозможности работать параллельно нескольким программам. Вы видели я вверху сделал две программы, а потом в третей их совместил. Конечно может вам это не покажется доводом. Для крутого программиста переписать много текста не проблема.
Повторюсь. Это просто еще один подход. Для кого-то хорош, для кого-то плох.
ПС: Совмещаются к сожалению только программы написаные этим подходом. Со старыми такой фокус не пройдет.
Ваша 1270-129
Моя старая 1478-141
поменял типы переменых на uint32_t и uint8_t
Стало 1446-129
поменял типы переменых на uint32_t и uint8_t
Стало 1446-129
Подход имеет право на существование, безусловно. Насчёт быстродействия: тут я согласен с a5021 - надо над этим ещё поработать. Например, не вижу смысла каждый раз дёргать millis во всех экземплярах класса - зачем такой оверхед? Достаточно в метод go передавать дельту между последним вызовом millis и текущим, эту дельту вычислять в loop. Тогда, при наличии 10 экземпляров класса - millis будет дёргаться только 1 раз, а не 10, согласитесь, это сильно лучше в плане эффективности?
То же самое касается и digitalWrite - жирно, очень жирно каждый раз её вызывать, если периодичность вызова довольно высокая. Тут уж - либо напрямую работа с портами напрямую, либо, если не хочется уходить от удобной привязки номеров пинов к портам - digitalPinToBitMask сотоварищи в конструкторе класса.
Но это уже частности, коотрые зависят от типа решаемой задачи, где-то и digitalWrite вполне себе живёт, а где-то - приходится выжимать быстродействие так, что юшка меж пальцев сочится.
Что касается архитектуры: вот смотрю я на 12 экземпляров класса, и так и просится паттерн "visitor", чтобы не писать в loop простыню из вызовов VD9.go(); и т.п. Впрочем, это тоже - дело вкуса.
1. Длинные портянки из почти одинаковых операторов как в setup, так и в loop выглядят, прямо скажем, отталкивающе.
2. Если уж делать класс, то следовало бы дать ему возможность самостоятельно управлять вызовом методов go. Т.е. мы в setup (или в любом другом месте программы) сообщаем управляющему классу, какие классы мы хотим включить в циклическую обработку, и уже он сам все это обеспечивает. Аналогично должен быть метод для исключения вызовов объектов из цикла. И пусть в loop все это выглядит вызовом единтственного управляющего объекта, а внутри он сам уже отслеживает, какие объекты ему нужно вызывать, а какие - нет.
Я согласен. Но вот какое дело? Если писать программу, то кодом в котором уверен. Конечно есть в мире конструкции, которые работают, но при этом их не знаешь. Ну да ,учится учится учится. Но что бы не быть Попугаем , висящим на форуме , и тролящим других. Надо писать код самому, даже с учетом того минимума , в котором уверен. Про "visitor" я ничего не знаю.
Если я вынесу содержимое setup() и loop() в отдельные функции, а заодно напишу еще кучку подобных функций с иным наполенением, то точно так же смогу вызывать.
а то и вовсе:
И чем это будет отличаться от вашего "совместил" ? Я уж не Бог весть, какой программист, но "много текста" это как раз при вашем подходе. И, что еще хуже, там к этому добавиться еще и много исполняемого кода.
Про "visitor" я ничего не знаю.
https://www.google.ru/webhp?sourceid=chrome-instant&ion=1&espv=2&ie=UTF-8#newwindow=1&q=%D0%BF%D0%B0%D1%82%D1%82%D0%B5%D1%80%D0%BD+%D0%BF%D0%BE%D1%81%D0%B5%D1%82%D0%B8%D1%82%D0%B5%D0%BB%D1%8C
Их там много разных, я не настаиваю, что надо обязательно применять тот или иной паттерн проектирования, но мы ведь в подобных темах обсуждаем различные подходы, не так ли?
Вот ещё, кстати, применительно к реализации разных поведенческих моделей: https://www.google.ru/webhp?sourceid=chrome-instant&ion=1&espv=2&ie=UTF-8#newwindow=1&q=%D0%BF%D0%B0%D1%82%D1%82%D0%B5%D1%80%D0%BD+%D0%BF%D0%BE%D0%B4%D0%BF%D0%B8%D1%81%D1%87%D0%B8%D0%BA
У меня не совсем класс. Я больше стороник считать что у меня ПРОЦЕСС получился.
Не льстите себе :). Это класс, что вы сами явно декларировали. Где в коде указано что это процесс? Нигде. Предсавление о том что одна из функций класса используется как процесс не заявлено, следовать это принято на прикладном уровне на основе навания функция и её описания. А для компилятора это ф-ия член класса и усьо.
Если бы Си поддерживал это , то код был таким.
Ну если бы у бабы были яйки, то Вы знаете.. А так - см. выше.
Кстати на каком языке этот пример?
Так что никакого наследования в принципе быть не может.
Хммм... Тут или ктото когото не понял или Вам с ООП еще игратся надо. Откройте обявление ваших 2-х классов и найдите совпадения. Вот то что совпало - в предок. И окажется что go именно в нем. Виртуальная. Тогда и код аналогичный приведенному в 2-м примере http://arduino.ru/forum/programmirovanie/klass-protsessy-i-programma-blink-bottom#comment-209760 напишется легко и непренужденно, но в ООП.
Однако имеет ли смысл делать как в 2-м примере http://arduino.ru/forum/programmirovanie/klass-protsessy-i-programma-blink-bottom#comment-209760 . Иногда да, но как правило нет. Обычная ситуация не 12 мигающих светодиодов, а некоторое количество зависимых друг от друга разнородных процессов. Например процессы опроса датчика, протокола обмена, обновления данных на экране, мигания иконки на экране. Причем обновление данных на экране активизируется после успешного опроса датчика а мигание иконки - при наличии обмена по протоколу в течении 5 секунд. И это логика самого верхнего уровня, очевидное её место - прямо в лупе, где она непосредственно решает какие из функций процессов активны, а какие нет. Конечно это тоже можно засунуть в класс, завернуть в функции возвращающие активность и т.д. А зачем? Это самая прога и есть, ей самое место в лупе.
ПС. Очень полезно когда функция процесса возвращает его статус (типа "жду", "завершить процес сейчас нельзя", "отправлен ответ", "возникла критическая ошибка" и т.д.) и принимает команду - "работай", "завершись сейчас", "пауза", "уходим в слип" и т.д. Тогда и логика управления активностью процессов выглядит просто и естественно.
Logic. Наследование это конечно хорошо. Но у меня наследование нормально не получилось.
Про
protected
: понятно. Но в классе
qw_a_son метод go() должен наследаваться целиком + еще модефикация и имя go() должно сохранится.Хотя для разового наследования virtual void logic() может подойти
Про
protected
: понятно. Но в классе
qw_a_son метод go() должен наследаваться целиком + еще модефикация и имя go() должно сохранится.Похоже
void
go(); надо перестать быть
void
Похоже
void
go(); надо перестать быть
void
Это уже детали реализации ;)
Причесал. Правда еще одна приятная неожиданость получилась
Причесал. Правда еще одна приятная неожиданость получилась
А теперь смотрите, пути дальнейшего улучшения: что делать, если надо динамически поменять интервал, например? Я в следующем посте напишу один из примеров реализации, раз уж мы тут разминаемся ;)
Так посмотреть код
Можно и так :) Кстати, в приведённом мной коде - недоработка серьёзная, прошу воспринимать как говноподелку :)
И шо это за ужас я увидел среди ночи?! Совсем распустились? Как циклами пользоватся забыли?! Сейчазже строки 62-76 в цикл засунуть! Пока другие спят и не видят! ;)
А это и есть цикл. Только цикл ИСПОЛНЯТЬ РАЗ 100 мсек.
Ну не зачем дергать датчики чаще, как чаще давать команды на исполнение.
А то что по строчке выдает на экран, так чаще и не надо. Это заготовка для Меню. LCD 1602 все за раз не поместится.
А это и есть цикл. Только цикл ИСПОЛНЯТЬ РАЗ 100 мсек.
У как все запущенно.. Какие операторы цикла в С Вы знаете (кроме if конечно))))
Инкремент адресов пинов сделан лихо. Так можна далеко не везде и всегда. По хорошему пины в массивы и выбирать через итератор цикла. BASE_Value если больше нигде не нужен - изкоренить.
Logik Вы когда нибудь клеммы видели. http://www.ru.all.biz/img/ru/catalog/1357495.jpeg Бесполезная вещь вроде.:) Ведь можно завести напрямую к устройcтву. А ведь народ извращается лепит везде. Вот такая штука и здесь. Только я не придумал как лучше ее реализовать. Вот приходится единую BASE делать из трех BASE_Format[] ,BASE_Title[ ], BASE_Value[ ].
Клемник видел, с его бесполезностью не согласен категоричо ;), т.к. приходилось открывать шкафы релейки и там их стоко... и без них никак.
Мой ответ несколько запоздалый. Знаете, море, пляж, винчик не способствуют висению на форуме, пока чаек покормиш, девок попоиш - уже и утро, снова пора на пляж... ))) Сегодня пасмурно.
По сути - Вам нужна структура и инициализированный массив этих структур, чтото типа
Можете заметить что структура очень похожа на класс. Злые языки поговаривают, что вообще нет разницы между ними и компилятор воспринимает class так же как struct. И классы в С++ это мировой заговор "сионистов" ))