【Zephyr开发实践系列】02_MPU6050极简驱动设计(轮询模式)

文章目录

  • 前言
  • 一、MPU6050驱动模型
      • 1.1 核心应用API(必须)
      • 1.2 设置数据结构
      • 1.3 硬件初始化
      • 1.4 设备实例化
  • 二、数据结构定义
      • 2.1 寄存器相关配置
      • 2.2 陀螺仪灵敏度值
      • 2.2 数据结构Data
      • 配置结构
  • 三、核心功能实现
      • 3.1 原数据解算
      • 3.2 通道数据获取
      • 3.3 采样数据获取
      • 3.4 初始化
  • 总结


前言

在传统嵌入式传感器开发中,裸机驱动往往需要数百行初始化代码,而复杂的RTOS驱动又面临框架学习成本高的问题。Zephyr RTOS的传感器框架给出了三重设计方案:

  • 设备树(DTS)自动管理硬件资源,消除i2c_configure()等样板代码
  • 物理量转换标准化,通过sensor_value统一处理浮点数据
  • 驱动-应用解耦,sample_fetch+channel_get双阶段操作简化流程
    本文针对滤除中断触发,针对轮询模式,详解MPU6050驱动。

一、MPU6050驱动模型

驱动模型包括以下几个要点:

1.1 核心应用API(必须)

  • sample_fetch:触发传感器数据采集(同步读取加速度/陀螺仪/温度原始值)
  • channel_get:将原始数据转换为标准物理量(m/s²、rad/s、℃)
  • init:设备初始化与配置(含自检流程)

1.2 设置数据结构

  • 配置寄存器(加速度,陀螺仪,温度,使能等)
  • 配置数据结构体data
  • 配置灵敏度等参数结构体config

1.3 硬件初始化

  • 检查I2C控制器是否就绪(device_is_ready)
  • 读取WHO_AM_I寄存器验证设备型号(MPU6050/MPU6500)
  • 唤醒设备(清除PWR_MGMT1睡眠位)
  • 设置加速度计/陀螺仪量程(ACCEL_CONFIG/GYRO_CONFIG寄存器)
  • 计算并存储灵敏度系数(根据量程选择)

1.4 设备实例化

  • 配置结构初始化: 从设备树提取基本配置
  • 设备注册宏: 使用DEVICE_DT_INST_DEFINE注册设备
  • 初始化优先级: 设置为POST_KERNEL

二、数据结构定义

2.1 寄存器相关配置

#define MPU6050_REG_CHIP_ID    0x75  // 芯片ID寄存器地址
#define MPU6050_REG_SMPLRT_DIV    0x19  // 采样率分频寄存器
#define MPU6050_REG_GYRO_CFG      0x1B  // 陀螺仪配置寄存器
#define MPU6050_GYRO_FS_SHIFT     3     // 陀螺仪量程位移
#define MPU6050_REG_ACCEL_CFG     0x1C  // 加速度计配置寄存器
#define MPU6050_ACCEL_FS_SHIFT    3     // 加速度计量程位移
#define MPU6050_REG_INT_EN        0x38  // 中断使能寄存器
#define MPU6050_DRDY_EN           BIT(0)// 数据就绪中断使能位
#define MPU6050_REG_DATA_START    0x3B  // 数据寄存器起始地址
#define MPU6050_REG_PWR_MGMT1     0x6B  // 电源管理1寄存器
#define MPU6050_SLEEP_EN          BIT(6)// 睡眠模式使能位

2.2 陀螺仪灵敏度值

static const uint16_t mpu6050_gyro_sensitivity_x10[] = {
    1310, 655, 328, 164  // 对应±250, ±500, ±1000, ±2000 °/s的灵敏度值×10
};

2.2 数据结构Data

struct mpu6050_data {
    - accel_x/y/z;               // 三轴加速度原始值
    - accel_sensitivity_shift;   // 加速度计灵敏度位移
    - temp;                      // 温度值
    - gyro_x/y/z;               // 三轴陀螺仪原始值
    - gyro_sensitivity_x10;     // 陀螺仪灵敏度×10
};

配置结构

struct mpu6050_config {
    struct i2c_dt_spec i2c;    // I2C设备树规格
    uint8_t accel_fs;          // 加速度计满量程
    uint16_t gyro_fs;          // 陀螺仪满量程  
    uint8_t smplrt_div;        // 采样率分频值
    struct gpio_dt_spec int_gpio; // 中断GPIO规格
};

三、核心功能实现

3.1 原数据解算

说明:

  • 加速度:mpu6050_convert_accel
  • 陀螺仪:mpu6050_convert_gyro
  • 温度:mpu6050_convert_temp
  • 解算方式请参考技术手册
// 加速度转换 (单位:m/s²)
void mpu6050_convert_accel(...)
{
    int64_t conv_val = ((int64_t)raw_val * SENSOR_G) 
                      >> sensitivity_shift;
    val->val1 = conv_val / 1000000;  // 整数部分
    val->val2 = conv_val % 1000000;  // 小数部分
}

