используя макросы для настройки - PullRequest
1 голос
/ 28 февраля 2009

Пишу прошивку на C для встроенного процессора. Я хочу, чтобы вся информация о конфигурации была в одном заголовочном файле с именем config.h. Это вызывает проблемы с инициализацией АЦП, где простые #defines не сработают. Прямо сейчас код выглядит так:

config.h

#define NUMBER_OF_POTS  1
#define POT_1_CHANNEL  27

adc.c

#define MAKE_CSS(channel) _CSS##channel
#define CALL_MAKE_CSS(channel) MAKE_CSS(channel)

void initialize_adc() {
   CALL_MAKE_CSS(POT_1_CHANNEL);
}

То, что я хочу сделать, это не касаться adc.c, если я изменю config.h на:

#define NUMBER_OF_POTS  2
#define POT_1_CHANNEL  27
#define POT_2_CHANNEL  29

adc.c должен просто автоматически добавить секунду CALL_MAKE_CSS с некоторыми хитростями макросов.

Полагаю, вопрос в следующем: есть ли уловка, которая дает вам возможность цикла с макросом?

Спасибо

Стив.

Ответы [ 5 ]

3 голосов
/ 28 февраля 2009

Я не проверял это:

// config.h

#define NUMBER_OF_POTS  2
extern int pots[];

// config.c

int pots[NUMBER_OF_POTS] = {
    27,
    29
};


// adc.c

void initialize_adc() {
    for (int i = 0; i < NUMBER_OF_POTS; i++) {
        CALL_MAKE_CSS(pots[i]);
    }
}
1 голос
/ 28 февраля 2009

Вам не нужно полностью полагаться на макросы. Просто определите ваши «магические числа» как # определяет.

Например:

В config.h:

#define NUMBER_OF_POTS 2
#define POT_1_CHANNEL  27
#define POT_2_CHANNEL  29

unsigned int PotChannelList[NUMBER_OF_POTS] = {POT_1_CHANNEL, POT_2_CHANNEL};

В adc.c:

for(i = 0; i < NUMBER_OF_CHANNELS; i++)
{
  initialize_adc(PotChannelList[i]);
}

Вы по-прежнему определяете настройку в config.h, и вам не нужно менять adc.c при добавлении канала. Вы просто добавляете его в список. Порядок списка также определяет порядок инициализации.

РЕДАКТИРОВАТЬ: Извините за беспорядок форматирования ...

0 голосов
/ 02 марта 2009

Хотя вы не можете делать циклы с препроцессором, вы можете делать развернутые циклы. Поэтому, если вы знаете, что у вас никогда не будет больше 4 банков, вы можете сделать это;

void initialize_adc() {
  #if NUMBER_OF_POTS > 0
    CALL_MAKE_CSS(POT_1_CHANNEL);
  #endif
  #if NUMBER_OF_POTS > 1
    CALL_MAKE_CSS(POT_2_CHANNEL);
  #endif
  #if NUMBER_OF_POTS > 2
    CALL_MAKE_CSS(POT_3_CHANNEL);
  #endif
  #if NUMBER_OF_POTS > 3
    CALL_MAKE_CSS(POT_4_CHANNEL);
  #endif
}

Единственное преимущество этого по сравнению с другими решениями здесь состоит в том, что нет никаких затрат времени выполнения вообще. Дополнительный встроенный код «волшебным образом» появляется тогда и только тогда, когда добавляется другой канал, как этого хотел спрашивающий. Чтобы извлечь уродство из вызова функции (за счет того, чтобы вместо этого поместить его раньше в свой код), определите 4 новых макроса каждый, используя один и тот же метод #if NUMBER_OF_POTS> x. Тогда ты сможешь пойти просто;

void initialize_adc() {
  INIT_CSS_1();
  INIT_CSS_2();
  INIT_CSS_3();
  INIT_CSS_4();
}
0 голосов
/ 02 марта 2009

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

0 голосов
/ 28 февраля 2009

Посмотрите на boost.preprocessor . Хотя boost обычно используется для C ++, библиотека метапрограммирования препроцессора работает, ну, в общем, только с CPP, поэтому она может делать то, что вы хотите. Он предоставляет несколько структур данных (списки, кортежи) и макросы итерации.

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

Примечание Только что увидел ответ Шредера. Не полагаться на ПП, если это не нужно, по-прежнему лучший вариант ...

...