2014-10-04 50 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);