??在《 智能魔法棒-硬件 》介绍了魔棒的硬件方案和结构设计,然后介绍了嵌入式软件设计方案。 ??注:本文涉及相关 MPU6050 感兴趣的学生可以通过目录快速定位相关内容参考使用方法、姿态解决方法、卡尔曼滤波建模和公式推导过程。
1 环境搭建
1.1 产品创建
??在开发魔法棒的固件之前,我们需要先做 涂鸦IoT平台 创建智能产品,不熟悉产品创建的学生可以通过涂鸦开发者平台的文档中心了解更多信息,点击快速介绍。
??魔法棒产品可以选择【找不到品类】进行自定义创建。本 Demo 涂鸦的选择 Bluetooth LE 模组 TYBN1.芯片平台是 nRF52832 。因此,通信协议的选择是蓝牙,云接入是【TuyaOS】,云接入硬件为【Nordic nRF52832】。当然也可以选择其他模块,可以参考 涂鸦云模块规格书 进行选型。比如选择了 BP3L 然后在硬件开发页面选择云接入硬件时选择模块【BP3L 模块。
??为了实现云接收魔法棒识别结果的目的,需要在功能定义页面上定制一个DP点,参数如下:
DP ID | 功能点名称 | 标识符 | 数据传输类型 | 数据类型 | 功能点属性 |
---|---|---|---|---|---|
101 | 手势 | gesture | 只上报 (ro) | 枚举型 (Enum) | 枚举值:none,ges1,ges2 … |
1.2 SDK 获取
??涂鸦提供了适用于涂鸦云模组各个芯片平台的 SDK,可用于魔法棒产品 找到页面左下角的最新版本 SDK 。
??下载后请先查看 SDK 中的 README_zh-CN.md
文件!以 nRF52832 以平台为例,文件中提示需要下载原厂 nRF5 SDK 15.3.0 文件。选择 版本, 选版介绍涉及 的即可,最后点击 。原厂 SDK 下载解压后,涂鸦需要 SDK 文件 tuya-ble-sdk-demo-project-nrf52832
拷贝到 nRF5_SDK_15.3.0_59ac345\examples\ble_peripheral
目录下 SDK 提供了各种 API 为帮助开发者快速实现产品功能,请参考开发指南 蓝牙 SDK 开发。
1.3 IDE 准备
??nRF52832 平台使用的 IDE 是 MDK-ARM Keil μVision ,未安装的学生可到官网下载。安装好了 IDE 之后,双击涂鸦 SDK 工程文件ble_app_uart_pca10040_s132.uvprojx
,软件包打开时会自动安装。如果安装失败,可以在 中找到 nRF52832 安装芯片对应的软件包,如下图所示:
1.4 烧录授权
??涂鸦云模组可以在【硬件开发】页面购买。需要先【新增自定义固件】(开发前可以使用 SDK Demo 默认固件),然后点击右侧立即购买 进入 购买过程。涂鸦提供多种烧录授权方法,可根据不同的开发阶段、芯片类型和生产方法进行选择,点击详细信息 授权固件烧录。(BN 烧录授权系列模块,PHY6222芯片烧录授权)
??如果有模块或开发板,只能购买授权代码。可通过左导航栏 中进入 页面,选择 购买。新用户也可以免费获得。 2 个授权码:
??调试阶段可选择交付形式 【授权码清单】提交订单后即可获得 Excel 授权码清单的形式包括 、 和 。如果交付形式为生产凭证或生产凭证-仅授权,则需要通过 授权方法参考前文 中的链接。
??如果交付形式是【授权码清单】,则需要将产品交付 ID (PID) 和授权码 (选取 1 组) 填入 tuya_ble_sdk_demo.h
文件的下列位置:
#define TY_DEVICE_NAME "demo" #define TY_DEVICE_PID "xxxxxxxx" /* PID */ #define TY_DEVICE_MAC "xxxxxxxx" /* mac */ #define TY_DEVICE_DID "xxxxxxxx" /* uuid */ #define TY_DEVICE_AUTH_KEY "xxxxxxxx" /* authkey */
??还需要 tuya_ble_sdk_demo.c
初始化参数将在文件中进行 use_ext_license_key
和device_id_len
将值分别修改为 1 和 为使授权码生效:
static tuya_ble_device_param_t tuya_ble_device_param = {
.use_ext_license_key = 1, // 1-info in tuya_ble_sdk_demo.h, 0-auth info
.device_id_len = 16, // DEVICE_ID_LEN,
.p_type = TUYA_BLE_PRODUCT_ID_TYPE_PID,
.product_id_len = 8,
.adv_local_name_len = 4,
.firmware_version = TY_DEVICE_FVER_NUM,
.hardware_version = TY_DEVICE_HVER_NUM,
};
编译通过后,将 J-Link 烧录器连接到开发板,连线方式如下:
模组引脚 | J-Link 引脚 |
---|---|
3.3V | VCC |
GND | GND |
SWDIO | SWDIO |
SWC | SWCLK |
在 Demo 固件下载前,必须先下载协议栈固件(同一块模组只需操作 1 次)。在 J-Link 官网下载 J-Link 软件开发包。安装完成后,打开 软件,点击 创建工程,芯片选择 nRF52832_xxAA 后点击 OK,如下图所示:
点击 打开涂鸦 SDK \pca10040\s132\arm5_no_packs\hex\material
目录下的 s132_nrf52_6.1.1_softdevice.hex
文件,如下图所示:
点击 连接芯片,成功连接后点击 开始下载,下载完成后点击 断开连接。Demo 固件可以直接通过 进行下载。
1.5 日志查看
开发过程中可以通过查看日志来进行功能调试,日志功能默认关闭,开启需对代码作如下修改:
#define TUYA_APP_LOG_ENABLE 1 /* 位于custom_tuya_ble_config.h文件中,0-关闭,1-开启 */
#define TY_LOG_ENABLE 1 /* 位于board.h文件,0-关闭,1-开启 */
将修改后的固件编译并烧录至开发板,然后打开 软件,会自动弹出以下对话框:
按上图内容完成设置后,点击 OK。成功连接就可以看到设备日志了,软件日志窗口也会出现如下提示:
2 固件设计
2.1 功能定义
魔法棒要实现的功能定义如下:
功能 | 说明 |
---|---|
手势动作识别 | 可识别出下列手势动作:- 手势动作 1:向上甩动;- 手势动作 2:向下甩动;- 手势动作 3:向左甩动;- 手势动作 4:向右甩动;- 手势动作 5:顺时针翻转;- 手势动作 6:逆时针翻转;… |
识别功能开关 | 可通过按键控制识别功能打开或关闭:- 按键按下时,手势识别功能打开;- 按键释放时,手势识别功能关闭。 |
手势数据上报 | 可将手势数据上报至云端,以实现手势动作对其他设备的控制。 |
配网状态重置 | 可通过配网键实现设备端解绑:- 长按配网键3秒,设备主动解绑。 |
配网等待时限 | 可在等待配网超过1分钟后结束等待,禁止用户绑定设别:- 上电时设备状态为未绑定或通过配网键重置时,设备进入配网等待;- 1分钟后仍未被绑定,则结束等待。 |
配网状态指示 | 可通过指示灯提示设备状态:- 等待配网时,指示灯快闪;- 配网结束时,指示灯关闭。 |
手电筒功能 | 可通过配网键短按切换指示灯开/关。 |
2.2 软件方案
1)模块划分
魔法棒的核心功能是识别不同的手势动作,从而达到通过涂鸦云平台控制其他设备的目的。这次硬件方案采取了 MPU6050 六轴惯性传感器来采集手势数据,包括 和 ,由此可计算出设备的,也可以通过内置的数字运动处理器 (DMP) 获取来计算姿态。结合这些数据对进行提取,就可以实现特定手势识别。根据魔法棒的硬件方案和功能定义,可以将 Demo 程序划分为以下 5 个模块:
模块 | 处理内容 |
---|---|
数据采集模块 | MPU6050 传感器的数据采集处理 |
姿态解算模块 | 根据角速度、加速度计算姿态角,并用卡尔曼滤波法进行数据融合处理 |
手势识别模块 | 应用采集到的数据和姿态解算结果,实现各个手势动作识别 |
联网处理模块 | 设备配网与解绑、配网状态指示、手势数据上报等 |
其他功能模块 | 手电筒功能、低功耗处理等 |
各模块的具体方案将在 中进行介绍。
2)软件框图
结合涂鸦 Bluetooth LE SDK 的软件架构和应用功能设计,魔法棒的软件框图如下:
3)软件流程
魔法棒的基本工作流程如下:
4)文件结构
应用入口:tuya_ble_sdk_demo.c -> tuya_gesture_controller.c
├── include
| ├── common
| | └── tuya_common.h /* 通用类型和宏定义 */
| ├── driver
| | ├── tuya_key.h /* 按键驱动 */
| | ├── tuya_led.h /* LED驱动 */
| | └── tuya_mpu6050.h /* MPU6050驱动 */
| ├── platform
| | ├── tuya_gpio.h /* 平台关联GPIO驱动 */
| | └── tuya_pwr_mgmt.h /* 平台关联低功耗模式处理 */
| ├── sdk
| | ├── tuya_ble_bulk_data_demo.h /* 大数据通道例程 */
| | ├── tuya_ble_product_test_demo.h /* 整机产测例程 */
| | └── tuya_ble_sdk_test.h /* 实现tuya_ble_sdk测试的串口指令 */
| ├── tuya_ble_sdk_demo.h /* 实现tuya_ble_sdk的初始化,应用程序入口 */
| ├── tuya_imu_daq.h /* 传感数据采集 */
| ├── tuya_gesture_controller.h /* 手势控制器管理中心 */
| ├── tuya_gesture_rec.h /* 手势动作识别 */
| ├── tuya_net_proc.h /* 设备联网处理 */
| └── tuya_svc_angle_calc.h /* 姿态解算服务 */
└── src
├── driver
| ├── tuya_key.c /* 按键驱动 */
| ├── tuya_led.c /* LED驱动 */
| └── tuya_mpu6050.c /* MPU6050驱动 */
├── platform
| ├── tuya_gpio_nRF52832.c /* nRF52832平台关联GPIO驱动 */
| └── tuya_pwr_mgmt_nRF52832.c /* nRF52832平台关联低功耗模式处理 */
├── sdk
| ├── tuya_ble_bulk_data_demo.c /* 大数据通道例程 */
| ├── tuya_ble_product_test_demo.c /* 整机产测例程 */
| └── tuya_ble_sdk_test.c /* SDK测试程序 */
├── tuya_ble_sdk_demo.c /* 实现tuya_ble_sdk的初始化,应用程序入口 */
├── tuya_gesture_controller.c /* 手势控制器管理中心 */
├── tuya_imu_daq.c /* 传感数据采集 */
├── tuya_gesture_rec.c /* 手势动作识别 */
├── tuya_net_proc.c /* 设备联网处理 */
└── tuya_svc_angle_calc.c /* 姿态解算服务 */
可将以上代码放至 SDK 的 tuya_ble_sdk_demo\app
目录下。如果使用的不是 nRF52832 芯片,需要对芯片平台相关的驱动部分进行移植。其中,platform
文件夹存放的是平台关联组件,目的是实现应用代码与芯片平台解耦,方便程序在不同芯片平台之间移植,也可以删除这些文件,在 tuya_key.c
、tuya_mpu6050.c
等文件中直接修改外设驱动相关的代码。
3 功能开发
下面详细介绍魔法棒各项功能的实现过程。Demo 仓库:tuya-iotos-embeded-demo-ble-gesture-controller
3.1 数据采集模块
这次开发采用的惯性测量单元是 MPU6050,其主要功能已经在硬件设计方案中进行了介绍。数据采集模块的目标是:通过 I2C 接口从 MPU6050 中读取设备的加速度数据和角速度数据。
1)I2C 通信
我们先来解决通信问题,在 MPU6050 产品规格书 的 9.2~9.4 节可以找到关于 I2C 的介绍。
MPU6050 的 7 位从机地址由 AD0 引脚决定,当 AD0 = 0 时,从机地址为 0x68;AD0 = 1 时,从机地址为 0x69。我们采用的方案是 AD0 接地,所以从机地址为 。
我们可以在产品规格书的 9.3 节找到关于 MPU6050 的寄存器读写时序的描述,包括单字节读写和多字节读写。其中,命令字节由从机地址 (bit[7:1]) 和读/写命令 (bit0) 组成,写命令为 0,读命令为 1。
涂鸦SDK提供了一些有关 I2C 通信的函数接口,需要包含 ty_i2c.h
文件。我们使用软件 I2C 来实现,编写寄存器读写函数:
#include "tuya_mpu6050.h"
#include "ty_i2c.h"
/* slave address */
#define MPU6050_DEV_ADDR_AD0_LOW 0x68
#define MPU6050_DEV_ADDR_AD0_HIGH 0x69
#define MPU6050_DEV_ADDR MPU6050_DEV_ADDR_AD0_LOW
/* I2C R/W command */
#define I2C_CMD_WRITE 0
#define I2C_CMD_READ 1
#define MPU6050_ADDR_CMD_WRITE ((MPU6050_DEV_ADDR << 1) | I2C_CMD_WRITE)
#define MPU6050_ADDR_CMD_READ ((MPU6050_DEV_ADDR << 1) | I2C_CMD_READ)
/** * @brief read data of MPU6050 * @param[in] reg_addr: register address * @param[in] len: data length * @param[out] data: data buffer * @return none */
STATIC VOID_T __mpu6050_read_data(_IN UCHAR_T reg_addr, _IN CONST UCHAR_T len, _OUT UCHAR_T *data)
{
i2c_start();
i2c_send_bytes(MPU6050_ADDR_CMD_WRITE, ®_addr, 1);
i2c_start();
i2c_rcv_bytes(MPU6050_ADDR_CMD_READ, data, len);
i2c_stop();
}
/** * @brief read register of MPU6050 * @param[in] reg_addr: register address * @return register value */
STATIC UCHAR_T __mpu6050_read_register(_IN UCHAR_T reg_addr)
{
UCHAR_T reg_val;
i2c_start();
i2c_send_bytes(MPU6050_ADDR_CMD_WRITE, ®_addr, 1);
i2c_start();
i2c_rcv_bytes(MPU6050_ADDR_CMD_READ, ®_val, 1);
i2c_stop();
return reg_val;
}
/** * @brief write register of MPU6050 * @param[in] reg_addr: register address * @param[in] reg_val: value to be written * @return none */
STATIC VOID_T __mpu6050_write_register(_IN CONST UCHAR_T reg_addr, _IN UCHAR_T reg_val)
{
i2c_soft_cfg(MPU6050_ADDR_CMD_WRITE, reg_addr, reg_val);
}
/** * @brief write register of MPU6050 * @param[in] reg_addr: register address * @param[in] data: data to be written * @param[in] valid_bit: the code of valid bits * @return none */
STATIC VOID_T __mpu6050_write_register_bit(_IN CONST UCHAR_T reg_addr, _IN CONST UCHAR_T data, _IN CONST UCHAR_T valid_bit)
{
UCHAR_T reg_val;
if (valid_bit == 0xFF) {
reg_val = data;
} else {
reg_val = __mpu6050_read_register(reg_addr);
reg_val = (reg_val & (~valid_bit)) | (data & valid_bit);
}
i2c_soft_cfg(MPU6050_ADDR_CMD_WRITE, reg_addr, reg_val);
}
此外,还需要确认配置的 I2C 引脚是否符合硬件设计,在ty_i2c_nRF52832.c
中修改:
#define TY_I2C_PIN_SCL 14
#define TY_I2C_PIN_SDA 11
2)传感器初始化
MPU6050 初始化的基本步骤和需要配置的寄存器如下表所示:
No. | 步骤 | 操作方法 |
---|---|---|
1 | 初始化 I2C 接口 | 软件 I2C:初始化 SCL 和 SDA 引脚; |
2 | 复位设备 | 设置寄存器 PWR_MGMT_1 的 bit7,复位后需至少100ms,否则初始化不成功; |
3 | 检查设备连接 | 读取寄存器 WHO_AM_I 进行校验,0x68 表示已连接; |
4 | 解除休眠 | 设置寄存器 PWR_MGMT_1 的 bit6,,即休眠模式; |
5 | 选择时钟源 | 设置寄存器 PWR_MGMT_1 的 bit2:0,一般选择陀螺仪某一轴的时钟源,以保证数据精度; |
6 | 设置陀螺仪满量程范围 | 设置寄存器 GYRO_CONFIG 的 bit4:3,4种可选; |
7 | 设置加速度计满量程范围 | 设置寄存器 ACCEL_CONFIG 的 bit4:3,4种可选; |
8 | 设置陀螺仪输出分频 | 设置寄存器 SMPRT_DIV; |
9 | 设置数字低通滤波器 | 设置寄存器 CONFIG 的 bit2:0; |
10 | 启用数据就绪中断 | 设置寄存器 INT_PIN_CFG 的 bit7:4 和寄存器 INT_ENABLE 的 bit0。 |
下面对初始化涉及到的寄存器做简单说明,也可以直接查看 MPU6050 寄存器手册,用上表中的寄存器名称进行搜索即可。注:括号内表示寄存器地址、寄存器名称、可读写情况和初值;省略的位为保留位,始终为 0。
>> (0x6B,PWR_MGMT_1,R/W,0x40)
Bit | 标识符 | 说明 |
---|---|---|
7 | DEVICE_RESET | 设备复位。0:复位完成;1:将所有内部寄存器重置为其默认值,复位完成后,该位自动清除为0。 |
6 | SLEEP | 睡眠模式设置。0:设备正常工作;1:进入低功耗睡眠模式。 |
5 | CYCLE | 循环模式设置。0:禁用循环模式;1:SLEEP=0时,MPU-60X0将进入循环模式,设备在睡眠和唤醒之间循环。 |
3 | TEMP_DIS | 温度传感器设置。0:启用温度传感器;1:禁用温度传感器。 |
2:0 | CLKSEL[2:0] | 系统时钟源选择。000:内部 8M RC 晶振;001:PLL,使用X轴陀螺仪作为参考;010:PLL,使用Y轴陀螺仪作为参考;011:PLL,使用Z轴陀螺仪作为参考;100:PLL,使用外部 32.768kHz 作为参考;101:PLL,使用外部 19.2MHz 作为参考;110:保留;111:关闭时钟,保持时序产生电路复位状态。 |
>> (0x75,WHO_AM_I,R,0x68)
Bit | 标识符 | 说明 |
---|---|---|
6:1 | WHO_AM_I[6:1] | 设备地址高 6 位,默认为 0x68。 |
>> (0x1B,GYRO_CONFIG,R/W,0x00)
Bit | 标识符 | 说明 |
---|---|---|
7:5 | XYZG_ST | 陀螺仪 X/Y/Z 轴自检控制。0:关闭自检;1:激活自检。 |
4:3 | FS_SEL[1:0] | 陀螺仪满量程范围设置。00:±250°/s;01:±500°/s;10:±1000°/s;11:±2000°/s。 |
>> (0x1C,ACCEL_CONFIG,R/W,0x00)
Bit | 标识符 | 说明 |
---|---|---|
7:5 | XYZA_ST | 加速度 X/Y/Z 轴自检控制。0:关闭自检;1:激活自检。 |
4:3 | AFS_SEL[1:0] | 加速度计满量程范围设置。00:±2g;01:±4g;10:±8g;11:±16g。 |
>> (0x19,SMPRT_DIV,R/W,0x00)
Bit | 标识符 | 说明 |
---|---|---|
7:0 | SMPLRT_DIV[7:0] | 陀螺仪输出速率分频设置。- 采样率 = 陀螺仪输出速率 / (1 + SMPLRT_DIV);- 禁用 DLPF (DLPF_CFG=0或7) 时,陀螺仪输出速率为 8kHz;- 启用 DLPF 时,陀螺仪输出速率为 1kHz。 |
>> (0x1A,CONFIG,R/W,0x00)
Bit | 标识符 | 说明 |
---|---|---|
5:3 | EXT_SYNC_SET[2:0] | 外部帧同步 (FSYNC) 引脚采样设置。 |
2:0 | DLPF_CFG[2:0] | 数字低通滤波器 (DLPF) 设置。 |
>> (0x37,INT_PIN_CFG,R/W,0x00)
Bit | 标识符 | 说明 |
---|---|---|
7 | INT_LEVEL | INT 引脚中断电平设置。0:高电平有效;1:低电平有效。 |
6 | INT_OPEN | INT 引脚输出模式设置。0:推挽输出;1:开漏输出。 |
5 | LATCH_INT_EN | 中断保持方式设置。0:产生 50us 脉冲;1:保持高电平直到中断清除。 |
4 | INT_RD_CLEAR | 中断状态清除方式设置。0:仅通过读取 INT_STATUS 来清除中断状态位;1:通过任何读操作清除中断状态位。 |
3 | FSYNC_INT_LEVEL | FSYNC 引脚中断电平设置。0:高电平有效;1:低电平有效。 |
2 | FSYNC_INT_EN | FSYNC 引脚中断功能设置。0:禁止 FSYNC 引脚作为主处理器的中断引脚;1:允许 FSYNC 引脚作为主处理器的中断引脚。 |
1 | I2C_BYPASS_EN | 辅助 I2C 总线访问权限设置。0:禁止主处理器直接访问辅助 I2C 总线;1:I2C_MST_EN = 0 时,允许主处理器直接访问辅助 I2C 总线。 |
>> (0x38,INT_ENABLE,R/W,0x00)
Bit | 标识符 | 说明 |
---|---|---|
6 | MOT_EN | 运动中断设置。0:禁用中断;1:启用中断。 |
4 | FIFO_OFLOW_EN | FIFO缓存区溢出中断设置。0:禁用中断;1:启用中断。 |
3 | I2C_MST_INT_EN | I2C主机中断设置。0:禁用中断;1:启用中断。 |
0 | DATA_RDY_EN | 数据就绪中断设置。0:禁用中断;1:启用中断。 |
#include "tuya_mpu6050.h" #include "ty_i2c.h" /* register map */ #define MPU6050_RA_SMPRT_DIV 0x19 #define MPU6050_RA_CONFIG 0x1A #define MPU6050_RA_GYRO_CONFIG 0x1B #define MPU6050_RA_ACCEL_CONFIG 0x1C #define MPU6050_RA_INT_PIN_CFG 0x37 #define MPU6050_RA_INT_ENABLE 0x38 #define MPU6050_RA_PWR_MGMT_1 0x6B #define MPU6050_RA_WHO_AM_I 0x75 /* MPU6050 Gyro full-scale range */ typedef BYTE_T MPU_GYRO_FSR_E; #define MPU_GYRO_FS_250 0x00 /* 250dps */ #define MPU_GYRO_FS_500 0x01 /* 500dps */ #define MPU_GYRO_FS_1000 0x02 /* 1000dps */ #define MPU_GYRO_FS_2000 0x03 /* 2000dps */ /* MPU6050 Accel full-scale range */ typedef BYTE_T MPU_ACCEL_FSR_E; #define MPU_ACCEL_FS_2 0x00 /* 2g */ #define MPU_ACCEL_FS_4 0x01 /* 4g */ #define MPU_ACCEL_FS_8 0x02 /* 8g */ #define MPU_ACCEL_FS_16 0x03 /* 16g */ STATIC FLOAT_T sg_gyro_sens = 0.0f; STATIC USHORT_T sg_accel_sens = 0; /** * @brief reset MPU6050 * @param[in] none * @return none */ STATIC VOID_T __mpu6050_reset(VOID_T) { __mpu6050_write_register_bit(MPU6050_RA_PWR_MGMT_1, MPU_RA_BIT_DEVICE_RESET, MPU_RA_BIT_DEVICE_RESET); tuya_ble_device_delay_ms(100); } /** * @brief get the identity of the device (default: 0x68) * @param[in] none * @return device id */ STATIC UCHAR_T __mpu6050_get_device_id(VOID_T) { return __mpu6050_read_register(MPU6050_RA_WHO_AM_I); } /** * @brief check if MPU6050 is connected * @param[in] none * @return TRUE - connected, FALSE - unconnected */ STATIC BOOL_T __mpu6050_is_connected(VOID_T) { if (__mpu6050_get_device_id() == MPU6050_DEV_ID) { return TRUE; } else { return FALSE; } } /** * @brief enable or disable sleep mode * @param[in] enabled: TRUE - sleep, FALSE - work * @return none */ STATIC VOID_T __mpu6050_set_sleep_mode(_IN CONST BOOL_T enabled) { if (enabled) { __mpu6050_write_register_bit(MPU6050_RA_PWR_MGMT_1, MPU_RA_BIT_SLEEP, MPU_RA_BIT_SLEEP); } else { __mpu6050_write_register_bit(MPU6050_RA_PWR_MGMT_1, ~MPU_RA_BIT_SLEEP, MPU_RA_BIT_SLEEP); } } /** * @brief enable or disable sleep mode * @param[in] enabled: TRUE - sleep, FALSE - work * @return none */ VOID_T tuya_mpu6050_set_sleep_mode(_IN CONST BOOL_T enabled) { __mpu6050_set_sleep_mode(enabled); } /** * @brief set clock source * @param[in] src: clock source * @return none */ STATIC VOID_T __mpu6050_set_clk_src(UCHAR_T src) { __mpu6050_write_register_bit(MPU6050_RA_PWR_MGMT_1, src, MPU_RA_BIT_CLKSEL); } /** * @brief set gyroscope's full-scale range * @param[in] range: gyroscope's full-scale range value * @return none */ STATIC VOID_T __mpu6050_set_gyro_fsr(_IN CONST MPU_GYRO_FSR_E range) { __mpu6050_write_register_bit(MPU6050_RA_GYRO_CONFIG, range<<3, MPU_RA_BIT_FS_SEL); } /** * @brief set accelerometer's full-scale range * @param[in] range: new full-scale accelerometer range value * @return none */ STATIC VOID_T __mpu6050_set_accel_fsr(_IN CONST MPU_ACCEL_FSR_E range) { __mpu6050_write_register_bit(MPU6050_RA_ACCEL_CONFIG, range<<3, MPU_RA_BIT_AFS_SEL); } /** * @brief set MPU6050's sample rate * @param[in] sr: sample rate gyroscope output rate divider value * @return none */ STATIC VOID_T __mpu6050_set_sample_rate(_IN USHORT_T sr) { UCHAR_T div; if (sr > MPU_GYRO_OUTPUT_RATE) { sr = MPU_GYRO_OUTPUT_RATE; } if (sr < (MPU_GYRO_OUTPUT_RATE/MPU_SMPRT_DIV_MAX)) { sr = (MPU_GYRO_OUTPUT_RATE/MPU_SMPRT_DIV_MAX); } div = MPU_GYRO_OUTPUT_RATE / sr - 1; __mpu6050_write_register(MPU6050_RA_SMPRT_DIV, div); } /** * @brief set MPU6050's DLPF * @param[in] bw: baud width * @return none */ STATIC VOID_T __mpu6050_set_dlpf(_IN CONST USHORT_T bw) { UCHAR_T cfg = 0; if (bw >= MPU_DLPF_BW_CFG_1) { cfg = 1; } else if (bw >= MPU_DLPF_BW_CFG_2) { cfg = 2; } else if (bw >= MPU_DLPF_BW_CFG_3) { cfg = 3; } else if (bw >= MPU_DLPF_BW_CFG_4) { cfg = 4; } else if (bw >= MPU_DLPF_BW_CFG_5) { cfg = 5; } else { cfg = 6; } __mpu6050_write_register(MPU6050_RA_CONFIG, cfg); } /** * @brief set intterupt * @param[in] active_low: TRUE - active low, FALSE - active high * @return none */ STATIC VOID_T __mpu6050_set_int(BOOL_T active_low) { UCHAR_T reg_value = 0; if (active_low) { __mpu6050_write_register(MPU6050_RA_INT_PIN_CFG, 0x90); } else { __mpu6050_write_register(MPU6050_RA_INT_PIN_CFG, 0x50); } __mpu6050_write_register(MPU6050_RA_INT_ENABLE, 0x01); } /** * @brief MPU6050 sensor driver init * @param[in] clk: clock source * @param[in] g_fsr: gyroscope's full-scale range * @param[in] a_fsr: accelerometer's full-scale range * @param[in] smp_rt: sample rate * @param[in] pin: interrupt pin * @param[in] type: interrupt type * @param[in] int_cb: interrupt callback function * @return operation result */ MPU_RET tuya_mpu6050_init(_IN CONST MPU_CLK_E clk, _IN CONST MPU_GYRO_FSR_E g_fsr, _IN CONST MPU_ACCEL_FSR_E a_fsr, _IN CONST USHORT_T smp_rt, _IN CONST TY_GPIO_PORT_E pin, _IN CONST TY_GPIO_IRQ_TYPE_E type, _IN TY_GPIO_IRQ_CB int_cb) { /* I2C init */ i2c_soft_gpio_init(); /* reset MPU6050 */ __mpu6050_reset(); /* check communication */ if (!__mpu6050_is_connected()) { return MPU_ERR_UNCONN 标签:
力传感器bk2300bk温度传感器bk电源连接器omega温度传感器os3271m三轴磁场传感器模块gy连接器继电器开关rps2p21