在传统嵌入式传感器开发中,裸机驱动往往需要数百行初始化代码,而复杂的RTOS驱动又面临框架学习成本高的问题。Zephyr RTOS的传感器框架给出了三重设计方案:
驱动模型包括以下几个要点:
#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)// 睡眠模式使能位
static const uint16_t mpu6050_gyro_sensitivity_x10[] = {
1310, 655, 328, 164 // 对应±250, ±500, ±1000, ±2000 °/s的灵敏度值×10
};
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规格
};
说明:
// 加速度转换 (单位: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)
{
-----
}
说明:
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;
}
说明:
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
说明:
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方便,统一,读者可根据具体寄存器进行配置。