Skip to content

I2C

I2C通信简介

  • I2C(Inter IC Bus)是由Philips公司开发的一种通用数据总线
  • 两根通信线:SCL(Serial Clock)、SDA(Serial Data)
  • 同步,半双工
  • 带数据应答
  • 支持总线挂载多设备(一主多从、多主多从)

硬件电路

  • 所有I2C设备的SCL连在一起,SDA连在一起
  • 设备的SCL和SDA均要配置成开漏输出模式
  • SCL和SDA各添加一个上拉电阻,阻值一般为4.7KΩ左右

1706263977088

1706263989395

I2C时序基本单元

  • **起始条件:**SCL高电平期间,SDA从高电平切换到低电平
  • **终止条件:**SCL高电平期间,SDA从低电平切换到高电平

1706264194346

  • **发送一个字节:**SCL低电平期间,主机将数据位依次放到SDA线上(高位先行),然后释放SCL,从机将在SCL高电平期间读取数据位,所以SCL高电平期间SDA不允许有数据变化,依次循环上述过程8次,即可发送一个字节

1706264284743

  • **接收一个字节:**SCL低电平期间,从机将数据位依次放到SDA线上(高位先行),然后释放SCL,主机将在SCL高电平期间读取数据位,所以SCL高电平期间SDA不允许有数据变化,依次循环上述过程8次,即可接收一个字节(主机在接收之前,需要释放SDA)

1706264383307

  • **发送应答:**主机在接收完一个字节之后,在下一个时钟发送一位数据,数据0表示应答,数据1表示非应答
  • **接收应答:**主机在发送完一个字节之后,在下一个时钟接收一位数据,判断从机是否应答,数据0表示应答,数据1表示非应答(主机在接收之前,需要释放SDA)

1706264434067

I2C时序

  • 指定地址写
  • 对于指定设备(Slave Address),在指定地址(Reg Address)下,写入指定数据(Data)

1706264556589

  • 当前地址读
  • 对于指定设备(Slave Address),在当前地址指针指示的地址下,读取从机数据(Data)

1706265129206

  • 指定地址读
  • 对于指定设备(Slave Address),在指定地址(Reg Address)下,读取从机数据(Data)

1706265164365

MPU6050简介

陀螺仪介绍

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

1706265567624

1706265575585

1706265587929

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、SDA I2C通信引脚
XCL、XDA 主机I2C通信引脚
AD0 从机地址最低位
INT 中断信号输出

1706265831995

1706265861339

软件模拟I2C(标准库)

所谓软件模拟I2C即使用代码手动拉高拉低电平,实现I2C时序操作,可以随意选择SDA和SCL引脚使用更加灵活。

I2C文件

创建I2C.c文件,编写I2C基本时序

#include "stm32f10x.h"                  // Device header
#include "MyI2C.h"
#include "Delay.h"


void MyI2C_W_SDA(uint8_t BitValue)
{
    GPIO_WriteBit(SDA_Port, SDA_Pin, (BitAction)BitValue);
    Delay_us(10);
}

void MyI2C_W_SCL(uint8_t BitValue)
{
    GPIO_WriteBit(SCL_Port, SCL_Pin, (BitAction)BitValue);
    Delay_us(10);
}

uint8_t MyI2C_R_SDA(void)
{
    uint8_t BitValue;
    BitValue = GPIO_ReadInputDataBit(SDA_Port, SDA_Pin);
    Delay_us(10);
    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 = SDA_Pin|SCL_Pin;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;

    GPIO_Init(SDA_Port, &GPIO_InitStructure);
    GPIO_SetBits(SDA_Port, SDA_Pin|SCL_Pin);
}

void MyI2C_Start(void)
{
    //起始条件:SCL高电平期间,SDA从高电平切换到低电平
    MyI2C_W_SDA(1);
    MyI2C_W_SCL(1);
    MyI2C_W_SDA(0);
    //SCL拉低,为--收发--数据做准备
    MyI2C_W_SCL(0);
}

void MyI2C_Stop(void)
{
    //终止条件:SCL高电平期间,SDA从低电平切换到高电平
    MyI2C_W_SDA(0);
    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));  //0x80=1000 0000
        //第二种写法
//      if((Byte & (0x80 >> i))==0) MyI2C_W_SDA(0);
//      else MyI2C_W_SDA(1);
        //拉高SCL读取数据
        MyI2C_W_SCL(1);
        //拉低,让SDA放数据
        MyI2C_W_SCL(0);
    }
}

