Jump to content

    

C++ и макросы имени Аскольда Волкова.

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

 

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

 

Если я вас чем-то обидел - прощу прощения и на том закончим.

Share this post


Link to post
Share on other sites
Вы внимательно пересмотрите свой топик.

 

Пересмотрел. Не увидел, в чём я неправ. Я лишь симметрично отвечал.

 

Не можете поддерживать в спокойном тоне дискуссию - не мои проблемы.

 

Могу. Пока кто-то не выведет дискуссию из спокойного русла.

 

Не можете ясно излагать свои идеи - тоже не ко мне.

 

Могу. Я излагаю свои идеи на форуме разработчиков электроники. Это подразумевает определённый уровень участников. Если кто-то не понимает - не мои проблемы.

 

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

 

Ах, вот оно что. Вы решили меня повоспитывать? Спасибо, не надо.

 

Если я вас чем-то обидел - прощу прощения и на том закончим.

 

Ок.

Share this post


Link to post
Share on other sites

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

 

Я делал так. это не совсем по теме, но...:
enum usci_module_t { USCI0, USCI1 };

template <usci_module_t const module>
class uscia_t
{
public:
     class usca_ctl0_t    /* USCI Ax Control Register 0 */
     {
     public:
         uint8_t operator=(uint8_t value) { module ? UCA1CTL0 = value : UCA0CTL0 = value; return value; }
         void operator|=(uint8_t value) { module ? UCA1CTL0 |= value : UCA0CTL0 |= value; }
         void operator&=(uint8_t value) { module ? UCA1CTL0 &= value : UCA0CTL0 &= value; }
         operator uint8_t() { return module ? UCA1CTL0 : UCA0CTL0; }
     } static CTL0;
...
// pins
     class txd_bit
     {
     public:
         operator uint8_t() { return module ? (1 << 6) : (1 << 4); }
     }  static TXD_BIT;
...
};

template <usci_module_t module>
class uart_t
{
     typedef uscia_t<module> UCA;
public:
     static INLINE inline void init(uint32_t const divider);
....
};

template <usci_module_t module>
void uart_t<module>::init(uint32_t const divider)
{
     UCA::CTL1 |= (1  * UCSWRST);
     UCA::CTL1 = 0
...
}

 

Здесь ведь можно сделать ещё красивее, если унаследовать uart_t от uscia_t:

template <usci_module_t module>
class uart_t: public uscia_t<module>
{
public:
     static INLINE inline void init(uint32_t const divider);
....
};

 

Тогда не потребуется указывать UCA:: при обращении к регистрам:

 

template <usci_module_t module>
void uart_t<module>::init(uint32_t const divider)
{
     CTL1 |= (1  * UCSWRST);
     CTL1 = 0
...
}

Share this post


Link to post
Share on other sites
Тогда не потребуется указывать UCA:: при обращении к регистрам:
А это мысль! Нет предела совершнству!

Share this post


Link to post
Share on other sites
А это мысль! Нет предела совершнству!

 

Оказывается, есть... Эта красота не работает в более свежих gcc. Ругается, что мембер из базового класса "was not declared in this scope" в классе-потомке.

Я покопался в интернете, оказывается, что стандарт на этот счёт гласит:

 

14.6.2/3

In the definition of a class template or a member of a class template, if a base class of the class template depends on a template-parameter, the base class scope is not examined during unqualified name lookup either at the point of definition of the class template or member or during an instantiation of the class template or member.

 

И даже есть специальный баг, из-за которого, возможно, это работает в msp-gcc :)

 

