2014-03-19 46 views
1

我使用ATmega128的LIS3DH傳感器來獲取加速度值以獲得運動。我瀏覽了數據表,但似乎不夠充分,所以我決定在這裏發佈。從其他文章中,我確信傳感器分辨率是12位而不是16位。我需要知道,當從x軸輸出寄存器中找到g值時,只有當OUT_X_H(高位寄存器)的符號位MSB爲1或每次都是這樣時,才計算寄存器值的二進制補碼位爲0如何計算LIS3DH傳感器的g值?

從我的計算,我認爲我們計算補時才OUT_X_H寄存器的MSB爲1

但是,數據表說,我們需要計算每次都OUT_X_L和OUT_X_H的二進制補碼。

任何人都可以在這方面啓發我嗎?

示例代碼

int main(void) 
{  
    stdout = &uart_str;    
    UCSRB=0x18; // RXEN=1, TXEN=1 
    UCSRC=0x06; // no parit, 1-bit stop, 8-bit data 
    UBRRH=0; 
    UBRRL=71; // baud 9600 

    timer_init(); 

    TWBR=216; // 400HZ 
    TWSR=0x03; 
    TWCR |= (1<<TWINT)|(1<<TWSTA)|(0<<TWSTO)|(1<<TWEN);//TWCR=0x04; 
    printf("\r\nLIS3D address: %x\r\n",twi_master_getchar(0x0F)); 
    twi_master_putchar(0x23, 0b000100000); 
    printf("\r\nControl 4 register 0x23: %x", twi_master_getchar(0x23));  
    printf("\r\nStatus register %x", twi_master_getchar(0x27)); 
    twi_master_putchar(0x20, 0x77); 

    DDRB=0xFF; 
    PORTB=0xFD; 
    SREG=0x80; //sei(); 


    while(1) 
    {    
     process(); 
    } 
} 
void process(void){ 
    x_l = twi_master_getchar(0x28); 
    x_h = twi_master_getchar(0x29); 
    y_l = twi_master_getchar(0x2a); 
    y_h = twi_master_getchar(0x2b); 
    z_l = twi_master_getchar(0x2c); 
    z_h = twi_master_getchar(0x2d); 
    xvalue = (short int)(x_l+(x_h<<8)); 
    yvalue = (short int)(y_l+(y_h<<8)); 
    zvalue = (short int)(z_l+(z_h<<8)); 
    printf("\r\nx_val: %ldg", x_val); 
    printf("\r\ny_val: %ldg", y_val); 
    printf("\r\nz_val: %ldg", z_val); 
} 

我寫的CTRL_REG4爲0x10的(4G),但是當我看到他們,我得到了爲0x20(8G)。這似乎有點奇怪。

回答

1

不計算的二進制補碼。這具有使結果成爲負面影響的效果。

相反,數據表告訴我們結果已經是一個有符號的值。也就是說,0不是最低值;它在規模的中間。 (0xffff只是略小於零,不是最高值。)

此外,結果總是16位,但結果並不意味着被認爲是準確的。您可以將控制寄存器值設置爲以犧牲電流消耗爲代價來生成更精確的值,但仍不能保證精確到最後一位。

+0

我從軸寄存器讀取兩個數據字節,並將低位字節(0x28)與高位字節(0x29)連接到int16_t變量中。我從傳感器得到x軸的結果:0xFC00 ,y軸:fd40,z軸:0x0F80。這些是我在傳感器處於靜止狀態並且周圍沒有任何動作時獲得的數值。狀態寄存器值爲0xFF,這意味着有新的數據可用。我已將其設置爲4g。數據表說,在靜止狀態下,x軸,y軸應接近0g,z軸接近1g。爲什麼我不斷收到其他數據? –

+0

您已經錯誤地將9位值傳遞給了控制寄存器4。這將分辨率設置爲+/- 8g。 x和y值是負值,但接近於0。按照-8g至+ 8g的比例,z值接近於0x1000。這些值都是數據表預測的。 – UncleO

+0

它看起來像你的傳感器可以傾斜一點點。您還應該在所有方向嘗試傳感器 - 與現在相反,沿着x軸,沿着y軸,並與之相反。 – UncleO

1

數據表沒有說明(至少是第8.2章中的寄存器描述),您必須計算2'補碼,但聲明2個寄存器的內容是2的補碼。

因此,您只需接收兩個字節並將其轉換爲int16_t即可獲取帶符號的原始值。

uint8_t xl = 0x00; 
uint8_t xh = 0xFC; 
int16_t x = (int16_t)((((uint16)xh) << 8) | xl); 

uint8_t xa[2] {0x00, 0xFC}; // little endian: lower byte to lower address 
int16_t x = *((int16*)xa); 

(含有希望沒有混合的東西了這一點)

+0

我從軸寄存器中讀取兩個數據字節,並將低位字節(0x28)與高位字節(0x29)連接到int16_t變量中。我從傳感器得到x軸的結果:0xFC00,y軸:fd40,z軸:0x0F80。這些是我在傳感器處於靜止狀態並且周圍沒有任何動作時獲得的數值。狀態寄存器值爲0xFF,這意味着有新的數據可用。我已將其設置爲4g。數據表說,在靜止狀態下,x軸,y軸應接近0g,z軸接近1g。爲什麼我不斷收到其他數據? –

+0

@avr_rookie你確定你沒有切換低位和高位? 0xFC00 - > 0x00FC:接近零; 0x0F80 - > 0x800F:接近零; 0xfd40 - > 0x40fd:possily(沒有考慮縮放因子)1g? –

+0

@avr_rookie添加了轉換示例代碼 –

0

我有另一種方法,可能更容易實現,因爲編譯器會爲您完成所有工作。編譯器可能會最有效地做到這一點,也沒有任何錯誤。

讀取原始數據轉換爲原始字段:

typedef union 
{ 
    struct 
    { 
     // in low power - 8 significant bits, left justified 
     int16 reserved : 8; 
     int16 value : 8; 
    } lowPower; 

    struct 
    { 
     // in normal power - 10 significant bits, left justified 
     int16 reserved : 6; 
     int16 value : 10; 

    } normalPower; 

    struct 
    { 
     // in high resolution - 12 significant bits, left justified 
     int16 reserved : 4; 
     int16 value : 12; 

    } highPower; 
    // the raw data as read from registers H and L 
    uint16 raw; 
} LIS3DH_RAW_CONVERTER_T; 

比使用根據您所使用的電力模式所需要的價值。

注意:在這個例子中,位域結構是BIG ENDIANS。 檢查是否需要顛倒「值」和「保留」的順序。