uint8_t MyI2C_ReceiveByte(void)
{
    uint8_t i, Byte=0x00;
//  MyI2C_W_SCL(0);
    MyI2C_W_SDA(1);
    for(i=0; i<8; i++)
    {
        //读取数据
        MyI2C_W_SCL(1);
        if(MyI2C_R_SDA() == 1) {Byte |=(0x80 >> i);} //0x00=0000 0000
        MyI2C_W_SCL(0);
    }   
    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);
    //读取应答
    MyI2C_W_SCL(1);
    AckBit = MyI2C_R_SDA();
    //进入下一个时序
    MyI2C_W_SCL(0);
    return AckBit;
}

I2C.h文件定义引脚和函数声明

#ifndef __MYI2C_H__
#define __MYI2C_H__
#include "stm32f10x.h" 

#define SDA_Pin GPIO_Pin_11
#define SCL_Pin GPIO_Pin_10
#define SCL_Port GPIOB
#define SDA_Port GPIOB

void MyI2C_Init(void);
uint8_t MyI2C_R_SDA(void);
void MyI2C_W_SCL(uint8_t BitValue);
void MyI2C_W_SDA(uint8_t BitValue);
void MyI2C_Start(void);
void MyI2C_Stop(void);
void MyI2C_SendByte(uint8_t Byte);
uint8_t MyI2C_ReceiveByte(void);
void MyI2C_SendAck(uint8_t AckBit);
uint8_t MyI2C_ReceiveAck(void);

#endif

Mpu6050文件

创建Mpu6050.c文件,编写MPU6050操作函数

#include "stm32f10x.h"                  // Device header
#include "MyI2C.h"
#include "Mpu6050.h"

#define MPU_Address 0xD0  //MPU6050的寻址 + R( Bit(0) )

void MPU6050_Init(void)
{
    //初始化I2C引脚
    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_WriteReg(uint8_t RegAddress, uint8_t Byte)
{
    MyI2C_Start();
    //-1-指定从机的寻址 + R/W
    MyI2C_SendByte(MPU_Address);
    //接收应答
    MyI2C_ReceiveAck();
    //-2-指定要写入寄存器地址
    MyI2C_SendByte(RegAddress);
    MyI2C_ReceiveAck();
    //-3-发送数据(一个字节)
    MyI2C_SendByte(Byte);
    MyI2C_ReceiveAck();
    MyI2C_Stop();
}


uint8_t MPU6050_ReadReg(uint8_t RegAddress)
{
    uint8_t Data;

    MyI2C_Start();
    MyI2C_SendByte(MPU_Address);
    MyI2C_ReceiveAck();
    MyI2C_SendByte(RegAddress);
    MyI2C_ReceiveAck();

    MyI2C_Start();
    MyI2C_SendByte(MPU_Address | 0x01);
    MyI2C_ReceiveAck();
    Data = MyI2C_ReceiveByte();
    MyI2C_SendAck(1);
    MyI2C_Stop();

    return Data;
}
uint8_t MPU6050_GetID(void)
{
    return MPU6050_ReadReg(MPU6050_WHO_AM_I);
}
/**
  * 函    数:MPU6050获取数据
  * 参    数:AccX AccY AccZ 加速度计X、Y、Z轴的数据,使用输出参数的形式返回,范围:-32768~32767
  * 参    数:GyroX GyroY GyroZ 陀螺仪X、Y、Z轴的数据,使用输出参数的形式返回,范围:-32768~32767
  * 返 回 值:无
  */
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;                               //定义数据高8位和低8位的变量

    DataH = MPU6050_ReadReg(MPU6050_ACCEL_XOUT_H);      //读取加速度计X轴的高8位数据
    DataL = MPU6050_ReadReg(MPU6050_ACCEL_XOUT_L);      //读取加速度计X轴的低8位数据
    *AccX = (DataH << 8) | DataL;                       //数据拼接,通过输出参数返回

    DataH = MPU6050_ReadReg(MPU6050_ACCEL_YOUT_H);      //读取加速度计Y轴的高8位数据
    DataL = MPU6050_ReadReg(MPU6050_ACCEL_YOUT_L);      //读取加速度计Y轴的低8位数据
    *AccY = (DataH << 8) | DataL;                       //数据拼接,通过输出参数返回

    DataH = MPU6050_ReadReg(MPU6050_ACCEL_ZOUT_H);      //读取加速度计Z轴的高8位数据
    DataL = MPU6050_ReadReg(MPU6050_ACCEL_ZOUT_L);      //读取加速度计Z轴的低8位数据
    *AccZ = (DataH << 8) | DataL;                       //数据拼接,通过输出参数返回

    DataH = MPU6050_ReadReg(MPU6050_GYRO_XOUT_H);       //读取陀螺仪X轴的高8位数据
    DataL = MPU6050_ReadReg(MPU6050_GYRO_XOUT_L);       //读取陀螺仪X轴的低8位数据
    *GyroX = (DataH << 8) | DataL;                      //数据拼接,通过输出参数返回

    DataH = MPU6050_ReadReg(MPU6050_GYRO_YOUT_H);       //读取陀螺仪Y轴的高8位数据
    DataL = MPU6050_ReadReg(MPU6050_GYRO_YOUT_L);       //读取陀螺仪Y轴的低8位数据
    *GyroY = (DataH << 8) | DataL;                      //数据拼接,通过输出参数返回

    DataH = MPU6050_ReadReg(MPU6050_GYRO_ZOUT_H);       //读取陀螺仪Z轴的高8位数据
    DataL = MPU6050_ReadReg(MPU6050_GYRO_ZOUT_L);       //读取陀螺仪Z轴的低8位数据
    *GyroZ = (DataH << 8) | DataL;                      //数据拼接,通过输出参数返回
}

