微 Controller 寄存器的更干净的命名空间

标签 c microcontroller code-cleanup

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

#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

此时,我更愿意使用 namespace 之类的东西,所以我可以做这样的事情:

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

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

最佳答案

您可以使用位字段,例如

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);

关于微 Controller 寄存器的更干净的命名空间,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26192618/

相关文章:

python - 如何编写Python词法分析器?

c - STM32写Flash

c - 在 LPC1788 的 USB ISR 中使用 embOS 函数

python - os.nice() 的最大nice值

javascript - 对象数组,当我寻找最大值时,使我的代码可读的最佳实践是什么

c - "STACK"之前的预期表达式错误

c - pthreads - 加入一组线程,等待一个线程退出

c - Microchip PIC16F1829深度 sleep

design-patterns - 在整洁的代码书中定义正常流程是什么意思?

c - Fread - 大量整数