从 MPU9150 读取传感器数据的 C I2C 代码不起作用

Posted

技术标签:

【中文标题】从 MPU9150 读取传感器数据的 C I2C 代码不起作用【英文标题】:C I2C code to read sensor data from MPU9150 not working 【发布时间】:2014-06-30 15:21:17 【问题描述】:

我正在尝试使用 LPC1343 微控制器通过 I2C 读取 MPU9150 传感器数据。我开发了以下 C 代码,但是,当读取加速度计 X 低位的值时,我收到零。这是我的代码:

/////////////// MPU9150 I2C CODE /////////////////////
 #define MPU9150_SELF_TEST_X        0x0D   // R/W
#define MPU9150_SELF_TEST_Y        0x0E   // R/W
#define MPU9150_SELF_TEST_Z        0x0F   // R/W
#define MPU9150_SELF_TEST_A        0x10   // R/W
#define MPU9150_SMPLRT_DIV         0x19   // R/W
#define MPU9150_CONFIG             0x1A   // R/W
#define MPU9150_GYRO_CONFIG        0x1B   // R/W
#define MPU9150_ACCEL_CONFIG       0x1C   // R/W
#define MPU9150_FF_THR             0x1D   // R/W
#define MPU9150_FF_DUR             0x1E   // R/W
#define MPU9150_MOT_THR            0x1F   // R/W
#define MPU9150_MOT_DUR            0x20   // R/W
#define MPU9150_ZRMOT_THR          0x21   // R/W
#define MPU9150_ZRMOT_DUR          0x22   // R/W
#define MPU9150_FIFO_EN            0x23   // R/W
#define MPU9150_I2C_MST_CTRL       0x24   // R/W
#define MPU9150_I2C_SLV0_ADDR      0x25   // R/W
#define MPU9150_I2C_SLV0_REG       0x26   // R/W
#define MPU9150_I2C_SLV0_CTRL      0x27   // R/W
#define MPU9150_I2C_SLV1_ADDR      0x28   // R/W
#define MPU9150_I2C_SLV1_REG       0x29   // R/W
#define MPU9150_I2C_SLV1_CTRL      0x2A   // R/W
#define MPU9150_I2C_SLV2_ADDR      0x2B   // R/W
#define MPU9150_I2C_SLV2_REG       0x2C   // R/W
#define MPU9150_I2C_SLV2_CTRL      0x2D   // R/W
#define MPU9150_I2C_SLV3_ADDR      0x2E   // R/W
#define MPU9150_I2C_SLV3_REG       0x2F   // R/W
#define MPU9150_I2C_SLV3_CTRL      0x30   // R/W
#define MPU9150_I2C_SLV4_ADDR      0x31   // R/W
#define MPU9150_I2C_SLV4_REG       0x32   // R/W
#define MPU9150_I2C_SLV4_DO        0x33   // R/W
#define MPU9150_I2C_SLV4_CTRL      0x34   // R/W
#define MPU9150_I2C_SLV4_DI        0x35   // R  
#define MPU9150_I2C_MST_STATUS     0x36   // R
#define MPU9150_INT_PIN_CFG        0x37   // R/W
#define MPU9150_INT_ENABLE         0x38   // R/W
#define MPU9150_INT_STATUS         0x3A   // R  
#define MPU9150_ACCEL_XOUT_H       0x3B   // R  
#define MPU9150_ACCEL_XOUT_L       0x3C   // R  
#define MPU9150_ACCEL_YOUT_H       0x3D   // R  
#define MPU9150_ACCEL_YOUT_L       0x3E   // R  
#define MPU9150_ACCEL_ZOUT_H       0x3F   // R  
#define MPU9150_ACCEL_ZOUT_L       0x40   // R  
#define MPU9150_TEMP_OUT_H         0x41   // R  
#define MPU9150_TEMP_OUT_L         0x42   // R  
#define MPU9150_GYRO_XOUT_H        0x43   // R  
#define MPU9150_GYRO_XOUT_L        0x44   // R  
#define MPU9150_GYRO_YOUT_H        0x45   // R  
#define MPU9150_GYRO_YOUT_L        0x46   // R  
#define MPU9150_GYRO_ZOUT_H        0x47   // R  
#define MPU9150_GYRO_ZOUT_L        0x48   // R  
#define MPU9150_EXT_SENS_DATA_00   0x49   // R  
#define MPU9150_EXT_SENS_DATA_01   0x4A   // R  
#define MPU9150_EXT_SENS_DATA_02   0x4B   // R  
#define MPU9150_EXT_SENS_DATA_03   0x4C   // R  
#define MPU9150_EXT_SENS_DATA_04   0x4D   // R  
#define MPU9150_EXT_SENS_DATA_05   0x4E   // R  
#define MPU9150_EXT_SENS_DATA_06   0x4F   // R  
#define MPU9150_EXT_SENS_DATA_07   0x50   // R  
#define MPU9150_EXT_SENS_DATA_08   0x51   // R  
#define MPU9150_EXT_SENS_DATA_09   0x52   // R  
#define MPU9150_EXT_SENS_DATA_10   0x53   // R  
#define MPU9150_EXT_SENS_DATA_11   0x54   // R  
#define MPU9150_EXT_SENS_DATA_12   0x55   // R  
#define MPU9150_EXT_SENS_DATA_13   0x56   // R  
#define MPU9150_EXT_SENS_DATA_14   0x57   // R  
#define MPU9150_EXT_SENS_DATA_15   0x58   // R  
#define MPU9150_EXT_SENS_DATA_16   0x59   // R  
#define MPU9150_EXT_SENS_DATA_17   0x5A   // R  
#define MPU9150_EXT_SENS_DATA_18   0x5B   // R  
#define MPU9150_EXT_SENS_DATA_19   0x5C   // R  
#define MPU9150_EXT_SENS_DATA_20   0x5D   // R  
#define MPU9150_EXT_SENS_DATA_21   0x5E   // R  
#define MPU9150_EXT_SENS_DATA_22   0x5F   // R  
#define MPU9150_EXT_SENS_DATA_23   0x60   // R  
#define MPU9150_MOT_DETECT_STATUS  0x61   // R  
#define MPU9150_I2C_SLV0_DO        0x63   // R/W
#define MPU9150_I2C_SLV1_DO        0x64   // R/W
#define MPU9150_I2C_SLV2_DO        0x65   // R/W
#define MPU9150_I2C_SLV3_DO        0x66   // R/W
#define MPU9150_I2C_MST_DELAY_CTRL 0x67   // R/W
#define MPU9150_SIGNAL_PATH_RESET  0x68   // R/W
#define MPU9150_MOT_DETECT_CTRL    0x69   // R/W
#define MPU9150_USER_CTRL          0x6A   // R/W
#define MPU9150_PWR_MGMT_1         0x6B   // R/W
#define MPU9150_PWR_MGMT_2         0x6C   // R/W
#define MPU9150_FIFO_COUNTH        0x72   // R/W
#define MPU9150_FIFO_COUNTL        0x73   // R/W
#define MPU9150_FIFO_R_W           0x74   // R/W
#define MPU9150_WHO_AM_I           0x75   // R

