MPU-6050 是一种流行的模块,包含温度传感器、加速度计和陀螺仪。用户可以通过 I2C 或 SPI 读取传感器信息。有两个文件可公开用于从 IC 寄存器中读取数据。这些是:
由于总线通信延迟,通过 I2C 读取 IMU 的各个寄存器会使样本随时间偏移。因此,传感器的 X、Y 和 Z 轴寄存器的顺序读取不同步。为了解决这个问题,该器件提供了一个 1024 字节的内部 FIFO 队列。配置为推送到队列的数据以采样率推送到一起。因此读取 FIFO 会产生同步数据。
见(2),第 7.17 节:
MPU-60X0 包含一个 1024 字节的 FIFO 寄存器,可通过串行接口访问。FIFO 配置寄存器决定将哪些数据写入 FIFO。可能的选择包括陀螺仪数据、加速度计数据、温度读数、辅助传感器读数和 FSYNC 输入。FIFO 计数器会跟踪 FIFO 中包含多少字节的有效数据。FIFO 寄存器支持突发读取。中断函数可用于确定新数据何时可用
数据表指定为了从 FIFO 读取,您必须执行以下操作:
0x6A,文档 (1),第 4.29 节)0x23,文档 (1),第 4.7 节)。我通过分别设置第 6、5、4 和 3 位来启用XG_FIFO_EN、YG_FIFO_EN、ZG_FIFO_EN和ACCEL_FIFO_EN。如果您已执行这些步骤,则它声称(文档 (1),第 4.33 节):
数据按寄存器编号的顺序(从低到高)写入 FIFO。如果所有 FIFO 使能标志(见下文)被使能并且所有外部传感器数据寄存器(寄存器 73 至 96)都与从设备相关联,则寄存器 59 至 96 的内容将以采样率按顺序写入。当传感器数据寄存器(寄存器 59 至 96)的内容在 FIFO_EN(寄存器 35)中相应的 FIFO 使能标志设置为 1 时,它们将被写入 FIFO 缓冲区。
然而,我发现这并不成立。鉴于我在配置寄存器中启用的标志,我希望以下序列来自 FIFO:
* ----------------------------------------------------------- *
* BYTE # | VALUE | Register (dec) *
* ----------------------------------------------------------- *
* 0 | ACCEL_XOUT[15:8] | 59 *
* 1 | ACCEL_XOUT[7:0] | 60 *
* ----------------------------------------------------------- *
* 2 | ACCEL_YOUT[15:8] | 61 *
* 3 | ACCEL_YOUT[7:0] | 62 *
* ----------------------------------------------------------- *
* 4 | ACCEL_ZOUT[15:8] | 63 *
* 5 | ACCEL_ZOUT[7:0] | 64 *
* ----------------------------------------------------------- *
* 6 | GYRO_XOUT[15:8] | 67 *
* 7 | GYRO_XOUT[7:0] | 68 *
* ----------------------------------------------------------- *
* 8 | GYRO_YOUT[15:8] | 69 *
* 9 | GYRO_YOUT[7:0] | 70 *
* ----------------------------------------------------------- *
* 10 | GYRO_ZOUT[15:8] | 71 *
* 11 | GYRO_ZOUT[7:0] | 72 *
* ----------------------------------------------------------- *
Run Code Online (Sandbox Code Playgroud)
然而,当读取单个寄存器时,从 FIFO 读取 12 个字节并不对应于相同的数据。当我加速或旋转 IMU 时,它似乎也没有多大意义。因此,我不确定如何准确读取 FIFO。这是我面临的问题
好的,所以我已经找到了问题所在。问题是我在读取之前未能重置FIFO - 否则一切都或多或少没问题。我将向您展示我现在如何设置 IMU。
我创建了一个源文件来读取 MPU-6050 寄存器。我已将它们附在此处以供在以下解释中参考:
为了设置 IMU,我在 FreeRTOS 任务中(在主循环之前)执行了以下步骤。
// Performs the I2C configuration for the MPU-6050 IMU. Saves handle
static mpu6050_err_t init_imu (mpu6050_i2c_cfg_t **handle) {
mpu6050_err_t err = MPU6050_ERR_OK;
uint8_t flags;
// Configure the MPU-6050 I2C data structure
static mpu6050_i2c_cfg_t i2c_cfg = (mpu6050_i2c_cfg_t) {
.sda_pin = I2C_SDA_PIN,
.scl_pin = I2C_SCL_PIN,
.slave_addr = I2C_IMU_SLAVE_ADDR,
.i2c_port = I2C_IMU_PORT_NUM,
.clk_speed = I2C_APB_CLK_FREQ / 200, // Requires 400kHz
.sda_pullup_en = IMU_ENABLE_INTERNAL_PULLUPS,
.scl_pullup_en = IMU_ENABLE_INTERNAL_PULLUPS
};
// Initialize I2C
if ((err = mpu6050_init(&i2c_cfg)) != MPU6050_ERR_OK) {
return err;
}
// Configure Power Management 1 to wake the IMU (don't reset)
flags = 0x0;
if ((err = mpu6050_configure_power(&i2c_cfg, flags)) != MPU6050_ERR_OK) {
return err;
}
// Configure accelerometer sensitivity
flags = A_CFG_8G;
if ((err = mpu6050_configure_accelerometer(&i2c_cfg, flags))
!= MPU6050_ERR_OK) {
return err;
}
// Configure gyro sensitivity
flags = G_CFG_500;
if ((err = mpu6050_configure_gyroscope(&i2c_cfg, flags))
!= MPU6050_ERR_OK) {
return err;
}
// Configure the Digital-Low-Pass-Filter
flags = DLFP_CFG_FILTER_2;
if ((err = mpu6050_configure_dlfp(&i2c_cfg, flags))
!= MPU6050_ERR_OK) {
return err;
}
// Set the sampling rate to ~50Hz
flags = 19;
if ((err = mpu6050_set_sample_rate_divider(&i2c_cfg, flags))
!= MPU6050_ERR_OK) {
return err;
}
// Configure interrupt behavior
flags = 0x0;
if ((err = mpu6050_configure_interrupt(&i2c_cfg, flags))
!= MPU6050_ERR_OK) {
return err;
}
// Enable interrupts after every sensor refresh
flags = INTR_EN_DATA_RDY;
if ((err = mpu6050_enable_interrupt(&i2c_cfg, flags))
!= MPU6050_ERR_OK) {
return err;
}
// Enable + Reset the FIFO
flags = USER_CTRL_FIFO_EN | USER_CTRL_FIFO_RST;
if ((err = mpu6050_enable_fifo(&i2c_cfg, flags))
!= MPU6050_ERR_OK) {
return err;
}
// Configure the data pushed to the FIFO
flags = FIFO_CFG_GX | FIFO_CFG_GY | FIFO_CFG_GZ | FIFO_CFG_AXYZ;
if ((err = mpu6050_configure_fifo(&i2c_cfg, flags)) != MPU6050_ERR_OK) {
return err;
}
// Save the configuration
*handle = &i2c_cfg;
return err;
}
Run Code Online (Sandbox Code Playgroud)
如果您按照我的描述进行配置,那么它应该可以工作。当然,您可能正在为设备使用不同的库或包装器,但您可以启用的功能应该可以类似地访问。完成所有这些后,我可以在每个中断处读取 FIFO,如下所示:
// Read the FIFO length
if (mpu6050_get_fifo_length(i2c_cfg_p, &len) != MPU6050_ERR_OK) {
ERR("FIFO length fetch error!");
break;
}
// Check if enough samples are ready - else continue (check later)
if (len < FIFO_BURST_LEN) {
continue;
}
// Fetch data from FIFO
if (mpu6050_receive_fifo(i2c_cfg_p, &data) != MPU6050_ERR_OK) {
ERR("FIFO data fetch error!");
break;
}
Run Code Online (Sandbox Code Playgroud)