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

Может я отстал от поезда, но объясните: какой смысл такой "экономии на спичках"?

есть программисты, которым подавай boost, stl, и т.п..... которые передают по каналам связи джейсон... 1 бит состояния хранят как "Масляный выключатель Включен" и "Масляный выключатель Выключен". те ни когда не опустятся ниже прикладного уровня Linux/Windows. Есть которые опускаются ниже, но не любят тесноты.... им подавай запас под их "красивый и легко читаемый код".... А есть проекты, где нужно сделать хороший функционал на дешевом процессоре. Тут спорить бессмысленно.

"Не хочу, не буду"
Прикладной программист для ПК не возмется за программирование stm32f100. Я не возьмусь за программирование СУБД.... Каждому своё. ;)

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


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

Мы тут о крутизне спорим, да?

О чем вы?

 

если результат хуже, чем стандартное применение дефайнов?

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

Но остался на том, что сейчас.

 

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

 

#include "Pin.hpp"

main()
{
   LedOpenDrain<RB0> ledRed;
....
    ledRed.on();
....
    ledRed.off();
....
}

 

есть программисты, которым подавай boost, stl, и т.п.....

(С) "Я ему про Фому, а он мне про Ерёму"

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


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

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

 

#include "MyInclude.h"

main()
{
   initRedLed();
....
    ledRedOn();
....
    ledRedOff();
....
}

 

а что вашего кода касательно.... с ходу.... не очень понятно что такое RB0? Не загялнув в инклуде не понятно, хотя может у вашего процессора есть порт RB0? У стм обычно PB0.

и второе.... вижу ledRed - это объект класса LedOpenDrain. Т.е. ledRed в будещем нельзя изменить и сделать как OutPullUp?

 

 

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


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

тысячные партии изделия, при низкой стоимости самого изделия

Ну вот всё и встало на места. Разные условия - разные подходы.

ЗЫ Тысячи это совсем мало. Размер партии слегка кастомного решения для средне размерного клиента.

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


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

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

Умеет. Да и чего бы ему не иметь, если это одно из его обычных расширений https://gcc.gnu.org/onlinedocs/gcc/Binary-c...inary-constants . Кстати умеет в чистом С. Только не забудьте ему ключик указать, чтобы он расширения включил.

 

P.S. Позабавили меня рассуждения последних нескольких страниц - столько внимания пину, можно подумать контроллер помощнее выбирался, чтобы ногами дрыгать через С++ классы :)

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


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

на дефайнах этот код не менее прост и понятен.

 

#include "MyInclude.h"

main()
{
   initRedLed();
....
    ledRedOn();
....
    ledRedOff();
....
}

 

Где ж он короче?

А содержимое initRedLed, ledRedOff, ledRedOn кто за вас писать будет? Вася Пупкин?

Иначе прога не соберется.

 

У меня Pin.hpp не зависит от проекта, он вообще вынесен в отдельный каталог к соотв. либе для соотв. семейства. Общий для всех проектов.

В него лазить и тем более править нет нужды, отладил и забыл.

 

а что вашего кода касательно.... с ходу.... не очень понятно что такое RB0?
Описка, должно быть PB0.

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

А в реальном коде этот PB0 "забит" дефайном в одном месте в файле настроек проекта (StaticSettings.hpp):

 

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

 

и второе.... вижу ledRed - это объект класса LedOpenDrain.

Т.е. ledRed в будещем нельзя изменить и сделать как OutPullUp?

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

лучше использовать для этого другой класс со своим функционалом: DigitalOutputPin

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

 

Вообще, LedOpenDrain у меня выглядит так (файл Pin.hpp):

 

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

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

 

подумать контроллер помощнее выбирался, чтобы ногами дрыгать через С++ классы :)

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

Ногодрыг на классах - лишь удобный довесок к куче других С++ полезностей, а вовсе не наоборот.

 

зы. Вот щас посматриваю в сторону С++ исключений, но пока просто изучаю матчасть, смотрю, что это дает, а что отбирает в МК ...

По этой же причине пока не использую кучу или что-то, что ее заменяет. Осторожничаю )))

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


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

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

