STM32读取MPU6050数据以及使用MPU6050辅助IIC读取LIS3MDLTR
一、概述
MPU6050是一款集成了加速度计和陀螺仪的传感器,LIS3MDLTR是一款磁力计传感器。下面将介绍如何在STM32平台上读取MPU6050的数据,并通过MPU6050的辅助IIC接口读取LIS3MDLTR的数据。
二、硬件连接
主控芯片使用STM32C8T6,通过IIC读取MPU6050的陀螺仪和加速度的数据,使用MPU6050的辅助IIC读取LIS3MDLTR磁力计数据。STM32的PB10、PB11引脚分别连接MPU6050的SCL和SDA引脚,MPU6050的AUX_CL和AUX_DA引脚连接LIS3MDLTR的SCL和SDA引脚,如图所示的产品数据手册接口示意图。
二、软件实现
2.1 IIC通信
参考正点原子的IIC通信程序,IIC多字节的读函数与写函数分别如下:
uint8_t MPU_Multi_Read(uint8_t addr,uint8_t reg,uint8_t len,uint8_t *buf)
{
MPU_IIC_Start();
MPU_IIC_Send_Byte((addr<<1)|0); //发送器件地址+写命令
if(MPU_IIC_Wait_Ack()) //等待应答
{
MPU_IIC_Stop();
return 1;
}
MPU_IIC_Send_Byte(reg); //写寄存器地址
MPU_IIC_Wait_Ack(); //等待应答
MPU_IIC_Start();
MPU_IIC_Send_Byte((addr<<1)|1); //发送器件地址+读命令
MPU_IIC_Wait_Ack(); //等待应答
while(len)
{
if(len==1)*buf=MPU_IIC_Read_Byte(0); //读数据,发送nACK
else *buf=MPU_IIC_Read_Byte(1); //读数据,发送ACK
len--;
buf++;
}
MPU_IIC_Stop(); //产生一个停止条件
return 0;
}
uint8_t MPU_Multi_Write(uint8_t addr,uint8_t reg,uint8_t len,uint8_t *buf)
{
uint8_t i;
MPU_IIC_Start();
MPU_IIC_Send_Byte((addr<<1)|0); //发送器件地址+写命令
if(MPU_IIC_Wait_Ack()) //等待应答
{
MPU_IIC_Stop();
return 1;
}
MPU_IIC_Send_Byte(reg); //写寄存器地址
MPU_IIC_Wait_Ack(); //等待应答
for(i=0;i<len;i++)
{
MPU_IIC_Send_Byte(buf[i]); //发送数据
if(MPU_IIC_Wait_Ack()) //等待ACK
{
MPU_IIC_Stop();
return 1;
}
}
MPU_IIC_Stop();
return 0;
}
两个函数中的变量addr和reg分别是器件地址和器件寄存器地址。本文中MPU6050的AD0接地,其地址为0x68,LIS3MDLTR的SD0接3.3V,其地址为0x1E。
2.2 MPU6050和LIS3MDLTR相关配置
1. MPU6050配置
(1)设置陀螺仪量程±2000dps。根据数据手册的器件寄存器介绍,即寄存器(MPU_GYRO_CFG)地址是0x1B。
FS_SEL根据下表选择陀螺仪输出的范围,选择量程范围是±2000dps(MPU6050_Gyr_2000)。
MPU_Write_Byte(MPU_ADDR, MPU_GYRO_CFG, MPU6050_Gyr_2000);
(2)设置加速度计量程±16g,寄存器(MPU_ACC_CFG)地址是0x1C,量程范围选择±16g( MPU6050_Acc_16)。
MPU_Write_Byte(MPU_ADDR, MPU_ACC_CFG, MPU6050_Acc_16);
(3)设置采样率500Hz,相关寄存器描述如下:
2. LIS3MDLTR配置
由于使用MPU6050的辅助IIC来读取 LIS3MDLTR数据,因此首先需要对MPU6050的相关寄存器配置,具体描述如图所示。
根据数据手册相关描述,本次设置首先对MPU6050设置旁通状态,由STM32直接驱动LIS3MDLTR,配置LIS3MDLTR相关寄存器,为读取数据做准备。然后对MPU6050设置主机模式,由LIS3MDLTR的数据通过辅助IIC传输至序号为73到96的寄存器,最后STM32通过MPU6050的IIC一起读出陀螺仪,加速度计和磁力计数据,完成数据的读取。
需要注意的是:对LIS3MDLTR的数据读取首先通过配置MPU6050的INT_PIN_CFG寄存器。INT_PIN_CFG寄存器的位1,当I2C_BYPASS_EN等于1且I2C_MST_EN(寄存器106位5)等于0时,主机应用程序处理器将能够直接访问MPU-60X0的辅助IIC总线。当该位等于0时,无论I2C_MST_EN的状态如何,主机应用程序处理器都将无法直接访问MPU-60X0的辅助IIC总线。
以下是使用辅助IIC读取LIS3MDLTR的步骤:
(1)设置MPU6050为直通模式,以便主控配置LIS3MDLTR。
(2)配置LIS3MDLTR。
(3)读取LIS3MDLTR数据。
(4)设置MPU6050为主模式,STM32读取数据。
MPU_Write_Byte(MPU_ADDR,MPU_INTBP_CFG, 0x02); //设置旁通状态
MPU_Write_Byte(MPU_ADDR,MPU_USER_CTRL, 0x00); //辅助 I2C 总线由主I2C总线(SDA 和 SCL)驱动。
MPU_Write_Byte(LIS3MDL_ADRESS, LIS3MDL_CTRL_REG1, FAST_ODR_300_HP); //配置CTRL_REG1寄存器
MPU_Write_Byte(LIS3MDL_ADRESS, LIS3MDL_CTRL_REG2, FULL_SCALE_8); //配置CTRL_REG2寄存器
MPU_Write_Byte(LIS3MDL_ADRESS, LIS3MDL_CTRL_REG3, CCM); //配置CTRL_REG3寄存器
MPU_Write_Byte(LIS3MDL_ADRESS, LIS3MDL_CTRL_REG4, (Z_HPM | BLE_MSB));//配置CTRL_REG4寄存器
MPU_Write_Byte(MPU_ADDR,MPU_INTBP_CFG, 0x00); //设置主模式。
MPU_Write_Byte(MPU_ADDR,MPU_USER_CTRL, 0x22);
MPU_Write_Byte(MPU_ADDR,MPU_I2CMST_CTRL, 0x0D);
MPU_Write_Byte(MPU_ADDR,MPU_I2CSLV0_ADDR, (LIS3MDL_ADRESS|0x80));
MPU_Write_Byte(MPU_ADDR,MPU_I2CSLV0, LIS3MDL_OUT_X_L);
MPU_Write_Byte(MPU_ADDR,MPU_I2CSLV0_CTRL,EXT_SENS_DATA_00);
LIS3MDLTR的四个配置寄存器是设置磁力计的量程范围和输出速率等相关配置,与MPU6050的配置类似,这里不再叙述。LIS3MDLTR和MPU6050还有一些其他配置,可以根据两个芯片的数据手册按需设置。
2.3 程序设计
1. 配置初始化
uint8_t MPU_Init(void)
{
uint8_t res;
MPU_IIC_Init();//初始化IIC总线
MPU_Write_Byte(MPU_ADDR,MPU_PWR_MGMT1 ,0X80); //复位MPU6050
delay_ms(100);
MPU_Write_Byte(MPU_ADDR,MPU_PWR_MGMT1 ,0X00); //唤醒MPU6050
MPU_Write_Byte(MPU_ADDR,MPU_INTBP_CFG, 0x02); //设置旁通状态
MPU_Write_Byte(MPU_ADDR,MPU_USER_CTRL, 0x00); //辅助 IIC 总线由主IIC总线驱动。
res=MPU_Read_Byte(LIS3MDL_ADRESS, LIS3MDL_ID);
if(res==LIS3MDL_ID_DATA) //器件ID正确
{
MPU_Write_Byte(LIS3MDL_ADRESS, LIS3MDL_CTRL_REG1, FAST_ODR_300_HP);
MPU_Write_Byte(LIS3MDL_ADRESS, LIS3MDL_CTRL_REG2, FULL_SCALE_8);
MPU_Write_Byte(LIS3MDL_ADRESS, LIS3MDL_CTRL_REG3, CCM);
MPU_Write_Byte(LIS3MDL_ADRESS, LIS3MDL_CTRL_REG4, (Z_HPM | BLE_MSB));
}else return 1;
MPU_Write_Byte(MPU_ADDR,MPU_INTBP_CFG, 0x00); //设置主模式。
MPU_Write_Byte(MPU_ADDR,MPU_USER_CTRL, 0x22);
MPU_Write_Byte(MPU_ADDR,MPU_I2CMST_CTRL, 0x0D);
MPU_Write_Byte(MPU_ADDR,MPU_I2CSLV0_ADDR, (LIS3MDL_ADRESS|0x80));
MPU_Write_Byte(MPU_ADDR,MPU_I2CSLV0, LIS3MDL_OUT_X_L);
MPU_Write_Byte(MPU_ADDR,MPU_I2CSLV0_CTRL, I2C_SLV0_CFG);
MPU_Write_Byte(MPU_ADDR, MPU_GYRO_CFG, MPU6050_Gyr_2000);//陀螺仪传感器,±2000dps
MPU_Write_Byte(MPU_ADDR, MPU_ACC_CFG, MPU6050_Acc_16);//加速度传感器,±16g
MPU_Write_Byte(MPU_ADDR,MPU_INT_EN ,0X00); //关闭所有中断
MPU_Write_Byte(MPU_ADDR,MPU_FIFO_EN ,0X00); //关闭FIFO
res=MPU_Read_Byte(MPU_ADDR,MPU_DEVICE_ID);
if(res==MPU_ADDR)//器件ID正确
{
MPU_Write_Byte(MPU_ADDR,MPU_PWR_MGMT1 ,0X01); //设置CLKSEL,PLL X轴为参考
MPU_Write_Byte(MPU_ADDR,MPU_PWR_MGMT2 ,0X00); //加速度与陀螺仪都工作
MPU_Set_Rate(500); //设置采样率为500Hz
}
else return 1;
return 0;
}
2. 读取数据
uint8_t MPU_Raw_Data(MPU6050_Raw_Data *Raw_Data)
{
uint8_t buf[14],res,buf1[6];
res=MPU_Multi_Read(MPU_ADDR,MPU_ACCEL_XOUTH,14,buf);
if(res==0)
{
Raw_Data->Acc_x_Raw=((uint16_t)buf[0]<<8)|buf[1];
Raw_Data->Acc_y_Raw=((uint16_t)buf[2]<<8)|buf[3];
Raw_Data->Acc_z_Raw=((uint16_t)buf[4]<<8)|buf[5];
Raw_Data->Temp_Raw=((uint16_t)buf[6]<<8)|buf[7];
Raw_Data->Gyr_x_Raw=((uint16_t)buf[8]<<8)|buf[9];
Raw_Data->Gyr_y_Raw=((uint16_t)buf[10]<<8)|buf[11];
Raw_Data->Gyr_z_Raw=((uint16_t)buf[12]<<8)|buf[13];
}
res=MPU_Multi_Read(MPU_ADDR,EXT_SENS_DATA_00,6,buf1);
if(res==0)
{
Raw_Data->Guass_x_Raw=((uint16_t)buf1[0]<<8)|buf1[1];
Raw_Data->Guass_y_Raw=((uint16_t)buf1[2]<<8)|buf1[3];
Raw_Data->Guass_z_Raw=((uint16_t)buf1[4]<<8)|buf1[5];
}
return res;
}
三、数据输出
采集的数据通过串口输出显示,从数据特征来看应该是正确采集到了陀螺仪、加速度计和磁力计数据。有错误的地方,欢迎指正,相互交流。
四、参考资料
MPU6050辅助IIC(HMC5883L,STM32F103C8T6)_mpu6050与hmc5883-CSDN博客http://www.openedv.com/docs/modules/other/ATK-MPU6050.html
作者:洛洛xin