<?xml version="1.0" encoding="UTF-8"?>        <rss version="2.0"
             xmlns:atom="http://www.w3.org/2005/Atom"
             xmlns:dc="http://purl.org/dc/elements/1.1/"
             xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
             xmlns:admin="http://webns.net/mvcb/"
             xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
             xmlns:content="http://purl.org/rss/1.0/modules/content/">
        <channel>
            <title>
									Сообщество | Библиотеки для STM32 на C++ - STM32				            </title>
            <link>https://microtechnics.ru/community/stm32/seriya-statej-pro-perehod-na-klassy-na-stm32/</link>
            <description>Обсуждение вопросов, посвященных программированию микроконтроллеров, разработке электроники и не только.</description>
            <language>ru-RU</language>
            <lastBuildDate>Sat, 06 Jun 2026 11:11:37 +0000</lastBuildDate>
            <generator>wpForo</generator>
            <ttl>60</ttl>
							                    <item>
                        <title>НА: Сообщество | Библиотеки для STM32 на C++</title>
                        <link>https://microtechnics.ru/community/stm32/seriya-statej-pro-perehod-na-klassy-na-stm32/paged/3/#post-4023</link>
                        <pubDate>Sun, 16 Nov 2025 14:53:14 +0000</pubDate>
                        <description><![CDATA[Может тогда Телега?]]></description>
                        <content:encoded><![CDATA[<p></p>
<p>Нет, не против &#x1f642; Главное - не забыть на каком сайте я был</p>
<p></p>
<p>Может тогда Телега?</p>]]></content:encoded>
						                            <category domain="https://microtechnics.ru/community/stm32/">STM32</category>                        <dc:creator>Эдуард</dc:creator>
                        <guid isPermaLink="true">https://microtechnics.ru/community/stm32/seriya-statej-pro-perehod-na-klassy-na-stm32/paged/3/#post-4023</guid>
                    </item>
				                    <item>
                        <title>НА: Сообщество | Библиотеки для STM32 на C++</title>
                        <link>https://microtechnics.ru/community/stm32/seriya-statej-pro-perehod-na-klassy-na-stm32/paged/3/#post-4022</link>
                        <pubDate>Sun, 16 Nov 2025 12:51:23 +0000</pubDate>
                        <description><![CDATA[Что касается настройки режима пинов, то просто выносите эти настройки за пределы функции настройки SPI или прочего. Вариант с вложенной настройкой пинов происходил из ложного убеждения, что ...]]></description>
                        <content:encoded><![CDATA[<p></p>
<p>А это для меня вообще больное место. Не смог придумать ничего лучшего.</p>
<p></p>
<p>Что касается настройки режима пинов, то просто выносите эти настройки за пределы функции настройки SPI или прочего. Вариант с вложенной настройкой пинов происходил из ложного убеждения, что дескать можно забыть настроить пины или забыть включить тактирование. Но ведь дело то в том, что SPI и ему подобные могут переназначаться на разные пины. И уж лучше оставить настройку пинов вне функции настройки SPI, чем городить излишний огород. </p>
<p>Касательно класса GPIO. Здесь есть некоторые неудобства, что GPIO - это как целый порт, так и одиночные пины в разных их комбинациях. Поэтому тут могут быть разные взгляды на описание GPIO. Я видел и перепробовал немало вариантов, и на сегодняшний момент пришел к некоему среднему, компромиссному варианту. Он неидеален (как впрочем и предыдущие), но вполне себе неплохо работает. Главное - работает быстро. </p>
<p>Основа та же самая - шаблонный класс Gpio, параметр которого - буква имени порта. Эту букву можно задать непосредственно ANSI-символом: template&lt;char Letter&gt; class Gpio; и прописать псевдоним using GpioA = Gpio&lt;'A'&gt;; <br />Но можно завести enum class Letter {A, B, C /*и так далее */} и написать template&lt;Letter Name&gt; class Gpio; using GpioA = Gpio&lt;Letter::A&gt;;<br />В свете того, что будут использоваться псевдонимы GpioA, GpioB и тд большой разницы в этих вариантах нет. Во втором варианте более строгая типизация шаблона, и при написании не ошибешься буквой. Впрочем, как уже сказал, в основном то используются заданные псевдонимы имени.</p>
<pre contenteditable="false">namespace HAL {
namespace GPIO {

enum class Letter {A, B, C /* и так далее */ };

template&lt;Letter Name&gt;
class Gpio {
public:
	template&lt;uint16_t Mask&gt;
	static void SetPins()
	{
		GetBase()-&gt;BSRR = Mask;
	}

	template&lt;uint16_t Mask&gt;
	static void ResetPins();

	template&lt;uint16_t Mask&gt;
	static void TogglePins();

	template&lt;uint16_t Mask&gt;
	static void WritePins(uint16_t value);

	static void WritePort(uint16_t value);
	static uint16_t ReadPort();

	template&lt;uint8_t N&gt;
	struct Pin {
		static constexpr uint16_t mask = 1 &lt;&lt; N;

		static void Set()
		{
			SetPins&lt;mask&gt;();
		}

		static void Reset();
		static void Toggle();

		enum class State {
			RESET = 0,
			SET = mask
		};

		static State Read();
	};

	using Pin0 = Gpio&lt;Name&gt;::Pin&lt;0&gt;;
	using Pin1 = Gpio&lt;Name&gt;::Pin&lt;1&gt;;

private:
	static constexpr GPIO_TypeDef* GetBase()
	{
#ifdef GPIOA
		if constexpr (Name == Letter::A) return GPIOA;
#endif
            /* и так далее */
	}
};</pre>
<p>Класс Gpio содержит вложенный класс template&lt;uint8_t N&gt; Pin, который описывает отдельный пин порта. Обращение к этому пину можно выполнять так:</p>
<pre contenteditable="false">GpioA::Pin0::Set();
GpioA::Pin0::Reset();
GpioA::Pin0::Set();
GpioA::Pin0::Reset();</pre>
<p>что при включенной оптимизации -O3 будет преобразовано в весьма короткий ассемблерный код:</p>
<pre contenteditable="false">movs	r1, #1
mov.w	r2, #65536
ldr	r3, 
movs	r0, #0

str	r1,  
str	r2, 
str	r1, 
str	r2, </pre>
<p>&nbsp;</p>
<p>А вот что касается конфигурации пинов, тут есть некоторая замута. Впрочем, не столь уж и сложная.<br />Лично я пошел по пути того, что описал свойства пинов раздельно для входа и для выхода, ибо они действительно разные. </p>
<pre contenteditable="false">enum class InType { HiZ, PU, PD };
enum class OutType { PP, OD };
enum class Speed { LOW, MED, HIGH, VHIGH };</pre>]]></content:encoded>
						                            <category domain="https://microtechnics.ru/community/stm32/">STM32</category>                        <dc:creator>YumaYuma</dc:creator>
                        <guid isPermaLink="true">https://microtechnics.ru/community/stm32/seriya-statej-pro-perehod-na-klassy-na-stm32/paged/3/#post-4022</guid>
                    </item>
				                    <item>
                        <title>НА: Сообщество | Библиотеки для STM32 на C++</title>
                        <link>https://microtechnics.ru/community/stm32/seriya-statej-pro-perehod-na-klassy-na-stm32/paged/3/#post-4021</link>
                        <pubDate>Sun, 16 Nov 2025 12:50:43 +0000</pubDate>
                        <description><![CDATA[Вполне поддается. Единственная проблема - это проблема самого языка С++ в отношении шаблонов и метапрограммирования - немалый список ограничений и невнятный инструментарий отладки. Например,...]]></description>
                        <content:encoded><![CDATA[<p></p>
<p>А код написанный на шаблонах отладке практически не поддаётся.</p>
<p></p>
<p>Вполне поддается. Единственная проблема - это проблема самого языка С++ в отношении шаблонов и метапрограммирования - немалый список ограничений и невнятный инструментарий отладки. Например, переданные в шаблоне функции параметры можно проверить только косвенно, либо вводя промежуточные переменные для отладки.</p>
<p></p>
<p>Вы не против, если буду обращаться к Вам за консультациями?</p>
<p></p>
<p>Нет, не против :) Главное - не забыть на каком сайте я был.</p>]]></content:encoded>
						                            <category domain="https://microtechnics.ru/community/stm32/">STM32</category>                        <dc:creator>YumaYuma</dc:creator>
                        <guid isPermaLink="true">https://microtechnics.ru/community/stm32/seriya-statej-pro-perehod-na-klassy-na-stm32/paged/3/#post-4021</guid>
                    </item>
				                    <item>
                        <title>НА: Сообщество | Библиотеки для STM32 на C++</title>
                        <link>https://microtechnics.ru/community/stm32/seriya-statej-pro-perehod-na-klassy-na-stm32/paged/3/#post-4020</link>
                        <pubDate>Sun, 16 Nov 2025 11:20:39 +0000</pubDate>
                        <description><![CDATA[Здесь Вы немного неправы. У меня отдельная библиотека для работы с графикой и текстом. Основана на Adafruit_GFX. Я её &quot;передрал&quot; и добавил русификацию utf-8 символов.
В драйвере дисплея тол...]]></description>
                        <content:encoded><![CDATA[<p></p>
<p>в файл работы с дисплеем вписал и работу с GPIO и SPI, и даже отрисовку графики.</p>
<p></p>
<p>Здесь Вы немного неправы. У меня отдельная библиотека для работы с графикой и текстом. Основана на Adafruit_GFX. Я её "передрал" и добавил русификацию utf-8 символов.</p>
<p>В драйвере дисплея только его инициализация и функции, которые могут отличаться от контроллера к контроллеру.</p>
<p>Единственный драйвер, который не пользуется графической библиотекой, на RA8875. Так как его контроллер сам умеет всё рисовать.<br />Достаточно ему только давать координаты.</p>
<p>Кроме этого я очень плохой теоретик. Я больше практик. А код написанный на шаблонах отладке практически не поддаётся.</p>
<p></p>
<p>Хм, а я думал, что за прошедшие несколько лет вы уже разобрались с этим</p>
<p></p>
<p>Всё, что лежит на сайте, давно устарело. Я уже начал разделять функционал как Вы говорите. Но мне некогда стало писать новые статьи и выкладывать новые библиотеки. Я больше схемотехник и теперь занимаюсь своей основной специальностью. Надеюсь после окончания шухера и выхода на пенсию смогу заняться этим более плотно.</p>
<p>Я попытаюсь осмыслить Ваши советы. Вы не против, если буду обращаться к Вам за консультациями?</p>
<p>&nbsp;</p>
<p>&nbsp;</p>]]></content:encoded>
						                            <category domain="https://microtechnics.ru/community/stm32/">STM32</category>                        <dc:creator>Эдуард</dc:creator>
                        <guid isPermaLink="true">https://microtechnics.ru/community/stm32/seriya-statej-pro-perehod-na-klassy-na-stm32/paged/3/#post-4020</guid>
                    </item>
				                    <item>
                        <title>НА: Сообщество | Библиотеки для STM32 на C++</title>
                        <link>https://microtechnics.ru/community/stm32/seriya-statej-pro-perehod-na-klassy-na-stm32/paged/3/#post-4019</link>
                        <pubDate>Sun, 16 Nov 2025 10:40:32 +0000</pubDate>
                        <description><![CDATA[@eduard 
Вкратце глянул. К сожалению, несмотря на применение шаблонов для передачи параметров, есть нелогичности в структуре кода. Как будто автор что-то не до конца понял - шаблоны то прим...]]></description>
                        <content:encoded><![CDATA[@eduard 
<p>Посмотрите его реализацию. По моему у него как раз так сделано как Вы сказали.</p>
<p></p>
<p>Вкратце глянул. К сожалению, несмотря на применение шаблонов для передачи параметров, есть нелогичности в структуре кода. Как будто автор что-то не до конца понял - шаблоны то применил, а всё остальное - написал как попало. </p>
<p>Сделаем на примере SPI:</p>
<p>Создаем файл Spi.hpp (лично я указываю расширение файла .hpp вместо .h просто для ясности, поскольку в языке С++ изменено назначение заголовочного файла .h)<br />В нем будет класс описания модулей SPIx. <br />Вычисление базового адреса регистров SPI выполняется во время компиляции по параметру шаблона класса, и этим заведует статическая constexpr-функция в private-области класса.<br />Остальные методы, тоже статические, размещены в public-области класса и реализуют элементарный функционал модуля. <br />Для создания "красивости и порядка" в именах используются namespace. В рассматриваемом примере их два: namespace HAL - общее имя Hardware Abstraction Layer (именно так расшифровывается HAL), и вложенное в него namespace SPI.<br />Для лучшего структурирования в этот класс вложены внутренние классы struct Flags, struct Irq, struct Dma.<br />Конфигурация SPI передается в параметрах шаблонного метода Init(). Параметры представлены в виде enum class. <br />Здесь я немного сократил код, иначе простыня длинная.<br />В конце using Spi1 = Spi&lt;1&gt; создает псевдоним Spi1, эквивалентный записи Spi&lt;1&gt; для более компактной записи.</p>
<pre contenteditable="false">#include "stm32f1xx.h"

namespace HAL {
namespace SPI {

enum class Role {MASTER, SLAVE};
enum class ClockDiv {_2, _4, _8 /* и так далее */};

template&lt;int N&gt;
class Spi {
public:
	template&lt;Role Role, ClockDiv BR /* и так далее */ &gt;
	static void Init()
	{
		GetBase()-&gt;CR1 = static_cast&lt;uint16_t&gt;(Role) | 
				         static_cast&lt;uint16_t&gt;(BR);
	}

	static void Enable()
	{
		GetBase()-&gt;CR1 |= SPI_CR1_SPE;
	}

	static void Disable()
	{
		GetBase()-&gt;CR1 &amp;= ~SPI_CR1_SPE;
	}

	static bool IsEnable()
	{
		return GetBase()-&gt;CR1 &amp; SPI_CR1_SPE;
	}

	static void WriteDR(uint16_t data)
	{
		GetBase()-&gt;DR = data;
	}

	static uint16_t ReadDR()
	{
		return GetBase()-&gt;DR;
	}

	static void Send(uint16_t data)
	{
		while(Flags::IsTXE() != true);
		WriteDR(data);
	}

	static uint16_t Receive()
	{
		while(Flags::IsRXNE() != true);
		return ReadDR();
	}

	static void WaitTxComplete()
	{
		while(Flags::IsTXE() != true);
		while(Flags::IsBusy() == true);
	}

	struct Flags {
		static bool IsTXE()
		{
			return GetBase()-&gt;SR &amp; SPI_SR_TXE;
		}

		static bool IsRXNE();
		static bool IsBusy();
		static bool IsOverrun();
		static bool IsModeFault();
		static bool IsCrcError();
	};

	struct Irq {
		struct Tx {
			static void Enable();
			static void Disable();
			static bool IsEnable();
		};

		struct Rx {
			static void Enable();
			static void Disable();
			static bool IsEnable();
		};

		struct Error {
			static void Enable();
			static void Disable();
			static bool IsEnable();
		};
	};

	struct Dma {
		struct Tx {
			static void Enable();
			static void Disable();
			static bool IsEnable();
		};

		struct Rx {
			static void Enable();
			static void Disable();
			static bool IsEnable();
		};
	};

private:
	static constexpr SPI_TypeDef* GetBase()
    {
#ifdef SPI1
        if constexpr (N == 1) return SPI1;
#endif
#ifdef SPI2
        if constexpr (N == 2) return SPI2;
#endif
    /* и так далее */
    }
};

#ifdef SPI1
  using Spi1 = Spi&lt;1&gt;;
#endif
#ifdef SPI2
  using Spi2 = Spi&lt;2&gt;;
#endif
 /* и так далее */</pre>
<p>Описания параметров конфигурации enum class можно поместить и внутрь класса Spi. Лично мне больше нравится снаружи, чтобы меньше букв писать потом. Но это вопрос чисто эстетический, у обоих вариантов есть свои плюсы и минусы.<br />static_cast&lt;uint16_t&gt;(Role) - это плюшка языка С++, указывающая на явное преобразование типа enum class Role к типу uint16_t. <br />Можно записать и покороче в стиле Си: <span style="background-color: #ffffff;padding: 0px 0px 0px 2px"><span style="color: #000000;background-color: #ffffff;font-size: 10pt"><span style="color: #000000">(</span><span style="color: #005032">uint16_t)Role</span></span></span></p>
<p>Применение класса:<br />using namespace HAL::SPI подключает пространство имен HAL::SPI, чтобы его не нужно было каждый раз писать перед Spi1.</p>
<pre contenteditable="false">using namespace HAL::SPI;
Spi1::Init&lt;Role::MASTER, ClockDiv::_4&gt;();
Spi1::Enable();
Spi1::Send(0xAF);
Spi1::WaitTxComplete();
Spi1::Dma::Tx::Enable();</pre>
<p>В таком подходе главная затея состоит в вычислении базового адреса регистров SPI1, SPI2 и тд во время компиляции, без влияния на скорость работы кода. При этом не требуется писать отдельного класса для каждого SPI или передавать базовый адрес в параметрах. Так же созданы функциональные обертки для работы с регистрами периферии, что положительно влияет на структурированность и независимость кода. А включение оптимизации -O2 или -O3 уберет вызовы методов и сделает максимально быстрый код, как если бы писали напрямую обращения к регистрам.</p>
<p>Аналогично можно описать и остальную периферию - GPIO, I2C, UART и прочее.</p>]]></content:encoded>
						                            <category domain="https://microtechnics.ru/community/stm32/">STM32</category>                        <dc:creator>YumaYuma</dc:creator>
                        <guid isPermaLink="true">https://microtechnics.ru/community/stm32/seriya-statej-pro-perehod-na-klassy-na-stm32/paged/3/#post-4019</guid>
                    </item>
				                    <item>
                        <title>НА: Сообщество | Библиотеки для STM32 на C++</title>
                        <link>https://microtechnics.ru/community/stm32/seriya-statej-pro-perehod-na-klassy-na-stm32/paged/3/#post-4018</link>
                        <pubDate>Sun, 16 Nov 2025 08:22:56 +0000</pubDate>
                        <description><![CDATA[@eduard Хм, а я думал, что за прошедшие несколько лет вы уже разобрались с этим :) Если честно, я писал просто &quot;вникуда&quot;, как бы отнефик делать &#x1f600; Просто лазил по инету, наткнулся, по...]]></description>
                        <content:encoded><![CDATA[@eduard Хм, а я думал, что за прошедшие несколько лет вы уже разобрались с этим :) Если честно, я писал просто "вникуда", как бы отнефик делать &#x1f600; Просто лазил по инету, наткнулся, поглазел, ну и написал то, что думаю.]]></content:encoded>
						                            <category domain="https://microtechnics.ru/community/stm32/">STM32</category>                        <dc:creator>YumaYuma</dc:creator>
                        <guid isPermaLink="true">https://microtechnics.ru/community/stm32/seriya-statej-pro-perehod-na-klassy-na-stm32/paged/3/#post-4018</guid>
                    </item>
				                    <item>
                        <title>НА: Сообщество | Библиотеки для STM32 на C++</title>
                        <link>https://microtechnics.ru/community/stm32/seriya-statej-pro-perehod-na-klassy-na-stm32/paged/3/#post-4017</link>
                        <pubDate>Sun, 16 Nov 2025 08:20:20 +0000</pubDate>
                        <description><![CDATA[И после того, как будут приведены в действительно С++-совый вид хотябы основные периферийные модули (GPIO, SPI, I2C, DMA) можно будет приступить к разбирательству с дисплеем. У автора - снов...]]></description>
                        <content:encoded><![CDATA[<p>И после того, как будут приведены в действительно С++-совый вид хотябы основные периферийные модули (GPIO, SPI, I2C, DMA) можно будет приступить к разбирательству с дисплеем. У автора - снова типичная ошибка ардуинщика - в файл работы с дисплеем вписал и работу с GPIO и SPI, и даже отрисовку графики. Из-за этого автору приходится для каждого дисплея писать отдельную библиотеку со всей требухой, и бОльшая часть её будет копироваться без изменений из файла в файл. Весьма неудобная вещь, которая пошла из демо-примеров к дисплеям. В тех примерах кидали всё в одну кучу просто для демонстрации работы, но никак не как руководство к действию.</p>
<p>Таким образом, файл для дисплея должен содержать исключительно инструментарий для управления дисплеем через какой-либо интерфейс, но ни работы интерфейса, ни построителя графики (прямоугольников, линий, текста) в этом файле быть не должно.</p>
<p>Для нашей задачи хорошо подойдет шаблонный класс:</p>
<pre contenteditable="false">template&lt;typename SPI, typename CS, typename DC&gt; class Ssd1306;</pre>
<p>в параметры шаблона которого мы передадим написанные ранее классы для SPI и GPIO:</p>
<pre contenteditable="false">using display = Ssd1306&lt;Spi1, GpioA::pin4, GpioA::pin6&gt;;</pre>
<p>Причем, для дисплея типа SSD1306, который может работать как по SPI, так и по I2C, можем предусмотреть два варианта интерфейса, переписав иначе:</p>
<pre contenteditable="false">template&lt;typename Ifc&gt; class Ssd1306: public Ifc;
template&lt;typename SPI, typename CS, typename DC&gt; class SpiIfc;
template&lt;typename I2C, uint8_t SlaveAddress&gt; class I2cIfc;</pre>
<p>и тогда класс Ssd1306 не придется переписывать под каждый тип интерфейса, дублируя текст. <br />Работа с дисплеем будет выглядеть в этом случае так:</p>
<pre contenteditable="false">using spi = SpiIfc&lt;Spi1, GpioA::pin4, GpioA::pin6&gt;;
using display = Ssd1306&lt;spi&gt;;

display::Open();
display::Init&lt;VertDir::UP, HorizDir::LEFT&gt;();
display::SetContrast(20);
display::PowerOn();
display::Close();</pre>
<p>Методы Open() и Close() прописаны в классах SpiIfc и I2cIfc и означают начало (открытие) и конец (закрытие) сеанса связи. Для интерфейса SPI это дергание ножкой CS, а для I2C - генерацию Start и Stop, а так же передачу адреса слейва.<br />Если у дисплея есть только один тип интерфейса, можно писать как в первом варианте.</p>
<p>В классе дисплея Ssd1306 пропишем СТАТИЧЕСКИЕ методы, реализующие взаимодействие непосредственно с дисплеем: </p>
<pre contenteditable="false">template&lt;VertDir VD, HorizDir HD&gt; static void Init();
static void PowerOn();
static void PowerOff();
static void SetContrast(uint8_t value);
static void SetColumn(uint8_t column);
static void SetPage(uint8_t page);</pre>
<p>и так далее.</p>
<p>Вот это уже будет человеческий, куда более правильный код на C++! <br />А всё, что касается отрисовки линий, прямоугольников, текста и прочего - это должно описываться совсем в других файлах, никак не связанных с дисплеем, и это тема совсем другого разговора. </p>
<p>Вывод. Причина, по которой проделано описанное выше разделение - избавление от дублирования (копирования) в разных файлах общих для всех них участков кода. Файл дисплея описывает ТОЛЬКО функционал дисплея. Если сомневаетесь, что нужно писать в этом файле, откройте даташит дисплея - вы увидите список команд, которые как раз и нужно описать в файле. И ничего другого более!</p>]]></content:encoded>
						                            <category domain="https://microtechnics.ru/community/stm32/">STM32</category>                        <dc:creator>YumaYuma</dc:creator>
                        <guid isPermaLink="true">https://microtechnics.ru/community/stm32/seriya-statej-pro-perehod-na-klassy-na-stm32/paged/3/#post-4017</guid>
                    </item>
				                    <item>
                        <title>НА: Сообщество | Библиотеки для STM32 на C++</title>
                        <link>https://microtechnics.ru/community/stm32/seriya-statej-pro-perehod-na-klassy-na-stm32/paged/3/#post-4016</link>
                        <pubDate>Sun, 16 Nov 2025 08:00:04 +0000</pubDate>
                        <description><![CDATA[А это для меня вообще больное место. Не смог придумать ничего лучшего.
Если бы Вы мне с этим помогли, был бы очень благодарен.
Есть ещё один человек, у которого другой подход. winnie_the_p...]]></description>
                        <content:encoded><![CDATA[<p></p>
<p>Особенно лишнее здесь GPIO. Просто потому, что I2C, как и многие другие модули, не фиксированы жестко на конкретных пинах, они могут быть перенесены. Следовательно, привязываться к пинам в функции настройки модуля - совершенно излишне. </p>
<p></p>
<p>А это для меня вообще больное место. Не смог придумать ничего лучшего.</p>
<p>Если бы Вы мне с этим помогли, был бы очень благодарен.</p>
<p>Есть ещё один человек, у которого другой подход. winnie_the_poo.</p>
<p>Посмотрите его реализацию. По моему у него как раз так сделано как Вы сказали.</p>
<p>https://microtechnics.ru/profilegrid_blogs/stm32-perehodim-na-sovremennyj-c-chast-1-nastrojka-rabochego-prostranstva/#more-19465</p>]]></content:encoded>
						                            <category domain="https://microtechnics.ru/community/stm32/">STM32</category>                        <dc:creator>Эдуард</dc:creator>
                        <guid isPermaLink="true">https://microtechnics.ru/community/stm32/seriya-statej-pro-perehod-na-klassy-na-stm32/paged/3/#post-4016</guid>
                    </item>
				                    <item>
                        <title>НА: Сообщество | Библиотеки для STM32 на C++</title>
                        <link>https://microtechnics.ru/community/stm32/seriya-statej-pro-perehod-na-klassy-na-stm32/paged/2/#post-4015</link>
                        <pubDate>Sun, 16 Nov 2025 07:53:12 +0000</pubDate>
                        <description><![CDATA[@yumayuma Спасибо за подсказки.
Я прекрасно понимаю, что как программист я не очень. Всю жизнь писал на ассемблере.
Нужда заставила перейти на С++, когда перешёл на STM.
И я оказался одни...]]></description>
                        <content:encoded><![CDATA[<p>@yumayuma Спасибо за подсказки.</p>
<p>Я прекрасно понимаю, что как программист я не очень. Всю жизнь писал на ассемблере.</p>
<p>Нужда заставила перейти на С++, когда перешёл на STM.</p>
<p>И я оказался одним из первых, кто занялся библиотеками для него. Все используют HAL и говорят, что С++ не нужен.</p>
<p>Я начал писать всё это, когда не совсем понимал, как лучше сделать. За пример брал Ардуиновские библиотеки, которые не могут быть эталоном.</p>
<p>Я уже начал переписывать их, правда сюда не выкладывал. Как Вы и говорите, я начал отделять "Мух от мёда".</p>
<p>Все, понимающие больше меня почему то не хотят с этим связываться.</p>]]></content:encoded>
						                            <category domain="https://microtechnics.ru/community/stm32/">STM32</category>                        <dc:creator>Эдуард</dc:creator>
                        <guid isPermaLink="true">https://microtechnics.ru/community/stm32/seriya-statej-pro-perehod-na-klassy-na-stm32/paged/2/#post-4015</guid>
                    </item>
				                    <item>
                        <title>НА: Сообщество | Библиотеки для STM32 на C++</title>
                        <link>https://microtechnics.ru/community/stm32/seriya-statej-pro-perehod-na-klassy-na-stm32/paged/2/#post-4014</link>
                        <pubDate>Sat, 15 Nov 2025 16:06:31 +0000</pubDate>
                        <description><![CDATA[Продолжая тему...
Посмотрел несколько файлов топикстартера. Ну, всё по-классике - типовая ошибка в смешивании функционала. Так называемый &quot;побочный эффект функции&quot;. То есть, функция (в С++ ...]]></description>
                        <content:encoded><![CDATA[<p>Продолжая тему...</p>
<p>Посмотрел несколько файлов топикстартера. Ну, всё по-классике - типовая ошибка в смешивании функционала. Так называемый "побочный эффект функции". То есть, функция (в С++ - метод) называется I2C::Init(). Её основное назначение - настройка модуля I2C. А у автора в ней прописана и настройка пинов, и подключение тактирования модуля. Это - и есть "побочный эффект функции". То есть, по названию I2C мы понимаем, что работаем только с I2C. Но по факту там работа и с GPIO, и с RCC. Особенно лишнее здесь GPIO. Просто потому, что I2C, как и многие другие модули, не фиксированы жестко на конкретных пинах, они могут быть перенесены. Следовательно, привязываться к пинам в функции настройки модуля - совершенно излишне. <br />Включение тактирования модуля в I2C::Init() хоть и не сильно мешается, но тоже побочный эффект. Оставить можно, но это будет не совсем чисто, так сказать. Потому как например SPI, и особенно DMA можно перенастраивать в течение работы программы. И повторное включение тактирования будет лишним. Особенно это заметно в DMA.</p>
<p>&nbsp;</p>
<p>&nbsp;</p>]]></content:encoded>
						                            <category domain="https://microtechnics.ru/community/stm32/">STM32</category>                        <dc:creator>YumaYuma</dc:creator>
                        <guid isPermaLink="true">https://microtechnics.ru/community/stm32/seriya-statej-pro-perehod-na-klassy-na-stm32/paged/2/#post-4014</guid>
                    </item>
							        </channel>
        </rss>
		