广州穗科建设管理有限公司网站,浙江省住房与城乡建设部网站,附近广告牌制作电话,php快速建站系统软件IIC读取MPU6050 最终现象一、GY-521 MPU6050三维角度传感器简介二、程序分析1、mpu6050.c2、MPU6050_reg.h 最终现象 一、GY-521 MPU6050三维角度传感器简介 一共八个引脚#xff0c;一般只用到四个#xff0c;其余的我也没有试过。 VCC、GND分别接5V电源和地#xff1b… 软件IIC读取MPU6050 最终现象一、GY-521 MPU6050三维角度传感器简介二、程序分析1、mpu6050.c2、MPU6050_reg.h 最终现象 一、GY-521 MPU6050三维角度传感器简介 一共八个引脚一般只用到四个其余的我也没有试过。 VCC、GND分别接5V电源和地SCL、SDA分别是IIC通讯中的时钟引脚和数据引脚。 MPU6050 是 全球首款整合性 6 轴运动处理组件免除了组合陀螺仪与加速器时之轴间差的问题。内部整合了 3 轴陀螺仪和 3 轴加速度传感器可以使用 InvenSense 公司提供的运动处理资料库非常方便的实现姿态解算降低了运动处理运算对操作系统的负荷同时大大降低了开发难度。 MPU6050之所以称之为6轴是因为它能感应 X、Y、Z三个方向的加速度和X、Y、Z方向的角速度 PS.mpu6050是这个GY-521模块上的芯片注意不要被这个名字搞蒙了。
二、程序分析
1、mpu6050.c
#include stm32f10x.h // Device header
#include MyI2C.h
#include MPU6050_Reg.h#define MPU6050_ADDRESS 0xD0 //写void MPU6050_WriteReg(uint8_t RegAddress, uint8_t Data)
{MyI2C_Start();//发送起始信号MyI2C_SendByte(MPU6050_ADDRESS);//发送mpu6050设备号及读写位写MyI2C_ReceiveAck();//等待从机响应MyI2C_SendByte(RegAddress);//发送要写入数据的寄存器的地址MyI2C_ReceiveAck();//等待从机响应MyI2C_SendByte(Data);//发送数据MyI2C_ReceiveAck();//等待从机响应MyI2C_Stop();//发送停止信号
}uint8_t MPU6050_ReadReg(uint8_t RegAddress)
{uint8_t Data;MyI2C_Start();//发送起始信号MyI2C_SendByte(MPU6050_ADDRESS);//发送mpu6050设备号及读写位写MyI2C_ReceiveAck();//等待从机响应MyI2C_SendByte(RegAddress);//发送要写入数据的寄存器的地址此时mpu6050内部寄存器指针就会指向这个地址下面再进行发送起始信号见下方//并且发送mpu6050设备号及读写位读MyI2C_ReceiveAck();//等待从机响应MyI2C_Start();//二次起始为读数据做准备MyI2C_SendByte(MPU6050_ADDRESS | 0x01);//发送mpu6050设备号及读写位读MyI2C_ReceiveAck();//等待从机响应Data MyI2C_ReceiveByte();//读取八位数据MyI2C_SendAck(1);//向从机发送不想再读数据的响应MyI2C_Stop();//发送停止信号return Data;
}void MPU6050_Init(void)
{MyI2C_Init();MPU6050_WriteReg(MPU6050_PWR_MGMT_1, 0x01);MPU6050_WriteReg(MPU6050_PWR_MGMT_2, 0x00);MPU6050_WriteReg(MPU6050_SMPLRT_DIV, 0x09);MPU6050_WriteReg(MPU6050_CONFIG, 0x06);MPU6050_WriteReg(MPU6050_GYRO_CONFIG, 0x18);MPU6050_WriteReg(MPU6050_ACCEL_CONFIG, 0x18);
}uint8_t MPU6050_GetID(void)
{return MPU6050_ReadReg(MPU6050_WHO_AM_I);
}void MPU6050_GetData(int16_t *AccX, int16_t *AccY, int16_t *AccZ, int16_t *GyroX, int16_t *GyroY, int16_t *GyroZ)//这就是根据MPU6050手册进行读取寄存器值的操作
{uint8_t DataH, DataL;DataH MPU6050_ReadReg(MPU6050_ACCEL_XOUT_H);DataL MPU6050_ReadReg(MPU6050_ACCEL_XOUT_L);*AccX (DataH 8) | DataL;DataH MPU6050_ReadReg(MPU6050_ACCEL_YOUT_H);DataL MPU6050_ReadReg(MPU6050_ACCEL_YOUT_L);*AccY (DataH 8) | DataL;DataH MPU6050_ReadReg(MPU6050_ACCEL_ZOUT_H);DataL MPU6050_ReadReg(MPU6050_ACCEL_ZOUT_L);*AccZ (DataH 8) | DataL;DataH MPU6050_ReadReg(MPU6050_GYRO_XOUT_H);DataL MPU6050_ReadReg(MPU6050_GYRO_XOUT_L);*GyroX (DataH 8) | DataL;DataH MPU6050_ReadReg(MPU6050_GYRO_YOUT_H);DataL MPU6050_ReadReg(MPU6050_GYRO_YOUT_L);*GyroY (DataH 8) | DataL;DataH MPU6050_ReadReg(MPU6050_GYRO_ZOUT_H);DataL MPU6050_ReadReg(MPU6050_GYRO_ZOUT_L);*GyroZ (DataH 8) | DataL;
}
由于MPU6050模块使用IIC与主机通讯这里解释一下代码中#define MPU6050_ADDRESS 0xD0 为什么会这样设置。如果IIC的通讯时序忘记了可以去复习一下https://www.bilibili.com/video/BV1th411z7sn/?p31spm_id_frompageDrivervd_source2a10d30b8351190ea06d85c5d0bfcb2a 起始位过后可以选择八位地址位但实际上只有七位是地址位最低位是读写控制位如果是写的话就给0读的话就给1。从手册中可以找到MPU6050的从机地址是0X68只有低七位有效这里需要进行写入操作所以最终给的八位地址位就是0XD0如果进行读的话就是0XD1。 mpu6050.c中都是调用最底层的IIC协议来组成特定的通讯时序使用这种方法可以很容易的控制各类使用IIC协议的外设只需要更改自己的驱动代码而不需要去更改底层的IIC通讯协议。 可以看到MPU6050的初始化就是调用了IIC的初始化之后向几个寄存器写入不同的值就好了这一般不用改动。最后的从MPU6050读取数据也是查看手册或者直接用这个就好了都是固定的不同寄存器读出来的就是不同的量将低八位和高八位拼接起来就是完整的16位数据。
2、MPU6050_reg.h
这里就是人家从手册中找到的寄存器地址封装成头文件方便修改。
#ifndef __MPU6050_REG_H
#define __MPU6050_REG_H#define MPU6050_SMPLRT_DIV 0x19
#define MPU6050_CONFIG 0x1A
#define MPU6050_GYRO_CONFIG 0x1B
#define MPU6050_ACCEL_CONFIG 0x1C#define MPU6050_ACCEL_XOUT_H 0x3B
#define MPU6050_ACCEL_XOUT_L 0x3C
#define MPU6050_ACCEL_YOUT_H 0x3D
#define MPU6050_ACCEL_YOUT_L 0x3E
#define MPU6050_ACCEL_ZOUT_H 0x3F
#define MPU6050_ACCEL_ZOUT_L 0x40
#define MPU6050_TEMP_OUT_H 0x41
#define MPU6050_TEMP_OUT_L 0x42
#define MPU6050_GYRO_XOUT_H 0x43
#define MPU6050_GYRO_XOUT_L 0x44
#define MPU6050_GYRO_YOUT_H 0x45
#define MPU6050_GYRO_YOUT_L 0x46
#define MPU6050_GYRO_ZOUT_H 0x47
#define MPU6050_GYRO_ZOUT_L 0x48#define MPU6050_PWR_MGMT_1 0x6B
#define MPU6050_PWR_MGMT_2 0x6C
#define MPU6050_WHO_AM_I 0x75#endif
3、IIC.c 软件IIC顾名思义就是控制IO口的高低电平来模拟产生时钟信号控制数据通信。这里使用PB10模拟时钟输出PB11控制数据交互以此封装起始位停止位发送一个字节读取一个字节发送主机响应接收从机响应。这里代码看不懂的话可以看 https://www.bilibili.com/video/BV1th411z7sn/?p33spm_id_frompageDrivervd_source2a10d30b8351190ea06d85c5d0bfcb2a
#include stm32f10x.h // Device header
#include Delay.h//PB10、PB11
void MyI2C_W_SCL(uint8_t BitValue)//这三个函数将读写io口封装起来增强可读性
{GPIO_WriteBit(GPIOB, GPIO_Pin_10, (BitAction)BitValue);Delay_us(10);
}void MyI2C_W_SDA(uint8_t BitValue)
{GPIO_WriteBit(GPIOB, GPIO_Pin_11, (BitAction)BitValue);Delay_us(10);
}uint8_t MyI2C_R_SDA(void)
{uint8_t BitValue;BitValue GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_11);Delay_us(10);return BitValue;
}void MyI2C_Init(void)//软件iic的两个gpio初始化注意是开漏输出
{RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);GPIO_InitTypeDef GPIO_InitStructure;GPIO_InitStructure.GPIO_Mode GPIO_Mode_Out_OD;GPIO_InitStructure.GPIO_Pin GPIO_Pin_10 | GPIO_Pin_11;GPIO_InitStructure.GPIO_Speed GPIO_Speed_50MHz;GPIO_Init(GPIOB, GPIO_InitStructure);GPIO_SetBits(GPIOB, GPIO_Pin_10 | GPIO_Pin_11);
}void MyI2C_Start(void)//发送起始信号
{MyI2C_W_SDA(1);//确保SCL,SDA都释放然后先拉低SDA再拉低SCLMyI2C_W_SCL(1);MyI2C_W_SDA(0);MyI2C_W_SCL(0);
}void MyI2C_Stop(void)//发送停止信号
{MyI2C_W_SDA(0);//此时SCL一定为低所以拉低SDA,然后先释放SCL,再释放SDAMyI2C_W_SCL(1);MyI2C_W_SDA(1);
}void MyI2C_SendByte(uint8_t Byte)//通过SDA发送一个字节
{uint8_t i;//进入此函数时SCL为低电平此时主机向SDA发送数据然后拉高SCL从机就会读取数据循环发送8位for (i 0; i 8; i ){MyI2C_W_SDA(Byte (0x80 i));MyI2C_W_SCL(1);MyI2C_W_SCL(0);}
}uint8_t MyI2C_ReceiveByte(void)//通过SDA读取一个字节由从机发送
{uint8_t i, Byte 0x00;MyI2C_W_SDA(1);//主机释放SDA让从机掌握SDA控制权for (i 0; i 8; i ){MyI2C_W_SCL(1);if (MyI2C_R_SDA() 1){Byte | (0x80 i);}//在SCL为高电平期间主机可以从SDA中读取从机发送的数据循环接收8位MyI2C_W_SCL(0);}return Byte;
}void MyI2C_SendAck(uint8_t AckBit)//发送主机响应信号
{MyI2C_W_SDA(AckBit);//进入此函数时SCL为低电平此时向SDA写入数据然后拉高SCL从机就会读取数据MyI2C_W_SCL(1);MyI2C_W_SCL(0);
}uint8_t MyI2C_ReceiveAck(void)//接收从机响应
{uint8_t AckBit;MyI2C_W_SDA(1);//主机释放SDA让从机掌握SDA控制权MyI2C_W_SCL(1);AckBit MyI2C_R_SDA();//在SCL为高电平期间主机可以从SDA中读取从机发送的数据MyI2C_W_SCL(0);return AckBit;
}
主函数中初始化MPU6050之后即可调用MPU6050_GetData(AX, AY, AZ, GX, GY, GZ);将读取的数据存储到定义的全局变量中。