Оптимизация - это вторично. Главное - user-код изолирован от реализации Pin, который впоследствии можно безболезненно переделать.

Какую кучу инициализации?

Вы что бредите?

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

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

То есть этот подход ничего общего не имеет к стилю написания, а имеет прямое отношение к стилю проектирования.

Порты инициализирую сразу, а не попиново, но инициализация всё равно имеет мнемонику пинов, что не ухудшает переносимость.

"Куча кода инициализации портов" получается 5/6 регистров на порт. Плюс не более 20 макросов управления ногодрыгом. И это на 144 ножный корпус.

Причём макросы это не обязательно ногодрыг. Например подключен АЦП на SPI. DIN/DOUT(RDY). Я передаю, потом переключаю линию разрешаю прерывания по готовности и так далее. То есть это уже к класу ногодрыга не совсем относится, но по логике работы общая.

Я не ратую за макросы. Сейчас это не рекомендуется. Можно оформить процедурами либо классами. Но зачем увязывать это с портами?

 

И главное, мне не ответили в чём выигрыш? Если класс получается непереносимый, и его нельзя заимствовать? Зачем? Вот главный вопрос.

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


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

кстати.... эти ваши плюсы.... вот на порту РА нужно проинитить пины 0, 1, 6, 7 как выход... на Led или на CS.... не важно. с SPL или си-стаил инит не такой красивый, но там инитятся порты все хором за раз (в stm32). Теперь допустим надо 0 и 6 выствить в "0", а 1 и 7 выставить в 1. через регистр BRRS это делается за 1 команду си/с++ (вроде как в асме выходит 3 команды). AHTOXА, Forger, Reflector - в ваших юСтайлах сколько строк дизасемблера занимает инит 4-х портов, и сколько переключение? если инит одного порта будет вызван 4 раза.... то в итоге... код будет вызываться один и тот же 4 раза. Но допустим, функция - зашли в неё и проинитили 4 порта, потом выставили на них значение - сколько машинных тактов будет крутиться код при ините и при переключении? А если не 4 пина, а 13 пинов и все на РА?

Если с парой светодиодов работать именно как с пинами, то нельзя их выставить в 0 одной командой. Будет две записи в BSRR, разница лишь в том, что для второго светодиода базовый адрес уже будет загружен и вместо 3 команд на ассме получим 2. Теоретически можно сделать такой метод, который бы принимал разные пины и инитил за раз, но особой необходимости в этом не вижу... Если же мы изначально выбираем работу с группой пинов, то при установке значений все равно будет одна запись в BSRR и получим практически или такой-же по размеру код, как и для одного пина. То же самое будет происходить если переключать группу пинов с входа на выход и т.п., т.е. частичную переинициализацию можно выполнять достаточно эффективно. При полной инициализации уже вызывается функция инициализации, для группы пинов она достаточно тяжелая, там в цикле считается двойная маска, я просто выбрал вариант с меньшим размером кода. Начальная инициализация выполняется один раз и скорость там не важна.

 

и второе.... вижу ledRed - это объект класса LedOpenDrain. Т.е. ledRed в будещем нельзя изменить и сделать как OutPullUp?

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

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


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

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

А я не пишу никаких local файлов. Пример выше собирается без доп. файлов. Нужно лишь указать путь к Pin.hpp в настройках проекта.

 

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

Именно поэтому всю привязку пинов я выношу в отдельный файл, просто ряд дефайнов, чтобы уйти от PA7, PB3 и т.п. на человеческие имена, соотв. схеме.

 

И главное, мне не ответили в чём выигрыш?

В переносимости и читаемости кода не в момент написания, а вообще, в любое время.

 

Я настраиваю пины именно в тех модулях, которым они принадлежат. У меня проект построен по модульному принципу. Модули имею логическое разделение, и делится не по периферии/портам и т.п., а по смыслу.

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

Мне важно контроллировать порядок и инициализации железа.

Для отладки удобно вообще отключать некоторые модули (два символа //)

Раньше все было свалено в кучу и создавала кучу проблем,

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

Мне сложно вам это объяснить, я до этого дорастал долго и мучительно, но обратно уже не вернусь. Тем более на груду макросов/дефайнов, раскиданных по всему коду ))

