В случае, если решение от hexa не вполне достаточно, вот второй вариант, который позволяет вам фактически моделировать поведение регистров, на которые ссылаются (включая побочные эффекты и т.д.). Как недостаток, для этого требуется C ++ (и ваш существующий код C может быть скомпилирован как C ++, что часто является сложным требованием), и что структуры не используют собственные типы напрямую, а вместо этого используют псевдоним.
Вы можете определить класс, который реализует operator=
, operator int
и любые другие функции доступа, которые вам могут понадобиться (&=
и т. Д.). Если поля в структуре GPIOC
указывают на тип, который вы можете изменить, вы можете просто изменить этот тип, чтобы он ссылался на ваш класс регистров.
Примерно так:
#ifdef USE_REAL_HW
typedef volatile uint32_t HW_REGISTER32;
#else // (USE_REAL_HW not defined)
template<class T>
class RegisterAbstractionClass {
public:
const T operator= (const T value) {
data = value;
return value;
};
operator const T() {
return data;
};
// Other operators...
protected:
volatile T data;
};
typedef RegisterAbstractionClass<uint32_t> HW_REGISTER32;
#endif // (USE_REAL_HW)
typedef struct {
HW_REGISTER32 IDR;
HW_REGISTER32 CRL;
} gpio_t;
(Обратите внимание, что вышеприведенное несколько упрощено: и IDR
, и CRL
будут вести себя одинаково в этом случае, что, вероятно, не относится к аппаратному обеспечению.)