0%

10-2软件I2C读写MPU6050

MPU6050简介

•MPU6050是一个6轴姿态传感器,可以测量芯片自身X、Y、Z轴的加速度、角速度参数,通过数据融合,可进一步得到姿态角,常应用于平衡车、飞行器等需要检测自身姿态的场景
•3轴加速度计(Accelerometer):测量X、Y、Z轴的加速度
•3轴陀螺仪传感器(Gyroscope):测量X、Y、Z轴的角速度

MPU6050参数

•16位ADC采集传感器的模拟信号,量化范围:-32768~32767
•加速度计满量程选择:±2、±4、±8、±16(g)
•陀螺仪满量程选择: ±250、±500、±1000、±2000(°/sec)
•可配置的数字低通滤波器
•可配置的时钟源
•可配置的采样分频
•I2C从机地址:1101000(AD0=0)
1101001(AD0=1)

硬件电路

硬件电路

引脚功能
VCC、GND电源
SCL、SDAI2C通信引脚
XCL、XDA主机I2C通信引脚
AD0从机地址最低位
INT中断信号输出

MPU6050框图

MPU6050框图

软件I2C读写MPU6050

MyI2C.c

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
#include "stm32f10x.h"                  // Device header
#include "Delay.h"

void MyI2C_W_SCL(uint8_t BitValue)//调用此函数,参数给1或者0,可以释放或拉低SCL
{
GPIO_WriteBit(GPIOB,GPIO_Pin_10,(BitAction)BitValue);
Delay_us(10);//延时一段时间,避免CPU主频太快,从设备跟不上
}

void MyI2C_W_SDA(uint8_t BitValue)//调用此函数,参数给1或者0,可以释放或拉低SDA
{
GPIO_WriteBit(GPIOB,GPIO_Pin_11,(BitAction)BitValue);
Delay_us(10);//延时一段时间,避免CPU主频太快,从设备跟不上
}

uint8_t MyI2C_R_SDA(void)//读SDA
{
uint8_t BitValue;
BitValue = GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_11);
Delay_us(10);//延时一段时间,避免CPU主频太快,从设备跟不上
return BitValue;
}

void MyI2C_Init(void)
{
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);//把PB10和11都置为高电平
}

void MyI2C_Start(void)//I2C起始
{
MyI2C_W_SDA(1);//先把SCL和SDA都释放,先释放SDA,再释放SCL,这个顺序是为了兼容重复起始
MyI2C_W_SCL(1);
MyI2C_W_SDA(0);//起始条件:先拉低SDA,再拉低SCL
MyI2C_W_SCL(0);
}

void MyI2C_Stop(void)//I2C停止
{
MyI2C_W_SDA(0);//终止条件:先拉低SDA,再释放SCL,再释放SDA
MyI2C_W_SCL(1);
MyI2C_W_SDA(1);
}

void MyI2C_SendByte(uint8_t Byte)
{
uint8_t i;
for(i = 0; i < 8; i++)
{
MyI2C_W_SDA(Byte & (0x80 >> i));//取出每一位,SDA根据传入的Byte修改电平
MyI2C_W_SCL(1);//释放SCL
MyI2C_W_SCL(0);//拉低SCL
}
}

uint8_t MyI2C_ReceiveByte(void)
{
uint8_t i, Byte = 0x00;//先定义一个接收字节
MyI2C_W_SDA(1);//释放SDA
for(i = 0; i < 8; i++)
{
MyI2C_W_SCL(1);//释放SCL
if(MyI2C_R_SDA() == 1)
{
Byte |= (0x80>>i);
}
MyI2C_W_SCL(0);//拉低SCL
}
return Byte;
}

void MyI2C_SendAck(uint8_t AckBit)
{
MyI2C_W_SDA(AckBit);
MyI2C_W_SCL(1);
MyI2C_W_SCL(0);
}

uint8_t MyI2C_ReceiveAck(void)
{
uint8_t AckBit;
MyI2C_W_SDA(1);//释放SDA
MyI2C_W_SCL(1);//释放SCL
AckBit = MyI2C_R_SDA();
MyI2C_W_SCL(0);//拉低SCL
return AckBit;
}

MPU6050.c

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
#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();//I2C启动
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();//I2C启动
MyI2C_SendByte(MPU6050_ADDRESS);//发送MPU6050的地址
MyI2C_ReceiveAck();//接收应答,下面还可以判断,此处省略
MyI2C_SendByte(RegAddress);//发送要读的地址
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);
}

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;

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;
}

main.c

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
#include "stm32f10x.h"                  // Device header
#include "Delay.h"
#include "OLED.h"
#include "MPU6050.h"

int16_t AX,AY,AZ,GX,GY,GZ;

int main(void)
{
OLED_Init();
MPU6050_Init();
//MPU6050_WriteReg(0x6B,0x00);//取消睡眠模式
//MPU6050_WriteReg(0x19,0x66);//采样模式修改
//uint8_t ID = MPU6050_ReadReg(0x19);

//OLED_ShowHexNum(1,1,ID,2);

while(1)
{
MPU6050_GetData(&AX,&AY,&AZ,&GX,&GY,&GZ);
OLED_ShowSignedNum(2,1,AX,5);
OLED_ShowSignedNum(3,1,AY,5);
OLED_ShowSignedNum(4,1,AZ,5);
OLED_ShowSignedNum(2,8,GX,5);
OLED_ShowSignedNum(3,8,GY,5);
OLED_ShowSignedNum(4,8,GZ,5);
}
}