【问题标题】:Cleaner namespaces for microcontroller registers微控制器寄存器的更干净的命名空间
【发布时间】:2014-10-04 12:02:04
【问题描述】:

使用微控制器时,您通常必须对寄存器进行读写操作,为了使代码更具可读性,您需要定义寄存器地址及其位。这有点好,但是当您拥有彼此非常相似的寄存器名称时,它很快就会变得混乱,例如此处所示

#define SYSAHBCLKCTRL (*(unsigned int*) 0x40048080)
#define TMR16B0TCR (*(unsigned int*) 0x4000C004)
#define TMR16B0TC (*(unsigned int*) 0x4000C008)
#define TMR16B0PR (*(unsigned int*) 0x4000C00C)
#define TMR16B0MR0 (*(unsigned int*) 0x4000C018) // Match register
#define ISER1 (*(unsigned int*) 0xE000E104) // Enable IRQ
#define TMR16B0MCR (*(unsigned int*) 0x4000C014) // Match Control
#define TMR16B0IR (*(unsigned int*) 0x4000C000) // Interrupt Flag Register

在这个级别上,它仍然可以管理,但是当您开始定义每个寄存器的关联标志时,它会变得更糟,例如这个寄存器

#define I2C1CONSET (* (unsigned int *) 0x4005C000)
#define I2C1CONSET_EN 0x40
// bit 5, start condition
#define I2C1CONSET_STA 0x20
// bit 4, stop condition
#define I2C1CONSET_STO 0x10
// bit 2, acknowledge signal
#define I2C1CONSET_ACK 0x04

此时,我更愿意使用命名空间之类的东西,所以我可以这样做:

I2C1CONSET |= _I2C1CONSET.EN | _I2C1CONSET.STA; // set EN and STA bits on I2C1CONSET register

我现在的工作方式有什么干净的替代方案吗?

【问题讨论】:

  • 点真的比下划线更清晰/整洁吗?
  • 保留文件范围内以下划线开头的标识符。
  • @NPE 本身并不干净,它不太容易出错,因为在命名空间下,我可以选择的选项很少。在全局命名空间中,一段时间后会有很多选项可供我选择,但是任何体面的编辑器只会向我显示在非全局命名空间下定义的选项。
  • @Azeirah:但是任何具有自动完成功能的体面 IDE 都只会在您的命名一致的情况下向您显示相关的 IDE(即输入 I2C1CONSET_ 只会为这四个标志提供自动完成建议)。
  • @OliverCharlesworth 你是对的。我正在寻找问题的解决方案,但我不知道问题是什么。我确实对这些寄存器感到沮丧,但我不知道为什么。我会尝试找出我真正想要解决的问题。

标签: c microcontroller code-cleanup


【解决方案1】:

你可以使用位域,例如

struct i2c1conset_flags
{
    unsigned     : 2;
    unsigned ack : 1;
    unsigned     : 1;
    unsigned sto : 1;
    unsigned sta : 1;
    unsigned en  : 1;
};

static volatile union {
    unsigned value;
    struct i2c1conset_flags flags;
} *const I2C1CONSET = (void *)0x4005C000;

这让你可以写

I2C1CONSET->value = 0;
I2C1CONSET->flags.sto = 1;

假设 C99

#define I2C1CONSET_FLAGS(...) ((struct i2c1conset_flags){ __VA_ARGS__ })

I2C1CONSET->flags = I2C1CONSET_FLAGS(.ack = 1, .en = 1);

但这真的有助于提高可读性吗?你必须自己决定。


现在我已经玩了更多,我认为这种方法实际上可以提高可读性。以下是我能想到的最好的,我相信它看起来确实不错:

#define I2C1CONSET (*(volatile unsigned *)0x4005C000)
struct I2C1CONSET_flags
{
    unsigned     : 2;
    unsigned ack : 1;
    unsigned     : 1;
    unsigned sto : 1;
    unsigned sta : 1;
    unsigned en  : 1;
    unsigned     : 25;
};

#define flags(REG) \
    (*(volatile struct REG ## _flags *)&REG)

#define mask(REG, ...) \
    (((union { unsigned value; struct REG ## _flags flags; }){ \
        .flags = { __VA_ARGS__ } \
    }).value)

flags(I2C1CONSET).sto = 1;
I2C1CONSET |= mask(I2C1CONSET, .ack = 1, .en = 1);

【讨论】:

    猜你喜欢
    • 2020-09-12
    • 1970-01-01
    • 2023-03-03
    • 2014-05-19
    • 2022-09-26
    • 1970-01-01
    • 1970-01-01
    • 2020-06-14
    • 1970-01-01
    相关资源
    最近更新 更多