资讯详情

7.4、LSM6DSL使用

7.4、 LSM6DSL使用

文章目录

  • 7.4、 LSM6DSL使用
    • 7.4.1、 LSM6DSL C_DRIVER库
      • 7.4.1.1、LSM6DSL C_DRIVE移植
    • 7.4.2、LSM6DSL MEMS库
      • 7.4.2.1、MEMS库使用方法
      • 7.4.2.2、MEMS库移植
个人认为有三种具体的使用方法,如下

  • C-Driver-MEMS

  • X-CUBE-MEMS1

  • 根据datasheet写驱动

7.4.1、 LSM6DSL C_DRIVER库

ST除了仓库中的各种传感器驱动外,还有自己传感器推出的标准C驱动的配套例子.该库支持SPI和IIC接口.

7.4.1.1、LSM6DSL C_DRIVE移植

下载后打开lsm6dsl_STdC文件夹,目录如下.

20201214230836 参考lsm6dsl_read_data_polling.c如果要使用文件,只需添加两个函数即可. 软件IIC参考软件IIC这一步.

static int32_t platform_write(void *handle, uint8_t Reg,                               uint8_t *Bufp,                               uint16_t len) { 
           if (handle == &hi2c1) { 
             HAL_I2C_Mem_Write(handle, LSM6DSL_I2C_ADD_H, Reg,                       I2C_MEMADD_SIZE_8BIT, Bufp, len, 1000);   }  #ifdef SPI_TRANSMIT    else if (handle == &hspi2) { 
             HAL_GPIO_WritePin(CS_SPI2_GPIO_Port, CS_SPI2_Pin, GPIO_PIN_RESET);     HAL_SPI_Transmit(handle, &Reg, 1, 1000);     HAL_SPI_Transmit(handle, Bufp, len, 1000);     HAL_GPIO_WritePin(CS_SPI2_GPIO_Port, CS_SPI2_Pin, GPIO_PIN_SET);   }  #endif   return 0; } static int32_t platform_read(void *handle, uint8_t Reg, uint8_t *Bufp,
                             uint16_t len)
{ 
        
  if (handle == &hi2c1) { 
        
    HAL_I2C_Mem_Read(handle, LSM6DSL_I2C_ADD_H, Reg,
                     I2C_MEMADD_SIZE_8BIT, Bufp, len, 1000);
  }

#ifdef SPI_TRANSMIT

  else if (handle == &hspi2) { 
        
    Reg |= 0x80;
    HAL_GPIO_WritePin(CS_DEV_GPIO_Port, CS_DEV_Pin, GPIO_PIN_RESET);
    HAL_SPI_Transmit(handle, &Reg, 1, 1000);
    HAL_SPI_Receive(handle, Bufp, len, 1000);
    HAL_GPIO_WritePin(CS_DEV_GPIO_Port, CS_DEV_Pin, GPIO_PIN_SET);
  }

#endif
  return 0;
}

然后在主函数内添加如下内容.

  stmdev_ctx_t dev_ctx;
  dev_ctx.write_reg = platform_write;
  dev_ctx.read_reg = platform_read;
  dev_ctx.handle = &hi2c1;

通过上述方法就可以具体调用lsm6dsl_reg.c文件内的api函数了,具体使用方法如下所示.

int main() 
{ 
        
    stmdev_ctx_t dev_ctx;
    dev_ctx.write_reg = platform_write;
    dev_ctx.read_reg = platform_read;
    dev_ctx.handle = &hi2c1;
    uint8_t whoamI = 0;

    lsm6dsl_device_id_get(&dev_ctx, &whoamI);

    if ( whoamI != LSM6DSL_ID )
        while (1); /*manage here device not found */
}

7.4.2、LSM6DSL MEMS库

MEMS库大概就是对C_Driver库进行了一层封装,上述的C_Driver库只是对一些操作进行了基本的封装,大概类似于STM32的STD库或者HAL库,MEMS库则是在该封装之上在进行一层封装,且多出了16个运动算法库. MEMS库架构如下所示.

  • hardware : 你所使用的硬件平台
  • hardware abstraction : 硬件平台本身的驱动及传感器的驱动
  • middleware : MEMS库比C_DRIVER库多出的地方,该部分ST官方只提供了静态库文件,没有源码,这是一个独立于平台的软件层
  • application : 应用逻辑层

