我必须在基于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
,例如:
#define US_BASE (0xFFFC4000)
#define US_BRGR (US_BASE + 0x16)
#define pBRGR ((vuint*) US_BRGR)
void init_usart (void)
{
*pBRGR = 0x030C;
}
就像这样,他说,你没有在堆栈中分配指针的开销。
就个人而言,我不喜欢#define
,也不喜欢其他预处理器指令。
所以问题是,在这种特殊情况下,#define
是否真的值得使用而不是enum
和堆栈分配指针?
相关问题:Want to configure a particular peripheral register in ARM9 based chip
答案 0 :(得分: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;
然后在代码中我可以使用
p_usart0->brgr = 0x030C;
当您拥有相同类型的外围设备的多个实例时,这种方法会更加清晰:
USART *p_usart1 = (USART * const) 0xFFFC5000;
USART *p_usart2 = (USART * const) 0xFFFC6000;
用户sbass提供了Dan Saks的an excellent column链接,提供了有关此技术的更多详细信息,并指出了其优于其他方法的优势。
如果你很幸运能够使用C ++,那么你可以为外设上的所有常见操作添加方法,并很好地封装设备的特性。
答案 1 :(得分:5)
答案 2 :(得分:3)
Dan Saks为嵌入式系统编程撰写了许多专栏文章。这是他的latest ones之一。他讨论了C,C ++,枚举,定义,结构,类等,以及为什么你可能会在另一个上面。绝对值得一读,总是很好的建议。
答案 3 :(得分:1)
根据我的经验,将#define
用于此类事情的一个重要原因是它更多地是嵌入式社区中使用的标准习惯。
使用枚举而不是#define
将从教师(以及将来的同事)中产生问题/评论,即使使用其他技术可能还有其他优点(例如不要踩到全局标识符命名空间)。
我个人喜欢使用枚举来表示数字常量,但有时你需要按照习惯做什么和你在哪里工作。
但是,性能不应成为问题。
答案 4 :(得分:1)
答案总是做老师想要的任何事情,然后通过课程然后根据自己的问题解决所有事情,并找出他们的理由是否有效并形成自己的意见。你不能赢得反对学校,不值得。
在这种情况下,很容易编译为汇编或反汇编,以查看enum和define之间的差异。
我建议定义enum,让编译器对枚举感到不适。我非常不鼓励使用指针,因为我看到每个编译器都无法准确地生成所需的指令,这种情况很少见,但是当它发生时,你会想知道你的最后几十年的编码是如何工作的。指向结构或其他任何东西都要糟糕得多。我经常因此受到抨击,并期待这一次。在块周围太多英里,用这些问题修复了太多破碎的代码以忽略根本原因。
答案 5 :(得分:0)
我不一定会说两种方式都更好。这只是个人偏好。至于你教授的论点,这真的是一个没有实际意义的问题。在堆栈上分配变量是一条指令,无论有多少指令,通常都是sub esp, 10h
形式。因此,如果您有一个本地或20,那么仍然只需要一条指令来为所有这些分配空间。
我想说#include的一个优点是,如果出于某种原因你想改变指针的访问方式,你只需要在一个位置更改它。
答案 6 :(得分:0)
我倾向于使用枚举,因为将来可能与C ++代码兼容。我这样说是因为在我的工作中,我们在项目之间共享了很多C头文件,其中一些使用C代码,其中一些使用C ++。对于那些使用C ++的人,我们经常喜欢将定义包装在命名空间中,以防止符号屏蔽,但是你不能将#define分配给命名空间。