но даже не знаю какой стандарт поддерживает avr-gcc в atmelstudio ведь не так давно вышел очередной стандарт с++17
Про это можете забыть сразу.
Вообще про плюсы на контроллере, да еще и Гарвардской архитектуры, вспоминать грешно.
Чтобы использовать C++ с комфортом, необходимо как минимум динамическое выделение памяти, а для микроконтроллера это непозволительная роскошь - здесь нормальный менеджер памяти сам почти всю доступную память и скушает. Отдельный поворот делу придает то, что AVR, например, не может выполнять код из RAM (Гарвардская архитектура, да).
Конечно, отдельные эстеты умудряются писать на плюсах и под мелкие МК, но к этому нельзя относиться всерьез.
Так что только ANSI C, причем, желательно, с учетом правил MISRA.
_________________ Разница между теорией и практикой на практике гораздо больше, чем в теории.
char mask = 0; if (! (BTN_PIN & BTN_LINE_UP)) mask = BTN_SHRT_UP; if (! (BTN_PIN & BTN_LINE_DN)) mask = BTN_SHRT_DN; if (! (BTN_PIN & BTN_LINE_POWER)) mask = BTN_SHRT_POWER; if (! (BTN_PIN & BTN_LINE_SW)) mask = BTN_SHRT_SW;
if (mask){ //опрос состояния кнопки if (BtnLockCoun < (BTN_LOCK_TIME/10)){ //клавиша нажата BtnLockCoun++; return; //защелка еще не дощитала - возврат } BtnLastState = mask; BtnLockBit =1; //нажатие зафиксировано if (BtnLongCoun >= (BTN_LONG_TIME/10)) return; //возврат, т.к. счетчик длинн нажат досчитал до максимума еще раньше if (++BtnLongCoun >= (BTN_LONG_TIME/10)) BtnFlags |= (BtnLastState<<4); //счетчик досчитал до максимума - устанавливаем биты длинного нажатия } else{ //клавиша отжата if (BtnLockCoun){ BtnLockCoun --; return; //защелка еще не обнулилась - возврат } if (! BtnLockBit) //СТАТИЧЕСКИЙ ВОЗВРАТ return; BtnLockBit =0; //отжатие зафиксировано if (BtnLongCoun < (BTN_LONG_TIME/10)) BtnFlags |= BtnLastState; //установка бита короткого нажатия BtnLongCoun = 0; //сброс счетчика длительности нажатия } } //----------****7SEG****---------- #define SEGA 6 #define SEGB 5 #define SEGC 1 #define SEGD 2 #define SEGE 3 #define SEGF 4 #define SEGG 0
#define ANOD1 4 #define ANOD2 7 #define ANOD3 4 //---------- void segchar (unsigned char seg) { switch (seg) { case 0: PORTC=(0<<SEGA)|(0<<SEGB)|(0<<SEGC)|(0<<SEGD)|(0<<SEGE)|(0<<SEGF)|(1<<SEGG);break; case 1: PORTC=(1<<SEGA)|(0<<SEGB)|(0<<SEGC)|(1<<SEGD)|(1<<SEGE)|(1<<SEGF)|(1<<SEGG);break; case 2: PORTC=(0<<SEGA)|(0<<SEGB)|(1<<SEGC)|(0<<SEGD)|(0<<SEGE)|(1<<SEGF)|(0<<SEGG);break; case 3: PORTC=(0<<SEGA)|(0<<SEGB)|(0<<SEGC)|(0<<SEGD)|(1<<SEGE)|(1<<SEGF)|(0<<SEGG);break; case 4: PORTC=(1<<SEGA)|(0<<SEGB)|(0<<SEGC)|(1<<SEGD)|(1<<SEGE)|(0<<SEGF)|(0<<SEGG);break; case 5: PORTC=(0<<SEGA)|(1<<SEGB)|(0<<SEGC)|(0<<SEGD)|(1<<SEGE)|(0<<SEGF)|(0<<SEGG);break; case 6: PORTC=(0<<SEGA)|(1<<SEGB)|(0<<SEGC)|(0<<SEGD)|(0<<SEGE)|(0<<SEGF)|(0<<SEGG);break; case 7: PORTC=(0<<SEGA)|(0<<SEGB)|(0<<SEGC)|(1<<SEGD)|(1<<SEGE)|(1<<SEGF)|(1<<SEGG);break; case 8: PORTC=(0<<SEGA)|(0<<SEGB)|(0<<SEGC)|(0<<SEGD)|(0<<SEGE)|(0<<SEGF)|(0<<SEGG);break; case 9: PORTC=(0<<SEGA)|(0<<SEGB)|(0<<SEGC)|(0<<SEGD)|(1<<SEGE)|(0<<SEGF)|(0<<SEGG);break; case 99: //OFF Все сегменты PORTC=(1<<SEGA)|(1<<SEGB)|(1<<SEGC)|(1<<SEGD)|(1<<SEGE)|(1<<SEGF)|(1<<SEGG);break; } }
Обязательным условием долгой и стабильной работы Li-FePO4-аккумуляторов, в том числе и производства EVE Energy, является применение специализированных BMS-микросхем. Литий-железофосфатные АКБ отличаются такими характеристиками, как высокая многократность циклов заряда-разряда, безопасность, возможность быстрой зарядки, устойчивость к буферному режиму работы и приемлемая стоимость. Но для этих АКБ очень важен контроль процесса заряда и разряда для избегания воздействия внешнего зарядного напряжения после достижения 100% заряда. Инженеры КОМПЭЛ подготовили список таких решений от разных производителей.
philosoraptor, я читал и эту статью, и ей подобные. И тут есть несколько моментов.
1. Автор рассматривает исключительно задачу работы с периферией, причем исключительно с портами. Выше же шла речь о более широком применении С++, в частности, и в основной логике - иначе зачем вообще заморачиваться?
2. Автор использует исключительно статические классы и ни словом не заикнулся (логично) про создание их экземпляров. И все равно, несмотря на все изгибание C++ для применимости в эмбеде, не обошлось без ограничений:
- "От динамической конфигурации линий ввода-вывода сразу отказываемся из-за необходимости доступа к портам через указатель со всеми вытекающими последствиями."
- "Мы не можем прочитать состояние выходных линий регистра – он всегда работает на выход, поэтому функцию чтения состояния не реализуем и не объявляем. Попытка прочитать состояние такого пора вызовет ошибку компиляции."
А динамическая конфигурация бывает нужна. Например, чтобы имитировать открытый коллектор на AVR.
Неизвестно, на какие компромиссы придется пойти при разработке API к другим специфичным блокам, которым периодически бывают нужны, например, особые последовательности доступа.
3. И несмотря на все ограничения код получился тяжеловесным и сложным для понимания. Даже сам автор в некоторый момент устал: "Обобщая доступ к отдельным битам в списке линий приходим к концепции среза. Не буду вдаваться в подробности их реализации".
4. В синтетических примерах автора результат дизассемблирования выглядит неплохо, но где гарантия, что в каких-то реальных условиях что-то не пойдет не так, и компилятор не сгенерирует код для того, что по задумке должен вычислять во время компиляции?
Родственный пример (для AVR-libc) - функции задержки, например, _delay_ms(). Если подставить в нее не константу, а переменную, будет сюрприз. Здесь может произойти нечто подобное.
struct MakePinList { private: // рекурсивно проходим все параметры // на следующей итерации Position увеличится на 1, // а T2 превратится в T1 и так далее typedef typename MakePinList < Position + 1,
...
5. В целом можно сказать, что фактически автор лишь использует механизм шаблонов C++ как продвинутый препроцессор. Впрочем, и без классического препроцессора не обходится:
Компания EVE выпустила новый аккумулятор серии PLM, сочетающий в себе высокую безопасность, длительный срок службы, широкий температурный диапазон и высокую токоотдачу даже при отрицательной температуре.
Эти аккумуляторы поддерживают заряд при температуре от -40/-20°С (сниженным значением тока), безопасны (не воспламеняются и не взрываются) при механическом повреждении (протыкание и сдавливание), устойчивы к вибрации. Они могут применяться как для автотранспорта (трекеры, маячки, сигнализация), так и для промышленных устройств мониторинга, IoT-устройств.
Так в программирование неуместно употреблять один подход, и скорее даже не возможно написать код следуя всего лишь одной парадигме программирования т.к даже на языке Си, который не является объектно-ориентированным, можно работать в соответствии с принципами объектно-ориентированного программирования, хотя это и сопряжено с определёнными сложностями, а функциональное программирование можно применять при работе на любом императивном языке, в котором имеются функции, Я решил закончить данную прошивку в стиле функционального программирования, а уже следующие не мение интересную попробовать написать (не потеряв при этом быстродействие) сделав уклон на ООП.
Добавлено after 8 minutes 23 seconds: А насчет MISRA C который являеться как бы ''стандартом разработки программного обеспечения на Си'" . предполгаю что на данный момент времени он не являеться актуальным т.к насколько мне известно они не удосужились внести С99 в описание своего стандарта, не говоря о уже о том что процесса сертификации MISRA не существует в принцепе.
Добавлено after 1 hour 7 minutes 32 seconds: Я вот думаю как все таки более лаконично написать легко переносимую функцию? для работы с динамической индикацией семи сегментного индикатора. А то segchar()+WriteSeg() выглядят как то не комильфо.
предполгаю что на данный момент времени он не являеться актуальным
Это всего лишь ваше предположение. Впрочем, некоторые говорят, что и Си не является актуальным.
Процесса сертификации MISRA не существует по простой причине: MISRA - это, так сказать, набор хороших советов, которые применимы для создания кода, используемого в разных применениях в разных отраслях с разными требованиями и подходами к сертификации. Например, устройство в целом может быть сертифицировано на некоторый уровень SIL, при этом для достижения этой цели логично использовать правила MISRA при написании прошивки - это уберет много граблей. Можно, конечно, не заморачиваться и идти путем проб и ошибок, самостоятельно переоткрывая рекомендации MISRA.
Цитата:
Я вот думаю как все таки более лаконично написать легко переносимую функцию?
Я для динамической индикации использую что-то вроде фреймбуфера, в который складываю паттерны для символов на индикаторе. Этот буфер выводится в порт по прерыванию. Заполняет его отдельная функция, которая заодно преобразует числа/символы в паттерны.
_________________ Разница между теорией и практикой на практике гораздо больше, чем в теории.
_delay_ms(). Если подставить в нее не константу, а переменную, будет сюрприз.
На эти грабли, пожалуй, все новички наступают.
YS писал(а):
В синтетических примерах автора результат дизассемблирования выглядит неплохо, но где гарантия, что в каких-то реальных условиях что-то не пойдет не так, и компилятор не сгенерирует код для того, что по задумке должен вычислять во время компиляции?
Гарантии нет в любом случае, даже если строго следовать всем стандартам. Остается уповать лишь на здравый смысл кодера и на способность препроцессора отловить совсем уж явные несуразности.
YS писал(а):
речь о более широком применении С++, в частности, и в основной логике - иначе зачем вообще заморачиваться?
Например, если мы неплохо владеем С++, то легко сможем составить на нем и полностью обратно-совместимый с чистым Си код. В чем профит, спросите вы? Ну, к примеру, есть множество ардуинообразных библиотек на С++, которые можно использовать и без ардуины. Да, их можно легко портировать и на Си, но это лишние телодвижения.
Гарантии нет в любом случае, даже если строго следовать всем стандартам.
Просто не надо полагаться на оптимизации вроде вычисления выражений на этапе компиляции (если только они не состоят исключительно из констант-дефайнов) и, тем более, замену компилятором участка кода на результат его выполнения. Это очень рискованно само по себе, а заодно усложняет портирование кода.
Я считаю, что на оптимизацию вообще полагаться не надо. Надо стараться, чтобы написанный код был как можно более прозрачен.
Цитата:
Например, если мы неплохо владеем С++, то легко сможем составить на нем и полностью обратно-совместимый с чистым Си код.
В этом случае обычно пишут библиотеку на чистом C, а на C++ делают только обертку для желающих. Такой подход гораздо лучше потому, что обеспечивает совместимость не только на уровне исходников, но и на бинарном уровне - скажем, DLL на чистом Си гораздо универсальнее. То же самое справедливо и для скомпилированных статических библиотек.
_________________ Разница между теорией и практикой на практике гораздо больше, чем в теории.
char mask = 0; if (! (BTN_PIN & BTN_LINE_UP)) mask = BTN_SHRT_UP; if (! (BTN_PIN & BTN_LINE_DN)) mask = BTN_SHRT_DN; if (! (BTN_PIN & BTN_LINE_POWER)) mask = BTN_SHRT_POWER; if (! (BTN_PIN & BTN_LINE_SW)) mask = BTN_SHRT_SW;
if (mask){ //опрос состояния кнопки if (BtnLockCoun < (BTN_LOCK_TIME/10)){ //клавиша нажата BtnLockCoun++; return; //защелка еще не дощитала - возврат } BtnLastState = mask; BtnLockBit =1; //нажатие зафиксировано if (BtnLongCoun >= (BTN_LONG_TIME/10)) return; //возврат, т.к. счетчик длинн нажат досчитал до максимума еще раньше if (++BtnLongCoun >= (BTN_LONG_TIME/10)) BtnFlags |= (BtnLastState<<4); //счетчик досчитал до максимума - устанавливаем биты длинного нажатия } else{ //клавиша отжата if (BtnLockCoun){ BtnLockCoun --; return; //защелка еще не обнулилась - возврат } if (! BtnLockBit) //СТАТИЧЕСКИЙ ВОЗВРАТ return; BtnLockBit =0; //отжатие зафиксировано if (BtnLongCoun < (BTN_LONG_TIME/10)) BtnFlags |= BtnLastState; //установка бита короткого нажатия BtnLongCoun = 0; //сброс счетчика длительности нажатия } } //----------****7SEG****---------- #define SEGA 6 #define SEGB 5 #define SEGC 1 #define SEGD 2 #define SEGE 3 #define SEGF 4 #define SEGG 0
#define ANOD1 4 #define ANOD2 7 #define ANOD3 4 //---------- void segchar (unsigned char seg) { switch (seg) { case 0: PORTC=(0<<SEGA)|(0<<SEGB)|(0<<SEGC)|(0<<SEGD)|(0<<SEGE)|(0<<SEGF)|(1<<SEGG);break; case 1: PORTC=(1<<SEGA)|(0<<SEGB)|(0<<SEGC)|(1<<SEGD)|(1<<SEGE)|(1<<SEGF)|(1<<SEGG);break; case 2: PORTC=(0<<SEGA)|(0<<SEGB)|(1<<SEGC)|(0<<SEGD)|(0<<SEGE)|(1<<SEGF)|(0<<SEGG);break; case 3: PORTC=(0<<SEGA)|(0<<SEGB)|(0<<SEGC)|(0<<SEGD)|(1<<SEGE)|(1<<SEGF)|(0<<SEGG);break; case 4: PORTC=(1<<SEGA)|(0<<SEGB)|(0<<SEGC)|(1<<SEGD)|(1<<SEGE)|(0<<SEGF)|(0<<SEGG);break; case 5: PORTC=(0<<SEGA)|(1<<SEGB)|(0<<SEGC)|(0<<SEGD)|(1<<SEGE)|(0<<SEGF)|(0<<SEGG);break; case 6: PORTC=(0<<SEGA)|(1<<SEGB)|(0<<SEGC)|(0<<SEGD)|(0<<SEGE)|(0<<SEGF)|(0<<SEGG);break; case 7: PORTC=(0<<SEGA)|(0<<SEGB)|(0<<SEGC)|(1<<SEGD)|(1<<SEGE)|(1<<SEGF)|(1<<SEGG);break; case 8: PORTC=(0<<SEGA)|(0<<SEGB)|(0<<SEGC)|(0<<SEGD)|(0<<SEGE)|(0<<SEGF)|(0<<SEGG);break; case 9: PORTC=(0<<SEGA)|(0<<SEGB)|(0<<SEGC)|(0<<SEGD)|(1<<SEGE)|(0<<SEGF)|(0<<SEGG);break; case 99: //OFF Все сегменты PORTC=(1<<SEGA)|(1<<SEGB)|(1<<SEGC)|(1<<SEGD)|(1<<SEGE)|(1<<SEGF)|(1<<SEGG);break; } }
void BtnUpdate(void) { ................................ ................................ ZoneNumber++; // !!!! здесь может вызваться обработчик INT0_vect??? Если да, то внимательно посмотрите, что произойдет!!!! if (ZoneNumber==6) { ZoneNumber=0; } .............................................. .............................................. }
Последний раз редактировалось viiv Пн окт 23, 2017 17:07:05, всего редактировалось 3 раз(а).
Обработчик прерываний асинхронный? т.е. может прервать программу в любом месте? Тогда посмотрите внимательно, что будет, если обработчик вызовится там, где у меня комментарий (при вызове обработчика ZoneNumber равняется 6).
2) unsigned char count = 0; // используется только в WriteSeg() - нет причин делать данную переменную глобальной; Ограничте видимость функцией WriteSeg(). Это не единственное, "видимость" чего желательно ограничить.
Насчет _delay_ms () знаю что не комильфо, но тот цикл используется всего лишь один раз при включении а более элегантного решения в голову не пришло (. Насчет всего остального спасибо еще немного покопаюсь в этом коде. А насчет 5того пункта компилятор не выдавал Warningов , хотя согласен логическое И правильней писать &&, странно что эти условия еще и работали.
Могут одновревенно стоять носколько бит? Если да, то (BtnMask == BTN_SHRT_UP) - неверно. Если нет, то и незачем определять, как маску - это сильно запутывет.
Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 31
Вы не можете начинать темы Вы не можете отвечать на сообщения Вы не можете редактировать свои сообщения Вы не можете удалять свои сообщения Вы не можете добавлять вложения