//MPU9150 Compass
#define MPU9150_CMPS_XOUT_L        0x4A   // R
#define MPU9150_CMPS_XOUT_H        0x4B   // R
#define MPU9150_CMPS_YOUT_L        0x4C   // R
#define MPU9150_CMPS_YOUT_H        0x4D   // R
#define MPU9150_CMPS_ZOUT_L        0x4E   // R
#define MPU9150_CMPS_ZOUT_H        0x4F   // R

#define MPU9150_READBIT 0x01 

// I2C address 0x69 could be 0x68 depends on your wiring. 
int MPU9150_ADDRESS = 0x68;

typedef enum

  MPU9150_ERROR_OK = 0,                // Everything executed normally
  MPU9150_ERROR_I2CINIT = 1,               // Unable to initialise I2C
  MPU9150_ERROR_I2CBUSY = 2,               // I2C already in use
  MPU9150_ERROR_NOCONNECTION = 3,          // Unable to read device ID during init
  MPU9150_ERROR_LAST = 4

MPU9150Error_t;

MPU9150Error_t MPU9150Init(void);
MPU9150Error_t MPU9150GetDeviceID(uint8_t *id);
MPU9150Error_t MPU9150GetXYZ(int16_t *accX, int16_t *accY, int16_t *accZ, int16_t *gyroX, int16_t *gyroY, int16_t *gyroZ);

