Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Библиотеки для STM32
Форум разработчиков электроники ELECTRONIX.ru > Микроконтроллеры (MCs) > ARM
Страницы: 1, 2, 3, 4, 5, 6, 7, 8
Alechek
Цитата(Forger @ Apr 7 2017, 21:08) *
Отсюда простой вопрос: зачем в имени указателя на класс указывать тот факт, что он указатель?
Приведите пример, где без этого никак не обойтись.

Обойтись всегда можно. Вопрос в последствиях. Которые я уже приводил
Код
memcpy( WorkData, InData, sizeof( WorkData));
memcpy(&WorkData, &InData, sizeof(*WorkData));

Наличие префикса сильно помогает в поиске таких багов.

Цитата(Forger @ Apr 7 2017, 21:08) *
Какой смысл каким-то образом выделять в имени переменных класса (правильно называть "поля" класса) их расовую принадлежность?
Приведите пример, где без этого никак не обойтись.
или хотя бы приведите пример, где необходимо выделения имени глобальной переменной?


Суть в том, чтобы было видно, что изменяется такая переменная, которая может использоваться вне тела функции.
И можно было не вникая и не подгружая ВЕСЬ проект, сказать что-то типа: чувак, вот ты зуб даешь, что ЭТУ переменную можно модифицировать неатомарно?
Forger
Цитата(Alechek @ Apr 7 2017, 19:31) *
Обойтись всегда можно. Вопрос в последствиях. Которые я уже приводил
Код
memcpy( WorkData, InData, sizeof( WorkData));
memcpy(&WorkData, &InData, sizeof(*WorkData));

Неужели наличие префиксов/суффиксов в переменных сильно помогает в поиске багов в таком "коде"? wink.gif

sizeof(WorkData) = 4 - размер указателя в байтах
чесс слово никогда не сталкивался с такой необходимостью - копировать указатель побайтно! smile3046.gif

Даже по пьяни я так не сумею написать, т.к. подобный код сам по себе есть рассадник багов на пустом месте - с memcpy нужно быть предельно аккуратным!


Цитата
Суть в том, чтобы было видно, что изменяется такая переменная, которая может использоваться вне тела функции.
И можно было не вникая и не подгружая ВЕСЬ проект, сказать что-то типа: чувак, вот ты зуб даешь, что ЭТУ переменную можно модифицировать неатомарно?

Для этого сделайте соотв. функции и обращайтесь к этой глабальной переменной ТОЛЬКО через эти функции, тогда этой переменной можно добавить static.
Внутри этих функций обеспечивайте атомарность.
Какой смысл это делать по всему коду, это если можно сделать в одном месте и в одном месте это отладить и проверить?
Alechek
Цитата(Forger @ Apr 7 2017, 21:44) *
Неужели наличие префиксов/суффиксов в переменных сильно помогает в поиске багов в таком "коде"? wink.gif

sizeof(WorkData) = 4 - размер указателя в байтах
чесс слово никогда не сталкивался с такой необходимостью - копировать указатель побайтно! smile3046.gif


Знаете, я тоже не сталкивался с НЕОБХОДИМОСТЬЮ копировать указатель побайтно. Но порой такое возникает вопреки желанию.
В этих 2-х строчках ошибки.

Смотрите чуть шире.
Forger
Цитата(Alechek @ Apr 7 2017, 20:57) *
В этих 2-х строчках ошибки.

Это не так - ошибки во ВСЕХ 4-х строчках sm.gif
https://electronix.ru/forum/index.php?s=&am...t&p=1491902

Ответьте наконец-то на этот вопрос, который тут уже прозвучал не раз: "Неужели наличие префиксов/суффиксов в переменных сильно помогает в поиске багов в таком "коде"?"
Alechek
ДА, помогает.

Более развернутый пример, как это случается.
Код
struct sdata
{
...
}

const struct sdata DefalutData = {1, 2};

void f(struct sdata * OutData)
{
...
//тра-ля-ля на строк 20-30 кода
...
  memcpy(OutData, &DefaultData, sizeof(DefautData); // тут сложно будеть выявить недостачу/переизбыток [?*]
  ...
  // дальнейшие манипуляции с OutData

}


повторю, это все равно упрощенный случай.
в конкретном случае можно было бы и обойтись
*OutData = DefaultData; // Хотя по мне так тоже некрасиво именовано.
Forger
Цитата(Alechek @ Apr 7 2017, 21:41) *
в конкретном случае можно было бы и обойтись
*OutData = DefaultData;

Так в чем проблема сразу сделать именно так?
Alechek
Цитата(Forger @ Apr 7 2017, 23:55) *
Так в чем проблема сразу сделать именно так?

3-я строчка снизу ответа выше.
Читать пока не поможет.
Forger
Я обратил внимание, что ваш код из примера по ходу развития этой темы неоднократно эволюционировал!
Прихожу к выводу, что вы все же прислушивались к постам участников, которые советовали как нужно изменить изначально кривой код. Это радует ))
В итоге пример перерос в то, чем он должен быть:
Код
*OutData = DefaultData;
(на названия переменных уже не обращаю внимание, в данном случае это не столь принципиально).

В этом случае при присвоении одной структуры другой неявно вызывается оператор копирования, внутри которого как раз и вызывается та самая memcpy, но вызывается с правильными параметрами.
Ошибиться в этом случае уже не получится - компилятор заругается. Цель достигнута! Бинго!

Однако, я никак не пойму вашего упорства .... впрочем, догадываюсь ))
Но это уже отдельный разговор и не для этой темы.
juvf
раз тут пошло обсуждение стилей.... спрошу тут...
в абдурино есть представление чисел в двоичной форме. например 0х82 выглядит в коде как-то так "b10000010". можно что-нибудь подобное макросами в си/с++ замутить?
Forger
Цитата(juvf @ Apr 18 2017, 09:03) *
раз тут пошло обсуждение стилей.... спрошу тут...
в абдурино есть представление чисел в двоичной форме. например 0х82 выглядит в коде как-то так "b10000010".

Это - анахронизм, оставшийся в наследство от ассемблера или некоторых с-компиляторов (я сам таким грешил на PIC-контроллерах, в свое время).
Лишь еще один способ представления "магических чисел".
В чистом коде не должно быть "магических" чисел!
Их все заменяют осмысленными #define, которые стараются размещать в одном месте.
Битовые же поля удобно упаковывать в структуры. Все современные компиляторы поддерживают безымянные union. Это позволяет к одним и тем же полям в структуре обращаться побитово или сразу словом.

Если же речь идет о прямом обращении к регистрам ARM проца, то под каждый такой проц. уже давно существуют соотв. файлы, где все биты регистров названы человеческими именами.

з.ы С одной стороны хорошо, что существует Arduino - значительно легче влиться в эту профессию, а с другой - он тянет кучу вредных привычек, от которых потом сложно переучиваться.
ViKo
Есть одно место, где двоичная кодировка рулит - нарисовать свой шрифт для ЖКИ. Я так делал. Еще и в четверичной системе делал, когда одна точка была представлена двумя битами. В данном форуме этих макросов выкладывалось не однажды.
Читая форум, копирую интересующие меня куски программ в файл. Кое от чего уже можно и избавиться. Можно еще и ссылки копировать.
Forger
Цитата(ViKo @ Apr 18 2017, 09:24) *
Есть одно место, где двоичная кодировка рулит - нарисовать свой шрифт для ЖКИ. Я так делал.

В настоящее время и в этом нет нужды - существует масса прог, которые сами формируют С-файл из нужного или нового/подправленного шрифта.
Тоже самое касается картинок.
Reflector
Цитата(juvf @ Apr 18 2017, 09:03) *
в абдурино есть представление чисел в двоичной форме. например 0х82 выглядит в коде как-то так "b10000010". можно что-нибудь подобное макросами в си/с++ замутить?

В C++ можно писать 0b10000010, если компилятор не сильно старый.
juvf
Цитата(Forger @ Apr 18 2017, 11:16) *
Это - анахронизм
я б так не сказал.... в современном verilog он есть.

Цитата
все заменяют ... #define
а может действительно, сгенерировать хидер и там 256 (или 2^16) дефайнов определить. сп за идею

