Добрый день! Нужен совет опытных программистов на С++ под ардуино. В общем ситуация такая:
Есть основной контроллер на esp8266, к нему через программный UART подключено некоторое количество ATMEGA168. Соединены цепочкой. Т.е. esp8266 -> ATMEGA168 -> ATMEGA168 -> ATMEGA168 -> обратно в esp8266 . Адресация относительная. Т.е. центральный передает на адрес 0x02, девайсы в цепочке последовательно отнимают от поля адрес единицу и так доходит до конца. Так сделал чтоб можно было просто расширять возможности девайса дополнительными блоками. Хотел общую шину, но не придумал как сделать арбитраж передачи.
Ладно, суть в том что периферийных девайсов на ATMEGA168 может быть много, и они могут быть разными. Какой-то просто GPIO, какой-то отвечает за 1wire сеть, другой - дисплей и тп. У каждого устройства есть свой тип и набор функций. примерно так:
Формат пакета данных
0 1 2 3 4 5 6 8 9 10
AA BB СС DDDDDDDD EEEE ZZ
AA - адрес получателя. Для центрального процессора всегда FF
BB - тип устройства. Для центрального процессора всегда 0
CC - код функции
DD - Параметры для функции произвольной длинны. Количество данных определяется кодом функции
EE - номер транзакции для подтверждения передачи
ZZ - контрольная сумма за исключением адреса устройства
данные могут быть произвольного размера, приемник понимает это по номеру функции. В базовом варианте передаются четыре байта, но в иных случаях может и килобайт засылаться.
Собственно весь вопрос в грамотной организации со стороны контроллера этого всего дела. Я хочу чтобы заданные события на портах периферии отрабатывались ей самой и на центр передавалось только само событие. Чтоб не задрачивать центр опросом портов и не тратить на это время. Тем более UART и так асинхронный.
Вопрос как это все красиво организовать. Мне представляется класс, который при инициализации получает указатель на поток UART, далее мы можем передать в порт команду перечисления устройств. Каждое вернет нам тип и свой порядковый номер на шине. И вот тут самое интересное: устройства могут быть разных типов. Разные структуры описывают их состояния, у них есть разные методы управления.
Что-то я заплутал в этом всем. Наверно слишком путано объясняю.
Неудачное решение.
Соединены цепочкой. Т.е. esp8266 -> ATMEGA168 -> ATMEGA168 -> ATMEGA168 -> обратно в esp8266 ... Так сделал чтоб можно было просто расширять возможности девайса дополнительными блоками.
...У каждого устройства есть свой тип и набор функций. примерно так:
Надеюсь, Вы понимаете, что ВСЕ команды должны быть заранее известны ВСЕМ устройствам. Т.е. просто придумать новое устройство и вставить его в уже существующую цепочку окажется невозможным.
Каждый первый, даже не каждый второй, программист, столкнувшись с миром микроконтроллеров, начинает писать "Общую систему всего". ;))) Это не плохо, это как детская болезнь, типа ветрянки, лучше переболеть раньше, избежать все-равно не выйдет.
Никто никогда не дописывает до конца, потому, что никому не надо, но в процессе создания часто рождается много хорошего кода, в основном - велосипеды, но, как бы сказать? - Вот: "Крафтовые"! ;))))))))
--------------
Пока в заголовок длину пакета добавь, тогда ретранслирующим устройствам не нужно будет парсить структуру дальше заголовка.
Ну, если хочется "кольцо", то все придумано до нас - https://ru.wikipedia.org/wiki/Token_ring
Но вылет одной ноды валит всю сеть напрочь. Так что лучше подумать в сторону шинной топологии.
UPD A чем I2C (aka TWI) не устраивает?
> Ну, если хочется "кольцо", то все придумано до нас - https://ru.wikipedia.org/wiki/Token_ring
> Но вылет одной ноды валит всю сеть напрочь. Так что лучше подумать в сторону шинной топологии.
> UPD A чем I2C (aka TWI) не устраивает?
i2C на меге занимает ADC, а мне их 8 штук надо. Вообще мегу ставлю только потому что в одном корпусе 8ADC и около 14 GPIO, чего для задачи в самый раз. И это получается дешевле чем i2C микросхемы ставить. Плюс разгружу центральный контроллер от опроса ног, хотя в этом особого смысла нет. Больше потребность в расширении портов. Токен Ринг тут мне не нужен, т.к. периферия между собой не обменивается данными никак.
как тут цитировать-то?
> Надеюсь, Вы понимаете, что ВСЕ команды должны быть заранее известны ВСЕМ устройствам. Т.е. просто придумать новое устройство и вставить его в уже существующую цепочку окажется невозможным.
безусловно понимаю. Пока у меня один тип устройства, на примете еще пара. Добавление нового типа устройств должно сопровождаться обновлением ПО. Но устройства не вникают в содержимое пакета если он не предназначен для него непосредственно. Разбирает заголовок и пересылает дальше
>Каждый первый, даже не каждый второй, программист, столкнувшись с миром микроконтроллеров, начинает писать "Общую систему всего". ;))) Это не плохо, это как детская болезнь, типа ветрянки, лучше переболеть раньше, избежать все-равно не выйдет.
> Никто никогда не дописывает до конца, потому, что никому не надо, но в процессе создания часто рождается много хорошего кода, в основном - велосипеды, но, как бы сказать?
я не новичок в программировании ;) Интересно что всегда я придерживался больше строительства костылей, чем велосипедов (их я готовые использовал), ибо считал "пока вы там на жаве свой шедевр точите, мы запилили на пхп из говна и палок и деньги зарабатываем". Просто конкретно в этом случае я хочу углубиться в C++ и сделать по-человечески. Не потому что так надо, а потому что так хочу (я художник, я так вижу ;))))
безусловно понимаю. Пока у меня один тип устройства, на примете еще пара. Добавление нового типа устройств должно сопровождаться обновлением ПО.
Но устройства не вникают в содержимое пакета если он не предназначен для него непосредственно. Разбирает заголовок и пересылает дальше
wdrakula Вам верно посоветовал: включите длину пакета в заголовок.
суть вопроса не в протоколе, не в длинах пакета, не в алгоритме передачи, это все детали. Суть вопроса в организации программы для работы с этими сущностями.
Как я себе это представляю в программном коде: например, центральный проц рассылает команду нумерации устройств, они все возвращают свой тип. Допустим их несколько разных. Дальше в коде должно как-то появиться несколько классов с методами, определенными для этого типа устройств. Это массив классов? Как это делается?
В процедурном программировании просто делаем кучку IF и обрабатываем все по-своему. С классами как это правильно организовать?
А в классе создаем метод обработать и указатель(*void) где полученый пакет лежит.
это понятно. Ладно, думаю сложно так вот объяснить...
Освежите в памяти операцию приведение типов. похоже вы о существовании ее даже не догадываетесь.
Как я себе это представляю в программном коде: например, центральный проц рассылает команду нумерации устройств, они все возвращают свой тип. Допустим их несколько разных.
Дальше в коде должно как-то появиться несколько классов с методами, определенными для этого типа устройств. Это массив классов? Как это делается?
В процедурном программировании просто делаем кучку IF и обрабатываем все по-своему. С классами как это правильно организовать?
IMHO wdrakula с самого начала поставил верный диагноз: Вы пытаетесь придумать сверхуниверсальное решение там, где по другим признакам даже малой степенью универсальности и не пахнет. По крайней мере, структура заголовка пакета полностью исключает всякую универсальность.
Начните с малого - с того, что можете самостоятельно сделать прямо сейчас. А потом уже думайте, что нужно, для того, чтобы это обобщить и универсализировать.
Опять же, протокол - более консервативная вещь, чем прошивка. Вот с универсального протокола и начните. А универсальностью прошивки будете заниматься потом. Если в этом возникнет необходимость.
я не новичок в программировании ;) Интересно что всегда я придерживался больше строительства костылей, чем велосипедов (их я готовые использовал), ибо считал "пока вы там на жаве свой шедевр точите, мы запилили на пхп из говна и палок и деньги зарабатываем". Просто конкретно в этом случае я хочу углубиться в C++ и сделать по-человечески. Не потому что так надо, а потому что так хочу (я художник, я так вижу ;))))
Писец, уже прямо и откровенно пишут. Делаю дерьмо, но за деньги. Так шуруй в раздел ищу исполнителя, там за заработаное на производстве костылей закажеш, тебе таких же костылей, их из велосипедов наваляют и будеш щасливо вкушать. Ты не новичек, ты хуже. Тя не учить нужно, а исправлять. Лучше физически, поскоку морально не выйдет, деньги убедили тебя в правоте подхода. И "сделать по-человечески" уже не сможеш.
По существу. Тебе тут правильно писали идея отстой полностю. От выбора контроллеров и уарта и до кольца и протокола. Но с последним проще всего, по крайней мере обозначеная проблема - отсутствие явной длинны переменной части тех самых DDDDD легко решаема, пусть будет LL. Еще полезно добавить контрольную сумму отдельно для заглавия. Почему так? Потому что ошибки в нем имеют большие необратимые последствия. Например прием команд с ошибкой в СС (или в LL) приведет к ожиданию неверной длинны сообщения (кол-ва DDDD) и рассинхронизации всей сети. Потому уж лучше так AA BB СС LL zz DDDDDDDD EEEE ZZ, где zz, ZZ - контрольные суммы заглавя и данных соответственно. Хотя остается вопрос, а что делать если на заданом AA нет указаного BB? Или думаете на одной ATMEGA168 много ВВ влезет? Ща! Дай бог чтоб сам протокол уместился нормально. Кстати чего хоть не ATMEGA328? Вобщем ВВ убрать, если вдруг потребуется - передаватьв составе DD. И архитектурно оно верней. Важный вопрос - размер места под DDDD зарезервированого в контроллере. Поясняю, вебдизайнеру сложно сразу вехать. В сети экран и датчик температуры. Для экрана нужно много DDDDDD например 1КБ для оледки например или 240*320*2 байт для покрупней (оно конечно можна и по частям, но скорость сразу сильно падает), а для датчика достаточно и 1-2 байт. Протокол должен эту проблему позволять решать без обявления больших буферов тем устройствам, которым оно не нужно. Вобще тут писать можна много, но пусть сразу хоть это услышано будет.
Альтернативой процедурного программирования есть объектное оринтированое программирование. Но как нет единого стандарта понимать что такое процедурное программирование. Что "правильное " процедурное програмирование а что "неверное" или еретическое. Вот так и с ООП. есть куча сектантов и адептов правильного и единственно верного ООП. Но вернемся к ООП и классам. 1- класс это не объект. И объект не класс. Класс это комплект чертежей по которым можно собрать объект . Можно один , можно много , а можно и не собирать, если в конкретной программе этого не надо. Вот этим и занимается компилятор. Вроде это заезженая мысль. Но почему-то у народа не находит понимания. Тут вроде понимает, а как только начинает использовать , не может.
Теперь ближе к теме. Пакет это что? Объект. Да у него есть общая схема (класс), здесь пишем адрес куда, здесь размер, здесь вес, здесь отметка о целостости и так далее. А так же в классе описаны методы как вскрывать, как пеносить как передавать и прочее.
Что бы передать пакет надо его отнести на почту . И почта его передает . Почта это что ? Вы удивитесь . Это тоже объект. И что для объекта почты объект посылка - это просто некий объем,вес,размер который надо передать без ущерба другому пункту почты.
И все.
Писец, уже прямо и откровенно пишут. Делаю дерьмо, но за деньги. Так шуруй в раздел ищу исполнителя, там за заработаное на производстве костылей закажеш, тебе таких же костылей, их из велосипедов наваляют и будеш щасливо вкушать. Ты не новичек, ты хуже. Тя не учить нужно, а исправлять. Лучше физически, поскоку морально не выйдет, деньги убедили тебя в правоте подхода. И "сделать по-человечески" уже не сможеш.
вам тоже всего хорошего!
я начал реализовывать, посмотрю что выйдет. Пока все не ясно. Изучаю ваши же примеры на этом форуме. Просто на C++ я только под ардуину программил, а с объектами в интерпретируемых языках без строгой типизации все как-то проще выходит.
Допустим Вася решил отправить Пете сапоги. Конечно у Васи есть не только сапоги, а Петя получает не только сапоги. Понятно что все это байты и желательно создать пользовательский тип - предметы. А то Петя получив сапоги начнет готовить из них борщ. То есть программист должен создать структуру данных сапоги. И присвоть им пользовательский тип 0х01. А для структуры свекла тип 0х02. И теперь Вася должен переслать Пете не только данные но и их тип, что бы Вася их одел на ноги, а не варил борщ.
Но Вася живет в Петербурге, а Петя в Москве. И пересылка происходит почтой. То есть ПочтаПетербург это отправка , а ПочтаМосква прием. Итак Вася с сапогами идет на ПочтуПетербург и там формируется посылка - тип сапоги-сапоги-ПочтаМосквы-Васе. И когда на ПочтуМосквы приходит куча пакетов и тип сапоги-сапоги-ПочтаМосквы-Васе , то Васе идет звонок из ПочтуМосквы- Придите и заберите свою Посылку. И Вася забирает тип сапоги-сапоги. Потому что уже ПочтаМосквы-Васе не надо. Конечно Жалательно указать то это от Пети. А то у Васи знакомых много. Может это сапоги от Мити из Владивостока. Так что имя отправителя и адрес проживания тоже желательно включить в посылку. А так как Почта может быть с чудесами, то и дату отправки тоже. А то пришли сапоги от бабушки , и пока шли Вася вырос закочил школу и стал взрослым. и эти сапоги ему не нужны.
Вот, что бывает, если отведать сапогов вместо борща...
Вот, что бывает, если отведать сапогов вместо борща...
Борщ впоследствии отправить в Тобольск дедушке Ангелины пока его не забрали в армию джедаем третьего ударного полка.
Про борщ хорошо конечно, но радиус кривизны рук пока не позволяет до сопог добраться ;)
Ошибка на строке 78
Что не так делаю?
Единственное что в голову приходит это у параметра неверный тип, от чего конструктор не может инициализировать объект, а значит нет определения для этого объекта. Но пробовал конструктор без параметров сделать - тоже самое.
Может объявление класса вынести в .h ? Это же Wiring, в нем много чудес.
Понятно что "Города" находятся на разных МК. Но скорее всего надо начинать со строительства почты.
Может объявление класса вынести в .h ? Это же Wiring, в нем много чудес.
не думаю что поможет. Ведь объявление непосредственно в коде происходит. Но попробую...
Ну а потом населять города людьми. В общем движение сверху вниз, а не снизу-вверх начиная с мелочей,как в процедурном программировании.
Населять города человечками на ардуино это конечно хорошо. Прям Sim City. Только вот ошибка была тривиальна: описание класса должно заканчиваться точкой с запятой. Но от компилятора сообщение непонятное (для меня-то). Теперь прошу помощи с конструктором. Ругается так:
cannot declare parameter '_s' to be of abstract type 'Stream'
на строчку 042 из моего листинга выше. Я не могу понять где накосячил. Уж очень много неочевидных тонкостей в С++
Может ну его С++?
https://vk.com/@physics_math-pochemu-ne-lisheno-smysla-pisat-kod-na-c-a-...
Хорошая статья, правда после нее идет статья "почему стоит писать на С++". Я придерживаюсь принципа KISS. Пару лет назад запилил некую платформу для приложений, Что-то типа фреймворка. Без единого объекта. Сидели потом с программерами думали, может стоит переделать на ООП. Получалось вдвое больше кода... А если сравнить с предыдущим фреймворком где одни объекты...
Наверно это моя профессиональная деформация. Мне приходится бороться за скорость выполнения кода микроконтроллером. Там ООП никогда не давал приимуществ, а как раз наоборот. Это потом на большом компе ООП применияю для обработки и визуализации данных.
Но от компилятора сообщение непонятное (для меня-то). Теперь прошу помощи с конструктором. Ругается так:
cannot declare parameter '_s' to be of abstract type 'Stream'
на строчку 042 из моего листинга выше. Я не могу понять где накосячил. Уж очень много неочевидных тонкостей в С++
Я, конечно, дико извиняюсь, но что именно непонятно в сообщении? Требуется помощь с переводом? Написано, что нельзя создавать экземпляр абстрактного класса. И таки правда нельзя!
Спасибо, капитан очевидность ;)
Было бы неплохо объяснить что не так.
Спасибо, капитан очевидность ;)
Было бы неплохо объяснить что не так.
В Вики даже есть статья "абстрактный класс". Ты принципиально не ищешь информацию сам, предпочитая ответы неизвестных людей с форума?
Прочти и всё поймешь. Потом, для проверки понимания, посмотри, как в ядре определен класс Stream.
================
ЗЫ:Прости стариковское ворчание, но я не думаю, что ты уж прям так на много моложе меня. Как, при наличии Инета можно разучиться учиться? Ведь ради нового учебника я, в 80-е годы, пробегал все известные букинисты, сидел в библиотеках, а теперь - два нажатия кнопки и у тебя на экране ответ НА ЛЮБОЙ ВОПРОС, только научиться фильтровать чушь от правды!
ЗЗЫ:Первый мой экземпляр КиР был отпечатан на огромном барабанном АЦПУ с СМ-4, в 84 году.
wdrakula, я тоже на форумах присутствую, только у меня другие компетенции, так же новичкам объясняю. Это круговорот информации и помощи в природе, так сказать. Обычно я ищу информацию по ошибке, вычитываю все что мне покажется подходящим. В любом случае я как-то разобрался. Сменил Stream на SoftwareSerial, я знал что он и HardwareSerial наследники от Stream. Просто хотел чтоб была независимость от типа подключения. Объяснения прошу от опытных людей, потому что в обилии литературы можно заблудиться. Хоть знать что читать. Стандарт C++ он же больше 700 стр, это только стандарт. К сожалению (или к счастью) это не мой основной язык, на котором программирую.
смени лучше Stream на Print, он памойму не абстрактный.
Срач на тему "программисты против веб-говнокодеров" уже всем поднадоел, но все же:
Если художника, любого ульра-пост-... современного, попросить нарисовать лошадку, или мастрера супер-трэш-металла попросить сыграть "к Элизе" или токкату Ре-минор, или математика тополога попросить решить квадратное уравнение - НИКТО из них не скажет, что у него "другие компетенции".
Вот так и С/С++ - это как обязательное сольфеджио для музыканта, или основы мат анализа для математика. То, что не может быть "вне компетенции". Как-то так ;))))))))))))))).
смени лучше Stream на Print, он памойму не абстрактный.
...ну, ...какбэ ...вот:
На этой-самой "врайте" весь класс построен. Сорри.
Если художника, любого ульра-пост-... современного, попросить нарисовать лошадку,
Живо представил себе результат: уши вместо хвоста, цвет - оранж с черными полосами.
смени лучше Stream на Print, он памойму не абстрактный.
...ну, ...какбэ ...вот:
На этой-самой "врайте" весь класс построен. Сорри.
Ну дак ты прав. Не надо шило на мыло менять.
Хотя странно, я могу обьявить указатель на абстрактный класс и присвоить ему любого потомка (не абстрактного), не должен компилятор ругаться, я ж экземпляр не создаю.
Срач на тему "программисты против веб-говнокодеров" уже всем поднадоел, но все же:
Если художника, любого ульра-пост-... современного, попросить нарисовать лошадку, или мастрера супер-трэш-металла попросить сыграть "к Элизе" или токкату Ре-минор, или математика тополога попросить решить квадратное уравнение - НИКТО из них не скажет, что у него "другие компетенции".
Вот так и С/С++ - это как обязательное сольфеджио для музыканта, или основы мат анализа для математика. То, что не может быть "вне компетенции". Как-то так ;))))))))))))))).
Так-то я когда-то и на ассемблере писал по пики, в начале жизненного пути на паскале, потом дельфи. Но плотно с C++ начал только на ардуино работать. А чтоб было привычно нужно лет 5 постоянно пользоваться.
Так-то я когда-то и на ассемблере писал по пики, в начале жизненного пути на паскале, потом дельфи. Но плотно с C++ начал только на ардуино работать. А чтоб было привычно нужно лет 5 постоянно пользоваться.
имхо, проблема не в отсуствии "привычки к С++" - а в отсутсвии привычки искать ответы самостоятельно в гугле, вместо того чтоб задавать элементарные вопросы на форуме...
вот только в эти в выходные сделал ровно ту же ошибку - забыл поставить точку с запятой в конце класса. Нашел ответ в гугле за 3 минуты.
"Привычка к С++" у меня примерно на вашем уровне, а вот гугль я люблю :)
Так-то я когда-то и на ассемблере писал по пики, в начале жизненного пути на паскале, потом дельфи. Но плотно с C++ начал только на ардуино работать. А чтоб было привычно нужно лет 5 постоянно пользоваться.
имхо, проблема не в отсуствии "привычки к С++" - а в отсутсвии привычки искать ответы самостоятельно в гугле, вместо того чтоб задавать элементарные вопросы на форуме...
вот только в эти в выходные сделал ровно ту же ошибку - забыл поставить точку с запятой в конце класса. Нашел ответ в гугле за 3 минуты.
"Привычка к С++" у меня примерно на вашем уровне, а вот гугль я люблю :)
ох любят тут попинать, любят. Наверное не все еще отписались на тему что я такой растакой гуглом пользоваться не умею?
Наверное не все еще отписались на тему что я такой растакой гуглом пользоваться не умею?
Ну я пропустил отписатся, извини. Исправлюсь. Неумееш и это.
ох любят тут попинать
А чё еще делать с челом, который на словах - в медалях из прошитых PIC на деле не архитектуру продумать, ни протокол составить ни, простигосподи, точку с запятой поставить без гугла и форума. С ними тоже вобщем не очень.
Наверное не все еще отписались на тему что я такой растакой гуглом пользоваться не умею?
Ну я пропустил отписатся, извини. Исправлюсь. Неумееш и это.
ох любят тут попинать
А чё еще делать с челом, который на словах - в медалях из прошитых PIC на деле не архитектуру продумать, ни протокол составить ни, простигосподи, точку с запятой поставить без гугла и форума. С ними тоже вобщем не очень.
ну пики я сразу не взлюбил, поэтому и проектов на них было мало. И было это 17 лет назад. Потом я программировал в основном напаскале, потом на Дельфи, фоксе. Потом уже VB, пых, js, node, perl и немного С. Есть еще несколько языков, но все они специфические. Если с ними столкнетесь и придете на форум где я есть, то вас не будут так тыкать носом. В данном конкретном случае я хочу научиться новому для меня подходу. Сделать чтоб работало - не проблема. Я хочу научиться.
У каждого человека, который встречается вам на пути есть своя битва, о которой вы не знаете ничего. Будьте вежливы. Всегда.
Если художника, любого ульра-пост-... современного, попросить нарисовать лошадку...
Супер!!!
Одну явно костылями подняли до требований заказчика.
Одну явно костылями подняли до требований заказчика.
Одну явно костылями подняли до требований заказчика.
Вот не скажу что это пост не по теме ;)