赞
踩
MPU-60X0是全球首例9轴运动处理传感器。它集成了3轴MEMS陀螺仪、三轴MEMS加速度计,以及一个可扩展的数字运动处理器DMP,可用I2C接口连接一个第三方的数字传感器,比如磁力计。扩展之后就可以通过其I2C或SPI接口输出一个9轴的信号。
MPU60X0的陀螺仪和加速度计分别采用了三个16位的ADC,将其测量的模拟量转化为客户处的数字量。传感器的测量范围是用户可控的,陀螺仪可测范围为
±
250
,
±
500
,
±
100
,
±
2000
°
/
秒
\pm250,\pm500,\pm100,\pm2000\degree/\text{秒}
±250,±500,±100,±2000°/秒,加速度计可测范围为
±
2
,
±
4
,
±
8
,
±
16
g
\pm2,\pm4,\pm8,\pm16g
±2,±4,±8,±16g。
一个片上1024字节的FIFO,有助于降低系统功耗。
和所有设备寄存器间的通信均采用I2C接口(速度<=400KHz)。另外,片上还内嵌了一个温度传感器和在工作环境下仅有
±
1
%
\pm1\%
±1%变动的振荡器。
MPU6050的系统结构如图中所示,可以清晰的观察到,MPU6050芯片中内置了三轴加速度传感器、三轴陀螺仪和一个温度传感器。右侧的INT引脚为MPU的中断输出脚,TCS为片选脚、AD0为IIC地址设置脚(AD0=0时0x68,AD0=1时0x69),SCL和SDA为主IIC接口,AUX_CL和AUX_DA为从IIC接口。主要用到的引脚就是AD0、SCL、SDA。
采样频率分频寄存器:SMPRT_DIV(0x19)
配置寄存器:CONFIG(0x1A)
陀螺仪配置寄存器:GYRO_CONFIG(0x1B)
加速度计配置寄存器:ACCEL_CONFIG(0x1C)
加速度计数据寄存器:ACCEL_XOUT_H 、ACCEL_XOUT_L、ACCEL_YOUT_H 、ACCEL_YOUT_L、ACCEL_ZOUT_H 、ACCEL_ZOUT_L(0x3B、0x3C、0x3D、0x3E、0x3F、0x40)
陀螺仪数据寄存器:GYRO_XOUT_H、GYRO_XOUT_L、GYRO_YOUT_H、GYRO_YOUT_L、GYRO_ZOUT_H、GYRO_ZOUT_L(0x43、0x44、0x45、0x46、0x47、0x48)
温度数据寄存器:TEMP_OUT_H、TEMP_OUT_L(0x41、0x42)
电源管理寄存器1:PWR_MGMT_1(0x6B)和电源管理寄存器2:PWR_MGMT_2
ID号寄存器:WHO AM I(0x75)
WHO_AM_I[6:1]只读寄存器:寄存器内容固定为0x68,AD0引脚的值并不反映到这个寄存器中。
注意:当芯片上电复位后所有寄存器默认值均为:0x00,除了PWR_MGMT_1为:0x40(睡眠模式),以及WHO_AM_I为:0x68,因此在操作MPU6050前,需要先解除睡眠,否则操作MPU6050寄存器无效。
查看数据手册可以找到I2C单字节写时序的为
其中S:起始信号,AD:六位IIC地址,W:写,ACK:应答信号,RA:寄存器地址,DATA:数据,P:停止信号
则根据博客【STM32F407学习笔记】模拟IIC协议可以实现单字节I2C写操作,实现如下:
/// @brief 写入指定设备,指定寄存器的一个字节 /// @param I2C_Addr 目标设备地址 /// @param reg 寄存器地址 /// @param data 写入的数据 /// @return 1失败 0成功 uint8_t IIC_WriteByteToSlave(uint8_t I2CAddr,uint8_t reg,uint8_t data) { IIC_Start(); IIC_SendByte((I2C_Addr<<1)|0); // 写入从机地址 if(IIC_waitACK()) { IIC_Stop(); return 1; // 写入失败 } IIC_SendByte(reg); // 发送寄存器地址 if(IIC_waitACK()) { IIC_Stop(); return 1; // 写入失败 } IIC_SendByte(data); // 发送数据 if(IIC_waitACK()) { IIC_Stop(); return 1; // 写入失败 } IIC_Stop(); return 0; }
查询数据手册,IIC多字节写入的时序为:
实现多字节I2C写操作,实现如下:
/// @brief 写入指定设备,指定寄存器的length个字节 /// @param I2C_Addr 目标设备地址 /// @param reg 寄存器地址 /// @param length 写入的数据长度 /// @param data 写入数据存放的指针 /// @return 1失败 0成功 uint8_t IIC_WriteByteToSlave(uint8_t I2CAddr,uint8_t reg,uint8_t length,uint8_t *data) { uint8_t count=0; IIC_Start(); IIC_SenByte((I2CAddr<<1)|0);// 写从机地址 if(IIC_waitACK()) { IIC_Stop(); return 1; // 写入失败 } IIC_SendByte(reg); // 寄存器地址 if(IIC_waitACK()) { IIC_Stop(); return 1; // 写入失败 } for(count=0;cout<length;count++) { IIC_SendByte(data[count]); if(IIC_waitACK()) { IIC_Stop(); return 1; // 写入失败 } } IIC_Stop(); return 0; }
查询数据手册,IIC单字节读的时序为:
实现单字节I2C读操作,实现如下:
/// @brief 读取指定设备,指定寄存器的一个字节 /// @param I2C_Addr 目标设备地址 /// @param reg 寄存器地址 /// @param buf 读取数据存放地址 /// @return 1失败 0成功 uint8_t ReadByteFromSlave(uint8_t I2CAddr,uint8_t reg,uint8_t *buf) { IIC_Start(); IIC_SendByte((I2CAddr<<1)|0); // I2CAddr+W 写入从机地址 if(IIC_waitACK()) { IIC_Stop(); return 1; // 写入失败 } IIC_SendByte(reg); // 写入寄存器地址 if(IIC_waitACK()) { IIC_Stop(); return 1; // 写入失败 } IIC_Start(); IIC_SendByte((I2CAddr<<1)|1); // I2CAddr+R if(IIC_waitACK()) { IIC_Stop(); return 1; // 写入失败 } *buf=IIC_ReadByte(0); // 仅读取一个字节,ReadByte(0)会返回NACK信号 IIC_Stop(); return 0; }
查询数据手册,IIC多字节读的时序为:
实现多字节I2C读操作,实现如下:
/// @brief 读取指定设备,指定寄存器的一个字节 /// @param I2C_Addr 目标设备地址 /// @param reg 寄存器地址 /// @param length 读取的字节长度 /// @param buf 读取数据存放地址 /// @return 1失败 0成功 uint8_t ReadByteFromSlave(uint8_t I2CAddr,uint8_t reg,uint8_t length,uint8_t *buf) { uint8_t count=0; uint8_t temp; IIC_Start(); IIC_SendByte((I2CAddr<<1)|0); // I2CAddr+W 写入从机地址 if(IIC_waitACK()) { IIC_Stop(); return 1; // 写入失败 } IIC_SendByte(reg); // 写入寄存器地址 if(IIC_waitACK()) { IIC_Stop(); return 1; // 写入失败 } IIC_Start(); IIC_SendByte((I2CAddr<<1)|1); // I2CAddr+R if(IIC_waitACK()) { IIC_Stop(); return 1; // 写入失败 } for(count=0;count<length;count++) { if(count!=length-1) // 非最后一个字节 { temp=IIC_ReadByte(1); // IIC_ReadByte(1) 会返回一个ACK } else // 最后一字节 { temp=IIC_ReadByte(0); // IIC_ReadByte(0) 会返回一个NACK } buf[count]=temp; // 存储数据 } IIC_Stop(); return 0; }
根据前述1,2小节将其综合可以实现如下的MPU6050操作
/// @brief 检查MPU6050是否连接 /// @param None /// @return 0 连接 1 未连接 uint8_t MPU6050_Check(void) { uint8_t ID; IIC_ReadByteFromSlave(MPU6050_Addr, MPU6050_WHO_AM_I, &ID); if (ID == 0x68) // WHO AM I寄存器默认值 { return 0; } return 1; } /// @brief MPU6050初始化 /// @param I2C_Addr MPU6050的从机IIC地址 void MPU6050_init(uint8_t I2C_Addr) { MPU6050_Addr = I2C_Addr; // 检查MPU6050是否连接 if (MPU6050_Check()) // 未连接 { return; } // 设置MPU6050为复位状态 IIC_WriteByteToSlave(MPU6050_Addr, MPU6050_PWR_MGMT_1, 0x80); // 设置为复位状态 delay_ms(50); // 等待复位 IIC_WriteByteToSlave(MPU6050_Addr, MPU6050_PWR_MGMT_1, 0x01); // 0000 0001 解除睡眠 使能温度传感器 选择时钟源使用X轴PLL作为时钟源 IIC_WriteByteToSlave(MPU6050_Addr, MPU6050_PWR_MGMT_2, 0x00); // 输出三轴陀螺仪和三轴加速度计数据 IIC_WriteByteToSlave(MPU6050_Addr, MPU6050_INT_ENBALE, 0x00); // 禁止中断 IIC_WriteByteToSlave(MPU6050_Addr, MPU6050_SMPLRT_DIV, 0x09); // 采样分频10 IIC_WriteByteToSlave(MPU6050_Addr, MPU6050_CONFGIG, 0x06); // 滤波参数最大 IIC_WriteByteToSlave(MPU6050_Addr, MPU6050_GYRO_CONFIG, 0x18); // 陀螺仪,最大量程 IIC_WriteByteToSlave(MPU6050_Addr, MPU6050_ACCEL_CONFIG, 0x18); // 加速度计,满量程 IIC_WriteByteToSlave(MPU6050_Addr, MPU6050_FIFO_EN, 0x00); // 关闭FIFO }
/// @brief 获取MPU6050 六轴数据 /// @param AccX X轴加速度数据 /// @param AccY Y轴加速度数据 /// @param AccZ Z轴加速度数据 /// @param GyroX X轴陀螺仪数据 /// @param GyroY Y轴陀螺仪数据 /// @param GyroZ Z轴陀螺仪数据 void MPU6050_GetData(int16_t *AccX, int16_t *AccY, int16_t *AccZ, int16_t *GyroX, int16_t *GyroY, int16_t *GyroZ) { uint8_t DataH, DataL; // 读取数据寄存器 IIC_ReadByteFromSlave(MPU6050_Addr, MPU6050_ACCEL_XOUT_H, &DataH); IIC_ReadByteFromSlave(MPU6050_Addr, MPU6050_ACCEL_XOUT_L, &DataL); *AccX = (DataH << 8) | DataL; IIC_ReadByteFromSlave(MPU6050_Addr, MPU6050_ACCEL_YOUT_H, &DataH); IIC_ReadByteFromSlave(MPU6050_Addr, MPU6050_ACCEL_YOUT_L, &DataL); *AccY = (DataH << 8) | DataL; IIC_ReadByteFromSlave(MPU6050_Addr, MPU6050_ACCEL_ZOUT_H, &DataH); IIC_ReadByteFromSlave(MPU6050_Addr, MPU6050_ACCEL_ZOUT_L, &DataL); *AccZ = (DataH << 8) | DataL; IIC_ReadByteFromSlave(MPU6050_Addr, MPU6050_GYRO_XOUT_H, &DataH); IIC_ReadByteFromSlave(MPU6050_Addr, MPU6050_GYRO_XOUT_L, &DataL); *GyroX = (DataH << 8) | DataL; IIC_ReadByteFromSlave(MPU6050_Addr, MPU6050_GYRO_YOUT_H, &DataH); IIC_ReadByteFromSlave(MPU6050_Addr, MPU6050_GYRO_YOUT_L, &DataL); *GyroY = (DataH << 8) | DataL; IIC_ReadByteFromSlave(MPU6050_Addr, MPU6050_GYRO_ZOUT_H, &DataH); IIC_ReadByteFromSlave(MPU6050_Addr, MPU6050_GYRO_ZOUT_L, &DataL); *GyroZ = (DataH << 8) | DataL; }
/// @brief 获取MPU6050当前温度
/// @param Tempdata 当前温度
void MPU6050_GetTemp(float *Tempdata)
{
uint8_t TempH, TempL;
short data;
IIC_ReadByteFromSlave(MPU6050_Addr, MPU6050_TEMP_OUT_H, &TempH);
IIC_ReadByteFromSlave(MPU6050_Addr, MPU6050_TEMP_OUT_H, &TempL);
data = (int16_t)((TempH << 8) | TempL);
*Tempdata = (36.53f + (float)data / 340);
}
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。