extern volatile uint8_t   I2CMasterBuffer[I2C_BUFSIZE];
extern volatile uint8_t   I2CSlaveBuffer[I2C_BUFSIZE];
extern volatile uint32_t  I2CReadLength, I2CWriteLength;

static bool _MPU9150Initialised = false;

/**************************************************************************/
/*! 
    @brief  Sends a single command byte over I2C
*/
/**************************************************************************/
static MPU9150Error_t MPU9150Write8 (uint8_t reg, uint8_t value)

  MPU9150Error_t error = MPU9150_ERROR_OK;

  // Clear write buffers
  uint32_t i;
  for ( i = 0; i < I2C_BUFSIZE; i++ )
  
    I2CMasterBuffer[i] = 0x00;
  

  I2CWriteLength = 3;
  I2CReadLength = 0;
  I2CMasterBuffer[0] = MPU9150_ADDRESS;       // I2C device address
  I2CMasterBuffer[1] = reg;                   // Register
  I2CMasterBuffer[2] = value;
  i2cEngine();

  // ToDo: Add in proper I2C error-checking
  return error;


/**************************************************************************/
/*! 
    @brief  Reads a 16 bit values over I2C
*/
/**************************************************************************/
static MPU9150Error_t MPU9150Read8(uint8_t reg, uint8_t *value)

  MPU9150Error_t error = MPU9150_ERROR_OK;

  // Clear write buffers
  uint32_t i;
  for ( i = 0; i < I2C_BUFSIZE; i++ )
  
    I2CMasterBuffer[i] = 0x00;
  

  I2CWriteLength = 2;
  I2CReadLength = 1;
  I2CMasterBuffer[0] = MPU9150_ADDRESS;         // I2C device address
  I2CMasterBuffer[1] = reg;                     // Command register
  // Append address w/read bit
  I2CMasterBuffer[2] = MPU9150_ADDRESS | MPU9150_READBIT;  
  i2cEngine();

  // Shift values to create properly formed integer
  *value = I2CSlaveBuffer[0];

  // ToDo: Add in proper I2C error-checking
  return error;


/**************************************************************************/
/*! 
    @brief  Initialises the I2C block
*/
/**************************************************************************/
MPU9150Error_t MPU9150Init(void)

  
  MPU9150Error_t error = MPU9150_ERROR_OK;

  // Initialise I2C
  if (i2cInit(I2CMASTER) == false)
  
    return MPU9150_ERROR_I2CINIT;    /* Fatal error */
  

  error = MPU9150Write8(MPU9150_PWR_MGMT_1, 0);
  //TODO - MPU9150_setupCompass(); if we want mag

  _MPU9150Initialised = true;
  return error;


/**************************************************************************/
/*! 
    @brief  Gets the latest X/Y/Z values
*/
/**************************************************************************/
MPU9150Error_t MPU9150GetXYZ(int16_t *accX, int16_t *accY, int16_t *accZ, int16_t *gyroX, int16_t *gyroY, int16_t *gyroZ )

  MPU9150Error_t error = MPU9150_ERROR_OK;

  uint8_t L = 0; uint8_t H = 0;
  
  error += MPU9150Read8(MPU9150_ACCEL_XOUT_L, &L);
  error += MPU9150Read8(MPU9150_ACCEL_XOUT_H, &H);
  *accX = (H<<8)+L; 
  
  error += MPU9150Read8(MPU9150_ACCEL_YOUT_L, &L);
  error += MPU9150Read8(MPU9150_ACCEL_YOUT_H, &H);
  *accY = (H<<8)+L;
  
  error += MPU9150Read8(MPU9150_ACCEL_ZOUT_L, &L);
  error += MPU9150Read8(MPU9150_ACCEL_ZOUT_H, &H);
  *accZ = (H<<8)+L;
  
  error += MPU9150Read8(MPU9150_GYRO_XOUT_L, &L);
  error += MPU9150Read8(MPU9150_GYRO_XOUT_H, &H);
  *gyroX = (H<<8)+L;
  
  error += MPU9150Read8(MPU9150_GYRO_YOUT_L, &L);
  error += MPU9150Read8(MPU9150_GYRO_YOUT_H, &H);
  *gyroY = (H<<8)+L;
  
  error += MPU9150Read8(MPU9150_GYRO_ZOUT_L, &L);
  error += MPU9150Read8(MPU9150_GYRO_ZOUT_H, &H);
  *gyroZ = (H<<8)+L;
  
  return error;