emmmm,这套代码库东西很是挺多的,但我用不到这么多,下面简单说一下我的使用方法.

7.4.2.1、MEMS库使用方法

我使用的工具如下.

  1. 软件
    • CUBEMX 6.1.0
    • X-CUBE-MEMS 8.2.0
    • STM32F4 Series 1.25.2
  2. 硬件
    • STM32F411
    • LSM6DSL

CUBEMX配置如下

  1. 选择使用的芯片芯片硬件使用的接口
  2. 因为我是自己打的板子,所以我选择的是CUSTOM/MOTION_SENSER,如果官方支持的板子,选择BOARD Extension里面对应型号即可.
  3. 选择你想使用的例子. 四五步略
  4. 第六步,根据你硬件方面的接线去选择.
  5. 最后,BUS_IO_DRIVER目前只能选择硬件IIC,但是可以自己手动替换.

: 如果想要使用MEMS库里面的算法库,可以在第三步的下面找到你要使用的算法库勾选上,生成的工程里就会包含该静态库文件.关于这些库文件的API文档和使用方法,可以根据库不同参考ST官方的应用笔记.以Motion EC库举例,参考UM2225.里面有资源占用详情及API的说明等等.

关于生成后的工程目录如下所示.

红框内的内容是手动添加的调试组件和IIC驱动.其余为CUBEMX自动生成的代码.

7.4.2.2、MEMS库移植

和C_Driver库的移植大同小异.

  1. 将下图红框内文件.

简单说一下文件作用.

lsm6dsl_reg.c就是LSM6DSL芯片的驱动,.lsm6dsl.c只是对驱动文件做了一些简单的封装,custom_motion_sensor.ccustom_motion_sensor_ex.c则是将lsm6dsl.c文件内容进行了分离,custom_motion_sensor.c只包含一些最基本的数据读取功能,custom_motion_sensor_ex.c则只包含了一些嵌入式功能. app_mems_int_pin_a_interface.c文件只是传感器中断引脚所接入控制器IO的硬件初始化及对应的中断事件处理.

  1. 这里我使用的是软件IIC,如果使用硬件IIC则直接进入下一步.

