1. 程式人生 > >博世BMI160六軸感測器I2C通訊配置

博世BMI160六軸感測器I2C通訊配置

博世BMI160簡介


Bosch Sensortec公司推出的最新BMI160慣性測量單元將最頂尖的16位3軸重力加速度計和超低功耗3軸陀螺儀集成於單一封裝。採用14管腳LGA封裝,尺寸為2.5×3.0×0.8mm3。當加速度計和陀螺儀在全速模式下執行時,耗電典型值低至950µA,僅為市場上同類產品耗電量的50%或者更低。


BMI160的Datasheet的下載連線如下:

點選此處進入下載網頁




BMI160資料流框圖和地址


從BMI160的Datasheet中可以看到它的資料流框圖如下:



從上面的框圖中,我們可以看到,BMI160與外部進行雙向資料傳輸的方式有兩種:SPI和I2C。下面,我們來看下通過I2C與外部進行通訊的方式。當BMI160通過I2C與外部進行通訊的時候,BMI160將作為I2C從裝置掛到主控晶片(主裝置)的I2C總線上,所以,主控晶片在配置其對應的I2C驅動時就需要知道BMI160的從裝置地址。

 

對於不同的硬體設計,BMI160的從裝置地址是不同的,從Datasheet中可以看到詳細介紹,截圖如下:



從上述描述中可以看出來:當SDO腳接GND的時候,BMI160的I2C地址是 0x68;當SDO腳接

VDDIO的時候,BMI160的I2C地址是 0x69。




BMI160暫存器表


BMI160的暫存器表在其Datasheet的45頁,下面,我們重點來介紹一下常用的比較重要的暫存器:

1.晶片ID

地址:0x00。暫存器名:CHIP_ID。預設值:0xD1。該暫存器只可以讀,不能寫。


2.BMI160工作模式暫存器

地址:0x03。暫存器名:PMU_STATUS。預設值:0x00。該暫存器只可以讀,不可以寫。該暫存器的值一共8個位元組,最高位的2個位保留。後面也是每兩個位組成一個值,分別是acc_pmu_status、gyr_pmu_status和mag_pmu_status的狀態值。

 

截圖如下:



各個狀態值代表的實際含義截圖如下:



3.控制暫存器

地址:0x7e。暫存器名:CMD。預設值:0x00。該暫存器可以讀也可以寫。

 

我們通過向該地址寫入不同的值來控制加速度或者陀螺儀的工作模式。

0x11:通過寫入該命令值,可以使加速度模組切換到正常工作模式。

0x15:通過寫入該命令值,可以使陀螺儀模組切換到正常工作模式。


4.加速度(Accelerometer)暫存器

通過讀該暫存器上的資料,可以得到加速度三個軸的原始資料。各個軸的暫存器地址及資料格式如下圖所示:



5.陀螺儀角速度(Gyroscope)暫存器

通過讀該暫存器上的資料,可以得到陀螺儀角速度三個軸的原始資料。各個軸的暫存器地址及資料格式如下圖所示:



6.加速度和陀螺儀量程配置暫存器

(1)加速度量程配置暫存器地址是 0x41,該暫存器地址上的資料格式表如下所示:



從上圖,我們可以看出,加速度量程配置只佔了低四位,即 bit 0-3。不同的值對應的量程值如下表:



(2)陀螺儀量程配置暫存器地址是 0x43,該暫存器地址上的資料格式表如下所示:



從上圖中可以看出,陀螺儀量程配置只佔用了低三位,即 bit 0-2,不同的值對應的量程值如下表:



注意:加速度量程配置暫存器預設值是 0x03,即預設量程是 ±2g;陀螺儀量程配置暫存器預設值是 0x00,即預設角速度量程是 ±2000°/s。建議使用預設配置的量程。




六軸資料獲取


