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

发布于 2024-09-28 07:56:55 字数 833 浏览 3 评论 0原文

我必须在基于 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 US_BASE (0xFFFC4000)
#define US_BRGR (US_BASE + 0x16)
#define pBRGR   ((vuint*) US_BRGR)

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

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

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


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

I have to program peripheral registers in an ARM9-based microcontroller.

For instance, for the USART, I store the relevant memory addresses in an enum:

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

Then, I use pointers in a function to initialize the registers:

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

But my teacher says I'd better use #defines, such as:

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

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

Like so, he says, you don't have the overhead of allocating pointers in the stack.

Personally, I don't like #defines much, nor other preprocessor directives.
So the question is, in this particular case, are #defines really worth using instead of enums and stack-allocated pointers?


Related question: Want to configure a particular peripheral register in ARM9 based chip

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(7

翻身的咸鱼 2024-10-05 07:56:55

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

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 提供了有关该技术的更多详细信息,并指出了它相对于其他方法的优势。

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

The approach I've always preferred is to first define a struct reflecting the peripherals register layout

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;

Then in code I can just use

p_usart0->brgr = 0x030C;

This approach is much cleaner when you have multiple instances of the same sort of peripheral:

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

User sbass provided a link to an excellent column by Dan Saks that gives much more detail on this technique, and points out its advantages over other approaches.

If you're lucky enough to be using C++, then you can add methods for all the common operations on the peripheral and nicely encapsulate the devices peculiarities.

空名 2024-10-05 07:56:55

我担心 enum 对于这样的任务来说是一个死胡同。该标准将enum常量定义为int类型,因此通常它们与指针兼容。

有一天,在具有 32 位 int 和 64 位指针的架构上,您可能会遇到一个不适合 int 的常量。目前尚不清楚会发生什么。

另一方面,enum 将在堆栈上分配某些内容的论点是无效的。它们是编译时常量,与函数堆栈无关,也与您通过宏指定的任何常量无关。

I am afraid that enum are a dead end for such a task. The standard defines enum constants to be of type int, so in general they are not compatible with pointers.

One day on an architecture with 32bit int and 64bit pointers you might have a constant that doesn't fit into an int. It is not well defined what will happen.

On the other hand the argument that enum would allocate something on the stack is not valid. They are compile time constants and have nothing to do with the function stack or no more than any constants that you specify through macros.

木有鱼丸 2024-10-05 07:56:55

Dan Saks 就此嵌入式系统编程撰写了许多专栏。这是他的最新文章之一。他讨论了 C、C++、枚举、定义、结构、类等,以及为什么您可能会一一讨论。绝对值得一读,并且总是好的建议。

Dan Saks has written a number of columns on this for Embedded Systems Programming. Here's one of his latest ones. He discusses C, C++, enums, defines, structs, classes, etc. and why you might one over another. Definitely worth reading and always good advice.

相对绾红妆 2024-10-05 07:56:55

根据我的经验,使用 #define 来处理此类事情的一个重要原因是它更像是嵌入式社区中使用的标准习惯用法。

使用枚举而不是#define 会产生来自教师(以及将来的同事)的问题/评论,即使使用其他技术可能有其他优点(例如不破坏全局标识符命名空间)。

我个人喜欢使用枚举来表示数字常量,但有时您需要按照您正在工作的内容和地点执行惯常的操作。

然而,性能不应该成为问题。

In my experience, one big reason to use #define for this kind of thing is that it's more of the standard idiom used in the embedded community.

Using enums instead of #define will generate questions/comments from instructors (and in the future, colleagues), even when using other techniques might have other advantages (like not stomping on the global identifier namespace).

I personally like using enums for numeric constants, but sometimes you need to do what is customary for what and where you're working.

However, performance shouldn't be an issue.

辞旧 2024-10-05 07:56:55

答案总是按照老师的要求去做,通过课程,然后根据你自己的问题,找出他们的理由是否有效,并形成你自己的意见。你赢不了学校,不值得。

在这种情况下,很容易编译为汇编程序或反汇编以查看枚举和定义之间的差异(如果有)。

我建议使用定义而不是枚举,因为编译器对枚举感到不舒服。我非常不鼓励像使用指针那样使用指针,我见过每个编译器都无法准确生成所需的指令,这种情况很少见,但当它发生时,你会想知道你过去几十年的编码是如何工作的。指向结构或其他任何东西要糟糕得多。我经常因此而受到批评,并且希望这一次也能如此。街区周围有太多英里,修复了太多带有这些问题的损坏代码,以至于忽略了根本原因。

The answer is always do whatever the teacher wants and pass the class then on your own question everything and find out if their reasons were valid and form your own opinions. You cant win against the school, not worth it.

In this case it is easy to compile to assembler or disassemble to see the difference if any between the enum and define.

I would recommend the define over enum, have had compiler discomfort with enums. I highly discourage using pointers the way you are using them, I have seen every compiler fail to accurately generate the desired instructions, it is rare but when it happens you will wonder how your last decades of coding ever worked. Pointing structs or anything else is considerably worse. I often get flamed for this, and expect to this time around. Too many miles around the block, fixed too much broken code with these problems to ignore the root cause.

我的黑色迷你裙 2024-10-05 07:56:55

我不一定会说这两种方式都更好。这只是个人喜好。至于你教授的论点,这确实是一个有争议的问题。在堆栈上分配变量是一条指令,无论有多少条指令,通常采用 sub esp, 10h 的形式。因此,如果您有 1 个本地或 20 个本地,则仍然需要一条指令来为所有本地分配空间。

我想说的是,#include 的一个优点是,如果由于某种原因您想更改该指针的访问方式,您只需在一个位置更改它即可。

I wouldn't necessarily say that either way is better. It is just personal preference. As for your professor's argument, it is really a moot point. Allocating variables on the stack is one instruction, no matter how many there are, usually in the form sub esp, 10h. So if you have one local or 20, it is still one instruction to allocate the space for all of them.

I would say that the one advantage of the #include is that if for some reason down the road you wanted to change how that pointer is accessed, you just need to change it in one location.

空城旧梦 2024-10-05 07:56:55

我倾向于使用枚举,以便将来与 C++ 代码兼容。我这样说是因为在我的工作中,我们有很多项目之间共享的 C 头文件,其中一些使用 C 代码,一些使用 C++。对于那些使用 C++ 的人来说,我们通常希望将定义包装在命名空间中,以防止符号屏蔽,但您不能将 #define 分配给命名空间。

I would tend towards using an enum, for potential future compatibility with C++ code. I say this because at my job, we have a lot of C header files shared between projects, some of which use C code and some of which use C++. For those using C++, we'd often like to wrap the definitions in a namespace, to prevent symbol masking, but you can't assign a #define to a namespace.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文