Я опечален :(

Share this post


Link to post
Share on other sites

Короче, вот что получилось в итоге: pin_h_stm32.rar

 

От общего виртуального предка я отказался, всё-таки оказалось накладно. Придумал другой способ передачи ножек в объект - через параметр шаблона.

Например, библиотечный файл adc.h:

template <typename cs_pin>class adc_t
{
private:
    spi_t& spi;
    cs_pin CS;
    void select() { CS.On(); }
    void deselect() { CS.Off(); }
public:
    adc_t(spi_t& spi_ref): spi(spi_ref) { CS.Mode(OUTPUT); deselect(); }
}

 

А в приложении:

typedef Pin<'A', 2, 'L'> adc_cs_t;
typedef adc_t<adc_cs_t> adc1_t;

и, наконец,

adc1_t adc(spi2);

 

Как-то так:) Конструктивная критика и предложения по улучшению - приветствуются:)

 

ЗЫ. Есть ещё такая-же, но для MSP, на днях выложу.

Share this post


Link to post
Share on other sites

На днях опять пришлось иметь дело с проектом, где с разными ножками контроллера поочередно выполняются одинаковые действия. Снова вернулся к проблеме обращения к ногам через ссылки в массиве. И хотя главную проблему так и не решил (неоправданное разрастание кода при использовании виртуальных функций в шаблонных классах), однако получилось написать класс, который понимает Аскольдовские объявления ножек, а также имеется возможность создать порты на разные контроллеры. В данном случае выкладываю порт на ADuc702x, который можно переделать например под AVR переписав небольшой класс BaseIO, или еще лучше добавить условную компиляцию...

#define Req1      1, 0, L
#define Req2      1, 1, L
//...
#define ChipSel1  1, 7, L
#define ChipSel2  0, 5, L
//...
#include "ascold.h"
#include "pin.hpp"
Pin<ChipSel1> CS1;
Pin<ChipSel2> CS2;

Pin<Req1> RQ1;
Pin<Req2,OUTPUT_OK> RQ2;

int main()
{
on(ChipSel1);  // макрос Аскольда Волкова
CS1.On();       // гибрид на С++
}

pin.zip

Share this post


Link to post
Share on other sites
On 9/8/2009 at 8:19 AM, AHTOXA said:

 

Здравствуйте.

В вашей библиотеке используется шаблоны для рабоы с ножками МК.

template<
    char port,
    int pin_no,
    char activestate = 'H',
    PinSpeed speed = PIN_SPEED_100MHZ
    > struct Pin;

Можно ли как-то на основе этих шаблонов сделать массив ножек?

Чтобы в дальнейшем обращаться к ним по интексу.

Например у меня 5 светодиодов. 

Я хочу чтобы у меня был массив светодиодов

LED[5];

И обращаться к нему как-то так (синтаксис абстрактный)

LED[1]::On();
LED[0]::Off();

 

Share this post


Link to post
Share on other sites

Это мы с dimka76 в личке пообщались, вот наша переписка:

AHTOXA 0

Привет!

К сожалению, поместить имеющиеся ножки в массив нельзя. Дело в том, что каждая ножка имеет свой, уникальный тип, поэтому в массив они не ложатся. 

Для формирования шины из отдельных ножек нужно что-то типа этого:

https://github.com/KonstantinChizhov/Mcucpp/blob/master/mcucpp/pinlist.h

Я периодически думаю, что надо бы сделать такое, но каждый раз мне не хватает времени/желания, и я обхожусь простым вариантом:

template<typename props>
void HD44780<props>::Write(uint8_t b)
{
	BusToOutput();
	ENABLE::On();
	D0::On(b&0x01);
	D1::On(b&0x02);
	D2::On(b&0x04);
	D3::On(b&0x08);
	D4::On(b&0x10);
	D5::On(b&0x20);
	D6::On(b&0x40);
	D7::On(b&0x80);
	BusDelay();
	ENABLE::Off();
}

Я себя успокаиваю тем, что это самый быстрый вариант :)

 

dimka76 0

Спасибо за ответ.

pinlist.h - видел.

Я только приглядываюсь к С++ и шаблоны для меня пока что-то вроде черной магии )))

Цитата

Я себя успокаиваю тем, что это самый быстрый вариант :)

Быстрый в плане реализации, но не в плане работы :)

Мене тут один знающий программист предлагал сделать примерно так.