1.三軸加速度資料獲取例項參考程式碼


  
  1. //加速度三軸資料獲取原始碼
  2. void getAccelerometerValue(void)
  3. {
  4. signed short acc_x,acc_y,acc_z;
  5. unsigned short x,y,z;
  6. //向命令暫存器寫入0x11,使加速度處於正常工作模式
  7. i2c_write_one_byte( 0x7e, 0x11);
  8. //切換工作模式之後,延時100ms
  9. Delay_Ms( 100);
  10. /////////////////////////////加速度 X軸///////////////////////////
  11. x =( i2c_read_one_byte( 0x12) & 0xff);
  12. x = x|(( i2c_read_one_byte( 0x13) & 0xff)<< 8);
  13. acc_x = ( signed short)x;
  14. //當量程為±2g時,轉換為g/s的加速度換算公式
  15. acc_x = ( signed short)(acc_x* 9.8)/( 0x8000/ 2);
  16. /////////////////////////////加速度 Y軸///////////////////////////
  17. y =( i2c_read_one_byte( 0x14) & 0xff) ;
  18. y = y|(( i2c_read_one_byte( 0x15) & 0xff)<< 8);
  19. acc_y = ( signed short)y;
  20. //當量程為±2g時,轉換為g/s的加速度換算公式
  21. acc_y = ( signed short)(acc_y* 9.8)/( 0x8000/ 2);
  22. /////////////////////////////加速度 Z軸///////////////////////////
  23. z =( i2c_read_one_byte( 0x16) & 0xff) ;
  24. z = z|(( i2c_read_one_byte( 0x17) & 0xff)<< 8);
  25. acc_z = ( signed short)z;
  26. //當量程為±2g時,轉換為g/s的加速度換算公式
  27. acc_z = ( signed short)(acc_z* 9.8)/( 0x8000/ 2);
  28. }


2.三軸陀螺儀資料獲取例項參考程式碼


  
  1. //陀螺儀角速度三軸資料獲取
  2. void getGyroscopeValue(void)
  3. {
  4. signed short gyr_x,gyr_y,gyr_z;
  5. unsigned short x,y,z;
  6. //向命令暫存器寫入0x15,使陀螺儀處於正常工作模式
  7. i2c_write_one_byte( 0x7e, 0x15);
  8. //切換工作模式之後,延時100ms
  9. Delay_Ms( 100);
  10. /////////////////////////////陀螺儀角速度 X軸///////////////////////////
  11. x =( i2c_read_one_byte( 0x0c) & 0xff) ;
  12. x = x|(( i2c_read_one_byte( 0x0d) & 0xff)<< 8);
  13. gyr_x = ( signed short)x;
  14. // range為±2000°/s時,轉換為角速度°/s的公式
  15. gyr_x = (gyr_x* 2000)/ 0x8000;
  16. /////////////////////////////陀螺儀角速度 Y軸///////////////////////////
  17. y =( i2c_read_one_byte( 0x0e) & 0xff) ;
  18. y = y|(( i2c_read_one_byte( 0x0f) & 0xff)<< 8);
  19. gyr_y = ( signed short)y;
  20. // range為±2000°/s時,轉換為角速度°/s的公式
  21. gyr_y = (gyr_y* 2000)/ 0x8000;
  22. /////////////////////////////陀螺儀角速度 Z軸///////////////////////////
  23. z =( i2c_read_one_byte( 0x10) & 0xff) ;
  24. z = z|(( i2c_read_one_byte( 0x11) & 0xff)<< 8);
  25. gyr_z = ( signed short)z;
  26. // range為±2000°/s時,轉換為角速度°/s的公式
  27. gyr_z = (gyr_z* 2000)/ 0x8000;
  28. }

上述原始碼中,有三個函式: i2c_write_one_byte Delay_Ms i2c_read_one_byte ,這三個函式的具體實現跟主控晶片有關,需要大家根據自己的主控晶片來自行封裝實現,另外涉及到I2C的時候一般開始需要先初始化,初始化過程需要的從裝置地址在前面已經講過了,具體初始化函式的封裝也需要大家自行根據主控晶片的介紹來實現。


上述提供的原始碼中,i2c_read_one_byte介面封裝的返回值是unsigned char型別的。下面,我們來看看上述原始碼中加速度和陀螺儀角速度換算的原理:

1.加速度換算原理

換算實現程式碼如下:


  
  1. /////////////////////////////加速度 X軸///////////////////////////
  2. x =( i2c_read_one_byte( 0x12) & 0xff);
  3. x = x|(( i2c_read_one_byte( 0x13) & 0xff)<< 8);
  4. acc_x = ( signed short)x;
  5. //當量程為±2g時,轉換為g/s的加速度換算公式
  6. acc_x = ( signed short)(acc_x* 9.8)/( 0x8000/ 2);

