1、特性
1.1、架构与数据处理
- 三通道架构,分别用于 UI、EIS、OIS 数据处理
- 可编程有限状态机,支持加速度计、陀螺仪、外部传感器高速数据处理,最高 960Hz 采样率
- 内置低功耗传感器融合算法
- 集成机器学习运算内核,可导出特征与滤波数据,适配 AI 应用
- 嵌入式自适应自配置(ASC)功能
1.2、低功耗与常驻运行
- 加速度计、陀螺仪支持 “永久在线” 工作模式,功耗极低
- 高性能组合模式下功耗仅 0.65mA
- 供电规格
- 模拟电源电压:1.71V ~ 3.6V
- 独立 IO 电源(宽压区间):1.08V ~ 3.6V
1.3、传感器量程规格
加速度计
满量程可选:±2g / ±4g / ±8g / ±16g
这里的g = 重力加速度,1g ≈ 9.8 m/s²,代表地球标准重力。 这是加速度计的满量程测量范围,芯片可软件配置切换这四档量程。
- ±2 g测量范围:-19.6 ~ +19.6 m/s² 适合:计步、姿态判断、手机平放 / 倾斜检测、日常 UI 翻转,精度最高。
- ±4 g测量范围:-39.2 ~ +39.2 m/s² 适合:轻度运动、走路慢跑、小幅晃动检测。
- ±8 g测量范围:-78.4 ~ +78.4 m/s² 适合:跑步、跳跃、颠簸场景、防抖基础采集。
- ±16 g测量范围:-156.8 ~ +156.8 m/s² 适合:剧烈震动、跌落检测、高速运动、工业冲击采集。
芯片 ADC 总采样位数固定,量程越小,单 bit 分辨率越高,测量越精细:
- ±2g:灵敏度最高,微小晃动都能识别(双击、抬手亮屏)
- ±16g:量程最大,但微小加速度变化分辨能力最弱
陀螺仪
满量程可选:±125 / ±250 / ±500 / ±1000 / ±2000 / ±4000 dps
dps = degrees per second,度每秒,是陀螺仪的量程单位,代表设备每秒旋转的角度。 这组参数是陀螺仪可配置的满量程测量范围,用来检测物体旋转、转动动作。
- ±125 dps量程最小、分辨率最高,适合缓慢小幅转动:手机屏幕翻转、日常姿态微调、UI 交互。
- ±250 dps轻度转动,适合普通手持设备日常姿态检测、慢速云台防抖。
- ±500 dps手机常规拍摄 EIS 电子防抖、日常短视频拍摄。
- ±1000 dps边走边拍、走路录像、小幅运动防抖。
- ±2000 dps快速转动、跑步拍摄、运动镜头、手持云台大幅度摇摆。
- ±4000 dps最大量程,适合极速旋转、剧烈运动、快速甩动、航拍、高速运动拍摄,能捕捉超大角度转动。
- 量程越小(如 ±125dps):每 1bit 代表的角度变化极小,微小转动都能精准捕捉,防抖、姿态检测精度更高;
- 量程越大(如 ±4000dps):能测高速旋转,但对细微转动的分辨能力会下降。
- g(重力加速度):测直线加速度、重力、震动、跌落、步数;
- dps(度 / 秒):测旋转、转动、摇晃,专门给 OIS 光学防抖、EIS 电子防抖提供数据。
1.4、存储与接口
- 智能 FIFO 缓冲区,最大 4.5KB
- 主通信接口:SPI / I²C/ MIPI I3C® v1.1,支持与主控数据同步
- 辅助 SPI 接口:输出陀螺仪、加速度计 OIS 防抖数据
- OIS 防抖功能可通过辅助 SPI、主接口(SPI/I²C/MIPI I3C v1.1)配置
- 主接口独立 EIS 电子防抖通道,配套专用滤波
- 内置模拟集线器,用于 ADC 采集与模拟输入数据处理
1.5、运动 & 姿态检测功能
- 高级计步套件:步数检测、步数统计
- 有效运动检测、倾斜检测
- 标准中断触发源:自由落体、唤醒、6 轴 / 4 轴姿态、单击、双击
1.6、人机交互 UI 模块(内置 Qvar 静电传感器)
支持触控交互:单击、双击、三击、长按、左右滑动(L/R–R/L swipe)
1.7、内置外设
- 片内温度传感器
- Qvar 静电传感器(UI 交互专用)
1.8、系统兼容性
- 符合 Android 系统标准
1.9、封装与环保标准
- 小型化尺寸:2.5 mm × 3 mm × 0.83 mm
- ECOPACK 环保封装,符合 RoHS 标准
2、IIC接口
2.1、接线
这款芯片兼容iic和spi,笔者这里使用的是iic接口
图片来源:春节不发货LSM6DSV16XTR模块六轴传感器,内置算法融合,AI应用-淘宝网
接线如下:
VCC接3.3V
GND接地
CS接3.3V拉高是iic模式,拉低是spi模式
ADO/MISO(SDO/SA0)决定iic从机地址,SDO/SA0接GND,地址:0X6A;SDO/SA0接VCC,地址:0X6B
必须固定电平,不能悬空
SCL/SCLK(SCL/SPC)、SDA/MOSI(SDA/SDI/SDO)正常接iic主机对应的接口
这里实物的接口名称和数据手册的接口名称不一样,括号里面的是数据手册的名称
数据手册这里描述了:SDO/SA0接GND,地址:0X6A;SDO/SA0接VCC,地址:0X6B
LSM6DSV16X 作为 I2C 从机,通信流程固定:
- 主机发起始信号 ST;
- 发送 7 位从地址 + 读写位,等待芯片应答 SAK;
- 应答成功后,主机发送8 位寄存器子地址 SUB(要读 / 写的芯片内部寄存器地址,比如 CTRL1、MLC 相关寄存器);
- 寄存器地址自动递增功能,由寄存器
CTRL3 (0x12)的 IF_INC 位控制。
- 写操作(R/W 位 = 0)发送从地址 + 写位 → ACK → 寄存器子地址 → 连续发多字节数据,总线方向不变,直接写入对应寄存器。
- 读操作(R/W 位 = 1)流程:起始 ST → 从地址 (写) → ACK → 寄存器子地址 →重复起始信号 SR→ 再发从地址 (读) → 读取芯片返回的数据。
通俗讲:I2C 读传感器必须先发一次 “写地址” 指定寄存器,再发重复起始切换读模式,不能直接发读地址。
| 列名 | 含义 |
|---|---|
| Command | 操作类型:Read(读)/ Write(写) |
| SAD[6:1] | 芯片固定高 6 位从机地址,固定二进制110101,不可修改 |
| SAD[0] = SA0 | 最低位,由硬件引脚SDO/SA0电平决定:SA0 接 GND → 0;SA0 接 3.3V (VDD) → 1 |
| R/W | I2C 读写控制位:0 = 写操作,1 = 读操作 |
| SAD+R/W | 完整 8 位 I2C 总线传输字节(二进制 + 十六进制) |
场景 1:SA0 接 GND(SAD [0]=0)
- Write 写操作SAD [6:1]=110101 + SAD [0]=0 + R/W=0 二进制:
11010100=0xD4对应你说的从机地址 0x6A(7 位地址是 0110101,即 0x6A,写字节 = 0x6A<<1=0xD4) - Read 读操作SAD [6:1]=110101 + SAD [0]=0 + R/W=1 二进制:
11010101=0xD5读字节 =0x6A << 1 | 1 = 0xD5
场景 2:SA0 接 3.3V(SAD [0]=1)
- Write 写操作SAD [6:1]=110101 + SAD [0]=1 + R/W=0 二进制:
11010110=0xD6对应你说的从机地址 0x6B(7 位地址 01101011=0x6B,写字节 = 0x6B<<1=0xD6) - Read 读操作SAD [6:1]=110101 + SAD [0]=1 + R/W=1 二进制:
11010111=0xD7读字节 =0x6B << 1 | 1 = 0xD7
- SA0/GND → 7 位地址
0x6A,写指令0xD4,读指令0xD5 - SA0/VCC → 7 位地址
0x6B,写指令0xD6,读指令0xD7
- 7 位从机地址:软件驱动里配置的设备 ID(0x6A / 0x6B)
- 8 位总线发送字节:硬件 I2C 实际发出去的字节(0xD4/D5/D6/D7),是 7 位地址左移 1 位,最低位填充 R/W 读写标记
3、初始化
这里以nRF54l15外接lsm6dsv16x为例,SCL/SCLK(SCL/SPC)、SDA/MOSI(SDA/SDI/SDO)正常接iic主机对应的接口,硬件实现iic。
一般调试这些芯片时,先获取设备ID,因此需要查询设备id存放的地址
整理一下所需要的寄存器地址
#define LSM6DSV16X_I2C_ADDR 0x6A // 对应原理图SA0/SDO下拉 #define LSM6DSV16X_WHO_AM_I 0x0F // 设备ID寄存器(默认0x70) #define LSM6DSV16X_CTRL1 0x10 // 启动加速度计 #define LSM6DSV16X_CTRL2 0x11 // 启动陀螺仪 #define LSM6DSV16X_CTRL3 0x12 // BDU/IF_INC #define LSM6DSV16X_CTRL6 0x15 // 陀螺仪量程/低通滤波器配置 #define LSM6DSV16X_CTRL8 0x17 // 加速度计量程/低通滤波器配置 #define LSM6DSV16X_TEMP_OUT_L 0x20 // 温度数据低8位 #define LSM6DSV16X_TEMP_OUT_H 0x21 // 温度数据高8位 #define LSM6DSV16X_GYRO_XOUT_L 0x22 // 陀螺仪X轴数据低8位 #define LSM6DSV16X_GYRO_XOUT_H 0x23 // 陀螺仪X轴数据高8位 #define LSM6DSV16X_GYRO_YOUT_L 0x24 // 陀螺仪Y轴数据低8位 #define LSM6DSV16X_GYRO_YOUT_H 0x25 // 陀螺仪Y轴数据高8位 #define LSM6DSV16X_GYRO_ZOUT_L 0x26 // 陀螺仪Z轴数据低8位 #define LSM6DSV16X_GYRO_ZOUT_H 0x27 // 陀螺仪Z轴数据高8位 #define LSM6DSV16X_ACCEL_XOUT_L 0x28 // 加速度X轴数据低8位 #define LSM6DSV16X_ACCEL_XOUT_H 0x29 // 加速度X轴数据高8位 #define LSM6DSV16X_ACCEL_YOUT_L 0x2A // 加速度Y轴数据低8位 #define LSM6DSV16X_ACCEL_YOUT_H 0x2B // 加速度Y轴数据高8位 #define LSM6DSV16X_ACCEL_ZOUT_L 0x2C // 加速度Z轴数据低8位 #define LSM6DSV16X_ACCEL_ZOUT_H 0x2D // 加速度Z轴数据高8位 #define LSM6DSV16X_WHO_AM_I_VAL 0x70 // 期望的WHO_AM_I返回值先列出这么多,阅读数据手册后,初始化的时候需要完成以下几步:
(1)配置总线行为: BDU + IF_INC,必须最先配置
(2)设置陀螺仪量程
(3)设置加速度计量程
(4)启动加速度计
(5)启动陀螺仪
3.1、配置总线行为
寄存器说明如下
Bit7:BOOT(内存重启):默认值为0,1是重启内存数据
Bit6:BDU(Block Data Update,数据锁存更新):默认值为1,高低字节全部读完后,才更新下一组采样数据
Bit2:IF_INC(寄存器地址自动自增):默认值为1,I2C/SPI/MIPI I3C 多字节读写时地址自动 + 1
Bit0:SW_RESET(软件复位):默认值为0,软件全局复位,所有控制寄存器恢复出厂默认值,写入 1 后硬件自动清零该位
所以这里需要:
(1)开启 BDU 数据锁存,保证 16 位传感器数据读取完整不错乱;
(2)开启 I2C 寄存器地址自动自增,支持连续批量读写寄存器;
(3)关闭 BOOT 重载、关闭软件复位、所有保留位清零
即向0x12地址写入0100 0100
// 后期用宏定义替换 lsm6dsv16x_write(0x12, 0x44);3.2、设置陀螺仪量程
Bit6~Bit4:LPF1_G_BW [2:0] 陀螺仪一阶低通滤波带宽选择:数值越小滤波越强、噪声抑制越好,但信号延迟变大。
| LPF1_G_BW[2:0] | 滤波特性(常用场景推荐) |
|---|---|
| 000 | 通带宽,高频保留多,噪声大,适合高速运动采集 |
| 001 / 010 / 011 | 中等滤波,平衡噪声与响应速度 |
| 100 | 中强滤波,运动识别 MLC 常规推荐档位 |
| 101 | 强滤波,小幅抖动抑制明显 |
| 110 | 极强滤波,仅保留极低频率运动 |
| 111 | 最强滤波,适合静止、慢动作识别 |
Bit3~Bit0:FS_G [3:0] 陀螺仪量程选择(Full Scale)
| FS_G[3:0] | 陀螺仪量程 | 特殊说明 |
|---|---|---|
| 0000 | ±125 dps | 默认量程,低速姿态检测 |
| 0001 | ±250 dps | 日常人体运动首选 |
| 0010 | ±500 dps | 快速转身、手部动作 |
| 0011 | ±1000 dps | 大幅度快速旋转 |
| 0100 | ±2000 dps | 高速旋转场景 |
| 1100 | ±4000 dps | 极限高速;必须关闭 OIS 防抖功能 |
| 其余编码 | 保留,禁止配置 |
如果不需要滤波,设置±500 dps的量程,这里:
向0x15地址写入0000 0010
// 后期用宏定义替换 lsm6dsv16x_write(0x15, 0x02);3.3、设置加速度计量程
Bit7~Bit5:HP_LPF2_XL_BW [2:0] 加速度二阶滤波带宽选择
Bit3:XL_DUAL_EN 加速度双通道模式
Bit1~Bit0:FS_XL [1:0] 加速度计量程选择
| FS_XL[1:0] | 量程 | 适用场景 |
|---|---|---|
| 00 | ±2 g | 姿态、倾角、缓慢人体运动(MLC 首选,分辨率最高) |
| 01 | ±4 g | 日常行走、手部动作 |
| 10 | ±8 g | 跑跳、剧烈运动 |
| 11 | ±16 g | 冲击、跌落检测 |
如果这里只设置加速度计量程为±8 g,则:
向0x17写入0000 0010
// 后期用宏定义替换 lsm6dsv16x_write(0x17, 0x02);3.4、启动加速度计
Bit6~Bit4 OP_MODE_XL [2:0] 加速度计工作模式
| 编码 | 模式名称 | 特性 & MLC 适用建议 |
|---|---|---|
| 000 | High-performance mode(高性能,默认) | 噪声最低、采样精度最高;MLC 运动识别首选,功耗中等 |
| 001 | High-accuracy ODR mode(高精度采样) | 采样时序更稳定,功耗略高于高性能模式 |
| 010 | 保留 | 禁止配置 |
| 011 | ODR-triggered mode(采样触发模式) | 外部信号触发采样,普通 I2C 轮询场景不用 |
| 100 | Low-power mode 1(2 次均值低功耗) | 低功耗,2 次采样平均,噪声小幅上升 |
| 101 | Low-power mode 2(4 次均值低功耗) | 更低功耗,4 次均值,平滑更强、延迟变大 |
| 110 | Low-power mode 3(8 次均值低功耗) | 最低功耗,8 次均值,适合长待机静止检测 |
| 111 | Normal mode(标准模式) | 性能、功耗折中,噪声高于高性能模式 |
Bit3~Bit0 ODR_XL [3:0] 加速度输出采样率
| ODR_XL[3:0] | 输出频率 (Hz) | 支持的工作模式 |
|---|---|---|
| 0000 | 断电 Power-down | 全部模式通用,休眠关闭加速度 |
| 0001 | 1.875 | 仅低功耗模式 |
| 0010 | 7.5 | 高性能 / 标准模式 |
| 0011 | 15 | 低功耗 / 高性能 / 标准 |
| 0100 | 30 | 低功耗 / 高性能 / 标准 |
| 0101 | 60 | 低功耗 / 高性能 / 标准 |
| 0110 | 120 | 低功耗 / 高性能 / 标准 |
| 0111 | 240 | 低功耗 / 高性能 / 标准 |
| 1000 | 480 | 高性能 / 标准 |
| 1001 | 960 | 高性能 / 标准 |
| 1010 | 1.92k | 高性能 / 标准 |
| 1011 | 3.84k | 仅高性能模式 |
| 1100 | 7.68k | 仅高性能模式 |
| 其余编码 | 保留 | 禁止配置 |
这里选择加速度计高性能模式、加速度输出采样率 120Hz:
向0x10写入0000 0110
// 后期用宏定义替换 lsm6dsv16x_write(0x10, 0x06);3.5、启动陀螺仪
OP_MODE_G [2:0] 陀螺仪工作模式(Bit6~Bit4)
| 编码 | 模式 | 说明 & MLC 选型 |
|---|---|---|
| 000 | High-performance mode(默认高性能) | 噪声最低,MLC 运动识别首选,功耗中等 |
| 001 | High-accuracy ODR mode | 采样时序更精准,功耗略高 |
| 010 | 保留 | 禁止配置 |
| 011 | ODR-triggered mode | 外部触发采样,普通 I2C 轮询不用 |
| 100 | Sleep mode | 陀螺仪休眠,仅保留基础电路 |
| 101 | Low-power mode | 低功耗,数据均值平滑,噪声上升 |
| 110 / 111 | 保留 | 禁止配置 |
ODR_G [3:0] 陀螺仪输出采样率(Bit3~Bit0)
| ODR_G[3:0] | 频率 | 支持模式 |
|---|---|---|
| 0000 | Power-down 断电 | 全部模式通用,关闭陀螺仪 |
| 0001 | 7.5 Hz | 低功耗 / 高性能 |
| 0010 | 15 Hz | 低功耗 / 高性能 |
| 0011 | 30 Hz | 低功耗 / 高性能 |
| 0100 | 60 Hz | 低功耗 / 高性能 |
| 0101 | 120 Hz | 低功耗 / 高性能(MLC 步态推荐) |
| 0110 | 240 Hz | 低功耗 / 高性能 |
| 1000 | 480 Hz | 仅高性能 |
| 1001 | 960 Hz | 仅高性能 |
| 1010 | 1.92 kHz | 仅高性能 |
| 1011 | 3.84 kHz | 仅高性能 |
| 1100 | 7.68 kHz | 仅高性能 |
| 其余编码 | 保留 | 禁止配置 |
这里选择陀螺仪高性能模式、陀螺仪输出采样率 120Hz:
向0x11写入0000 0101
// 后期用宏定义替换 lsm6dsv16x_write(0x11, 0x05);3.6、读加速度计、陀螺仪数据
读高位、低位,再或起来即可,也可连续读(地址连续)不再赘述。
4、完整代码
4.1、lsm6dsv16x.h
#ifndef LSM6DSV16X_H #define LSM6DSV16X_H #include <stdint.h> #define LSM6DSV16X_I2C_ADDR 0x6A // 对应原理图SA0/SDO下拉 #define LSM6DSV16X_WHO_AM_I 0x0F // 设备ID寄存器(默认0x70) #define LSM6DSV16X_CTRL1 0x10 // 启动加速度计 #define LSM6DSV16X_CTRL2 0x11 // 启动陀螺仪 #define LSM6DSV16X_CTRL3 0x12 // BDU/IF_INC #define LSM6DSV16X_CTRL6 0x15 // 陀螺仪量程/低通滤波器配置 #define LSM6DSV16X_CTRL8 0x17 // 加速度计量程/低通滤波器配置 #define LSM6DSV16X_TEMP_OUT_L 0x20 // 温度数据低8位 #define LSM6DSV16X_TEMP_OUT_H 0x21 // 温度数据高8位 #define LSM6DSV16X_GYRO_XOUT_L 0x22 // 陀螺仪X轴数据低8位 #define LSM6DSV16X_GYRO_XOUT_H 0x23 // 陀螺仪X轴数据高8位 #define LSM6DSV16X_GYRO_YOUT_L 0x24 // 陀螺仪Y轴数据低8位 #define LSM6DSV16X_GYRO_YOUT_H 0x25 // 陀螺仪Y轴数据高8位 #define LSM6DSV16X_GYRO_ZOUT_L 0x26 // 陀螺仪Z轴数据低8位 #define LSM6DSV16X_GYRO_ZOUT_H 0x27 // 陀螺仪Z轴数据高8位 #define LSM6DSV16X_ACCEL_XOUT_L 0x28 // 加速度X轴数据低8位 #define LSM6DSV16X_ACCEL_XOUT_H 0x29 // 加速度X轴数据高8位 #define LSM6DSV16X_ACCEL_YOUT_L 0x2A // 加速度Y轴数据低8位 #define LSM6DSV16X_ACCEL_YOUT_H 0x2B // 加速度Y轴数据高8位 #define LSM6DSV16X_ACCEL_ZOUT_L 0x2C // 加速度Z轴数据低8位 #define LSM6DSV16X_ACCEL_ZOUT_H 0x2D // 加速度Z轴数据高8位 #define LSM6DSV16X_WHO_AM_I_VAL 0x70 // 期望的WHO_AM_I返回值 /* ------------------------------------------------------------------ */ /* CTRL1 — bit[6:4]=OP_MODE_XL[2:0], bit[3:0]=ODR_XL[3:0] */ /* ------------------------------------------------------------------ */ #define LSM6DSV16X_OP_MODE_HIGH_PERF (0x00 << 4) /* 000: high-performance (default) */ #define LSM6DSV16X_OP_MODE_NORMAL (0x07 << 4) /* 111: normal mode */ #define LSM6DSV16X_ODR_XL_POWER_DOWN 0x00 #define LSM6DSV16X_ODR_XL_15HZ 0x03 #define LSM6DSV16X_ODR_XL_30HZ 0x04 #define LSM6DSV16X_ODR_XL_60HZ 0x05 #define LSM6DSV16X_ODR_XL_120HZ 0x06 #define LSM6DSV16X_ODR_XL_240HZ 0x07 /* ------------------------------------------------------------------ */ /* CTRL2 — bit[6:4]=OP_MODE_G[2:0], bit[3:0]=ODR_G[3:0] */ /* ------------------------------------------------------------------ */ #define LSM6DSV16X_ODR_G_POWER_DOWN 0x00 #define LSM6DSV16X_ODR_G_15HZ 0x02 #define LSM6DSV16X_ODR_G_30HZ 0x03 #define LSM6DSV16X_ODR_G_60HZ 0x04 #define LSM6DSV16X_ODR_G_120HZ 0x05 #define LSM6DSV16X_ODR_G_240HZ 0x06 /* ------------------------------------------------------------------ */ /* CTRL6 (0x15) — bit[3:0]=FS_G[3:0] 陀螺仪量程 */ /* ------------------------------------------------------------------ */ #define LSM6DSV16X_FS_G_125DPS 0x00 /* ±125 dps */ #define LSM6DSV16X_FS_G_250DPS 0x01 /* ±250 dps */ #define LSM6DSV16X_FS_G_500DPS 0x02 /* ±500 dps */ #define LSM6DSV16X_FS_G_1000DPS 0x03 /* ±1000 dps */ #define LSM6DSV16X_FS_G_2000DPS 0x04 /* ±2000 dps */ /* ------------------------------------------------------------------ */ /* CTRL8 (0x17) — bit[1:0]=FS_XL[1:0] 加速度计量程 */ /* ------------------------------------------------------------------ */ #define LSM6DSV16X_FS_XL_2G 0x00 /* ±2g */ #define LSM6DSV16X_FS_XL_4G 0x01 /* ±4g */ #define LSM6DSV16X_FS_XL_8G 0x02 /* ±8g */ #define LSM6DSV16X_FS_XL_16G 0x03 /* ±16g */ /** * @brief 通用控制 * BDU=1: 读完整对才更新输出寄存器(防撕裂) * IF_INC=1: 连续读时地址自动递增(burst read 必须置位) */ #define LSM6DSV16X_CTRL3_BDU (1 << 6) #define LSM6DSV16X_CTRL3_IF_INC (1 << 2) /** * @brief lsm6dsv16x初始化函数 */ void lsm6dsv16x_init(void); /** * @brief 指定地址读数据 * @param reg_address 指定的地址 * @return 读出的数据 */ uint8_t lsm6dsv16x_read(uint8_t reg_address); /** * @brief 指定地址读数据 * @param reg_address 指定的地址 * @param data 写入的数据 */ void lsm6dsv16x_write(uint8_t reg_address, uint8_t data); /** * @brief 获取设备ID */ uint8_t lsm6dsv16x_get_id(void); /** * @brief 获取数据寄存器的值 * @param acc_x 加速度寄存器x轴数据,LSB = 0.244 mg/LSB(±8g 量程) * @param acc_y 加速度寄存器y轴数据 * @param acc_z 加速度寄存器z轴数据 * @param gyro_x 陀螺仪寄存器x轴数据,LSB = 17.5 mdps/LSB(±500dps 量程) * @param gyro_y 陀螺仪寄存器y轴数据 * @param gyro_z 陀螺仪寄存器z轴数据 * @param temp 温度传感器的数据,°C = raw / 256.0f + 25.0f */ void lsm6dsv16x_get_data(int16_t *acc_x, int16_t *acc_y, int16_t *acc_z, int16_t *gyro_x, int16_t *gyro_y, int16_t *gyro_z, int16_t *temp); #endif注:加速度、陀螺仪的高性能模式编码都是000,移位<<4后数值完全一致,因此我混着用了
4.2、lsm6dsv16x.c
#include "lsm6dsv16x.h" #include <zephyr/kernel.h> #include <zephyr/device.h> #include <zephyr/drivers/i2c.h> #include <zephyr/logging/log.h> LOG_MODULE_REGISTER(lsm6dsv16x, LOG_LEVEL_DBG); #define I2C_NODE DT_NODELABEL(lsm6dsv16x) static const struct i2c_dt_spec dev_i2c = I2C_DT_SPEC_GET(I2C_NODE); /** * @brief lsm6dsv16x初始化函数 */ void lsm6dsv16x_init(void) { if (!device_is_ready(dev_i2c.bus)) { LOG_ERR("I2C bus %s not ready", dev_i2c.bus->name); return; } uint8_t id = lsm6dsv16x_get_id(); if (id != LSM6DSV16X_WHO_AM_I_VAL) { LOG_ERR("WHO_AM_I mismatch: got 0x%02X, expect 0x%02X", id, LSM6DSV16X_WHO_AM_I_VAL); return; } LOG_INF("WHO_AM_I OK: 0x%02X", id); // 配置总线行为: BDU + IF_INC,必须最先配置 lsm6dsv16x_write(LSM6DSV16X_CTRL3, LSM6DSV16X_CTRL3_BDU | LSM6DSV16X_CTRL3_IF_INC); // 设置陀螺仪量程: 陀螺仪量程 ±500dps lsm6dsv16x_write(LSM6DSV16X_CTRL6, LSM6DSV16X_FS_G_500DPS); // 设置加速度计量程: 加速度计量程 ±8g lsm6dsv16x_write(LSM6DSV16X_CTRL8, LSM6DSV16X_FS_XL_8G); // 启动加速度计: 加速度计 high-performance + 120Hz lsm6dsv16x_write(LSM6DSV16X_CTRL1, LSM6DSV16X_OP_MODE_HIGH_PERF | LSM6DSV16X_ODR_XL_120HZ); // 启动陀螺仪: 陀螺仪 high-performance + 120Hz lsm6dsv16x_write(LSM6DSV16X_CTRL2, LSM6DSV16X_OP_MODE_HIGH_PERF | LSM6DSV16X_ODR_G_120HZ); LOG_INF("lsm6dsv16x init done"); } /** * @brief 指定地址读数据 * @param reg_address 指定的地址 * @return 读出的数据 */ uint8_t lsm6dsv16x_read(uint8_t reg_address) { uint8_t data = 0; int ret = i2c_reg_read_byte_dt(&dev_i2c, reg_address, &data); if (ret != 0) { LOG_ERR("i2c_reg_read_byte_dt failed: %d", ret); return 0; } return data; } /** * @brief 指定地址读数据 * @param reg_address 指定的地址 * @param data 写入的数据 */ void lsm6dsv16x_write(uint8_t reg_address, uint8_t data) { int ret = i2c_reg_write_byte_dt(&dev_i2c, reg_address, data); if (ret != 0) { LOG_ERR("i2c_reg_write_byte_dt failed: %d", ret); } } /** * @brief 获取设备ID */ uint8_t lsm6dsv16x_get_id(void) { return lsm6dsv16x_read(LSM6DSV16X_WHO_AM_I); } /** * @brief 获取数据寄存器的值 * @param acc_x 加速度寄存器x轴数据,LSB = 0.244 mg/LSB(±8g 量程) * @param acc_y 加速度寄存器y轴数据 * @param acc_z 加速度寄存器z轴数据 * @param gyro_x 陀螺仪寄存器x轴数据,LSB = 17.5 mdps/LSB(±500dps 量程) * @param gyro_y 陀螺仪寄存器y轴数据 * @param gyro_z 陀螺仪寄存器z轴数据 * @param temp 温度传感器的数据,°C = raw / 256.0f + 25.0f */ void lsm6dsv16x_get_data(int16_t *acc_x, int16_t *acc_y, int16_t *acc_z, int16_t *gyro_x, int16_t *gyro_y, int16_t *gyro_z, int16_t *temp) { // uint8_t data_high, data_low; // data_high = lsm6dsv16x_read(LSM6DSV16X_ACCEL_XOUT_H); // 读取加速度寄存器X轴的高8位 // data_low = lsm6dsv16x_read(LSM6DSV16X_ACCEL_XOUT_L); // 读取加速度寄存器X轴的低8位 // *acc_x = (data_high << 8) | data_low; // 通过指针返回回去 // data_high = lsm6dsv16x_read(LSM6DSV16X_ACCEL_YOUT_H); // 读取加速度寄存器y轴的高8位 // data_low = lsm6dsv16x_read(LSM6DSV16X_ACCEL_YOUT_L); // 读取加速度寄存器y轴的低8位 // *acc_y = (data_high << 8) | data_low; // 通过指针返回回去 // data_high = lsm6dsv16x_read(LSM6DSV16X_ACCEL_ZOUT_H); // 读取加速度寄存器z轴的高8位 // data_low = lsm6dsv16x_read(LSM6DSV16X_ACCEL_ZOUT_L); // 读取加速度寄存器z轴的低8位 // *acc_z = (data_high << 8) | data_low; // 通过指针返回回去 // data_high = lsm6dsv16x_read(LSM6DSV16X_GYRO_XOUT_H); // 读取陀螺仪寄存器x轴的高8位 // data_low = lsm6dsv16x_read(LSM6DSV16X_GYRO_XOUT_L); // 读取陀螺仪寄存器x轴的低8位 // *gyro_x = (data_high << 8) | data_low; // 通过指针返回回去 // data_high = lsm6dsv16x_read(LSM6DSV16X_GYRO_YOUT_H); // 读取陀螺仪寄存器y轴的高8位 // data_low = lsm6dsv16x_read(LSM6DSV16X_GYRO_YOUT_L); // 读取陀螺仪寄存器y轴的低8位 // *gyro_y = (data_high << 8) | data_low; // 通过指针返回回去 // data_high = lsm6dsv16x_read(LSM6DSV16X_GYRO_ZOUT_H); // 读取陀螺仪寄存器z轴的高8位 // data_low = lsm6dsv16x_read(LSM6DSV16X_GYRO_ZOUT_L); // 读取陀螺仪寄存器z轴的低8位 // *gyro_z = (data_high << 8) | data_low; // 通过指针返回回去 // data_high = lsm6dsv16x_read(LSM6DSV16X_TEMP_OUT_H); // 读温度的高8位 // data_low = lsm6dsv16x_read(LSM6DSV16X_TEMP_OUT_L); // 读温度的低8位 // *temp = (data_high << 8) | data_low; /* * LSM6DSV16X 输出寄存器从 0x20 开始连续排列(IF_INC=1): * [0x20~0x21] TEMP * [0x22~0x27] GYRO XYZ * [0x28~0x2D] ACCEL XYZ * 共 14 字节,一次 burst 读完。 * * 与MPU6050不同,这里是小端(低字节在低地址) */ uint8_t buf[14] = {0}; int ret = i2c_burst_read_dt(&dev_i2c, LSM6DSV16X_TEMP_OUT_L, buf, sizeof(buf)); if (ret != 0) { LOG_ERR("burst read failed: %d", ret); return; } /* 小端拼装 */ *temp = (int16_t)(buf[1] << 8 | buf[0]); /* TEMP */ *gyro_x = (int16_t)(buf[3] << 8 | buf[2]); /* GYRO X */ *gyro_y = (int16_t)(buf[5] << 8 | buf[4]); /* GYRO Y */ *gyro_z = (int16_t)(buf[7] << 8 | buf[6]); /* GYRO Z */ *acc_x = (int16_t)(buf[9] << 8 | buf[8]); /* ACC X */ *acc_y = (int16_t)(buf[11] << 8 | buf[10]); /* ACC Y */ *acc_z = (int16_t)(buf[13] << 8 | buf[12]); /* ACC Z */ }4.3、设备树
&i2c21 { status = "okay"; clock-frequency = <I2C_BITRATE_STANDARD>; // 100kHz pinctrl-0 = <&i2c21_default>; pinctrl-1 = <&i2c21_sleep>; pinctrl-names = "default", "sleep"; zephyr,concat-buf-size = <257>; lsm6dsv16x: lsm6dsv16x@6a { compatible = "st,lsm6dsv16x", "i2c_device"; reg = <0x6a>; status = "okay"; }; }; &pinctrl { // iic21 i2c21_default: i2c21_default { group1 { // 按实际接线修改 psels = <NRF_PSEL(TWIM_SCL, x, y)>, <NRF_PSEL(TWIM_SDA, x, y)>; bias-pull-up; nordic,drive-mode = <NRF_DRIVE_S0D1>; }; }; i2c21_sleep: i2c21_sleep { group1 { // 按实际接线修改 psels = <NRF_PSEL(TWIM_SCL, x, y)>, <NRF_PSEL(TWIM_SDA, x, y)>; low-power-enable; }; }; };4.4、main.c
#include <zephyr/kernel.h> #include <zephyr/drivers/spi.h> #include <zephyr/devicetree.h> #include "lsm6dsv16x.h" #include <zephyr/logging/log.h> void test02() { lsm6dsv16x_init(); uint8_t device_id = lsm6dsv16x_get_id(); LOG_INF("MPU6050's device is = 0x%02x\n", device_id); int16_t acc_x, acc_y, acc_z, gyro_x, gyro_y, gyro_z, temp; // 1. 读取原始数据 lsm6dsv16x_get_data(&acc_x, &acc_y, &acc_z, &gyro_x, &gyro_y, &gyro_z, &temp); LOG_INF("acc: x = %d, y = %d, z = %d | gyro: x = %d, y = %d, z = %d | temp = %d\n", acc_x, acc_y, acc_z, gyro_x, gyro_y, gyro_z, temp); } int main(void) { while (1) { test02(); k_msleep(1000); LOG_INF("running - test ver 1.0"); } return 0; }