class dbg_led_base_t
{
 public:
	virtual void led_on() = 0;
	virtual void led_off() = 0;
	virtual void led_toggle() = 0;
};

template<
	char port,
	int pin_no,
	char activestate = 'L',
	PinSpeed speed = PIN_SPEED_2MHZ
	>
class dbg_led_t;

template<char port, int pin_no, char activestate, PinSpeed speed>
class dbg_led_t : public dbg_led_base_t
{
private:
	typedef Pin<port, pin_no, activestate, speed> LED_PIN;
public:
	INLINE dbg_led_t()
	{
		// configure pins
		LED_PIN::Direct(OUTPUT);
	}

	INLINE void led_on() { LED_PIN::On(); }
	INLINE void led_off() { LED_PIN::Off(); }
	INLINE void led_toggle() { LED_PIN::Cpl(); }
};

А использовать так

 

dbg_led_base_t* leds[4];

leds[0] = new dbg_led_base_t<'C', 0>();
leds[1] = new dbg_led_base_t<'A', 5>();

 

Но тут появляется куча.

 

AHTOXA 0

В 26.05.2019 в 22:50, dimka76 сказал:

Быстрый в плане реализации, но не в плане работы :) 

Нет, и в плане работы тоже. Конечно, если ножки все "вразброс". Если сравнивать с вариантом GPIOC->ODR = b; , то медленнее.

В 26.05.2019 в 22:50, dimka76 сказал:

А использовать так


dbg_led_base_t* leds[4];

leds[0] = new dbg_led_base_t<'C', 0>();
leds[1] = new dbg_led_base_t<'A', 5>();

Но тут появляется куча. 

Можно и без кучи:

dbg_led_base_t* leds[4];

dbg_led_base_t<'C', 0> led0;
dbg_led_base_t<'A', 5> led1;

leds[0] = &led0;
leds[1] = &led1;

Но это тоже будет медленнее, чем вариант "в лоб".

 

ОК.

Спасибо.

Буду пробовать.

 

AHTOXA 0

Если ещё интересно: вот .

Глядя в листинг, получается очень хорошо, практически один-в-один с вариантом "в лоб". Живьём пока не пробовал.

(Требуется c++17)

 

Спасибо !.

Интересно. Попробую. 

В вашем примере все ножки принадлежать одному порту и идут подряд.

А если группа ног разбросана по разным портам ?

AHTOXA 0

Это без разницы. Они в любом случае обрабатываются по отдельности.

 

Ясно. Спасибо.

./common/CMSIS/core_cmFunc.h: In function 'uint32_t __get_PSP()':
./common/CMSIS/core_cmFunc.h:405:21: warning: ISO C++1z does not allow 'register' storage class specifier [-Wregister]

 

Share this post


Link to post
Share on other sites

Подытожу.

В дополнение к pin.h теперь есть pin_bus.h.

Использовать так:

 // объявляем ножки для шины:
     using D0 = Pin<'E', 0>;
     using D1 = Pin<'E', 1>;
     using D2 = Pin<'E', 2>;
     using D3 = Pin<'E', 3>;
     using D4 = Pin<'E', 4>;
     using D5 = Pin<'E', 5>;
     using D6 = Pin<'E', 6>;
     using D7 = Pin<'E', 7>;
 
 // объявляем класс шины:
     using TestBus = STM32TPL::Bus<D0, D1, D2, D3, D4, D5, D6, D7>;
 
 // используем его:
     TestBus::mode(OUTPUT);
     auto value = TestBus::get();
     TestBus::set(value + 1);

Пока это только набросок, в работе не проверял.

Share this post


Link to post
Share on other sites
On 5/29/2019 at 9:23 AM, AHTOXA said:

Пока это только набросок, в работе не проверял.

Попробовал с компилятором arm-none-eabi-gcc (GNU Tools for Arm Embedded Processors 7-2017-q4-major) 7.2.1

Все работает.

Пробовал с четырьмя выводами, принадлежащими одному порту.

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

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

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now