#define与用于寻址外围设备的枚举

par*_*ras 6 c embedded enums arm c-preprocessor

我必须在基于ARM9的微控制器中编程外设寄存器.

例如,对于USART,我将相关的内存地址存储在enum:

enum USART
{
    US_BASE = (int) 0xFFFC4000,
    US_BRGR = US_BASE + 0x16,
    //...
};
Run Code Online (Sandbox Code Playgroud)

然后,我在函数中使用指针来初始化寄存器:

void init_usart (void)
{
    vuint* pBRGR = (vuint*) US_BRGR;
    *pBRGR = 0x030C;
    //...
}
Run Code Online (Sandbox Code Playgroud)

但我的老师说我最好使用#defines,例如:

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

void init_usart (void)
{
    *pBRGR = 0x030C;
}
Run Code Online (Sandbox Code Playgroud)

他说,就像这样,你没有在堆栈中分配指针的开销.

就个人而言,我不太喜欢#define,也不喜欢其他预处理器指令.所以问题是,在这种特殊情况下,#define真的值得使用而不是enums和堆栈分配的指针吗?


相关问题:想在基于ARM9的芯片中配置特定的外设寄存器

Ste*_*eel 12

我一直偏好的方法是首先定义一个反映外设寄存器布局的结构

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;
Run Code Online (Sandbox Code Playgroud)

然后在代码中我可以使用

p_usart0->brgr = 0x030C;
Run Code Online (Sandbox Code Playgroud)

当您拥有相同类型的外围设备的多个实例时,此方法会更加清晰:

USART *p_usart1 = (USART * const) 0xFFFC5000;
USART *p_usart2 = (USART * const) 0xFFFC6000;
Run Code Online (Sandbox Code Playgroud)

用户sbass提供了Dan Saks 的优秀专栏链接,该专栏提供了有关此技术的更多详细信息,并指出了其优于其他方法的优势.

如果你很幸运能够使用C++,那么你可以为外设上的所有常见操作添加方法,并很好地封装设备的特性.


Jen*_*edt 5

我担心enum这样的任务是死路一条.标准将enum常量定义为类型int,因此通常它们与指针兼容.

有一天在32位int和64位指针的架构上你可能有一个不适合的常量int.尚未明确定义将会发生什么.

另一方面enum,在堆栈上分配内容的参数无效.它们是编译时常量,与函数堆栈无关,或者与通过宏指定的任何常量无关.