MPU6050_GetData函数的使用方法见主函数代码,采用了指针做形参传递的方法。

创建Mpu6050.h文件,定义MPU6050各个寄存器地址

#ifndef __MPU6050_H__
#define __MPU6050_H__
//#include "stm32f10x.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

uint8_t MPU6050_GetID(void);
void MPU6050_Init(void);
void MPU6050_WriteReg(uint8_t RegAddress, uint8_t Byte);
uint8_t MPU6050_ReadReg(uint8_t RegAddress);
void MPU6050_GetData(int16_t *AccX, int16_t *AccY, int16_t *AccZ, 
                        int16_t *GyroX, int16_t *GyroY, int16_t *GyroZ);

#endif

main主函数

#include "stm32f10x.h"                  // Device header
#include "Delay.h"
#include "OLED.h"
#include "MPU6050.h"

uint8_t ID;                             //定义用于存放ID号的变量
int16_t AX, AY, AZ, GX, GY, GZ;         //定义用于存放各个数据的变量

int main(void)
{
    /*模块初始化*/
    OLED_Init();        //OLED初始化
    MPU6050_Init();     //MPU6050初始化

    /*显示ID号*/
    OLED_ShowString(1, 1, "ID:");       //显示静态字符串
    ID = MPU6050_GetID();               //获取MPU6050的ID号
    OLED_ShowHexNum(1, 4, ID, 2);       //OLED显示ID号

    while (1)
    {
        MPU6050_GetData(&AX, &AY, &AZ, &GX, &GY, &GZ);      //获取MPU6050的数据
        OLED_ShowSignedNum(2, 1, AX, 5);                    //OLED显示数据
        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);
    }
}

I2C硬件外设

  • STM32内部集成了硬件I2C收发电路,可以由硬件自动执行时钟生成、起始终止条件生成、应答位收发、数据收发等功能,减轻CPU的负担
  • 支持多主机模型
  • 支持7位/10位地址模式
  • 支持不同的通讯速度,标准速度(高达100 kHz),快速(高达400 kHz)
  • 支持DMA
  • 兼容SMBus协议
  • STM32F103C8T6 硬件I2C资源:I2C1、I2C2

I2C框图

1706267084943

I2C基本结构

1706267260181

主机发送

1706267294207

主机接收

1706267321796

硬件I2C(标准库)

保持I2C文件代码不编,修改Mpu6050.c的配置代码

#include "stm32f10x.h"                  // Device header
#include "MyI2C.h"
#include "Mpu6050.h"

#define SDA_Pin GPIO_Pin_11
#define SCL_Pin GPIO_Pin_10
#define SCL_Port GPIOB
#define SDA_Port GPIOB
#define MPU_Address 0xD0  //MPU6050的寻址 + R( Bit(0) )

void MPU6050_WaitEvent(I2C_TypeDef* I2Cx, uint32_t I2C_EVENT)
{
    uint32_t Timeout;
    Timeout = 10000;
    while (I2C_CheckEvent(I2Cx, I2C_EVENT) != SUCCESS)
    {
        Timeout --;
        if (Timeout == 0)
        {
            break;
        }
    }
}