添加IIC驱动文件,我这里只是简单的测试,所以移植了原子的部分代码做了些简单的修改,具体内容如下.emmm,因为测试的时候求快,所以代码有点乱,使用的时候最好整理一下…

 #include "myiic.h"
 #include "delay.h"
 int32_t IIC_Init(void)
 { 
        
     GPIO_InitTypeDef GPIO_Initure;

     __HAL_RCC_GPIOB_CLK_ENABLE();

     //PH4,5初始化设置
     GPIO_Initure.Pin = GPIO_PIN_2 | GPIO_PIN_10;
     GPIO_Initure.Mode = GPIO_MODE_OUTPUT_PP; //推挽输出
     GPIO_Initure.Pull = GPIO_PULLUP;        //上拉
     GPIO_Initure.Speed = GPIO_SPEED_FAST;   //快速
     HAL_GPIO_Init(GPIOB, &GPIO_Initure);

     IIC_SDA = 1;
     IIC_SCL = 1;
     return BSP_ERROR_NONE;
 }

 //产生IIC起始信号
 void IIC_Start(void)
 { 
        
     SDA_OUT();     //sda线输出
     IIC_SDA = 1;
     IIC_SCL = 1;
     delay_us(4);
     IIC_SDA = 0; //START:when CLK is high,DATA change form high to low
     delay_us(4);
     IIC_SCL = 0; //钳住I2C总线,准备发送或接收数据
 }
 //产生IIC停止信号
 void IIC_Stop(void)
 { 
        
     SDA_OUT();//sda线输出
     IIC_SCL = 0;
     IIC_SDA = 0; //STOP:when CLK is high DATA change form low to high
     delay_us(4);
     IIC_SCL = 1;
     IIC_SDA = 1; //发送I2C总线结束信号
     delay_us(4);
 }
 //等待应答信号到来
 //返回值:1,接收应答失败
 // 0,接收应答成功
 uint8_t IIC_Wait_Ack(void)
 { 
        
     uint8_t ucErrTime = 0;
     IIC_SDA = 1;
     delay_us(1);
     IIC_SCL = 1;
     delay_us(1);
     
     SDA_IN();      //SDA设置为输入

     while(READ_SDA)
     { 
        
         ucErrTime++;

         if(ucErrTime > 250)
         { 
        
             IIC_Stop();
             return 1;
         }
     }

     IIC_SCL = 0; //时钟输出0
     return 0;
 }
 //产生ACK应答
 void IIC_Ack(void)
 { 
        
     IIC_SCL = 0;
     SDA_OUT();
     IIC_SDA = 0;
     delay_us(2);
     IIC_SCL = 1;
     delay_us(2);
     IIC_SCL = 0;
 }
 //不产生ACK应答
 void IIC_NAck(void)
 { 
        
     IIC_SCL = 0;
     SDA_OUT();
     IIC_SDA = 1;
     delay_us(2);
     IIC_SCL = 1;
     delay_us(2);
     IIC_SCL = 0;
 }
 //IIC发送一个字节
 //返回从机有无应答
 //1,有应答
 //0,无应答
 void IIC_Send_Byte(uint8_t txd)
 { 
        
     uint8_t t;
     SDA_OUT();
     IIC_SCL = 0; //拉低时钟开始数据传输

     for(t = 0; t < 8; t++)
     { 
        
         if(txd & 0x80)
             IIC_SDA = 1;
         else
             IIC_SDA = 0;
         txd <<= 1;
         delay_us(2);   //对TEA5767这三个延时都是必须的
         IIC_SCL = 1;
         delay_us(2);
         IIC_SCL = 0;
         delay_us(2);
     }
 }
 //读1个字节,ack=1时,发送ACK,ack=0,发送nACK
 uint8_t IIC_Read_Byte(unsigned char ack)
 { 
        
     unsigned char i, receive = 0;
     SDA_IN();//SDA设置为输入

     for(i = 0; i < 8; i++)
     { 
        
         IIC_SCL = 0;
         delay_us(2);
         IIC_SCL = 1;
         receive <<= 1;

         if(READ_SDA)receive++;

         delay_us(1);
     }

     if(!ack)
         IIC_NAck();//发送nACK
     else
         IIC_Ack(); //发送ACK

     return receive;
 }
 int32_t I2C_Read_Byte_Len(uint16_t _device_addr, uint16_t _reg, uint8_t *_pData, uint16_t _Len)
 { 
        
     IIC_Start();
     IIC_Send_Byte((_device_addr<<1) | 0);

     if(IIC_Wait_Ack())
     { 
        
         IIC_Stop();//产生一个停止条件
         return BSP_ERROR_PERIPH_FAILURE;
     }

     IIC_Send_Byte(_reg & 0xFF); //发送低地址

     if(IIC_Wait_Ack())
     { 
        
         IIC_Stop();//产生一个停止条件
         return BSP_ERROR_PERIPH_FAILURE;
     }

     IIC_Start();
     IIC_Send_Byte((_device_addr<<1) | 1);	  //发器件地址

     if(IIC_Wait_Ack())
     { 
        
         IIC_Stop();//产生一个停止条件
         return BSP_ERROR_PERIPH_FAILURE;
     }

     while(_Len)
     { 
        
         if(_Len == 1)
             *_pData = IIC_Read_Byte(0);//读数据,发送nACK
         else
             *_pData = IIC_Read_Byte(1);//读数据,发送ACK

         _Len--;
         _pData++;
     }

     IIC_Stop();//产生一个停止条件
     return BSP_ERROR_NONE;
 }
 int32_t I2C_Write_Reg_Len(uint16_t _device_addr, uint16_t _reg, uint8_t *_pData, uint16_t _Len)
 { 
        
     uint8_t i;

     IIC_Start();
     IIC_Send_Byte((_device_addr<<1) | 0);

     if(IIC_Wait_Ack())
     { 
        
         return BSP_ERROR_PERIPH_FAILURE;
     }

     IIC_Send_Byte(_reg & 0xFF); //发送低地址
     IIC_Wait_Ack();

     for(i = 0; i < _Len; i++)
     { 
        
         IIC_Send_Byte(_pData[i]);//发送数据

         if(IIC_Wait_Ack())
         { 
        
             return BSP_ERROR_PERIPH_FAILURE;
         }
     }

     IIC_Stop();//产生一个停止条件
     return BSP_ERROR_NONE;
 }

 #ifndef _MYIIC_H
 #define _MYIIC_H
 #include "main.h"

 #define BITBAND(addr, bitnum) ((addr & 0xF0000000)+0x2000000+((addr &0xFFFFF)<<5)+(bitnum<<2))
 #define MEM_ADDR(addr) *((volatile unsigned long *)(addr))
 #define BIT_ADDR(addr, bitnum) MEM_ADDR(BITBAND(addr, bitnum))
 #define GPIOB_ODR_Addr (GPIOB_BASE+20) //0x40020414 
 #define PBout(n) BIT_ADDR(GPIOB_ODR_Addr,n) //输出 
 #define PBin(n) BIT_ADDR(GPIOB_IDR_Addr,n) //输入

 #define SDA_IN() {GPIOB->MODER&=~(3<<(10*2));GPIOB->MODER|=0<<(10*2);} //PB10输入模式
 #define SDA_OUT() {GPIOB->MODER&=~(3<<(10*2));GPIOB->MODER|=1<<(10*2);} //PB10输出模式
 //IO操作
 #define IIC_SCL PBout(2) //SCL
 #define IIC_SDA PBout(10) //SDA
 #define READ_SDA PBin(10) //输入SDA


   //IIC所有操作函数
 int32_t IIC_Init(void);                //初始化IIC的IO口
 void IIC_Start(void);//发送IIC开始信号
 void IIC_Stop(void);//发送IIC停止信号
 void IIC_Send_Byte(uint8_t txd);//IIC发送一个字节
 uint8_t IIC_Read_Byte(unsigned char ack);//IIC读取一个字节
 uint8_t IIC_Wait_Ack(void);//IIC等待ACK信号
 void IIC_Ack(void);//IIC发送ACK信号
 void IIC_NAck(void);//IIC不发送ACK信号

 int32_t I2C_Read_Byte_Len(uint16_t _device_addr, uint16_t _reg, uint8_t *_pData, uint16_t _Len) ;
 int32_t I2C_Write_Reg_Len(uint16_t _device_addr, uint16_t _reg, uint8_t *_pData, uint16_t _Len);
 #endif