Цитата
Все современные компиляторы поддерживают безымянные union. Это позволяет к одним и тем же полям в структуре обращаться побитово или сразу словом.
да, но только это обращение "долгое". гораздо быстрее с константами работать, чем из юниона вытаскивать битики.

Цитата(Reflector @ Apr 18 2017, 11:50) *
В C++ можно писать 0b10000010, если компилятор не сильно старый.
Вкатило. То что нужно. СПАСБО!!!!
ViKo
Код
/* Макро для использования двоичного формата чисел */
#define _BITSET(bits) \
  ((uint16_t) ( \
  (bits % 010) | \
  (bits / 010 % 010) << 1 | \
  (bits / 0100 % 010) << 2 | \
  (bits / 01000 % 010) << 3 | \
  (bits / 010000 % 010) << 4 | \
  (bits / 0100000 % 010) << 5 | \
  (bits / 01000000 % 010) << 6 | \
  (bits / 010000000 % 010) << 7 | \
  (bits / 0100000000 % 010) << 8 | \
  (bits / 01000000000 % 010) << 9 | \
  (bits / 010000000000 % 010) << 10 | \
  (bits / 0100000000000 % 010) << 11 | \
  (bits / 01000000000000 % 010) << 12 | \
  (bits / 010000000000000 % 010) << 13 | \
  (bits / 0100000000000000 % 010) << 14 | \
  (bits / 01000000000000000 % 010) << 15))
#define BIN(bits) _BITSET(0##bits)

/* Макро для использования четверичного формата чисел */
#define _PAIRSET(digits) \
  ((uint16_t) ( \
  (digits % 010) | \
  (digits / 010 % 010) << 2 | \
  (digits / 0100 % 010) << 4 | \
  (digits / 01000 % 010) << 6 | \
  (digits / 010000 % 010) << 8 | \
  (digits / 0100000 % 010) << 10 | \
  (digits / 01000000 % 010) << 12 | \
  (digits / 010000000 % 010) << 14))
#define QUAD(digits) _PAIRSET(0##digits)
Forger
Цитата(juvf @ Apr 18 2017, 10:05) *
я б так не сказал.... в современном verilog он есть.

А при чем тут verilog????

Цитата
а может действительно, сгенерировать хидер и там 256 (или 2^16) дефайнов определить. сп за идею

Если в коде есть такое огромное число магических чисел, то могу только посочувствовать ....

Цитата
да, но только это обращение "долгое". гораздо быстрее с константами работать, чем из юниона вытаскивать битики.

У меня в подъезде на всех этажах уже более двух лет стоят светодиодные лампочки, включаются от датчиков приближения и автоматически гаснут.
Так находятся чудаки, которые выключают эти лапочки (выключатель на первом этаже).
Ради интереса я посчитал в сколько обходятся электричество на все эти лампочки - менее 50 коп. на квартиру в мес! .... так и разориться недолго! wacko.gif
Reflector
Цитата(juvf @ Apr 18 2017, 10:05) *
Вкатило. То что нужно. СПАСБО!!!!

Там еще можно разделитель вставлять, например, 0b1000'0010, 0x1234'4567.
juvf
2ViKo для си подойдёт. спасибо

Цитата(Reflector @ Apr 18 2017, 13:39) *
Там еще можно разделитель вставлять, например, 0b1000'0010, 0x1234'4567.

вообще зачет!!! как в верилоге!

Цитата(Forger @ Apr 18 2017, 12:18) *
У меня в подъезде на всех этажах уже более двух лет стоят светодиодные лампочки, включаются от датчиков приближения и автоматически гаснут.
Так находятся чудаки, которые выключают эти лапочки (выключатель на первом этаже).
Ради интереса я посчитал в сколько обходятся электричество на все эти лампочки - менее 50 коп. на квартиру в мес! .... так и разориться недолго! wacko.gif
пфффф.... так заказчик хочет конфетку получить в процессоре за 36.55 рублей (пруфлинк). Лишний рубль заложить в проц - проиграть конкурентам. Приходиться каждый такт процессора экономить и каждый байт флеша.

Цитата
А при чем тут verilog????
Анахронизм - в переносном смысле — что-либо несовременное, пережиток старины. В старом си не помню двоичного представления. в современных языках HD, такие как верилог такое есть. даже в с++ есть (как оказалось).

Иногда приходиться работать с двоичным представлением. удобнее видеть 0b1100'1000, чем MY_DEFINE.
Reflector
Цитата(juvf @ Apr 18 2017, 12:29) *
Анахронизм - в переносном смысле — что-либо несовременное, пережиток старины. В старом си не помню двоичного представления. в современных языках HD, такие как верилог такое есть. даже в с++ есть (как оказалось).

Бинарные литералы появились в С++14, Java 7 и ,совсем недавно, в C# 7, так что можно сказать их использование наоборот является современной тенденцией sm.gif
Forger
Цитата(Reflector @ Apr 18 2017, 12:59) *
Бинарные литералы появились в С++14, Java 7 и ,совсем недавно, в C# 7, так что можно сказать их использование наоборот является современной тенденцией sm.gif


Пророчество сбывается, скоро исходники будут выглядеть вот так. И лишь "избранные" смогут их читать и отлаживать lol.gif
Нажмите для просмотра прикрепленного файла

Цитата(juvf @ Apr 18 2017, 12:29) *
пфффф.... так заказчик хочет конфетку получить в процессоре за 36.55 рублей

Речь не про мк, а про код, который в нем крутится.
Я сильно сомневаюсь, что вы будете брать тонкий проц и пытаться в него втоптать толстую прогу.
Обычно, делают наоборот - сначала решают задачу на любом проце, который более-менее подходит под задачу с запасом!, а уже потом оптимизирует, и то, если в этом есть нужда.
С устойчивым соблазном оптимизации (вылизывания) кода ДО его отладки нужно бороться еще с пеленок будущего программера sm.gif

Экономить чужие деньги - самый страшный грех любого разработчика, т.к. подобный "альтруизм" ВСЕГДА оборачивается массой геморроя со стороны заказчика, который настаивает на такой "экономии на спичках".
Вообще, советую обходить стороной такого заказчика, т.к. в 99,9% случаев выяснится он не знает чего хочет, что в итоге печально кончится для разработчика - мозг бедолаги полностью потеряет свою функциональность cranky.gif

Опытный разработчик в первую очередь экономит СВОИ деньги и СВОЕ время, что косвенно приводит к экономической выгоде заказчика:
чистый код не тот, который чистят, а тот, который изначально не был испачкан ... битовыми литералами и т.п. магическими числами sm.gif
juvf
Цитата(Forger @ Apr 18 2017, 16:01) *
Я сильно сомневаюсь, что вы будете брать тонкий проц и пытаться в него втоптать толстую прогу.
так и есть....
Цитата
сначала решают задачу на любом проце, который более-менее подходит под задачу с запасом!, а уже потом оптимизирует, и то, если в этом есть нужда.
так и есть.... сначала сделано на жирном ките... потом оптимизация/заталкиванеи в тонкий проц. И второе, где такую оптимизачию пришлось делать, это когда не в тонкий проц заказчик попросил добавить функционал... но там уже под завязку... и надо чуть дожать... а переход на более жирный проц - не есть хорошо, ибо это плодить номенклатуру.

Цитата
Экономить чужие деньги - самый страшный грех любого разработчика
я их не экономлю. Мне дают ТЗ - я выполняю. Мне дают новое ТЗ - выполняю.... Имею хлеб с маслом. А с вашей философией....
Код
чистый код не тот, который чистят, а тот, который изначально не был испачкан ... битовыми литералами и т.п. магическими числами
Это вы пачкаете форум своей философией. Вам же говорят - они появляются/есть в современных языках. Значит они востребованы. Так-то можно сказать, что 0х81 (шестнадцатеричные литералы) - магические цифры, которые пачкают код. Чем "х" лучше "b"? Вам не удобно битовые литералы - не пользуйте. Какие проблемы?



Forger
Цитата
так и есть.... сначала сделано на жирном ките... потом оптимизация/заталкиванеи в тонкий проц.
А кто принимал решение ставить такой "тонкий проц"?