void MPU6050_Init(void)
{
    //初始化I2C引脚
    //替换MyI2C_Init();
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C2, ENABLE);
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);

    GPIO_InitTypeDef GPIO_InitStrcture;
    GPIO_InitStrcture.GPIO_Mode = GPIO_Mode_AF_OD;
    GPIO_InitStrcture.GPIO_Pin = SDA_Pin|SCL_Pin;
    GPIO_InitStrcture.GPIO_Speed = GPIO_Speed_50MHz;

    GPIO_Init(SDA_Port, &GPIO_InitStrcture);

    I2C_InitTypeDef I2C_InitStructure;
    I2C_InitStructure.I2C_Ack = I2C_Ack_Enable;
    I2C_InitStructure.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit;
    I2C_InitStructure.I2C_ClockSpeed = 50000;
    I2C_InitStructure.I2C_DutyCycle = I2C_DutyCycle_2;
    I2C_InitStructure.I2C_Mode = I2C_Mode_I2C;
    I2C_InitStructure.I2C_OwnAddress1 = 0x00;

    I2C_Init(I2C2, &I2C_InitStructure);
    I2C_Cmd(I2C2, ENABLE); //使能I2C2

    //配置寄存器
    MPU6050_WriteReg(MPU6050_PWR_MGMT_1, 0x01); //电源管理寄存器1,取消睡眠模式,选择时钟源为X轴陀螺仪
    MPU6050_WriteReg(MPU6050_PWR_MGMT_2, 0x00); //电源管理寄存器2,保持默认值0,所有轴均不待机
    MPU6050_WriteReg(MPU6050_SMPLRT_DIV, 0x09);     //采样率分频寄存器,配置采样率
    MPU6050_WriteReg(MPU6050_CONFIG, 0x06);         //配置寄存器,配置DLPF
    MPU6050_WriteReg(MPU6050_GYRO_CONFIG, 0x18);    //陀螺仪配置寄存器,选择满量程为±2000°/s
    MPU6050_WriteReg(MPU6050_ACCEL_CONFIG, 0x18);   //加速度计配置寄存器,选择满量程为±16g
}


void MPU6050_WriteReg(uint8_t RegAddress, uint8_t Byte)
{
    /*  软件I2C
    MyI2C_Start();
    //-1-指定从机的寻址 + R/W
    MyI2C_SendByte(MPU_Address);
    //接收应答
    MyI2C_ReceiveAck();
    //-2-指定要写入寄存器地址
    MyI2C_SendByte(RegAddress);
    MyI2C_ReceiveAck();
    //-3-发送数据(一个字节)
    MyI2C_SendByte(Byte);
    MyI2C_ReceiveAck();
    MyI2C_Stop();
    */  
    //硬件I2C
    I2C_GenerateSTART(I2C2, ENABLE); 
    //等待EV5事件(主机模式已选择)
    MPU6050_WaitEvent(I2C2, I2C_EVENT_MASTER_MODE_SELECT);
    I2C_Send7bitAddress(I2C2, MPU_Address, I2C_Direction_Transmitter);
    //等待EV6事件
    MPU6050_WaitEvent(I2C2, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED);
    I2C_SendData(I2C2, RegAddress);
    //等待EV8事件
    MPU6050_WaitEvent(I2C2, I2C_EVENT_MASTER_BYTE_TRANSMITTING);
    I2C_SendData(I2C2, Byte);
    //等待EV8-2事件
    MPU6050_WaitEvent(I2C2, I2C_EVENT_MASTER_BYTE_TRANSMITTED);
    I2C_GenerateSTOP(I2C2, ENABLE);
}


