2014-02-20 62 views
1

我編程一個PIC18F94K20與MCP7941X I2C RTCC船和24AA128 I2C CMOS串行EEPROM裝置一起使用。目前,我擁有能夠成功初始化RTCC秒/天/等值的代碼並啓動計時器,並在每秒更換一次時切換LED。邏輯運算符&比特分離計算在C(PIC編程)

我試圖擴大代碼讀回這些值的正確的數據,但我遇到了麻煩,當我試圖解釋在價值的各種「額外」位。內存映射可能有助於闡明幾分我的問題:

RTCC Memory Map

服用,例如,小時列或02H地址。位6設置爲1切換12小時時間,將01000000添加到小時位。我可以在這個地址讀回字節的全部內容,但是我想使用if語句來檢測12或24小時的時間是否到位,並相應地進行調整。我並不擔心10小時的位數,因爲我可以用BCD轉換循環輕鬆計算(我認爲)。

我先前使用的位OR運算符在C原始小時的數據擴充到24餘初始化的時間在此特定情況下爲0x11,並且設置12小時控制位,它是0x64。當設置時間:

WriteI2C(0x11|0x64); 

它可以看到使用按位或。

當讀回的時間,我怎麼可以將運營商到我的代碼多餘的比特從實際時間位分開?我試着做這樣的事情:

current_seconds = ReadI2C(); 
current_seconds = ST & current_seconds; 

但這完全毀了一切。它編譯,但設備在這個序列上「卡住」。

如何從我需要的實際數據中分離出ST/AMPM/VBATEN位,以及對於各種環境實現循環的好方法是什麼(例如,如果第6位回讀12小時時間= 0和24小時時間,如果bit6 = 1,依此類推)。

我有點一個C新手,這是我第一次涉足電子產品,所以我真的很感謝所有幫助。謝謝。

+0

我不認爲這個問題適合在這裏。只需閱讀有關C位運算符(|,&,<<)和位操作。 –

+0

你是否推薦任何可能更合適的地方?對不起,如果我錯了。 – samanthapants

+0

要查看的位的掩碼用&運算符完成,並將要設置爲1的位進行分隔。所以如果你是從我的閱讀秒看可能只是轉換((((regdata&0x7)* 10)+(regdata&0xf);我認爲 – kenny

回答

3

要刪除(零)位,可以具有其他所有位設置了屏蔽值,即位的,你要零補,如:

value_without_bit_6 = value & ~(1<<6); 

要隔離在一個整數中的一個位,你可以用一個只有那些位被設置的掩碼來和值。對於檢查標誌,這是所有你需要做的,例如,

if (value & (1<<6)) { 
    // bit 6 is set 
} else { 
    // bit 6 is not set 
} 

要讀一個小的整數中較大的一個偏移值,第一隔離位,然後向右最低的指數將它們轉移位(以獲得至少顯著位到正確的位置),例如:

value_in_bits_4_and_5 = (value & ((1<<4)|(1<<5))) >> 4; 

更多可讀的代碼,你應該使用常量或#define d宏來表示你需要,例如不同的屏蔽位:

#define BIT_VBAT_EN (1<<3) 

if (value & BIT_VBAT_EN) { 
    // VBAT is enabled 
} 

另一種方式來做到這一點是利用位域來定義的位的組織,例如:

typedef union { 
    struct { 
     unsigned ones:4; 
     unsigned tens:3; 
     unsigned st:1; 
    } seconds; 
    uint8_t byte; 
} seconds_register_t; 

seconds_register_t sr; 
sr.byte = READ_ADDRESS(0x00); 
unsigned int seconds = sr.seconds.ones + sr.seconds.tens * 10; 

與位域的一個潛在問題是,由編譯器生成的代碼可以是不可預知的大或效率低下,這有時是微控制器所關心的問題,但顯然讀取和寫入會更好。 (經常提到的另一個問題是,比特字段的組織,比如字節序,在C標準中很大程度上沒有規定,因此不能保證在編譯器和平臺上的可移植性。然而,我認爲微控制器的低級開發傾向於本質上是不可移植的,所以如果你找到合適的位佈局,我不會考慮使用位域「錯誤」,尤其是對於愛好者項目。)

然而,你可以用宏來完成類似可讀的語法;它只是宏本身是不易閱讀:

#define GET_SECONDS(r) (((r) & 0x0F) + (((r) & 0x70) >> 4) * 10) 
uint8_t sr = READ_ADDRESS(0x00); 
unsigned int seconds = GET_SECONDS(sr); 
1

關於位屏蔽本身,你會想,以使該存儲器映射模型在微控制器。要做到這一點,最簡單的,cudest的辦法是#define若干位掩碼,就像這樣:

#define REG1_ST   0x80u 
#define REG1_10_SECONDS 0x70u 
#define REG1_SECONDS  0x0Fu 

#define REG2_10_MINUTES 0x70u 
... 

然後讀取每個字節時,屏蔽掉你感興趣的數據例如:

bool st   = (data & REG1_ST) != 0; 
uint8_t ten_seconds = (data & REG1_10_SECONDS) >> 4; 
uint8_t seconds  = (data & REG1_SECONDS); 

重要的部分是儘量減少源代碼中「幻數」的數量。

寫入數據:

reg1 = 0; 
reg1 |= st ? REG1_ST : 0; 
reg1 |= (ten_seconds << 4) & REG1_10_SECONDS; 
reg1 |= seconds & REG1_SECONDS; 

請注意,我離開了這個的I2C通信。