Цитата
не есть хорошо, ибо это плодить номенклатуру.

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

Цитата
я их не экономлю. Мне дают ТЗ - я выполняю. Мне дают новое ТЗ - выполняю....

Тогда все выше относится не к вам, а к тому, кто эти ТЗ составляет для вас.
Впрочем, если вас устраивает такое положение - втаптывать толстый код в тонкий проц, то это уже другое дело - © "Ежики кололись, но все равно ели кактус"

Цитата
Вам же говорят - они появляются/есть в современных языках. Значит они востребованы.
... среди индусов, которые пишут куб для st biggrin.gif

Цитата
А с вашей философией.... Это вы пачкаете форум своей философией.

Цитата
Вам не удобно битовые литералы - не пользуйте. Какие проблемы?

Коли вам не по душе моя "философия", игнорируйте, какие проблемы? wink.gif

Цитата
Так-то можно сказать, что 0х81 (шестнадцатеричные литералы) - магические цифры, которые пачкают код. Чем "х" лучше "b"?

Вы правы! Это магические числа.
А раз нет разницы, ток какой смысл использовать разные методы написания этих чисел?

Reflector
Цитата(Forger @ Apr 18 2017, 14:01) *
Пророчество сбывается, скоро исходники будут выглядеть вот так. И лишь "избранные" смогут их читать и отлаживать lol.gif

Для примера, у меня вот такая инициализация портов для FSMC:
Код
GpioD<0xC8B3>(PinMode::AF_PushPull_VeryHighSpeed, 12);
GpioE<0x0780>(PinMode::AF_PushPull_VeryHighSpeed, 12);

Т.к. пины там жестко привязаны, то меня такая форма записи абсолютно не напрягает, но при желании можно маску пинов перевести в бинарный вид:
Код
GpioD<0b1100'1000'1011'0011>(PinMode::AF_PushPull_VeryHighSpeed, 12);

Или расписать более подробно, как обычно и делают:
Код
const uint32_t FSMC_PD = GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_4 | GPIO_Pin_5 | GPIO_Pin_7 | GPIO_Pin_11 | GPIO_Pin_14  | GPIO_Pin_15;
GpioD<FSMC_PD>(PinMode::AF_PushPull_VeryHighSpeed, 12);

Лучше ли последняя форма первых двух? Не уверен sm.gif
Forger
Цитата(Reflector @ Apr 18 2017, 16:47) *
Для примера, у меня вот такая инициализация портов для FSMC:
Код
GpioD<0xC8B3>(PinMode::AF_PushPull_VeryHighSpeed, 12);
GpioE<0x0780>(PinMode::AF_PushPull_VeryHighSpeed, 12);


Т.к. пины там жестко привязаны, то меня такая форма записи абсолютно не напрягает, но при желании можно маску пинов перевести в бинарный вид:
Код
GpioD<0b1100'1000'1011'0011>(PinMode::AF_PushPull_VeryHighSpeed, 12);

Хрен редьки не слаще - как было нифига не понятно, что значат эти магические числа, так оно и осталось. sm.gif
Битовые литералы тут как собаке - пятая нога )))


Цитата
Или расписать более подробно, как обычно и делают:
Код
const uint32_t FSMC_PD = GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_4 | GPIO_Pin_5 | GPIO_Pin_7 | GPIO_Pin_11 | GPIO_Pin_14  | GPIO_Pin_15;
GpioD<FSMC_PD>(PinMode::AF_PushPull_VeryHighSpeed, 12);

Мне такой вариант вообще не по душе, поэтому накидал свой класс Pin.hpp (для каждого семейства процов он разный):


CODE
.............
typedef enum
{
PA0, PA1, PA2, PA3, PA4, PA5, PA6, PA7, PA8, PA9, PA10, PA11, PA12, PA13, PA14, PA15,
PB0, PB1, PB2, PB3, PB4, PB5, PB6, PB7, PB8, PB9, PB10, PB11, PB12, PB13, PB14, PB15,
PC0, PC1, PC2, PC3, PC4, PC5, PC6, PC7, PC8, PC9, PC10, PC11, PC12, PC13, PC14, PC15,
PD0, PD1, PD2, PD3, PD4, PD5, PD6, PD7, PD8, PD9, PD10, PD11, PD12, PD13, PD14, PD15,
PE0, PE1, PE2, PE3, PE4, PE5, PE6, PE7, PE8, PE9, PE10, PE11, PE12, PE13, PE14, PE15,
PF0, PF1, PF2, PF3, PF4, PF5, PF6, PF7, PF8, PF9, PF10, PF11, PF12, PF13, PF14, PF15,
PH0, PH1, PH2, PH3, PH4, PH5, PH6, PH7, PH8, PH9, PH10, PH11, PH12, PH13, PH14, PH15,
} PIN;

.................

class PinBase
{
public:
PinBase(PIN pin)
{
portIndex = pin / 16;
pinIndex = pin % 16;
pinMask = (((UNSIGNED32)1) << pinIndex);
.....
}

.....

inline void setToHigh(void) { port->BSRRL = pinMask; }
inline void setToLow(void) { port->BSRRH = pinMask; }
inline bool isHigh(void) { return (((port->IDR) & pinMask) != 0); }
inline bool isLow(void) { return (((port->IDR) & pinMask) == 0); }
inline void toggle(void) { port->ODR ^= pinMask; }

protected:
volatile GPIO_TypeDef * port;
volatile UNSIGNED8 portIndex;
volatile UNSIGNED8 pinIndex;
volatile UNSIGNED32 pinMask;
};

...............

template <PIN pin>
class Pin : public PinBase
{
public:
Pin(void) : PinBase(pin) { }
};

..........

template <PIN pin>
class DigitalOutputPin : public PinBase
{
public:
DigitalOutputPin(void) : PinBase(pin)
{
setAsDigitalOutput();
setAsPushPull();
setOutputSpeed40MHz();
}
};

.......................

template <PIN pin>
class LedOpenDrain : public PinBase
{
public:
LedOpenDrain(void) : PinBase(pin)
{
setAsDigitalOutput();
setAsOpenDrain();
setOutputSpeed10MHz();
off();
}

void on(void) { setToLow(); }
void off(void) { setToHigh(); }
};

........




Все привязки пинов описаны в одном файле, так удобнее изменять привязку портов при смене камня и просто при переносе кусков кода из проекта в проект:

CODE
......
// EXTERNAL ADC
#define PIN_ADC_CONVST (PB14)
#define PIN_ADC_SCLK (PB13)
#define PIN_ADC_DATA (PC6)

// LEDS
#define PIN_LED_GREEN (PB6)
#define PIN_LED_RED (PB5)

......





Вот так применяю:
*.hpp:
Код
    class ExternalDAC
    {
    public:
        void initialize(void);
        void setVoltage(FLOAT32 voltage);
        FLOAT32 getVoltage(void) const { return (voltage); }

    private:
        DigitalOutputPin<PIN_DAC_CS>     pinCS;
        DigitalOutputPin<PIN_DAC_SCK>     pinSCK;
        DigitalOutputPin<PIN_DAC_MOSI>     pinMOSI;
        FLOAT32 voltage;
    };


*.cpp
Код
void ExternalDAC::initialize(void)
{
    pinCS.setToHigh();
    pinSCK.setToHigh();
    pinMOSI.setToLow();
}
juvf
Цитата(Forger @ Apr 18 2017, 17:22) *
А вы считали, что выгоднее - чуток раздуть номеклатуру или мудохаться с отладкой и утаптыванием кода в тонкий проц в ущерб читаемости и переносимости этого кода?
Всему есть своя цена, главное - как можно раньше выяснить ее.
Вот меня всегда поражают подобные персонажи. А вы мой проект считали? Я считал. Дешевле написать тонкий код и засунуть его в дешевый процессор, чем писать жир и требовать проц жирнее... Вы от куда знаете всю ситуацию? Я не мудохаюсь с кодом.... и ни чего ни куда не втаптываю. Ни какого ущерба читаемости нет. Битовые литералы - испокон веков используются на МК. Их пофиксили при переходе с асма на си. Не потому что 0х82 удобнее, а потому что си не поддерживал двоичную запись. Сейчас возвращяют литералы в языки высокого уровня.
Цитата
"Ежики кололись, но все равно ели кактус"
я не колюсь. это вы походу чем-то колитесь wink.gif меня не напрягают литералы. меня отсутствие литерала b напрягало.