uint8_t MPU6050_ReadReg(uint8_t RegAddress)
{
    uint8_t Data;
    /* 软件I2C
    MyI2C_Start();
    MyI2C_SendByte(MPU_Address);
    MyI2C_ReceiveAck();
    MyI2C_SendByte(RegAddress);
    MyI2C_ReceiveAck();

    MyI2C_Start();
    MyI2C_SendByte(MPU_Address | 0x01);
    MyI2C_ReceiveAck();
    Data = MyI2C_ReceiveByte();
    MyI2C_SendAck(1);
    MyI2C_Stop();
    */
    //硬件I2C
    I2C_GenerateSTART(I2C2, ENABLE); 
    //等待EV5事件(主机模式已选择)
    MPU6050_WaitEvent(I2C2, I2C_EVENT_MASTER_MODE_SELECT);
    I2C_Send7bitAddress(I2C2, MPU_Address, I2C_Direction_Transmitter);
    //等待EV6事件
    MPU6050_WaitEvent(I2C2, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED);
    I2C_SendData(I2C2, RegAddress);
    //等待EV8-2事件
    MPU6050_WaitEvent(I2C2, I2C_EVENT_MASTER_BYTE_TRANSMITTED);

    I2C_GenerateSTART(I2C2, ENABLE); 
    //等待EV5事件(主机模式已选择)
    MPU6050_WaitEvent(I2C2, I2C_EVENT_MASTER_MODE_SELECT);

    I2C_Send7bitAddress(I2C2, MPU_Address, I2C_Direction_Receiver);
    //等待EV6事件
    MPU6050_WaitEvent(I2C2, I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED);
    //提前将--应答位置0--产生停止条件
    I2C_AcknowledgeConfig(I2C2, DISABLE);
    I2C_GenerateSTOP(I2C2, ENABLE);
    //等待EV7事件
    MPU6050_WaitEvent(I2C2, I2C_EVENT_MASTER_BYTE_RECEIVED);    

    Data = I2C_ReceiveData(I2C2);
    //应答位置1
    I2C_AcknowledgeConfig(I2C2, ENABLE);

    return Data;
}
uint8_t MPU6050_GetID(void)
{
    return MPU6050_ReadReg(MPU6050_WHO_AM_I);
}
/**
  * 函    数:MPU6050获取数据
  * 参    数:AccX AccY AccZ 加速度计X、Y、Z轴的数据,使用输出参数的形式返回,范围:-32768~32767
  * 参    数:GyroX GyroY GyroZ 陀螺仪X、Y、Z轴的数据,使用输出参数的形式返回,范围:-32768~32767
  * 返 回 值:无
  */
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;                               //定义数据高8位和低8位的变量

    DataH = MPU6050_ReadReg(MPU6050_ACCEL_XOUT_H);      //读取加速度计X轴的高8位数据
    DataL = MPU6050_ReadReg(MPU6050_ACCEL_XOUT_L);      //读取加速度计X轴的低8位数据
    *AccX = (DataH << 8) | DataL;                       //数据拼接,通过输出参数返回

    DataH = MPU6050_ReadReg(MPU6050_ACCEL_YOUT_H);      //读取加速度计Y轴的高8位数据
    DataL = MPU6050_ReadReg(MPU6050_ACCEL_YOUT_L);      //读取加速度计Y轴的低8位数据
    *AccY = (DataH << 8) | DataL;                       //数据拼接,通过输出参数返回

    DataH = MPU6050_ReadReg(MPU6050_ACCEL_ZOUT_H);      //读取加速度计Z轴的高8位数据
    DataL = MPU6050_ReadReg(MPU6050_ACCEL_ZOUT_L);      //读取加速度计Z轴的低8位数据
    *AccZ = (DataH << 8) | DataL;                       //数据拼接,通过输出参数返回

    DataH = MPU6050_ReadReg(MPU6050_GYRO_XOUT_H);       //读取陀螺仪X轴的高8位数据
    DataL = MPU6050_ReadReg(MPU6050_GYRO_XOUT_L);       //读取陀螺仪X轴的低8位数据
    *GyroX = (DataH << 8) | DataL;                      //数据拼接,通过输出参数返回

    DataH = MPU6050_ReadReg(MPU6050_GYRO_YOUT_H);       //读取陀螺仪Y轴的高8位数据
    DataL = MPU6050_ReadReg(MPU6050_GYRO_YOUT_L);       //读取陀螺仪Y轴的低8位数据
    *GyroY = (DataH << 8) | DataL;                      //数据拼接,通过输出参数返回

    DataH = MPU6050_ReadReg(MPU6050_GYRO_ZOUT_H);       //读取陀螺仪Z轴的高8位数据
    DataL = MPU6050_ReadReg(MPU6050_GYRO_ZOUT_L);       //读取陀螺仪Z轴的低8位数据
    *GyroZ = (DataH << 8) | DataL;                      //数据拼接,通过输出参数返回
}

main主函数代码

#include "stm32f10x.h"                  // Device header
#include "Delay.h"
#include "OLED.h"
#include "MPU6050.h"

uint8_t ID;                             //定义用于存放ID号的变量
int16_t AX, AY, AZ, GX, GY, GZ;         //定义用于存放各个数据的变量

int main(void)
{
    /*模块初始化*/
    OLED_Init();        //OLED初始化
    MPU6050_Init();     //MPU6050初始化

    /*显示ID号*/
    OLED_ShowString(1, 1, "ID:");       //显示静态字符串
    ID = MPU6050_GetID();               //获取MPU6050的ID号
    OLED_ShowHexNum(1, 4, ID, 2);       //OLED显示ID号

    while (1)
    {
        MPU6050_GetData(&AX, &AY, &AZ, &GX, &GY, &GZ);      //获取MPU6050的数据
        OLED_ShowSignedNum(2, 1, AX, 5);                    //OLED显示数据
        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);
    }
}