在我的主要功能中,我正在测试如下:

I2Cerr = MPU9150Init(); 

//now in my while(1) loop:

I2Cerr = MPU9150GetXYZ(&aX, &aY, &aZ, &gX, &gY, &gZ);
uint8_t test = 55;
I2Cerr =  MPU9150Read8(MPU9150_ACCEL_XOUT_L, &test); //always reads 0 into &arg???

作为参考,我开始的代码库是https://github.com/microbuilder/LPC1343CodeBase

我正在使用 ADXL345 加速度计修改 LPC 示例中的示例 I2C 驱动程序:https://github.com/microbuilder/LPC1343CodeBase/blob/master/drivers/sensors/adxl345/adxl345.c 以及使用此示例 Arduino 代码中的 MPU9150 细节:http://playground.arduino.cc/Main/MPU-9150

这是一个相当复杂的固件问题。

编辑

我正在为 i2cEngine() 函数添加代码:

uint32_t i2cEngine( void ) 

  I2CMasterState = I2CSTATE_IDLE;
  RdIndex = 0;
  WrIndex = 0;
  if ( I2CStart() != TRUE )
  
    I2CStop();
    return ( FALSE );
  

  /* wait until the state is a terminal state */
  while (I2CMasterState < 0x100);

  return ( I2CMasterState );

【问题讨论】:

你能把i2cEngine()的代码贴出来吗?在我看来,在MPU9150Read8() 中设置了I2CWriteLength = 2,但随后你用三个字节加载I2CMasterBuffer[],这对我来说似乎很可疑。 i2cEngine() 是否为读取操作发送第三个字节? i2cEngine() 代码现已发布。对我来说,该功能看起来并不那么有见地,但希望它有所帮助。如果您认为深入研究 i2c.c 文件会有所帮助,请点击此处:github.com/microbuilder/LPC1343CodeBase/blob/master/core/i2c/… 您能否成功读取any I2C 寄存器的可信值?您是否能够针对任何其他目标亲自验证 I2C 代码和 I/O 设置?你能用示波器甚至声音逻辑探头检查线路上的活动吗? @ChrisStratton 还没有。不幸的是,这是在使用 LPC1343 分线板和 MPU9150 分线板的手工焊接板上。我正在使用逻辑探针检查 SDA/SCL 上的值,很快就会报告。 哎呀。那些大容量存储解决方案看起来很可爱,但可能不是最有效的。你能找到便宜的 SWD 解决方案吗?对于我使用的同类 ST cortex-M 芯片,他们 10-20 美元的评估板中的任何一个都可以用作低品脱 JTAG 调试接口。我至少会尝试使用 TTL USB 串行电缆或其他东西将我的调试输出通道连接到有线通道。 【参考方案1】:

查看数据表 (http://www.invensense.com/mems/gyro/documents/PS-MPU-9150A-00v4_3.pdf, p35) 看起来您需要发送重复开始,即 start->dev_address->register_to_read->start->dev_address->read_data->stop。许多 I2C 实现不支持重复启动(即停止必须始终与启动匹配),但硬件本身几乎总是支持。您的实现可能就是这种情况,但如果没有更多上下文(例如 i2cStart、i2cStop 和 i2c 中涉及的 ISR),很难很好地了解 i2cEngine() 正在做什么。

【讨论】:

以上是关于从 MPU9150 读取传感器数据的 C I2C 代码不起作用的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 STM32g4xx_HAL_Driver HAL 库通过 i2c 读取传感器数据?

STM32 姿态传感器mpu6050的使用

ARM开发板linux下用I2C读取mpu6050的数据

Aduino ESP9266通过I2C接口读取MPU6050模块数据

Aduino ESP9266通过I2C接口读取MPU6050模块数据+OLED显示

[Motion]MPU9250的Motion Driver