А почему такая агрессия? Тролль что-ли? Ну не нравятся литералы - ну не используйте.


Цитата
накидал свой класс Pin.hpp (для каждого семейства процов он разный)
Ха.... дружище... всё с вами понятно.... типичный оверинженеринг.... и вы считаете, что такой код прозрачен, что его стороннему программисту легко поддерживать и разобраться? ))))))))))))

я проще делаю...
определение и объявление примерно так
#define csOn() (GPIOA->BSRR = GPIO_Pin_4_BR)
использование
csOn();

ps да, увидел у вас обращение к port->BSRR, но не увидел инициализацию указателя *port.

pps
Цитата
Раком оверинжиниринга отрасль охвачена, пожалуй, полнее, чем рынок — быдлодевайсами, а телевизор — зомбопрограммами. Она охвачена им практически вся. Результаты, собственно, печальны и наблюдаемы невооружённым глазом. Умирающий от ожирения код пишется визуально генерируется умирающими от ожирения средствами разработки, а количество багов в результате просто астрономическое (преподносится этот бред как «средства, помогающие минимизировать людские ошибки» — быдломенеджеры по внедрению верят буклетам больше, чем визуально наблюдаемой картине). Скорость достижения результата тоже прямо противоположна заявам (на ассемблере и то было бы быстрее написать). Вопрос «нахуя?» "зачем?" вызывает в ответ тонны шизофазии про «прогрессивные методы и смелый взгляд в будущее». Запасаемся попкорном и ждём прорыва этого гнойника.
(С)
Forger
Цитата(juvf @ Apr 18 2017, 18:15) *
Вот меня всегда поражают подобные персонажи. А вы мой проект считали? Я считал. Дешевле написать тонкий код и засунуть его в дешевый процессор, чем писать жир и требовать проц жирнее...
Вы от куда знаете всю ситуацию?

Не знаю, поэтому и задал вопросы (см. внимательнее ))
"А почему такая агрессия"?

Цитата
Я не мудохаюсь с кодом.... и ни чего ни куда не втаптываю. Ни какого ущерба читаемости нет.
Битовые литералы - испокон веков используются на МК.

Поправляю - использовались, в настоящее время в существующем недревнем коде их уже не встретишь,
но подобный подход можно встретить лишь у программеров, которые пересели с асм и PIC/AVR на более серьезные камни,
но остались по-прежнему в тех далеких временах ...

Цитата
Их пофиксили при переходе с асма на си. Не потому что 0х82 удобнее, а потому что си не поддерживал двоичную запись.

В те времена, этого действительно не хватало, т.к. народ переползал с asm на си, длительное время сохраняя идеологию мышления asm.
Да и к тому же о "чистоте кода", "принципах именования" и т.п. в помине не было - каждый писал как привык. Даже goto использовали! cranky.gif
Но те времена давно ушли, кто-то остался в тех временах, а кто-то движется вперед ... sm.gif

Цитата
Сейчас возвращяют литералы в языки высокого уровня.
Причина тут очевидная - нытье "ассемблерщиков" утомило разработчиков стандарта, вот они и сжалились santa2.gif

Цитата
меня не напрягают литералы. меня отсутствие литерала b напрягало.

D свое время я тоже пересел с ассемблера, где без битовых литералов ну просто делать нечего.
И уход на С, где битовых литералов не было, я воспринимал весьма болезненно, поэтому понимаю вас, одно время спасало, что в С-компиляторе для PIC они все же были,
но, к счастью, в свое время я переболел это "недуг" ("закодировался" )))), и теперь мне уже до лампочки наличие или отсутствие этих битовых литералов.
Ни капельки не тянет, даже когда теперь они есть sm.gif

Цитата
А почему такая агрессия?

Извиняюсь, если показался агрессивным ))
juvf
ppps вопрос скорее риторический.... зачем использовать UNSIGNED32 или BYTE, WORD, U32 и т.п. поделки? есть же uint32_t, uint16_t и т.д. Это тоже относится к переносимости кода.

pppps
Цитата
Код
void ExternalDAC::initialize(void)

если пишете на с++, так уж пишите на с++
Код
void ExternalDAC::initialize()


Цитата(Forger @ Apr 18 2017, 20:40) *
в настоящее время в существующем недревнем коде их уже не встретишь,
но подобный подход можно встретить лишь у программеров, которые пересели с асм и PIC/AVR на более серьезные камни,
в современных HD языках это есть и было всегда. Есть места где удобно b. Это не только GPIO порты.... не только битовые поля. В ЦОС иногда это очень даже полезно.
Эдди
Цитата(Forger @ Apr 18 2017, 18:40) *
Даже goto использовали!

Что за нафиг? Без goto невозможно писать ни на С, ни на цепепе! Как вы из вложенных циклов будете выходить? Или деструкторы в случае ошибок вызывать?
В подавляющем большинстве случаев если goto позволяет упростить читаемость кода, я использую goto.
А некоторые еще и обработчики ошибок через longjump реализуют!!!

Цитата(juvf @ Apr 18 2017, 18:50) *
Есть места где удобно b.

К сожалению, gcc их не умеет. А было бы удобно, конечно. Правда, в случае 32-битных регистров удобство уже сомнительно, но с 8/16 все ОК.
Forger
Цитата(juvf @ Apr 18 2017, 18:50) *
если пишете на с++, так уж пишите на с++

В данном случае это непринципиально, хотя некоторые С++ компиляторы видят в этом разницу:
http://stackoverflow.com/questions/693788/...292431#36292431

Цитата
в современных HD языках это есть и было всегда. Есть места где удобно b. Это не только GPIO порты.... не только битовые поля.

Если без них никак не удается сделать читаемый и переносимый код, ради бога, используйте на здоровье )))

Цитата
В ЦОС иногда это очень даже полезно.

Дык, ЦОС обычно используют как суровую числодробилку со своими узкоспециализированными задачами.
Это другой мир с иными правилами и порядками.
Впрочем, к битовым литералам это не имеет отношения.







Цитата(Эдди @ Apr 18 2017, 18:57) *
Без goto невозможно писать ни на С, ни на цепепе!

Я вам искренне сочувствую, чесс слово, аж самому взгруснулось crying.gif


Цитата
Правда, в случае 32-битных регистров удобство уже сомнительно, но с 8/16 все ОК.

Вот и я о том же - в 8-битниках периферия элементарнее некуда, там в целом без разница как писать - с битовыми литералами или без, все одно комментировать придется каждое такое обращение.
Reflector
Цитата(Forger @ Apr 18 2017, 17:08) *
Хрен редьки не слаще - как было нифига не понятно, что значат эти магические числа, так оно и осталось. sm.gif
Битовые литералы тут как собаке - пятая нога )))

Мне такой вариант вообще не по душе, поэтому накидал свой класс Pin.hpp (для каждого семейства процов он разный):

А я думаешь чьим классом пользуюсь? sm.gif Тоже взял и написал, один для пина, как у тебя, второй для порта целиком. И что там может быть непонятного, аж целых два числа, маска для пинов и в конце необязательный параметр для AF. Ладно тут еще был 8 бит FSMC, а для 16 бит уже нужно 20 ног проинитить, предлагаешь это делать 20 раз для каждого отдельного пина?

Касательно твоего класса... Я видел более старую реализацию, там в базовом классе хранился только порт и маска, теперь еще индексы порта и пина, это 10 байт на пин, которые округлятся до 12. Никаких переменных там не должно быть в принципе, порт и номер пина передаются в базовый класс как параметры шаблона, у меня это выглядит так:
Код
template<uint32_t gpio, uint32_t pin, uint32_t af_>
struct PinT
{
    static auto base() { return (GPIO_TypeDef*)gpio; }

    PinT() {}
    PinT(PinMode mode) { init(mode); }
.....
    static void write(bool data) { base()->BSRR = (0x10000 << pin) | (data << pin); }
};

