• 关于LSI3DH的使用(转载)


    https://blog.csdn.net/u012523921/article/details/107016750/

    最近在调试lis3dh加速度计,网上一搜能找到很多资料,但是描述正确的,感觉不是很多,所以这里我来总结一下,也是在网友博客的基础上将正确的地方集中整理一下。

    1.   首先说驱动,驱动网上流传的基本上就是一份,.h.c文件随便一搜就能下载到lis3dh的驱动,由于我的是公司电脑,文件是加密,就不上传驱动了,大家可以自行搜索其他的资源下载,驱动下载下来后,用户需要完成的就是底层SPI(这里我用的是SPI读写方法,IIC的没用过)的读写寄存器的函数,我把自己写的粘贴出来,大家参考一下,用的而是HAL函数,这里有一点需要说明一下,就是SPI的速率配置,开始我配置的6M,读取WHO_AM_I寄存器以及任何寄存器读出来都是0x88,检查很多地方都找不出原因来,后来偶然的情况下改成了3M,竟然读取ID成功了0x33, LIS3DH datasheet上写的最大支持spi速率是10MHz.看来实际支持不了这么大的速率。

    另外,对于下载的驱动还有一点说明,要注意里面函数返回值的定义,原有驱动是:

    typedef enum {
        MEMS_SUCCESS                =        0x01,
        MEMS_ERROR                =        0x00,  
    } status_t;

    为了适应HAL库驱动,我给改成了:

    typedef enum {
        MEMS_SUCCESS                =        0x00,
        MEMS_ERROR                =        0x01    
    } status_t;

    另外驱动里面的每个函数返回值的判断是 :

    if( !LIS3DH_ReadReg(LIS3DH_FIFO_CTRL_REG, &value) )
            return MEMS_ERROR;

    我改成了:

    if( LIS3DH_ReadReg(LIS3DH_FIFO_CTRL_REG, &value) ) //为了适应返回0就是成功,返回非0是失败。
            return MEMS_ERROR;

    1.  
      /*注意:lis3dh波特率设置为3M可以读取正确,设置为8分频6M就不行*/
    2.  
      extern SPI_HandleTypeDef hspi2;
    3.  
      uint8_t LIS3DHInit(void)//SPI初始化
    4.  
      {
    5.  
      LIS3DH_CS_DISABLE; 取消片选
    6.  
      MX_SPI2_Init();
    7.  
      return HAL_OK;
    8.  
      }
    9.  
      /*******************************************************************************
    10.  
      * Function Name : LIS3DH_ReadReg
    11.  
      * Description : Generic Reading function. It must be fullfilled with either
    12.  
      * : I2C or SPI reading functions
    13.  
      * Input : Register Address
    14.  
      * Output : Data REad
    15.  
      * Return : None
    16.  
      *******************************************************************************/
    17.  
      uint8_t LIS3DH_ReadReg(uint8_t Reg, uint8_t* Data) {
    18.  
       
    19.  
      uint8_t ret;
    20.  
      uint8_t txdata;
    21.  
      /* Start SPI transmission */
    22.  
      LIS3DH_CS_ENABLE;
    23.  
      /* Add read bit */
    24.  
      Reg |= 0x80;
    25.  
      /* Send address */
    26.  
      HAL_SPI_Transmit(&hspi2,&Reg,1,100);
    27.  
      /* Receive data */
    28.  
      txdata = LIS302DL_LIS3DSH_DUMMY_BYTE;
    29.  
      ret = HAL_SPI_TransmitReceive(&hspi2,&txdata,Data,1,100);
    30.  
      /* Stop SPI transmission */
    31.  
      LIS3DH_CS_DISABLE;
    32.  
      return ret;
    33.  
      }
    34.  
       
    35.  
       
    36.  
      /*******************************************************************************
    37.  
      * Function Name : LIS3DH_WriteReg
    38.  
      * Description : Generic Writing function. It must be fullfilled with either
    39.  
      * : I2C or SPI writing function
    40.  
      * Input : Register Address, Data to be written
    41.  
      * Output : None
    42.  
      * Return : None
    43.  
      *******************************************************************************/
    44.  
      uint8_t LIS3DH_WriteReg(uint8_t WriteAddr, uint8_t Data)
    45.  
      {
    46.  
      uint8_t txdata[2],ret;
    47.  
      txdata[0] = WriteAddr;
    48.  
      txdata[1] = Data;
    49.  
      /* Start SPI transmission */
    50.  
      LIS3DH_CS_ENABLE;
    51.  
      /* Send address */
    52.  
      ret = HAL_SPI_Transmit(&hspi2,txdata,2,100);
    53.  
      /* Stop SPI transmission */
    54.  
      LIS3DH_CS_DISABLE;
    55.  
       
    56.  
      return ret;
    57.  
      }
    58.  
      uint8_t LIS3DH_MultiRead(uint8_t start_addr,uint8_t len,uint8_t *data)//连续读读寄存器
    59.  
      {
    60.  
      uint8_t ret,txdata;
    61.  
       
    62.  
      /* Add read bit and autoincrement bit */
    63.  
      start_addr |= 0xC0;
    64.  
      txdata = start_addr;
    65.  
      /* Start SPI transmission */
    66.  
      LIS3DH_CS_ENABLE;
    67.  
      /* Send address */
    68.  
      HAL_SPI_Transmit(&hspi2,&txdata,1,100);
    69.  
      /* Receive data */
    70.  
      ret = HAL_SPI_TransmitReceive(&hspi2,data,data,len,1000);
    71.  
      /* Stop SPI transmission */
    72.  
      LIS3DH_CS_DISABLE;
    73.  
       
    74.  
      return ret;
    75.  
      }

    2. 初始化以及参数配置:

        LIS3DHInit(); //1.中代码有这个函数的实现,主要是SPI初始化以及片选信号拉高
        Reset_LIS3DH(); //复位各个寄存器
        ret = gsensor_init(); //配置参数
        if(ret != RT_EOK){
            rt_kprintf("gsensor_init failed:%d. ",ret);
            ret = -RT_ERROR;
            return ret;
        }
        gsensor_set_threshold(44,1);//中断阈值设置,这里主要设置产生中断的阈值,当加速度达到这个值后就会触发中断1.

    下面给出各个函数的具体实现:

    1.  
      void Reset_LIS3DH(void)
    2.  
      {
    3.  
      LIS3DH_WriteReg(LIS3DH_TEMP_CFG_REG,0x00);
    4.  
      LIS3DH_WriteReg(LIS3DH_CTRL_REG1,0x07); //XYZ轴使能
    5.  
      LIS3DH_WriteReg(LIS3DH_CTRL_REG2,0x00);
    6.  
      LIS3DH_WriteReg(LIS3DH_CTRL_REG3,0x00);
    7.  
      LIS3DH_WriteReg(LIS3DH_CTRL_REG4,0x00);
    8.  
      LIS3DH_WriteReg(LIS3DH_CTRL_REG5,0x00);
    9.  
      LIS3DH_WriteReg(LIS3DH_CTRL_REG6,0x00);
    10.  
      LIS3DH_WriteReg(LIS3DH_REFERENCE_REG,0x00);
    11.  
      LIS3DH_WriteReg(LIS3DH_FIFO_CTRL_REG,0x00);
    12.  
      LIS3DH_WriteReg(LIS3DH_INT1_CFG,0x00);
    13.  
      LIS3DH_WriteReg(LIS3DH_INT1_THS,0x00);
    14.  
      LIS3DH_WriteReg(LIS3DH_INT1_DURATION,0x00);
    15.  
      LIS3DH_WriteReg(LIS3DH_CLICK_CFG,0x00);
    16.  
      LIS3DH_WriteReg(LIS3DH_CLICK_THS,0x00);
    17.  
      LIS3DH_WriteReg(LIS3DH_TIME_LIMIT,0x00);
    18.  
      LIS3DH_WriteReg(LIS3DH_TIME_LATENCY,0x00);
    19.  
      LIS3DH_WriteReg(LIS3DH_TIME_WINDOW,0x00);
    20.  
      }
    21.  
      int gsensor_init(void)
    22.  
      {
    23.  
      uint8_t response = 0;
    24.  
      response |= LIS3DH_SetODR(LIS3DH_ODR_100Hz);//设置数据输出频率
    25.  
      response = response << 1;
    26.  
      response |= LIS3DH_SetMode(LIS3DH_NORMAL);//设置正常模式
    27.  
      response = response << 1;
    28.  
      response |= LIS3DH_SetFullScale(LIS3DH_FULLSCALE_2);//设置量程为±2g, BIT6:DATA LSB
    29.  
      response = response << 1;
    30.  
      response |= LIS3DH_SetAxis(LIS3DH_X_ENABLE | LIS3DH_Y_ENABLE | LIS3DH_Z_ENABLE);//使能三轴数据输出
    31.  
      response = response << 1;
    32.  
      return response;
    33.  
      }
    34.  
      uint8_t gsensor_set_threshold(uint8_t threshold_value,uint8_t interrupt_ID)
    35.  
      {
    36.  
      /*
    37.  
      1 LSb = 16 mg @ FS = ±2 g
    38.  
      1 LSb = 32 mg @ FS = ±4 g
    39.  
      1 LSb = 62 mg @ FS = ±8 g
    40.  
      1 LSb = 186 mg @ FS = ±16 g
    41.  
      */
    42.  
      uint8_t response = 0;
    43.  
      if(interrupt_ID == 1)
    44.  
      {
    45.  
      LIS3DH_HPFAOI1Enable(MEMS_DISABLE);//High pass filter enabled for AOI function on interrupt 1,
    46.  
      response|= LIS3DH_SetIntConfiguration(LIS3DH_INT1_ZHIE_ENABLE|LIS3DH_INT1_ZLIE_ENABLE|
    47.  
      LIS3DH_INT1_YHIE_ENABLE|LIS3DH_INT1_YLIE_ENABLE|
    48.  
      LIS3DH_INT1_XHIE_ENABLE|LIS3DH_INT1_XLIE_ENABLE);//INT1_CFG中enable
    49.  
      response|= LIS3DH_SetInt6D4DConfiguration(LIS3DH_INT1_6D_ENABLE);
    50.  
      response|= LIS3DH_SetIntMode(LIS3DH_INT_MODE_6D_POSITION);
    51.  
      response|= LIS3DH_SetInt1Threshold(threshold_value);//16 * 16mg == 256mg
    52.  
      response|= LIS3DH_SetInt1Pin(LIS3DH_I1_INT1_ON_PIN_INT1_ENABLE);
    53.  
      }
    54.  
      }

    3. 数据采集及计算,有两种方法:

    1)通过公式计算得到:

    首先调用LIS3DH_GetAccAxesRaw()获得xyz三个方向的寄存器值,然后通过公式计算。参考文章是这篇:

    https://blog.csdn.net/sinat_23338865/article/details/51612872

    首先在2中参数配置里,配置了fullsacle满量程是±2g, LIS3DH是16bit的data output,其中有一bit是符号位,所以还剩15bit的数据值,2^15 = 32768,2g = 2000mg,精度为2g/2^15= 2000mg/32768 =0.061mg,所以可以计算三个方向的值为:

    X = X * 2000 /32768; 单位:mg

    Y= Y * 2000 /32768; 单位:mg

    Z = Z * 2000 /32768; 单位:mg

    2)通过移位的方式获得:

    1.  
      void LIS3DH_Get_AccRaw(int16_t* pdata)
    2.  
      {
    3.  
      uint8_t i = 0;
    4.  
      uint8_t regValue[6] = {0, 0, 0, 0, 0, 0};
    5.  
      int16_t symbol[3] = {0,0,0};
    6.  
      for(i=0;i<6;i++)
    7.  
      {
    8.  
      LIS3DH_ReadReg(LIS3DH_OUT_X_L+i, regValue+i);
    9.  
      }
    10.  
      /* Format the data. */
    11.  
      for(i=0;i<3;i++)
    12.  
      {
    13.  
      if(regValue[2*i+1] & 0x80) symbol[i] = 0xF000;
    14.  
      else symbol[i] = 0x0000;
    15.  
      }
    16.  
      pdata[0] =symbol[0] | ((( ( ( int16_t )regValue[1] ) << 8 ) + ( int16_t )regValue[0] ) >> 4);
    17.  
      pdata[1] =symbol[1] | ((( ( ( int16_t )regValue[3] ) << 8 ) + ( int16_t )regValue[2] ) >> 4);
    18.  
      pdata[2] =symbol[2] | ((( ( ( int16_t )regValue[5] ) << 8 ) + ( int16_t )regValue[4] ) >> 4);
    19.  
       
    20.  
      }
    21.  
      /*
    22.  
      *function:LIS3DH_Get_Sensitivity
    23.  
      *作用:读取满量程值:(00: +/- 2G; 01: +/- 4G; 10: +/- 8G; 11: +/- 16G)
    24.  
      */
    25.  
      static void LIS3DH_Get_Sensitivity(uint8_t* sensitivity)
    26.  
      {
    27.  
      uint8_t fullscale = 0;
    28.  
      LIS3DH_ReadReg(LIS3DH_CTRL_REG4,&fullscale);
    29.  
      fullscale = (fullscale & 0x30) >> 4; //0x30:0011 0000
    30.  
      switch (fullscale)
    31.  
      {
    32.  
      case 0:*sensitivity = 1;break;
    33.  
      case 1:*sensitivity = 2;break;
    34.  
      case 2:*sensitivity = 4;break;
    35.  
      case 3:*sensitivity = 12;break;
    36.  
      default : break;
    37.  
      }
    38.  
      }
    39.  
       
    40.  
      void LIS3DH_Get_AccValue(AxesRaw_t *pdata)
    41.  
      {
    42.  
      int16_t dataRaw[3];
    43.  
      uint8_t sensitivity = 0;
    44.  
      LIS3DH_Get_AccRaw(dataRaw);//获取3个方向的加速度值,
    45.  
      LIS3DH_Get_Sensitivity(&sensitivity);
    46.  
      pdata->AXIS_X = ( int32_t )( dataRaw[0] * sensitivity );
    47.  
      pdata->AXIS_Y = ( int32_t )( dataRaw[1] * sensitivity );
    48.  
      pdata->AXIS_Z = ( int32_t )( dataRaw[2] * sensitivity );
    49.  
      }

    讲解一下移位方法的理解:最高位bit16是符号位,所以数据位是15bit=32768,那么1个值是多少个mg就是2000mg/32768=1/16mg,就是读取出来的寄存器值需要除以16,除以16就是右移4bit,(2^4 = 16). 相对第一种方法,这种方法算出来的更准确一些应该,因为没有小数的运算。

    方法2参考文章:https://www.pianshen.com/article/2045248726/

    后记,现在明白了这种移位的方法了,加速度值在寄存器中是以补码的形式存在的,上面LIS3DH_Get_AccRaw()是获取数据的补码的实现方法:

    举例:regvalue[2] = 0xF0, regvalue[3] = 0xFB;

    那么,if(regValue[2*i+1] & 0x80) symbol[i] = 0xF000; /*假如是负数,高4位保留(因为移位4位后,数据是0x0XXX的形式,补码需要数值前面符号位后面都是1,所以这里是0xF000),取补码,负数是以补码的形式输出*/

    symbol[1]  | ( ( ( ((int16_t)regValue[3]) << 8 ) + (int16_t)regValue[2] ) >> 4);执行后,结果是0xF000 | 0xFBF = 0xFFBF;

    0xFFBF的二进制是 1111 1111 1011 1111

    减一:1111 1111 1011 1110, 取反:0000 0000 0100 0001

    它的原码是 0000 0000 0100 0001,换成10进制是65,加上负号就是-65,

    4,测试结果:

    1.  
      void cmd_lis3dh_test(char *args){
    2.  
      rt_device_t lis3dh_dev;
    3.  
      int8_t ret;
    4.  
      AxesRaw_t acc,acc1;
    5.  
      int32_t x,y,z;
    6.  
       
    7.  
      lis3dh_dev = n_device_find("lis3dh");//基于RTTthrea的方式实现的代码
    8.  
      if(lis3dh_dev == NULL){
    9.  
      cmd_printf("lis3dh not find. ");
    10.  
      }
    11.  
      ret = n_device_open(lis3dh_dev,RT_DEVICE_FLAG_RDWR);
    12.  
      if(ret != HAL_OK)
    13.  
      cmd_printf("lis3dh open failed!. ");
    14.  
      uint8_t lis_id;
    15.  
      n_device_control(lis3dh_dev,N_LIS3DH_CTRL_ID,&lis_id);
    16.  
      rt_kprintf("data= 0x%x ",lis_id);
    17.  
       
    18.  
      LIS3DH_GetAccAxesRaw(&acc);//方法1)
    19.  
      cmd_printf("LIS3DH read Acceleration adval, x:%d, y:%d, z:%d. ",acc.AXIS_X,acc.AXIS_Y,acc.AXIS_Z);
    20.  
       
    21.  
      acc.AXIS_X = acc.AXIS_X * 2000 / 32768;
    22.  
      acc.AXIS_Y = acc.AXIS_Y * 2000 / 32768;
    23.  
      acc.AXIS_Z = acc.AXIS_Z * 2000 / 32768;
    24.  
      cmd_printf("LIS3DH read Acceleration mg, x:%d, y:%d, z:%d. ",acc.AXIS_X,acc.AXIS_Y,acc.AXIS_Z);
    25.  
      LIS3DH_Get_AccValue(&acc1); //方法2)
    26.  
      cmd_printf("LIS3DH read Acceleration g, x:%d, y:%d, z:%d. ",acc1.AXIS_X,acc1.AXIS_Y,acc1.AXIS_Z);
    27.  
      cmd_printf("LIS3DH read INT1 Level: %d ",n_gpio_readpin(GPIOE,GPIO_PIN_13));//显示加速度计中断
    28.  
       
    29.  
      n_device_close(lis3dh_dev);
    30.  
      }

    5,测试结果:

    0x33是lis3dh的ID。

    adval是寄存器中的值; mg是方法1算出来的结果,应该是0.992g(第一行),g是方法2算出来的结果1.017g,单位标的不对。

    看lis3dh知道,如果加速度计在水平放置时,在z轴方向上是1个g,x或y方向垂直放时,在x或y方向是1个g,其他两个方向应该是0,但是实际中不可能完全是0,会有微小的值存在。

  • 相关阅读:
    SpringBoot整合SpringDataJPA,今天没啥事情就看了一下springboot整合springdataJPA,实在是香啊,SQL语句都不用写了
    SpringMVC+Spring+Mybatis整合
    开源的分布式事务框架 springcloud Alibaba Seata 的搭建使用 一次把坑踩完。。。
    spring cloud Alibaba --sentinel组件的使用
    springcloud整合config组件
    springcloud整合geteway网关服务
    springcloud组件之hystrix服务熔断,降级,限流
    干货 springcloud之 poenFeign的使用
    springcloud组件之注册中心eureka学习
    面试题---->线程的入门,读完可以应付一般的面试(管理员不要移除我的随笔啊)
  • 原文地址:https://www.cnblogs.com/constanto/p/13960424.html
Copyright © 2020-2023  润新知