主要修改内容在I2C_Read_Byte_LenI2C_Write_Reg_Len函数上面,这两个是按照DATASHEET上给出的时序图来做的.

修改lsm6dsl_reg.h文件内#define LSM6DSL_I2C_ADD_L 0xD5U#define LSM6DSL_I2C_ADD_L 0x6AU,至于硬件IIC需不需要修改ID则需要具体测试一下.条件有限,只测试了软件IIC.

  1. 替换IIC读写函数.

打开custom_mems_conf.h文件,修改如下宏.硬件IIC的话参考官方custom_bus.c文件.

#define CUSTOM_LSM6DSL_0_I2C_Init IIC_Init
#define CUSTOM_LSM6DSL_0_I2C_DeInit IIC_Init
#define CUSTOM_LSM6DSL_0_I2C_ReadReg I2C_Read_Byte_Len
#define CUSTOM_LSM6DSL_0_I2C_WriteReg I2C_Write_Reg_Len
  1. 初始化及搭建自己的应用逻辑. 根据自己硬件配置修改app_mems.c文件中的MX_MEMS_Init,根据自己业务逻辑修改MX_MEMS_Process函数即可.

备注:不建议使用app_mems.c文件,但是在搭建自己应用逻辑时,建议参考MX_MEMS_Init函数.

测试时候使用的功能是LSM6DSL_FIFOContMode,具体效果如下.

以上,关于LSM6DSL的使用结束了,下周边开发边整理LVGL的笔记.

标签: dsl传感器

锐单商城拥有海量元器件数据手册IC替代型号,打造 电子元器件IC百科大全!

锐单商城 - 一站式电子元器件采购平台