template<uint32_t pin, uint32_t af_ = 0>
using PinA = PinT<GPIOA_BASE, pin, af_>;

template<uint32_t pin, uint32_t af_ = 0>
using PinB = PinT<GPIOB_BASE, pin, af_>;
....

Код
PinA<5>  redLed;  // хоть глобально, код еще не генерится
....
redLed.init(PinMode::PushPull_HighSpeed);
redLed.set();


Цитата
Все привязки пинов описаны в одном файле, так удобнее изменять привязку портов при смене камня и просто при переносе кусков кода из проекта в проект:

Хорошо, возьмем твой класс ExternalDAC, я бы мог просто сделать его шаблонным:
Код
ExternalDAC<PinA<5>, PinA<6>, PinA<7>> externalDAC;

Но т.к. под SPI такой класс уже есть, то скорее всего я передам именно его, т.к. это избавляет от написания лишнего кода:
Код
using spi1 = Spi1<PinA<5>, PinA<6>, PinA<7>>;
ExternalDAC<spi1> externalDAC;

И зачем мне какие-то дефайны в другом файле, где все свалено в кучу? Какие используются пины видно прямо в месте создания экземпляра класса, я это место легко найду.
Эдди
Интересно дизассемблер этого цепепешного ужаса глянуть. Неужто оптимизирует?
Forger
Цитата(Reflector @ Apr 18 2017, 19:10) *
А я думаешь чьим классом пользуюсь? sm.gif
sm.gif

Цитата
для 16 бит уже нужно 20 ног проинитить, предлагаешь это делать 20 раз для каждого отдельного пина?

Нет, достаточно наследовать от Pin нужный класс и сделать в нем соотв. инициализацию, и уже создавать экземпляры этого класса.
Все просто ))
У меня так сделаны DigitalOutputPin, LedOpenDrain, DigitalInputPin, AnalogInputPin
В некоторые из низ добавлены дополнительные методы, расширяющие возможности "голого" Pin.

Цитата
Касательно твоего класса... Я видел более старую реализацию, там в базовом классе хранился только порт и маска, теперь еще индексы порта и пина, это 10 байт на пин, которые округлятся до 12. Никаких переменных там не должно быть в принципе, порт и номер пина передаются в базовый класс как параметры шаблона

В этом случае на каждый такой экземпляр Pin инстанцируется свой класс со своим объектным кодом. Т.к. код растет не по-децки.
Поэтому я сделал базовый класс с уже реализованными общими методами. 12-байт - это фигня, с ОЗУ проблем нет.
А уже от него наследую шаблонный класс с параметрами, которые как-то нужно передать в базовый.
Экономия кода, но не озу.

Цитата
Хорошо, возьмем твой класс ExternalDAC, я бы мог просто сделать его шаблонным:

В данном случае он не нужен шаблонный, т.к. spi программный и уникальный для данного применения (внешний ЦАП со своими тараканами).
Поэтому класс объявлен внутри другого класса в поле private. Здесь я просто не стал это показывать.

Цитата
И зачем мне какие-то дефайны в другом файле, где все свалено в кучу? Какие используются пины видно прямо в месте создания экземпляра класса, я это место легко найду.

Мне совершенно до лампочки, какие именно пины используются в месте объявления классов пинов, для чтения и отладки кода это не имеет значения.
Т.к. при отладки железа смотрю на схему и вижу имена цепей, которые совпадают с человеческими названия пинов в коде, а не некими PAx, PBy и т.п.
В самой схеме девайса цепи, которые идут к пинам, у меня называются точно также, как в это едином для всех пинов файле.

А пишу в одном месте для ВСЕГО проекта, так мне таким образом проще переносить код, править приходится только в одном месте.
Мне так удобнее, иначе пришлось прыгать от исходника к исходнику. Полагаю, что тут во многом дело привычки.
Reflector
Цитата(Эдди @ Apr 18 2017, 19:20) *
Интересно дизассемблер этого цепепешного ужаса глянуть. Неужто оптимизирует?

Есть такой код:
Код
GpioD<0b0011'1111'1100> pd;
volatile uint32_t data = 59;
pd.writeAligned(data);

Я не рассматриваю настройку порта на вывод, только функцию writeAligned, которая пишет data в порт, со сдвигом, так чтобы попасть в окно из 8 бит указанных в маске, т.е. там вызывается рекурсивная функция которая проверяет биты маски начиная с нулевого, пока не встретит 1, и потом перед записью сдвигает на нужную величину data, в данном случае на 2. Что у нас на выходе?
Код
0x200008d0  ldr r3, [sp, #4]
0x200008d2  ldr r4, [pc, #184]
0x200008d4  lsls r3, r3, #2
0x200008d6  orr.w r3, r3, #66846720
0x200008da  str r3, [r4, #24]

Точно такой же выхлоп у строки, где нужный сдвиг вычислен самостоятельно. А чистый С да, нагенерит в разы больше.
Код
GPIOD->BSRR = (0x03FC << 16) | (data << 2);

Идем дальше, установим для наших 8 бит AF в 5:
Цитата
pd.altFunc(5);

Получаем
Код
0x200008d0  ldr r4, [pc, #200]; (0x2000099c <main()+340>)
0x200008d2  ldr r3, [r4, #32]
0x200008d4  uxtb r3, r3
0x200008d6  orr.w r3, r3, #1426085120; 0x55005500
0x200008da  orr.w r3, r3, #5570560; 0x550000
0x200008de  str r3, [r4, #32]
0x200008e0  ldr r3, [r4, #36]; 0x24
0x200008e2  bic.w r3, r3, #255; 0xff
0x200008e6  orr.w r3, r3, #85; 0x55
0x200008ea  str r3, [r4, #36]; 0x24

Больше, но и регистра тут уже два. Сама функция:
Код
static void altFunc(uint32_t af)
{
    if (pinsMask & 0x00FF)  base()->AFR[0] = base()->AFR[0] & ~qmask(pinsMask) | (qmul(af) & qmask(pinsMask));
    if (pinsMask & 0xFF00)  base()->AFR[1] = base()->AFR[1] & ~qmask(pinsMask >> 8) | (qmul(af) & qmask(pinsMask >> 8));
}

static constexpr uint32_t _Os_ qmask(uint32_t val, uint32_t outVal = 0, int cnt = 8)
{
    return cnt ? qmask(val >> 1, (val & 1) ? (outVal >> 4) | 0xF0000000 : outVal >> 4, cnt - 1) : outVal;
}

static constexpr _Os_ uint32_t qmul(uint32_t af) _always_inline_
{
    return af | (af << 4) | (af << 8) | (af << 12) | (af << 16) | (af << 20) | (af << 24) | (af << 28);
}


Цитата(Forger @ Apr 18 2017, 19:30) *
Нет, достаточно наследовать от Pin нужный класс и сделать в нем соотв. инициализацию, и уже создавать экземпляры этого класса.
Все просто ))
У меня так сделаны DigitalOutputPin, LedOpenDrain, DigitalInputPin, AnalogInputPin
В некоторые из низ добавлены дополнительные методы, расширяющие возможности "голого" Pin.

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

Цитата
В этом случае на каждый такой экземпляр Pin инстанцируется свой класс со своим объектным кодом. Т.к. код растет не по-децки.
Поэтому я сделал базовый класс с уже реализованными общими методами. 12-байт - это фигня, с ОЗУ проблем нет.
А уже от него наследую шаблонный класс с параметрами, которые как-то нужно передать в базовый.
Экономия кода, но не озу.

Создаю новый проект, пишу следующий код:
Код
PinA<3>(PinMode::AF_OpenDrain_HighVerySpeed);
PinB<6>(PinMode::PushPull_HighSpeed);
PinC<14>(PinMode::OpenDrain_MediumSpeed);

Первая функция добавляет 100 байт, каждая последующая по 22. ОЗУ, как уже говорилось, ноль. А у тебя сколько? Про куб вообще молчу sm.gif

Цитата
В данном случае он не нужен шаблонный, т.к. spi программный и уникальный для данного применения (внешний ЦАП со своими тараканами).
Поэтому класс объявлен внутри другого класса в поле private. Здесь я просто не стал это показывать.

Было два варианта, или передаешь пины в класс SPI, или прямо в ExternalDAC, суть не меняется. У меня есть шаблонный класс для работы с DS18B20, он принимает два шаблонных класс DMA и один USART, в последний, в свою очередь, можно передавать шаблонные классы пинов sm.gif

Цитата
А пишу в одном месте для ВСЕГО проекта, так мне таким образом проще переносить код, править приходится только в одном месте.
Мне так удобнее, иначе пришлось прыгать от исходника к исходнику. Полагаю, что тут во многом дело привычки.

Конечно много зависит от привычки, но это не отменяет того факта, что привычки могут быть вредными sm.gif
juvf
Цитата(Forger @ Apr 18 2017, 21:05) *
В данном случае это непринципиально, хотя некоторые С++ компиляторы видят в этом разницу:
http://stackoverflow.com/questions/693788/...292431#36292431
При чем тут чьи-то форумы? Открываем стандарт, читаем, пользуемся.

Код
Я вам искренне сочувствую, чесс слово, аж самому взгруснулось :crying:
2Эдди есть костыльные методы для выхода из глубоких вложенных циклов.... но пока нет равнозначной альтернативы готу. но это отдельный холивар )))

Цитата
в целом без разница как писать - с битовыми литералами или без
+1
Forger
Цитата(Reflector @ Apr 18 2017, 21:13) *
Создаю новый проект, пишу следующий код:
Код
PinA<3>(PinMode::AF_OpenDrain_HighVerySpeed);
PinB<6>(PinMode::PushPull_HighSpeed);
PinC<14>(PinMode::OpenDrain_MediumSpeed);

Первая функция добавляет 100 байт, каждая последующая по 22. ОЗУ, как уже говорилось, ноль. А у тебя сколько?


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

А как у тебя работает ногодрыг? Покажи асм код, когда попеременно дергаешь пин (переключать несколько раз подряд, но не в цикле)

Цитата
Про куб вообще молчу sm.gif

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

Цитата
Было два варианта, или передаешь пины в класс SPI, или прямо в ExternalDAC, суть не меняется.

Мой проект, где используется ExternalDAC, не требует такой широкой абстракции, но она появится, если эта сущность (ExternalDAC) потребует этого.
Как только появляются общие вещи, я выношу их в отдельный общий каталог Projects/Common/... (разумеется, под SVN).
Но пока есть сомнения в такой необходимости, сущность остается в приватной секции соотв. класса, которой она принадлежит.

Цитата
У меня есть шаблонный класс для работы с DS18B20, он принимает два шаблонных класс DMA и один USART, в последний, в свою очередь, можно передавать шаблонные классы пинов sm.gif

Ничто не мешает в мое случае передавать не шаблон, а ссылку на базовый класс PinBase.
В этом случае нет привязки к конкретной специализации шаблона.
Мои познания в плюсах хоть и не плохие, но практика пока хромает )))


