Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: дефайны засунуть в массив и вызывать
Форум разработчиков электроники ELECTRONIX.ru > Сайт и форум > В помощь начинающему > Программирование
Метценгерштейн
Есть некоторые дефайны:

Код
#define LED_0    LN8_Pin
#define LED_1    LN7_Pin
#define LED_2    LN6_Pin
#define LED_3    LN5_Pin
#define LED_4    LN4_Pin
#define LED_5    LN3_Pin
#define LED_6    LN2_Pin
#define LED_7    LN1_Pin


надо в цикле по очереди их вызывать. Как это делается обычно? Может в массив затолкнуть и по элементам идти?
_pv
const char /*int??*/ array[] = {LED_0, LED_1, LED_2, LED_3, LED_4, LED_5, LED_6, LED_7};

PORT = array[i];
Метценгерштейн
не хочет проглатывать

там дальше
Код
#define  LN8_Pin    GPIOA, GPIO_PIN_2, H


мне в коде надо подставлять, например
Код
on(LED_0);


А не хочет проглатывать, т.к. тип LED_0 вовсе не char или int.

Надо может в enum затолкать и тип enum дать, но ругается на такие энумы, т.к. уже определены в дефайне.
Swup
вероятно надо как-то через # и ## действовать, но что-то не соображу как.
_pv
в этом случае с макросами Волкова не очень красиво получается, так как там в одном месте через запятую перечислены указатель на порт volatile void *, маска unsigned short, и активный уровень, который вообще не имеет типа, так как просто приклеивается препроцессором в нужное место.
соответственно последнее сильно мешает, так как засунуть эту H или L из препроцессора в переменную ещё как-то можно, а вот обратно - никак.
препроцессор не может достать значение переменной и вклеить в кусок кода.

можно попробовать сделать похожие макросы Волкова, небольшие inline функции,
void on(const tPin &pin){
if (pin.polarity == "H") pin.port|= pin.mask; else pin.port &= ~pin.mask;
}

typedef struct{
volatile void * port;
unsigned short mask;
unsigned char polarity;
}tPin;

const tPin LED0 = {GPIOA, (1<<5), "H"};

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

другой тупой способ:
void on_n(int n){
switch(n){
case 0: on(LED0);
case 1: on(LED1);
case 2: on(LED2);
case 3: on(LED3);
...
}
}

on_n(i);
Метценгерштейн
Да, это макросы Аскольда.
Спасибо за подсказку.
_pv
похожие по сути на макросы Волкова вещи ещё легко делаются на шаблонах С++.
http://www.webalice.it/fede.tft/stm32/stm3...rogramming.html

ну это если отсутсвуют религиозные убеждения, что плюсам в программах для МК уровня контроллера светодиода делать нечего sm.gif
Slash
Или так на шаблонах (по-русски с подробным объяснением) http://easyelectronics.ru/rabota-s-portami...erov-na-si.html
brag
Лет 6 работаю с gpio только на шаблонах(compile-time) и интерфейсах (рантайм).
Compile-time:
CODE
template<char GPN> static inline LPC_GPIO_TypeDef* GetGpioByName();
template<> inline LPC_GPIO_TypeDef* GetGpioByName<'0'>(){ return LPC_GPIO0; }
template<> inline LPC_GPIO_TypeDef* GetGpioByName<'1'>(){ return LPC_GPIO1; }
...
template<char GPN> class GpioPort{
public:
static LPC_GPIO_TypeDef* gpio(){ return GetGpioByName<GPN>(); }

static void set(uint32_t msk){ gpio()->FIOSET = msk; }
static void clear(uint32_t msk){ gpio()->FIOCLR = msk; }
//....
};

template<char PORT, int PIN> class GpioPin{
public:
static LPC_GPIO_TypeDef* gpio(){ return GetGpioByName<PORT>(); }

static void set(){ GpioPort<PORT>::set(msk); }
static void clear(){ GpioPort<PORT>::clear(msk); }
// ....
enum{ Pin=PIN, msk=1<<PIN};
static const char Port = PORT;
};

// usage:
#define LED1_pin GpioPin<'0',10>

LED1_pin::set();
//....
LED1_pin::clear();


Runtime:
CODE
class IGpioPin{
public:
virtual ~IGpioPin(){}

virtual void set()=0;
virtual void clear()=0;
// ....
};

template<class T> class IGpioPin_T;

template<char PORT, int PIN>
class IGpioPin_T<GpioPin<PORT,PIN> > : public IGpioPin{
public:
virtual void set(){
GpioPin<PORT, PIN>::set();
};

virtual void clear(){
GpioPin<PORT, PIN>::clear();
}
// .....
};

// usage:

#define LED1_pin GpioPin<'0',10>
IGpioPin_T<LED1_pin> LED1_pin_rt;
//...

IGpioPin* const array[3] = {&LED1_pin_rt, &LED2_pin_rt, &LED3_pin_rt};
void f(){
for(int i=0; i<3; i++)array[i]->set();
}

В итоге при переходе на совершенно другой контроллер софт править не нужно, правится только платформо-зависимый код драйвера.
SSerge
Цитата(Метценгерштейн @ Sep 12 2016, 15:42) *
Надо может в enum затолкать и тип enum дать, но ругается на такие энумы, т.к. уже определены в дефайне.

массивы и енумы удобно генерировать с помощью
https://en.wikipedia.org/wiki/X_Macro
k155la3
Цитата(Метценгерштейн @ Sep 12 2016, 10:07) *
Есть некоторые дефайны:
. . .
надо в цикле по очереди их вызывать. Как это делается обычно? Может в массив затолкнуть и по элементам идти?


Вот была аналогичная задача, добрые люди здесь подсказали.
"Номер" с массивом.
Код
enum
{
LED1,
LED2,
. . . .
LED_MAX
};

int my_array[] =
{
[LED1] = LED8_Pin, // это можно из деф
[LED2] = LED5_Pin,
. . . .
[LED_MAX] = 0
};


for(int i=0; i<LED_MAX; i++) . . . . .


ps - это какраз XMacro из предыд. поста.
brag
Кода будут пины из разных портов, (PORTA, PORTB) - у Вас с этими всеми массивами и дефайнами начнется платформозависимый мрак.
А я в то время просто напишу:
Код
#define LED1_pin GpioPin<'А',5> // этот пин GPIOA.5
#define LED2_pin GpioPin<'B',7> // а этот GPIOB.7
...
IGpioPin_T<LED1_pin> LED1_pin_rt;
IGpioPin_T<LED2_pin> LED2_pin_rt;
//...

IGpioPin* const array[xxx] = {&LED1_pin_rt, &LED2_pin_rt, &LED3_pin_rt,...};
void f(){
for(int i=0; i<sizeof(array)/sizeof(array[0]); i++)array[i]->set();
}

И то, это довольно длинный код, я обычно делаю гораздо короче. Просто привел, чтобы сама суть была понятна.
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.