// 陀螺仪转换 (单位:rad/s)
void mpu6050_convert_gyro(...)
{
    int64_t conv_val = ((int64_t)raw_val * SENSOR_PI * 10)
                      / (sensitivity_x10 * 180U);
}

//温度解算
static inline void mpu6050_convert_temp(enum mpu6050_device_type device_type,
                                       struct sensor_value *val, int16_t raw_val)
{
    -----
}

3.2 通道数据获取

说明:

  • 可以根据陀螺仪型号定义相关数据
static int mpu6050_channel_get(const struct device *dev,
                              enum sensor_channel chan,
                              struct sensor_value *val)
{
    struct mpu6050_data *drv_data = dev->data;  // 获取驱动数据
    
    switch (chan) {
    case SENSOR_CHAN_ACCEL_XYZ:         // 三轴加速度
        mpu6050_convert_accel(val, drv_data->accel_x, ...);      // X轴
        mpu6050_convert_accel(val + 1, drv_data->accel_y, ...);  // Y轴  
        mpu6050_convert_accel(val + 2, drv_data->accel_z, ...);  // Z轴
        break;
    case SENSOR_CHAN_ACCEL_X:           // 单轴加速度X/Y/Z
    // ... 类似处理
    case SENSOR_CHAN_GYRO_XYZ:          // 三轴陀螺仪
        mpu6050_convert_gyro(val, drv_data->gyro_x, ...);        // X轴
        mpu6050_convert_gyro(val + 1, drv_data->gyro_y, ...);    // Y轴
        mpu6050_convert_gyro(val + 2, drv_data->gyro_z, ...);    // Z轴
        break;
    // ... 单轴陀螺仪处理
    case SENSOR_CHAN_DIE_TEMP:          // 芯片温度
        mpu6050_convert_temp(drv_data->device_type, val, drv_data->temp);
        break;
    default:
        return -ENOTSUP;                // 不支持的通道
    }
    
    return 0;
}

3.3 采样数据获取

说明:

  • 根据寄存器顺序配置,易错乱
if (i2c_burst_read_dt(&cfg->i2c, MPU6050_REG_DATA_START, (uint8_t *)buf,
			      14) < 0) {
		LOG_ERR("Failed to read data sample.");
		return -EIO;
	}
	drv_data->accel_x = sys_be16_to_cpu(buf[0]);  // 加速度x
    drv_data->accel_y = sys_be16_to_cpu(buf[1]);  // 加速度Y
    drv_data->accel_z = sys_be16_to_cpu(buf[2]);  // 加速度Z
    drv_data->temp = sys_be16_to_cpu(buf[3]);     // 温度
    drv_data->gyro_x = sys_be16_to_cpu(buf[4]);   // 陀螺仪X
    drv_data->gyro_y = sys_be16_to_cpu(buf[5]);   // 陀螺仪Y
    drv_data->gyro_z = sys_be16_to_cpu(buf[6]);   // 陀螺仪Z

3.4 初始化

说明:

  • 设备检查
  • 检查设备ID
  • 唤醒芯片
  • 配置量程与采样率
int mpu6050_init(const struct device *dev)
{
	if (!device_is_ready(cfg->i2c.bus)) {
		LOG_ERR("Bus device is not ready");
		return -ENODEV;
	}

	/* check chip ID */
	if (i2c_reg_read_byte_dt(&cfg->i2c, MPU6050_REG_CHIP_ID, &id) < 0) {
		LOG_ERR("Failed to read chip ID.");
		return -EIO;
	}

	/* wake up chip */
	if (i2c_reg_update_byte_dt(&cfg->i2c, MPU6050_REG_PWR_MGMT1,
				   MPU6050_SLEEP_EN, 0) < 0) {
		LOG_ERR("Failed to wake up chip.");
		return -EIO;
	}

	/* set accelerometer full-scale range */
	for (i = 0U; i < 4; i++) {
		if (BIT(i+1) == cfg->accel_fs) {
			break;
		}
	}
-----

	if (i2c_reg_write_byte_dt(&cfg->i2c, MPU6050_REG_GYRO_CFG,
				  i << MPU6050_GYRO_FS_SHIFT) < 0) {
		LOG_ERR("Failed to write gyro full-scale range.");
		return -EIO;
	}

	drv_data->gyro_sensitivity_x10 = mpu6050_gyro_sensitivity_x10[i];

	if (i2c_reg_write_byte_dt(&cfg->i2c, MPU6050_REG_SMPLRT_DIV,
				  cfg->smplrt_div) < 0) {
		LOG_ERR("Failed to write samplerate divider.");
		return -EIO;
	}

	return 0;
}

总结

本驱动实现了完整的MPU6050传感器功能:数据转换、采样、初始化和设备注册。Zephyr在传感器方面的应用较其他RTOS方便,统一,读者可根据具体寄存器进行配置。

你可能感兴趣的:(Zephyr实践开发,单片机,物联网,嵌入式硬件,驱动开发,iot,linux,stm32)