Цитата
Конечно много зависит от привычки, но это не отменяет того факта, что привычки могут быть вредными sm.gif

Мне важно видеть всю привязку пинов к процу в одном месте.
Именно поэтому я ушел от отдельного порта и пина, т.е. два параметра шаблона стали одним. Меньше писанины в коде и нагляднее.
Мне так удобнее переносить код из проекта в проект - все настройки проекта и привязку пинов я выношу в один файл StaticSettings.hpp, там ТОЛЬКО дефайны и больше ничего.

У меня в каждом проекте все кому-то принадлежит, т.к. существует однозначная классовая иерархия, это исключает необходимость в глобальных объектах. Меньше головной боли.
По сути, создана модульная система, где каждый модуль ничего не знает о других, в каждом модуле могут быть потоки или не быть.
Привязка к железу очень сильно отрезана от кода и максимально локализована.
Можно, конечно, прятать назначение пинов внутри модулей, но пока мне, просто, удобнее собирать привязку всех пинов в одном месте.
Хотя инициализация и создание классов пинов осуществляется в соотв. модулях, которым они принадлежат.
Reflector
Цитата(Forger @ Apr 18 2017, 21:41) *
Не знаю, не задавался этим вопросом так детально. Просто, сделал, работает, по применению меня вполне устраивает.
Но глянуть, гляну )) Даже любопытно стало. Попробую по-изучать твой способ ))

Главное функцию инициализации вынести из класса, иначе компилятор ее постоянно намеревается заинлайнить.

Цитата
А как у тебя работает ногодрыг? Покажи асм код, когда попеременно дергаешь пин (переключать несколько раз подряд, но не в цикле)

Если сделать set(), clear(), set(), clear(), то получится
Цитата
0x200008b6 ldr r4, [pc, #196]
0x200008b8 mov.w r2, #256
0x200008bc mov.w r3, #16777216
0x200008c0 str r2, [r4, #24]
0x200008c2 str r3, [r4, #24]
0x200008c4 str r2, [r4, #24]
0x200008c6 str r3, [r4, #24]


Цитата
Ничто не мешает в мое случае передавать не шаблон, а ссылку на базовый класс PinBase.

В самом начале я сделал два класса Pin, обычный и шаблонный, обычный именно из-за того, что его можно передать как параметр в обычные функции, но оверхед был приличный и позже от этой идеи отказался. Чтобы передать шаблонный класс часто не нужен другой подобный класс, можно обойтись одной шаблонной функцией.

Цитата
Мне важно видеть всю привязку пинов к процу в одном месте.
Именно поэтому я ушел от отдельного порта и пина, т.е. два параметра шаблона стали одним. Меньше писанины в коде и нагляднее.
Мне так удобнее переносить код из проекта в проект - все настройки проекта и привязку пинов я выношу в один файл StaticSettings.hpp, там ТОЛЬКО дефайны и больше ничего.

Ты ушел и от альтернативных функций sm.gif Мало кто будет использовать софтовый SPI, а у аппаратного нужно задавать еще и AF, как тут помогут твои PA5, которые еще и засоряют пространство имен? Еще один дефайн? Пожалуйста, можно взять мой PinA<5> и поместить его в отдельный файл, с этим никаких проблем. Но у него еще есть второй необязательный параметр, AF. Так, например:
Код
using PIN_DAC_SCK = PinA<5, 7>;
// потом где-то в другом месте
PIN_DAC_SCK dac_csk;

Причем идеологически PIN_DAC_SCK - это именно Pin, т.е. то, что он есть на самом деле.
Forger
Цитата(Reflector @ Apr 18 2017, 22:13) *
Главное функцию инициализации вынести из класса, иначе компилятор ее постоянно намеревается заинлайнить.

Нужно лишь добавить virtual ))

Цитата
Если сделать set(), clear(), set(), clear(), то получится

Норм, быстрее некуда, да и не надо )))

Кстати, set - весьма неудачное имя для установки пина в 1, т.к. set - префикс любой функци-сеттера, которая задает указанное значение, т.е. требует параметр.
А clear - тоже неоднозначна, т.к. в случае например флэш-памяти она означает запись одних единиц....
Поэтому я задал явные имена High и Low для методов управления состоянием пинов. Их сложно спутать с чем-то иным.
Да и трудно найти им другое применение, кроме как лишь в классе пинов.

Цитата
В самом начале я сделал два класса Pin, обычный и шаблонный, обычный именно из-за того, что его можно передать как параметр в обычные функции, но оверхед был приличный и позже от этой идеи отказался.

Передавал ссылку или экземпляр класса пина???

Цитата
Чтобы передать шаблонный класс часто не нужен другой подобный класс, можно обойтись одной шаблонной функцией.

Поясни примером.

Цитата
Ты ушел и от альтернативных функций sm.gif

Нет, в данном случае мне нужен именно программный SPI, скорости тут детские, обмен редкий.
Альтернативные функции используются, но настраиваются в самом модулей, где настраивается соотв. периферия и там же настраиваются соотв. пины.
При смене пинов альт. функция не изменится, т.к. она задает некий номер периферии.
Т.е. логично локализовать ее настройку именно там, где она используется, а вот привязка пина к этому отношения уже не имеет, но нужно убедиться, что этот пин имеет такую функцию.
Но для этого уже есть даташит.

Цитата
Мало кто будет использовать софтовый SPI