Покажу примером (Application.cpp):

 

#include "Kernel.hpp"
#include "Application.hpp"

void Kernel::initializeModules()
{
    WatchDog::getInstance().initialize();
    Communication::getInstance().initialize();
....
    MotionControl::getInstance().initialize();
    Leds::getInstance().initialize();
    Settings::getInstance().initialize();
}

void Kernel::runModules()
{
    WatchDog::getInstance().run();
    Communication::getInstance().run();
.....
    MotionControl::getInstance().run();
    Leds::getInstance().run();
    Settings::getInstance().run();
}

void Kernel::initializeHardware(void)
{
... настраивается максимум тактирование ядра и шин
}

 

В каждом таком модуле может быть несколько задач (потоков) или вообще не быть.

Пины и периферия "принадлежат" модулям, там же инициализируются и настраиваются.

Прерывания тоже сделаны в виде классов (долго мудохался, но добился своего), никаких extern "C" irq и т.п.

 

Функция main скрыта в библиотеки rtos, ее не нужно реализовывать, достаточно лишь подключить соотв. lib файл и Kernel.hpp

 

Никаких глобальных объектов, все обращение модулей друг другу ТОЛЬКО через соотв. открытые методы.

 

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

Откуда такие выводы? Все как раз наоброт!

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


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

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

лучше использовать для этого другой класс со своим функционалом: DigitalOutputPin

Этот DigitalOutputPin, его же можно заставить работать и на вход? :)

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


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

Этот DigitalOutputPin, его же можно заставить работать и на вход? :)

Да, можно. Но это можно сделать лишь нарочно, т. е. сознательно ставить палки в колеса. Мазохизм в чистом виде :)

Если бы этот код уходил в виде библиотеки для имбицилов-программеров, то он выглядел бы совсем иначе. Где подобные "фокусы" не работали бы... Но это - уход от темы.

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


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

Да, можно. Но это можно сделать лишь нарочно, т. е. сознательно ставить палки в колеса. Мазохизм в чистом виде :)

Если бы этот код уходил в виде библиотеки для имбицилов-программеров, то он выглядел бы совсем иначе. Где подобные "фокусы" не работали бы... Но это - уход от темы.

Есть у меня один экранчик, там ноги тача совмещены с данными, соответственно они могут работать как цифровые входы/выходы или как аналоговый вход. Какой класс пина нужно выбрать?

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


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

Где ж он короче?
я не говорю, что он короче. в данном контексте я сказал что он также понятен и прост. Не залазия в хидер всё понятно.

 

А содержимое initRedLed, ledRedOff, ledRedOn кто за вас писать будет? Вася Пупкин?

тот же кто напишет Pin.hpp

 

какой смысл в runtime делать такие странные вещи - изменять схему подключения пина
Есть 1Wire, програмный i2c, can.....

 

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

 

например.... динамическая индикация 4-х 7-ми сегментников с точкой. в прерывании от таймера нужно 8 портов выкл/откл, плюс общие катоды (4 шт). можно конечно вашими классами это сделать, проскочить по всем пинам и дернуть у всех On() или Off(). сколько вы просидите в прерывании? И если на остальное времени не хватит... то вы "не будете втаптывать код".... попросите вагон спичек, ну чтоб не экономить.

а это можно сделать одной командой

GPIOA->BSRR = indicator[++curentNumber&3]; //где uint32_t indicator[4] - выставляется код каждого символа в основном потоке

 

 

да я согласен, что с++ рулит на мк. но не всегда и не везде. И ваш Pin.hpp не имеет отношения к использованию b. оно может жить и вместе и порознь. вкус и цвет....

 

 

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


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

Есть у меня один экранчик, там ноги тача совмещены с данными, соответственно они могут работать как цифровые входы/выходы или как аналоговый вход. Какой класс пина нужно выбрать?

Просто Pin, от которого наследуются более узкоспециализированные (появились сравнительно недавно, так оказалось удобнее).

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


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

Порты инициализирую сразу, а не попиново, но инициализация всё равно имеет мнемонику пинов, что не ухудшает переносимость.

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

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


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

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

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

Гость
Ответить в этой теме...

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

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

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

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

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

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