Перейти к содержанию
    

Интересно дизассемблер этого цепепешного ужаса глянуть. Неужто оптимизирует?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

А я думаешь чьим классом пользуюсь? :)
:)

 

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

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

Все просто ))

У меня так сделаны DigitalOutputPin, LedOpenDrain, DigitalInputPin, AnalogInputPin

В некоторые из низ добавлены дополнительные методы, расширяющие возможности "голого" Pin.

 

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

В этом случае на каждый такой экземпляр Pin инстанцируется свой класс со своим объектным кодом. Т.к. код растет не по-децки.

Поэтому я сделал базовый класс с уже реализованными общими методами. 12-байт - это фигня, с ОЗУ проблем нет.

А уже от него наследую шаблонный класс с параметрами, которые как-то нужно передать в базовый.

Экономия кода, но не озу.

 

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

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

Поэтому класс объявлен внутри другого класса в поле private. Здесь я просто не стал это показывать.

 

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

Мне совершенно до лампочки, какие именно пины используются в месте объявления классов пинов, для чтения и отладки кода это не имеет значения.

Т.к. при отладки железа смотрю на схему и вижу имена цепей, которые совпадают с человеческими названия пинов в коде, а не некими PAx, PBy и т.п.

В самой схеме девайса цепи, которые идут к пинам, у меня называются точно также, как в это едином для всех пинов файле.

 

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

Мне так удобнее, иначе пришлось прыгать от исходника к исходнику. Полагаю, что тут во многом дело привычки.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Интересно дизассемблер этого цепепешного ужаса глянуть. Неужто оптимизирует?

Есть такой код:

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);
}

 

Нет, достаточно наследовать от 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. ОЗУ, как уже говорилось, ноль. А у тебя сколько? Про куб вообще молчу :)

 

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

Поэтому класс объявлен внутри другого класса в поле private. Здесь я просто не стал это показывать.

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

 

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

Мне так удобнее, иначе пришлось прыгать от исходника к исходнику. Полагаю, что тут во многом дело привычки.

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

В данном случае это непринципиально, хотя некоторые С++ компиляторы видят в этом разницу:

http://stackoverflow.com/questions/693788/...292431#36292431

При чем тут чьи-то форумы? Открываем стандарт, читаем, пользуемся.

 

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

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

 

в целом без разница как писать - с битовыми литералами или без
+1

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Создаю новый проект, пишу следующий код:

PinA<3>(PinMode::AF_OpenDrain_HighVerySpeed);
PinB<6>(PinMode::PushPull_HighSpeed);
PinC<14>(PinMode::OpenDrain_MediumSpeed);

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

 

Не знаю, не задавался этим вопросом так детально. Просто, сделал, работает, по применению меня вполне устраивает.

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

 

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

 

Про куб вообще молчу :)

Не пользую это "чудо", не позволяет религия, т. к. он создан исключительно для "ардуинщиков", т. е. новичков.

Навязывает свой подход к построению и организации кода, абсолютно несовместим с моими методами )))

 

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

Мой проект, где используется ExternalDAC, не требует такой широкой абстракции, но она появится, если эта сущность (ExternalDAC) потребует этого.

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

Но пока есть сомнения в такой необходимости, сущность остается в приватной секции соотв. класса, которой она принадлежит.

 

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

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

В этом случае нет привязки к конкретной специализации шаблона.

Мои познания в плюсах хоть и не плохие, но практика пока хромает )))

 

 

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

Мне важно видеть всю привязку пинов к процу в одном месте.

Именно поэтому я ушел от отдельного порта и пина, т.е. два параметра шаблона стали одним. Меньше писанины в коде и нагляднее.

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

 

У меня в каждом проекте все кому-то принадлежит, т.к. существует однозначная классовая иерархия, это исключает необходимость в глобальных объектах. Меньше головной боли.

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

Привязка к железу очень сильно отрезана от кода и максимально локализована.

Можно, конечно, прятать назначение пинов внутри модулей, но пока мне, просто, удобнее собирать привязку всех пинов в одном месте.

Хотя инициализация и создание классов пинов осуществляется в соотв. модулях, которым они принадлежат.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Не знаю, не задавался этим вопросом так детально. Просто, сделал, работает, по применению меня вполне устраивает.

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

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

 

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

Если сделать 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, там ТОЛЬКО дефайны и больше ничего.

Ты ушел и от альтернативных функций :) Мало кто будет использовать софтовый SPI, а у аппаратного нужно задавать еще и AF, как тут помогут твои PA5, которые еще и засоряют пространство имен? Еще один дефайн? Пожалуйста, можно взять мой PinA<5> и поместить его в отдельный файл, с этим никаких проблем. Но у него еще есть второй необязательный параметр, AF. Так, например:

using PIN_DAC_SCK = PinA<5, 7>;
// потом где-то в другом месте
PIN_DAC_SCK dac_csk;

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

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

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

 

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

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

 

Кстати, set - весьма неудачное имя для установки пина в 1, т.к. set - префикс любой функци-сеттера, которая задает указанное значение, т.е. требует параметр.

А clear - тоже неоднозначна, т.к. в случае например флэш-памяти она означает запись одних единиц....

Поэтому я задал явные имена High и Low для методов управления состоянием пинов. Их сложно спутать с чем-то иным.

Да и трудно найти им другое применение, кроме как лишь в классе пинов.

 

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

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

 

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

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

 

Ты ушел и от альтернативных функций :)