Стараюсь именно такой и использовать, конечно, если не требуется интенсивный обмен данными. Скажем прочитать данные с акселерометра или опросить SPI датчик температуры.
Это позволяет вешать на любые порты, а не искать свободные аппаратные SPI. Да и от железа вообще не зависит.

Вот одна из причин, почему привязку пинов (дефайны) складываю в один файл:
Код
// DIGITAL INPUTS
#if (HARDWARE_VERSION == 10)
    #define PIN_IS_DRIVE_DISABLED            (PA10)
#elif (HARDWARE_VERSION == 11)
    #define PIN_IS_DRIVE_ENABLED            (PA11)
#endif
#define PIN_DRIVE_ERROR1                    (PA8)
#define PIN_DRIVE_ERROR2                    (PB0)
#define PIN_DRIVE_POWER_IS_OK                (PC4)

// DIGITAL OUTPUTS
#if (HARDWARE_VERSION  == 10)
    #define PIN_READY                        (PA11)
#elif (HARDWARE_VERSION == 11)
    #define PIN_READY                        (PA12)
    #define PIN_DRIVE_ENABLE                (PA10)
#endif

Тут зависимость от HARDWARE_VERSION локализована в одном месте.
В данном случае только здесь.
Мне так проще - перед глазами схема с названиями цепей, и тут же в одном файле их привязка - легко заполнять и проверять на ошибки.

Цитата
которые еще и засоряют пространство имен?

А засорять особое нечего, я не создаю новые пространства имен, лишь использую чужие.
К тому же enum можно переместить внутрь класса Pin, тогда вообще ничего не засоряется )))

Цитата
Причем идеологически PIN_DAC_SCK - это именно Pin, т.е. то, что он есть на самом деле.

У меня большими буквами записываются ТОЛЬКО дефайны, простые платформозависимые типы или макросы (стараюсь не использовать, иначе читаемость ухудшается),
типы - первая большая буква, объекты - маленькая.

Наружу для всех видны только дефайны и привязка пинов (для удобства, причины указал выше). Все остальное "попрятано" по своим местам.
Глобальных объектов нет, ни одного.
SasaVitebsk
Использовать универсальные дрова на ногодрыг бессмысленно. Внутри семейства это почти ничего не экономит, внутри одного проекта, наоборот городит, над семействами не живёт. И совершенно бессмысленно на уровне проекта. Так как pina.set или типа pinpwr.set - не создаёт переносимый код. Для этого надо что-то более удобоваримое. Ну типа POWERLED_ON или powerled(RED) по вкусу. А это требует ещё один уровень над той ээээ абстракцией, что вы написали. То есть, получается, что вы написали целый пустой уровень абстракции.
Универсальных дров нижнего уровня тоже нет. Они избыточны и плохопереносимы. В результате их всё равно приходится допиливать.
Ну там какие-нибудь spi ещё реальны или там i2c на ногодрыге. А уже USART будет колом даже внутри STM.
Зато целесообразны дрова второго уровня: AT24, dataflash, modbus и тому подобное. Это действительно живёт годами.

А со стилем, очень много - дело вкуса. Главное, чтобы автор хоть иногда смотрел, как пишут другие. Тогда, как правило, вопросов возникает мало.
AHTOXA
О, пришла пора мериться пинами! sm.gif
Внесу свою лепту: тынц.
Reflector
Цитата(Forger @ Apr 18 2017, 22:42) *
Кстати, set - весьма неудачное имя для установки пина в 1, т.к. set - префикс любой функци-сеттера, которая задает указанное значение, т.е. требует параметр.
А clear - тоже неоднозначна, т.к. в случае например флэш-памяти она означает запись одних единиц....

С таким подходом можно большую часть слов забраковать, просто считай, что у set есть неявный параметр true sm.gif

Цитата
Передавал сам класс пина, а не ссылку??? Не путаешь?

Ссылку, конечно. Все равно неэффективно, там и сам класс более тяжелый, т.к. как минимум порт и пин придется в нем хранить и они уже не будут считаться константами, прощай contexpr и т.д....

Цитата
Поясни примером.

Допустим аппаратный классы SPI или USART можно не делать шаблонными или делать, но с небольшим числом параметров, а Pin'ы передавать только в шаблонную функцию инициализации, ведь они только там и нужны. Это для софтовой реализации нужно эти пины дергать и в других функциях.

Цитата
Нет, в данном случае мне нужен именно программный SPI, скорости тут детские, обмен редкий.
Альтернативные функции используются, но настраиваются в самом модулей, где настраивается соотв. периферия и там же настраиваются соотв. пины.
При смене пинов альт. функция не изменится, т.к. она задает некий номер периферии.
Т.е. логично локализовать ее настройку именно там, где она используется, а вот привязка пина к этому отношения уже не имеет, но нужно убедиться, что этот пин имеет такую функцию.
Но для этого уже есть даташит.

Например, для STM32F0 возможна ситуация, когда у SPI2 SCK будет AF5, MISO - AF0, а MOSI - AF1. AF связывает пины с конкретной периферией, пины выбираются с учетом того, чтобы они могли работать с этой периферией, логично, что то и другое задается в одном месте.

Цитата
Вот одна из причин, почему привязку пинов (дефайны) складываю в один файл:
Тут зависимость от HARDWARE_VERSION локализована в одном месте.
В данном случае только здесь.
Мне так проще - перед глазами схема с названиями цепей, и тут же в одном файле их привязка - легко заполнять и проверять на ошибки.

Да это понятно, складывай все в один файл, но делается это в стиле С, а не С++. Собственно если глянуть на твой класс, то сразу бросается в глаза, то конструктор почему-то принимает void, а перед enum почему-то typedef sm.gif

Цитата
А засорять особое нечего, я не создаю новые пространства имен, лишь использую чужие.
К тому же enum можно переместить внутрь класса Pin, тогда вообще ничего не засоряется )))

Так чего не перенесешь? У такого подхода есть какие-то недостатки? sm.gif
Forger
Цитата(Reflector @ Apr 19 2017, 00:41) *
С таким подходом можно большую часть слов забраковать, просто считай, что у set есть неявный параметр true sm.gif

Ага )))
"Голый" set ничего не значит, это, просто, глагол, и к нему нужно добавить существительное, если метод без параметров,
или передать значение, скажем, LOW/HIGH:
Вот два варианта:
1) setToLow()
2) set(LOW)

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

Вообще, set/get - это типовое парное сочетание, префикс для названия метода. Их еще называют сеттер/геттер. Обычно, ходят парами ))

Цитата
они уже не будут считаться константами, прощай contexpr и т.д....

И чем этого грозит?


Цитата
Например, для STM32F0 возможна ситуация, когда у SPI2 SCK будет AF5, MISO - AF0, а MOSI - AF1. AF связывает пины с конкретной периферией, пины выбираются с учетом того, чтобы они могли работать с этой периферией, логично, что то и другое задается в одном месте.

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

Цитата
Собственно если глянуть на твой класс, то сразу бросается в глаза, то конструктор почему-то принимает void,

Это - старая привычка, научил меня давно один гуру, что в некоторых случаях в С++ есть разница между foo() и foo(void), но это было давно и более неактуально, но привычка осталась..
Со временем исправлюсь ))

Цитата
а перед enum почему-то typedef sm.gif

Не знаю, это все непринципиальные мелочи, ни на что не влияют.

Цитата
Так чего не перенесешь? У такого подхода есть какие-то недостатки? sm.gif

Не могу щас ответить, но когда так делал, как ты пишешь, возникали сложности в некоторых применениях. Поэтому разделил шаблонную и базовую общую часть.
Мне вполне удобно применять такое решение.
Эдди
Цитата(AHTOXA @ Apr 19 2017, 00:33) *
О, пришла пора мериться пинами! sm.gif
Внесу свою лепту: тынц.

