#define vs. enums для адресации периферийных устройств - PullRequest
6 голосов
/ 19 октября 2010

Я должен программировать периферийные регистры в микроконтроллере на базе ARM9.

Например, для USART я храню соответствующие адреса памяти в enum:

enum USART
{
    US_BASE = (int) 0xFFFC4000,
    US_BRGR = US_BASE + 0x16,
    //...
};

Затем я использую указатели в функции для инициализации регистров:

void init_usart (void)
{
    vuint* pBRGR = (vuint*) US_BRGR;
    *pBRGR = 0x030C;
    //...
}

Но мой учитель говорит, что мне лучше использовать #define s, например:

#define US_BASE (0xFFFC4000)
#define US_BRGR (US_BASE + 0x16)
#define pBRGR   ((vuint*) US_BRGR)

void init_usart (void)
{
    *pBRGR = 0x030C;
}

Вот такПо его словам, у вас нет лишних затрат на размещение указателей в стеке.

Лично мне не очень нравятся #define s или другие директивы препроцессора.Таким образом, вопрос в данном конкретном случае: действительно ли стоит #define s вместо enum s и указателей, выделенных в стеке?


Смежный вопрос: Хотите настроить конкретныйпериферийный регистр в чипе на базе ARM9

Ответы [ 7 ]

12 голосов
/ 19 октября 2010

Подход, который я всегда предпочитал, состоит в том, чтобы сначала определить структуру, отражающую структуру регистров периферийных устройств

typedef volatile unsigned int reg32; // or other appropriate 32-bit integer type
typedef struct USART
{
    reg32 pad1;
    reg32 pad2;
    reg32 pad3;
    reg32 pad4;
    reg32 brgr;
    // any other registers
} USART;

USART *p_usart0 = (USART * const) 0xFFFC4000;

Затем в коде я могу просто использовать

p_usart0->brgr = 0x030C;

Этот подход оченьчище, когда у вас есть несколько экземпляров одного и того же вида периферийных устройств:

USART *p_usart1 = (USART * const) 0xFFFC5000;
USART *p_usart2 = (USART * const) 0xFFFC6000;

Пользователь sbass предоставил ссылку на превосходный столбец Дэна Сакса, который дает гораздо больше подробностей об этой технике, иуказывает на его преимущества перед другими подходами.

Если вам достаточно повезло с использованием C ++, вы можете добавить методы для всех распространенных операций на периферии и красиво инкапсулировать особенности устройств.

5 голосов
/ 19 октября 2010

Боюсь, что enum - тупик для такой задачи.Стандарт определяет enum константы типа int, поэтому в общем случае они не совместимы с указателями.

Однажды в архитектуре с 32-битными int и 64-битными указателямиу вас может быть константа, которая не вписывается в int.Что еще произойдет, пока неясно.

С другой стороны, аргумент, что enum выделит что-то в стеке, недопустим.Они являются константами времени компиляции и не имеют ничего общего со стеком функций или не более, чем с любыми константами, указанными вами в макросах.

3 голосов
/ 20 октября 2010

Дэн Сакс написал несколько колонок об этом для программирования встроенных систем. Вот один из его последних . Он обсуждает C, C ++, перечисления, определения, структуры, классы и т. Д., А также причины, по которым вы можете встретиться. Обязательно стоит прочитать и всегда полезные советы.

1 голос
/ 19 октября 2010

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

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

Я бы порекомендовал определение over enum, у которого компилятор испытывал дискомфорт от enum. Я настоятельно не рекомендую использовать указатели так, как вы их используете. Я видел, что каждый компилятор не может точно сгенерировать нужные инструкции, это редко, но когда это произойдет, вы удивитесь, как работали последние десятилетия программирования. Указывающие структуры или что-то еще значительно хуже. Меня часто зажигают за это, и я ожидаю этого времени. Слишком много миль вокруг блока, исправлено слишком много неработающего кода с этими проблемами, чтобы игнорировать основную причину.

1 голос
/ 19 октября 2010

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

Использование перечислений вместо #define вызовет вопросы/ комментарии от инструкторов (и в будущем, коллеги), даже когда использование других методов может иметь другие преимущества (например, не топать пространство имен глобального идентификатора).

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

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

0 голосов
/ 19 октября 2010

Я бы склонялся к использованию enum для потенциальной будущей совместимости с кодом C ++.Я говорю это потому, что на моей работе у нас есть много файлов заголовков C, которые используются проектами, некоторые из которых используют код C, а некоторые используют C ++.Для тех, кто использует C ++, мы часто хотели бы обернуть определения в пространство имен, чтобы предотвратить маскирование символов, но вы не можете присвоить #define пространству имен.

0 голосов
/ 19 октября 2010

Я бы не сказал, что в любом случае лучше. Это просто личное предпочтение. Что касается аргумента вашего профессора, это действительно спорный вопрос. Распределение переменных в стеке - это одна инструкция, независимо от того, сколько их, обычно в форме sub esp, 10h. Так что если у вас есть один локальный или 20, это все еще одна инструкция, чтобы выделить место для всех из них.

Я бы сказал, что одним из преимуществ #include является то, что если по какой-то причине в будущем вы захотите изменить способ обращения к указателю, вам просто нужно изменить его в одном месте.

...