加速度每個軸佔兩個位元組,所以從感測器中讀取的值需要按照高低位進行拼接,並且因為加速度每個軸都是有方向的,也就是說加速度每個軸的值應該是有正負之分的,因此拼接之後的值強制型別轉化為signed short。轉換之後,我們需要將轉換的值換算成加速度的單位。換算公式如下:


acc_x = (signed short)(acc_x*9.8)/(0x8000/2);


9.8是重力加速度的標準值;因為預設量程是 ±2g,最大和最小值相差 4g,而上述公式,我們取的是量程的一半,也就是2g;因為acc_x對應的signed short的範圍是32768 ~ +32767最大到最小值一共是 65536個值,相當於65536個刻度,同樣取一半的話就是0x8000。上述公式通過對應轉換之後將取樣讀取的值乘以 g,這樣取樣獲取值的範圍0x8000就需要除以2。


2.陀螺儀角速度換算原理

換算實現程式碼如下:


  
  1. /////////////////////////////陀螺儀角速度 X軸///////////////////////////
  2. x =( i2c_read_one_byte( 0x0c) & 0xff) ;
  3. x = x|(( i2c_read_one_byte( 0x0d) & 0xff)<< 8);
  4. gyr_x = ( signed short)x;
  5. // range為±2000°/s時,轉換為角速度°/s的公式
  6. gyr_x = (gyr_x* 2000)/ 0x8000;
陀螺儀角速度每個軸也是佔用2個位元組,所以從感測器中讀取的值需要按照高低位進行拼接,並且因為陀螺儀角速度每個軸都是有方向的,也就是說陀螺儀角速度每個軸的值也應該是有正負之分的,因此拼接之後的值強制型別轉化為 signed short 。轉換之後,我們需要將轉換的值換算成陀螺儀角速度的單位。換算公式如下:


gyr_x = (gyr_x*2000)/0x8000; 


因為預設量程是 ±2000°/s,最大和最小值相差 4000,而上述公式,我們取的是量程的一半,也就是2000;因為gyr_x對應的signed short的範圍是-32768 ~ +32767最大到最小值一共是 65536個值,相當於65536個刻度,同樣取一半的話就是0x8000。所以對應換算之後就出現了上述公式。



注意事項


預設BMI160開機上電啟動的時候處於掛起模式,這個時候加速度和陀螺儀都處於未工作狀態,無法讀取資料。如果想讀取相應資料,需要通過向0x7E命令控制暫存器寫入相應命令來切換工作狀態,具體命令前面介紹過了。

 

每次讀取加速度資料前,都需要呼叫i2c_write_one_byte(0x7e,0x11);使加速度模組進入正常工作模式;每次讀取陀螺儀角速度前,當然也需要呼叫i2c_write_one_byte(0x7e,0x15);使陀螺儀模組進入正常工作模式。這樣才能成功讀取到資料。





				<script>
					(function(){
						function setArticleH(btnReadmore,posi){
							var winH = $(window).height();
							var articleBox = $("div.article_content");
							var artH = articleBox.height();
							if(artH > winH*posi){
								articleBox.css({
									'height':winH*posi+'px',
									'overflow':'hidden'
								})
								btnReadmore.click(function(){
									if(typeof window.localStorage === "object" && typeof window.csdn.anonymousUserLimit === "object"){
										if(!window.csdn.anonymousUserLimit.judgment()){
											window.csdn.anonymousUserLimit.Jumplogin();
											return false;
										}else if(!currentUserName){
											window.csdn.anonymousUserLimit.updata();
										}
									}
									
									articleBox.removeAttr("style");
									$(this).parent().remove();
								})
							}else{
								btnReadmore.parent().remove();
							}
						}
						var btnReadmore = $("#btn-readmore");
						if(btnReadmore.length>0){
							if(currentUserName){
								setArticleH(btnReadmore,3);
							}else{
								setArticleH(btnReadmore,1.2);
							}
						}
					})()
				</script>
				</article>