Очередной подход к калокубу.
Хотя, возможно, шаблоны С++ и разворачиваются в static inline, ХЗ. Но мне как-то неприятно видеть цепепешный код применительно к микроконтроллерам, а также оформление инициализации периферии в виде общих функций (как в SPL или калокубе). Либо делать каждый раз явно, либо оформлять как макросы (на худой конец — static inline функции).
Ну и, конечно, не опускаться до абдуринщиков, которые все делают ногодрыгом. Ладно, у них авр с никакими ресурсами, но уж у STM32 этих ресурсов хоть отбавляй! Не хватает только аппаратного 1-wire, чтобы не нужно было на таймерах с DMA (или USART с DMA) городить отсебятину.

Цитата(juvf @ Apr 18 2017, 21:41) *
Код
Я вам искренне сочувствую, чесс слово, аж самому взгруснулось :crying:
2Эдди есть костыльные методы для выхода из глубоких вложенных циклов.... но пока нет равнозначной альтернативы готу. но это отдельный холивар )))

Я читал книжку "совершенный код", с каждой страницей все больше приходил к мнению, что автор несет какую-то тупую отсебятину с совершенно бредовыми идеями. И про goto у него был идиотизм какой-то. Если код без goto разрастется не больше, чем на 2-3 строчки, можно сделать и так. А если же придется лепить уйму дополнительных проверок, то получится тот же самый "спагетти-код". Просто осторожно нужно goto использовать: если goto и метка лежат не дальше, чем в пределах 1-2 страниц текста, то этот код читать удобно; если дальше — могут возникнуть проблемы. Вот с longjump хуже: он значительно больше проблем может вызывать, хоть и добавляет уйму плюшек при, скажем, обработке сигналов или ошибок.
Да, книжку эту я на треть прочитал и бросил: просто взбесило содержание! Ну и примеры: автор в основном касается цепепе (ну, это я стерпеть могу еще) и вижуал васика (это ж полный треш!). И пишет, что M$ office, над которым этот автор, похоже, работал — прямо таки идеал софта (хотя в реале — та еще свистопердящая дрянь, да еще и в последнее время с неюзабельным интерфейсом; бедные мастдайщики!!!).
Forger
Цитата(Эдди @ Apr 19 2017, 08:16) *
Очередной подход к калокубу.

Цитата
Но мне как-то неприятно видеть цепепешный код применительно к микроконтроллерам,

Цитата
Либо делать каждый раз явно, либо оформлять как макросы (на худой конец — static inline функции).

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

Цитата
Я читал книжку "совершенный код", с каждой страницей все больше приходил к мнению, что автор несет какую-то тупую отсебятину с совершенно бредовыми идеями.

Вы ошиблись темой. Здесь собрался народ с совершенно иными взглядами на мир. Нам не по пути. Проходите мимо.










Цитата(SasaVitebsk @ Apr 19 2017, 00:32) *
....То есть, получается, что вы написали целый пустой уровень абстракции.

Как раз наоборот, объем кода с инициализацией пинов резко сократился, читаемость и переносимость выросли на порядок. Код стал чище.
Производительность не пострадала. Цели достигнуты ))
SasaVitebsk
Цитата(AHTOXA @ Apr 19 2017, 00:33) *
О, пришла пора мериться пинами! sm.gif
Внесу свою лепту: тынц.

И что?
Ещё раз повторяю. Совершенно бессмысленно.
Приведу пример. Только что делал модификацию прибора. Изменилось количество каналов, полностью переразведена плата, на первой версии стояла отдельный МК который управлял клавой, светодиодами пищалкой и подключен был по I2C. В новой версии применили 595/165 SPI и отдельный таймер на пищалку.
Отладку нового проекта производил на старой плате. При переносе старый файл local.h переименовал в local_v1.h. Добавил файл local_v2.h с данными новой платы, и написал local.h где переключатель хидеров. В main.h ввёл макрос выбора версии платы. Написал один файл обработки новой клавы и внёс некоторые изменения в инициализацию - прерывания (так как поменялись таймеры каналы spi и прочее). Думаю всего изменения коснулись строчек 10. У меня в main.h указываются дефайны типа spi_dataflash/ spi_adc. И всё! Проект компилится для двух версий плат.
Чем поможет конструкция "PA5::On()"? По всему проекту её ловить? И что такое On? Я сейчас использую двухцветные светодиоды. Очень удобно Конструкция проще, информативность выше. И что даст ко всему этому PA5::On()? То есть нужен ещё слой, чтобы PA5::On превратился в удобоваримое powerled(red) или adc_cs_on. Я сейчас не о стилистике написания, поймите. Пусть стилистика будет ваша. Но применять по тексту основной программы обезличенные данные аппаратных ресурсов - тоже, что писать reg = 5. Это также недопустимо! Ни одной константы по тексту программы.
Итак над этой хренью появляется ещё один файл абстракций. Итого 2. А у меня он 1. Сразу аппаратура в абстракцию.
======
Ну хорошо рассмотрим переносимость данного класса и его применимость в другом проекте.
Ну и какая она? Громко заявлена, что она pin_stm32F4xx.h. То есть сразу же радуемся, что при использовании этой чудо хрени в stm32f0 мы в пролёте. Более того, при использовании её в f1 там придётся переписать половину.
Но и это ещё не всё. Я утверждаю, что эта хрень не заработает даже на всех камнях F4. Почему? Поищите сами. Или наступите на грабли.
При переносе на lpc это полностью переписать. И код использующий данный класс - тоже будет полностью переписан.
Вот у меня теперь вопрос. В ЧЁМ ВЫИГРЫШ БРАТ?!!!
Kabdim
Цитата(Эдди @ Apr 18 2017, 18:57) *
Что за нафиг? Без goto невозможно писать ни на С, ни на цепепе! Как вы из вложенных циклов будете выходить?

Вообще это редкий usecase. Но если очень надо, то как правило задача довольно хорошо бьется на функцию в которой все циклы, а выход соответственно return.
Эдди
Цитата(Forger @ Apr 19 2017, 09:06) *
Вы ошиблись темой. Здесь собрался народ с совершенно иными взглядами на мир. Нам не по пути. Проходите мимо.

Это как раз таки вы ошиблись темой!
Вам к ардуинщикам надо.
Forger
Цитата(Эдди @ Apr 19 2017, 09:37) *
Это как раз таки вы ошиблись темой!
Вам к ардуинщикам надо.

Опять хамить изволите?
Reflector
Цитата(AHTOXA @ Apr 19 2017, 00:33) *
О, пришла пора мериться пинами! sm.gif
Внесу свою лепту: тынц.

В общем так, проинитил я 5 пинов, получил 144 байта, против 188 у меня. Проинитил 10 пинов, получил 252 vs 216, уже в мою пользу. Но при этом твой код изначально не работает на F1, также там используется bitBand, значит он не работает и на F0, но главное это его размер в дебаге... У меня он вырос в 2.4 раза, у тебя в 110 sm.gif Ты принципиально не пользуешься отладкой?
Forger
Цитата(Reflector @ Apr 19 2017, 09:45) *
В общем так, проинитил я 5 пинов, получил 144 байта, против 188 у меня. Проинитил 10 пинов, получил 252 vs 216, уже в мою пользу.

На момент создания всего этого у меня было две задачи: убрать кучу кода инициализации пинов, спратав это внутрь одного файла (Pin.hpp), сохранить скорость работы ногодрыга.
Оптимизация - это вторично. Главное - user-код изолирован от реализации Pin, который впоследствии можно безболезненно переделать.

Цитата
Но при этом твой код изначально не работает на F1, также там используется bitBand, значит он не работает и на F0,

По них существуют другие соотв. файлы Pin.hpp, размещенные в своих соотв. каталогах.

Цитата
но главное это его размер в дебаге... У меня он вырос в 2.4 раза, у тебя в 110 sm.gif

До оптимизации в дебаге не доходил. Не было нужды. Хотя за цифры спасибо. Заставляет задуматься ))

Цитата
Ты принципиально не пользуешься отладкой?

Отладкой, разумеется, пользуюсь. А недавно проникся SystemView (segger), жалею, что раньше не освоил ((
Reflector
Цитата(Forger @ Apr 19 2017, 09:56) *
До оптимизации в дебаге не доходил. Не было нужды. Хотя за цифры спасибо. Заставляет задуматься ))

Эээ. Вообще-то это был ответ AHTOXЕ, твоего полного кода у меня то нет sm.gif
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.