EEWorld 电子工程世界

文章数:10804 被阅读:13623255

账号入驻

干货 | 当BLE遇到MEMS——收服和调教

最新更新时间:2018-03-21
    阅读数:


EEWORLD

行业资讯 犀利解读 

技术干货 每日更新

 


当BLE遇到MEMS,就如同天使有了翅膀。本期从有浅入深的介绍BLE与MEMS的那些事,就从ST的STEVAL-IDB007V1开发板中BLE_SensorDemo例程开始。


蓝牙入门
网上资料很多,可参考《蓝牙BLE权威教程》,或者看看
干货 | BLE开发,你要知道这几件事


开发环境搭建
请参考论坛帖子
STEVAL-IDB007V1之透传演示操作流程和所需软件资源下载(https://bbs.eeworld.com.cn/thread-604229-1-1.html),从开始菜单进入BlueNRG-1 Navigator可以实际运行各种例程查看效果。

硬件连接:
使用ST-Link V2中SWCLK与SWDIO与开发板对应的引脚连接,用来仿真;供电和串口都通过USB线缆



程序烧录
蓝牙芯片的开发和普通MCU的开发并没什么不同,虽说蓝牙芯片里面有协议栈,但是基本不用管,也不要害怕会将其覆盖,学会调用其接口函数就好。打开安装路径下BLE_Examples\BLE_SensorDemo工程,编译烧录(如果烧录不进,使用BlueNRG-1Flasher将内存擦除,然后使用BlueNRG-1 ST-LINK Utility工具确认能够连接上)。


程序初窥
官方代码并没有使用HAL库或者LL库,很多地方直接操作寄存器,或许这是为了节约内存吧,程序的流程是手机发送指令,芯片接收指令后发送相关的数据,例如发送一个需求加速度计值的指令,芯片就发送一次数据过去。

官方的演示是可以姿态的,但实际上程序的姿态的获取确只用到了加速度计,加速度计在晃动的时候会抖动的厉害,实际情况却还是不错的,是因为程序将数据更新频率设为了13Hz,虽然没有开启滤波但是这样却大大的减少了抖动,这样使用加速度计来估计姿态在低速下是不错的,而且可以节约计算,但是确是相当的不准确。其实芯片是自带有高通滤波和底通滤波的,如果开启的话效果会更好。


更准确的读取数据
陀螺仪加速度计使用的是LSM6DS3,这个不算是ST最新的。在之前我做小车的时候曾经用过这款,发现过不少的坑,其中之一就是,连续读取值会读到错误值,下图是将更新频率设置为6600Hz的时候,连续采集时候的陀螺仪的值。



下图是局部放大图:



会发现陀螺仪的值会跳变(不同的倾角下跳变的概率不一样,更新频率越高,跳变的概率越大),由于陀螺仪在原始的寄存器值上乘以了70,将跳变值除以70后为+255和-255。

经过一系列的摸索,和ST工程师的帮助,终于解决了问题,见下图,那就是将BDU(Block Data Update)位置1,没有置1的话,数据没有准备好就被读出来也是有可能的,这也就是为何更新频率设置的越高就会越容易出现错误值的原因。



其实早在2015年在数据手册中就建议将BDU位置1了,后来的官方初始化程序中也都将BDU置1了。



下面是不动芯片,仅仅将BDU置1后的效果:



因此想要准确的的获取的数据记得将BDU位置1哦。


更高效的读取数据
该传感器使用的是SPI接口,这点很好,相比于IIC,SPI这是要快太多了,我们可以节约更多的时间用来做其他的事,也有利于节能,该芯片最高支持10MHz的SPI速度,但是驱动却写的不是很高效,官方代码如下:


  1. static IMU_6AXES_StatusTypeDef    LSM6DS3_G_GetAxes( int32_t *pData )

  2. {

  3.   /*Here we have to add the check if the parameters are valid*/

  4.   int16_t pDataRaw[3];

  5.   float sensitivity = 0.0f;

  6.   if(LSM6DS3_G_GetAxesRaw(pDataRaw) != IMU_6AXES_OK)

  7.   {

  8.     return IMU_6AXES_ERROR;

  9.   }

  10.   if(LSM6DS3_G_GetSensitivity( &sensitivity ) != IMU_6AXES_OK)

  11.   {

  12.     return IMU_6AXES_ERROR;

  13.   }

  14.   pData[0] = (int32_t)(pDataRaw[0] * sensitivity);

  15.   pData[1] = (int32_t)(pDataRaw[1] * sensitivity);

  16.   pData[2] = (int32_t)(pDataRaw[2] * sensitivity);

  17.   return IMU_6AXES_OK;


  1. static IMU_6AXES_StatusTypeDef LSM6DS3_G_GetAxesRaw( int16_t *pData )

  2. {

  3.   /*Here we have to add the check if the parameters are valid*/

  4.   uint8_t tempReg[2] = {0, 0};

  5.   if(LSM6DS3_IO_Read(&tempReg[0], LSM6DS3_XG_MEMS_ADDRESS, LSM6DS3_XG_OUT_X_L_G, 2) != IMU_6AXES_OK)

  6.   {

  7.     return IMU_6AXES_ERROR;

  8.   } 

  9.   pData[0] = ((((int16_t)tempReg[1]) << 8) + (int16_t)tempReg[0]);

  10.   if(LSM6DS3_IO_Read(&tempReg[0], LSM6DS3_XG_MEMS_ADDRESS, LSM6DS3_XG_OUT_Y_L_G, 2) != IMU_6AXES_OK)

  11.   {

  12.     return IMU_6AXES_ERROR;

  13.   }

  14.   pData[1] = ((((int16_t)tempReg[1]) << 8) + (int16_t)tempReg[0]);

  15.   if(LSM6DS3_IO_Read(&tempReg[0], LSM6DS3_XG_MEMS_ADDRESS, LSM6DS3_XG_OUT_Z_L_G, 2) != IMU_6AXES_OK)

  16.   {

  17.     return IMU_6AXES_ERROR;

  18.   }

  19.   pData[2] = ((((int16_t)tempReg[1]) << 8) + (int16_t)tempReg[0]);

  20.   return IMU_6AXES_OK;

  21. }


每次都是单次读取(读两个字节)每一轴的数据,而且还获取了一次sensitivity(读一个字节)。

我们知道SPI要完成一次读数据的操作,本质是需要读写两次的,第一次将地址写进去,然后再将0写入,将数据弄出来。因此驱动如果需要读取6轴的数据一共需要写12次,读18次SPI。而我认为sensitivity是开始设置的,可以不读,然后6轴的数据可以一次全部读出来,因为默认SPI地址是会累加的,如

因此程序可以改成如下,然后将陀螺仪值乘以70,加速度计值乘以0.122


  1. void Get_Sensor_RawData(void){

  2.       Sensor_IO_Read(NULL,LSM6DSL_ACC_GYRO_OUTX_L_G,regValue, 12);     

  3.        for(int i=0;i<6;i++){

  4.          Sensor_Raw_Data[/size][/font][font=微软雅黑][size=3] = ( ( ( ( int16_t )m_rx_buf[2*i+2] ) << 8 ) + (int16_t )m_rx_buf[2*i+1] );

  5.        }

  6. }


从0x22地址开读,也就是写1次,读12次,而且还节约了SPI的开启和关闭的耗时,这样就大大的提高的数据获取的速度,如果可以使用DMA能够更高效。


因此如果想要更加高效的使用陀螺仪加速度计,记得要连续的读取12个字节且无需读取灵敏度哦。


 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

About Us 关于我们 客户服务 联系方式 器件索引 网站地图 最新更新 手机版

站点相关: TI培训

北京市海淀区中关村大街18号B座15层1530室 电话:(010)82350740 邮编:100190

电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved