Jump to content

    

AHTOXA

Свой
  • Content Count

    3643
  • Joined

  • Last visited

Community Reputation

0 Обычный

1 Follower

About AHTOXA

  • Rank
    фанат дивана
  • Birthday 09/04/1970

Контакты

  • Сайт
    https://antongus.github.io

Информация

  • Город
    Уфа

Recent Profile Visitors

12348 profile views
  1. STM32L082 в спячке ест больше, чем на всем скаку

    А если на пробу отключить STOP? (У меня подозрение, что из-за попыток спячки контроллер не полностью переключается в стоп).
  2. Ну, переупаковывать в любом случае придётся. Скажем, если подцепить 8-битный дисплей на произвольные ноги порта. Либо это будет делать сам класс (суб)шины при записи/чтении, либо программист вручную перед этим. Лучше уж пусть это делается в самой (суб)шине, чем каждый раз переделывать свой код при смене порядка ножек.
  3. Здесь тоже есть цикл, только он, во-первых, по номерам ног шины, а во-вторых, развёрнут. В случае наличия бит-банда, это, конечно, самый оптимальный вариант. К сожалению, бит-банд на GPIO есть не у всех контроллеров, и даже не у всех STM-ок. Да, согласен. Но ещё подумаю, вдруг осенит:-)
  4. Да, именно это я и имел в виду, когда написал, что без цикла не обойтись. Хотя, если есть порт типа BSRR в STM32, то можно вычислить две маски - для сброса и для установки битов. В каких-то случаях это будет быстрее.
  5. Ну, запись/чтение шины сложно будет оптимизировать, для случая произвольного расположения ножек. Без цикла, думаю, не обойтись. А вот, например, конфигурирование группы ножек будет красивым: template <char portLetter = 'A'> class Port { ... // вложенный класс "шина" template<unsigned... Pins> struct Bus { static void setOutput() { getPortStruct()->pinDirs |= getMask(); } ... } };
  6. Да, запись ножки есть, комментарий не соответствует. Чтение по аналогии, там тривиально. getMask в случае одного параметра обрабатывается в ветке if constexpr()... Вернее, когда параметр один, то эта ветка не выполняется. Это вариант для c++17. Если c++11, то придётся делать две функции - с одним параметром и с несколькими.
  7. Ну вот, набросал кусочек. #include <iostream> #include <cstdlib> #include <cstdint> #include <cstddef> // тестовая структура для проверки работы класса порта struct PortStruct { volatile uint32_t pinValues; // значения ног volatile uint32_t pinDirs; // направления ног (0 = вход) }; // это у нас будут типа регистры портов. static PortStruct portA { 0, 0 }; static PortStruct portB { 0, 0 }; // шаблонный класс порта. Параметр шаблона - буква порта (для проверки идеи этого достаточно) template <char portLetter = 'A'> class Port { public: // выдать указатель на регистры порта. static constexpr volatile PortStruct* getPortStruct() { if (portLetter == 'A') return reinterpret_cast<volatile PortStruct*>(&portA); return reinterpret_cast<volatile PortStruct*>(&portB); } // чтение/запись порта целиком static void set(uint32_t value) { getPortStruct()->pinValues = value; } static uint32_t get() { return getPortStruct()->pinValues; } // чтение одной ножки порта static void setPin(int pinNum, bool on) { if (on) getPortStruct()->pinValues |= (1UL << pinNum); else getPortStruct()->pinValues &= ~(1UL << pinNum); } // вложенный класс "шина" template<unsigned... Pins> struct Bus { // выдать маску шины (единички в тех позициях, которые включены в эту шину) static constexpr uint32_t getMask() { return getMask<Pins...>(); } // прочитать значение шины (только те биты, которые включены в шину) static uint32_t get() { auto result { 0u }; for (auto pin = 0u, mask = getMask(), value = Port::get() & mask; value; mask >>= 1, value >>= 1) { if (mask & 1u) { if (value & 1u) result |= (1u << pin); ++pin; } } return result; } // запись значения в шину static void set(unsigned value) { for (auto mask = getMask(), pin = 0u; mask; mask >>= 1, ++pin) { if (mask & 1u) { Port::setPin(pin, value & 1); value >>= 1; } } } private: // вспомогательная шаблонная функция для вычисления маски шины template<uint32_t FirstPin, uint32_t... OtherPins> static constexpr uint32_t getMask() { uint32_t value { 0 }; if constexpr (sizeof...(OtherPins) > 0) { value = getMask<OtherPins...>(); } value |= (1 << FirstPin); return value; } }; }; int main() { using PortA = Port<'A'>; PortA::setPin(1, true); // установим бит 1 в единичку std::cout << "Читаем порт, должно быть число 2: " << PortA::get() << std::endl; PortA::setPin(2, true); // установим бит 2 в единичку std::cout << "Читаем порт, должно быть число 6: " << PortA::get() << std::endl; PortA::set(0); std::cout << "Читаем порт, должно быть число 0: " << PortA::get() << std::endl; // шина из битов 0, 2, 4 порта A using PortA_Pins024 = PortA::Bus<0, 2, 4>; static_assert (PortA_Pins024::getMask() == 21, ""); // проверим маску. std::cout << "Читаем шину, должно быть число 0: " << PortA_Pins024::get() << std::endl; PortA_Pins024::set(1); std::cout << "Читаем шину, должно быть число 1: " << PortA_Pins024::get() << std::endl; std::cout << "Читаем порт, должно быть число 1: " << PortA::get() << std::endl; PortA_Pins024::set(2); std::cout << "Читаем шину, должно быть число 2: " << PortA_Pins024::get() << std::endl; std::cout << "Читаем порт, должно быть число 4: " << PortA::get() << std::endl; PortA_Pins024::set(3); std::cout << "Читаем шину, должно быть число 3: " << PortA_Pins024::get() << std::endl; std::cout << "Читаем порт, должно быть число 5: " << PortA::get() << std::endl; } Можно потыкать вот тут. Думаю, идея понятна.
  8. Допустим, сам класс может предоставлять базовый адрес порта и структуру регистров. Также он может давать функции установки/сброса/смены режима битов порта по маске. А вложенный шаблон класса (типа моего PinBus) - содержит лишь набор ножек, и умеет вычислять маски. Вот и удобство. Я редко во всё это погружаюсь, поэтому быстренько набросать не получается :-)
  9. Я прошу прощения за задержку с ответом. Неожиданно навалилась куча дел по работе :-)
  10. Контейнер = объект (экземпляр). А так можно обойтись классами, без экземпляров. Для эмбеда это плюс.
  11. Я обычно проверяю мелкие вещи вот здесь: https://wandbox.org/ А если надо посмотреть дизассемблер разных компиляторов под разные архитектуры, то есть https://godbolt.org/
  12. Ну, я подозревал, что в шаблонных функциях он понадобится, вот и объявил. А как именно использовать - не знал. По остальному чуть позже отвечу. (Пока можете глянуть на вот эту мою заготовку).
  13. Вы бы словами описали, что надо-то. А так - вот: template <char portLetter> class Port { public: static constexpr char portName { portLetter }; template <typename First> static uint64_t comb(First value) { return value; } template <typename First, typename... Other> static uint64_t comb(First value, Other ... values) { return comb(values ...) << 8 | comb(value); } }; int main() { using PortA = Port<'A'>; std::cout << PortA::comb(1, 1, 1) << std::endl; } Правда, я не понимаю, зачем тут класс, но раз надо, то пусть будет :-)
  14. Просто вокруг них написать class и поставить скобочки :-) Получится шаблонный класс (со своими параметрами, типа, номер порта), и внутри него шаблонные функции, со своими параметрами.
  15. Я не очень понял, что нужно. Просто комбинировать маски? Это просто: // шаблонная функция с одним параметром (она будет завершать рекурсию) template <typename First> uint32_t Comb(First value) { return value; } // шаблонная функция с более чем одним параметром. Первый параметр // отделяется в First, остальные - упакованы в Other template <typename First, typename... Other> uint32_t Comb(First first, Other... other) { return Comb(other...) << 8 | Comb(first); } // Применение: std::cout << Comb('A', 'B', 'C') << std::endl; std::cout << Comb(2, 1, 1) << std::endl; // Для c++17 можно проще, через if constexpr: template <typename First, typename... Other> uint32_t CombC17(First first, Other... other) { uint32_t value { 0 }; if constexpr (sizeof...(Other) > 0) { value = CombC17(other...) << 8; } value |= first; return value; } // Примененять так же: std::cout << CombC17('A', 'B', 'C') << std::endl; std::cout << CombC17(2, 1, 1) << std::endl;