2014-10-04 45 views
0

使用微控制器,通常你必须从寄存器写入和读取,为了使代码更具可读性,你需要定义寄存器地址及其位。这有点细,但很快就会变得混乱,当你有那真的是彼此相似的寄存器名称,如这里看到例如清洁微控制器寄存器的命名空间

#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 

我现在有什么干净的替代方案?

+3

点是否真的比下划线更清晰/整洁? – NPE 2014-10-04 12:04:55

+0

保留在文件范围内以下划线开头的标识符。 – starrify 2014-10-04 12:05:37

+0

@NPE不是每个人都是干净的,它不太容易出错,因为在命名空间下,我只能选择很少的选项。在全局命名空间中,经过一段时间后会有很多选项供我选择,但是任何像样的编辑器都只会显示在非全局命名空间下定义的选项。 – Azeirah 2014-10-04 12:08:55

回答

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