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)
但我的老师说我最好使用#define
s,例如:
#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
真的值得使用而不是enum
s和堆栈分配的指针吗?
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++,那么你可以为外设上的所有常见操作添加方法,并很好地封装设备的特性.
我担心enum
这样的任务是死路一条.标准将enum
常量定义为类型int
,因此通常它们与指针不兼容.
有一天在32位int
和64位指针的架构上你可能有一个不适合的常量int
.尚未明确定义将会发生什么.
另一方面enum
,在堆栈上分配内容的参数无效.它们是编译时常量,与函数堆栈无关,或者与通过宏指定的任何常量无关.