Нет, в данном случае мне нужен именно программный 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, т.е. то, что он есть на самом деле.

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

типы - первая большая буква, объекты - маленькая.

 

Наружу для всех видны только дефайны и привязка пинов (для удобства, причины указал выше). Все остальное "попрятано" по своим местам.

Глобальных объектов нет, ни одного.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Использовать универсальные дрова на ногодрыг бессмысленно. Внутри семейства это почти ничего не экономит, внутри одного проекта, наоборот городит, над семействами не живёт. И совершенно бессмысленно на уровне проекта. Так как pina.set или типа pinpwr.set - не создаёт переносимый код. Для этого надо что-то более удобоваримое. Ну типа POWERLED_ON или powerled(RED) по вкусу. А это требует ещё один уровень над той ээээ абстракцией, что вы написали. То есть, получается, что вы написали целый пустой уровень абстракции.

Универсальных дров нижнего уровня тоже нет. Они избыточны и плохопереносимы. В результате их всё равно приходится допиливать.

Ну там какие-нибудь spi ещё реальны или там i2c на ногодрыге. А уже USART будет колом даже внутри STM.

Зато целесообразны дрова второго уровня: AT24, dataflash, modbus и тому подобное. Это действительно живёт годами.

 

А со стилем, очень много - дело вкуса. Главное, чтобы автор хоть иногда смотрел, как пишут другие. Тогда, как правило, вопросов возникает мало.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Кстати, set - весьма неудачное имя для установки пина в 1, т.к. set - префикс любой функци-сеттера, которая задает указанное значение, т.е. требует параметр.

А clear - тоже неоднозначна, т.к. в случае например флэш-памяти она означает запись одних единиц....

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

 

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

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

 

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

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

 

Нет, в данном случае мне нужен именно программный SPI, скорости тут детские, обмен редкий.

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

При смене пинов альт. функция не изменится, т.к. она задает некий номер периферии.

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

Но для этого уже есть даташит.

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

 

Вот одна из причин, почему привязку пинов (дефайны) складываю в один файл:

Тут зависимость от HARDWARE_VERSION локализована в одном месте.

В данном случае только здесь.

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

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

 

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

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

Так чего не перенесешь? У такого подхода есть какие-то недостатки? :)

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

Ага )))

"Голый" 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 :)

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

 

Так чего не перенесешь? У такого подхода есть какие-то недостатки? :)

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

Мне вполне удобно применять такое решение.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

О, пришла пора мериться пинами! :)

Внесу свою лепту: тынц.

Очередной подход к калокубу.

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

Ну и, конечно, не опускаться до абдуринщиков, которые все делают ногодрыгом. Ладно, у них авр с никакими ресурсами, но уж у STM32 этих ресурсов хоть отбавляй! Не хватает только аппаратного 1-wire, чтобы не нужно было на таймерах с DMA (или USART с DMA) городить отсебятину.

 

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

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

Я читал книжку "совершенный код", с каждой страницей все больше приходил к мнению, что автор несет какую-то тупую отсебятину с совершенно бредовыми идеями. И про goto у него был идиотизм какой-то. Если код без goto разрастется не больше, чем на 2-3 строчки, можно сделать и так. А если же придется лепить уйму дополнительных проверок, то получится тот же самый "спагетти-код". Просто осторожно нужно goto использовать: если goto и метка лежат не дальше, чем в пределах 1-2 страниц текста, то этот код читать удобно; если дальше — могут возникнуть проблемы. Вот с longjump хуже: он значительно больше проблем может вызывать, хоть и добавляет уйму плюшек при, скажем, обработке сигналов или ошибок.

Да, книжку эту я на треть прочитал и бросил: просто взбесило содержание! Ну и примеры: автор в основном касается цепепе (ну, это я стерпеть могу еще) и вижуал васика (это ж полный треш!). И пишет, что M$ office, над которым этот автор, похоже, работал — прямо таки идеал софта (хотя в реале — та еще свистопердящая дрянь, да еще и в последнее время с неюзабельным интерфейсом; бедные мастдайщики!!!).

Изменено пользователем Эдди

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Очередной подход к калокубу.

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

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

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

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

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

 

 

 

 

 

 

 

 

 

 

....То есть, получается, что вы написали целый пустой уровень абстракции.

Как раз наоборот, объем кода с инициализацией пинов резко сократился, читаемость и переносимость выросли на порядок. Код стал чище.

Производительность не пострадала. Цели достигнуты ))

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

О, пришла пора мериться пинами! :)

Внесу свою лепту: тынц.

И что?

Ещё раз повторяю. Совершенно бессмысленно.

Приведу пример. Только что делал модификацию прибора. Изменилось количество каналов, полностью переразведена плата, на первой версии стояла отдельный МК который управлял клавой, светодиодами пищалкой и подключен был по 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 это полностью переписать. И код использующий данный класс - тоже будет полностью переписан.

Вот у меня теперь вопрос. В ЧЁМ ВЫИГРЫШ БРАТ?!!!

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Что за нафиг? Без goto невозможно писать ни на С, ни на цепепе! Как вы из вложенных циклов будете выходить?

Вообще это редкий usecase. Но если очень надо, то как правило задача довольно хорошо бьется на функцию в которой все циклы, а выход соответственно return.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Присоединяйтесь к обсуждению

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

Гость
К сожалению, ваш контент содержит запрещённые слова. Пожалуйста, отредактируйте контент, чтобы удалить выделенные ниже слова.
Ответить в этой теме...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...