STM32通过I2C软件读写MPU6050

文章目录​​​​​​​

[1. MPU6050](#1. MPU6050)

[1.1 运动学概念](#1.1 运动学概念)

[1.2 工作原理](#1.2 工作原理)

[2. 参数](#2. 参数)

[2.1 量程选择](#2.1 量程选择)

[2.2 I2C从机地址配置](#2.2 I2C从机地址配置)

[3. 硬件电路](#3. 硬件电路)

[4. 框架图](#4. 框架图)

[5. 软件和硬件波形对比](#5. 软件和硬件波形对比)

[6. 软件I2C读写MPU6050](#6. 软件I2C读写MPU6050)

[6.1 程序整体构架](#6.1 程序整体构架)

[6.2 一些需要注意的点:](#6.2 一些需要注意的点:)

[6.3 MPU6050初始化配置](#6.3 MPU6050初始化配置)

[6.4 传感器模型](#6.4 传感器模型)

[7. 代码实现](#7. 代码实现)

[​​​​​​​7.1 MyI2C.c](#7.1 MyI2C.c)

[​​​​​​​7.2 MyI2C.h](#7.2 MyI2C.h)

[7.3 MPU6050.C](#7.3 MPU6050.C)

[7.4 MPU6050.H](#7.4 MPU6050.H)

[7.5 MPU6050_Reg.h](#7.5 MPU6050_Reg.h)

[7.6 main.c](#7.6 main.c)


1. MPU6050

对于I2C通信和MPU6050的详细解析可以看下面这篇文章

STM32单片机I2C通信详解-CSDN博客

对于STM32通过I2C硬件读写MPU6050的代码,可以看下面这篇文章

STM32通过I2C硬件读写MPU6050-CSDN博客

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

3轴加速度计(Accelerometer):测量X、Y、Z轴的加速度

3轴陀螺仪传感器(Gyroscope):测量X、Y、Z轴的角速度

1.1 运动学概念

  • 欧拉角
    • 欧拉角是用来描述三维空间中刚体旋转的三个角度:俯仰角(Pitch)、滚转角(Roll)和偏航角(Yaw)。
    • 俯仰角(Pitch):飞机机头上下倾斜的角度。
    • 滚转角(Roll):飞机左右倾斜的角度。
    • 偏航角(Yaw):飞机左右转向的角度。

1.2 工作原理

  1. 加速度计
    • 在X、Y、Z轴方向上测量加速度。通过检测重力加速度,可以推断出设备的倾斜角度。例如,在一个静止状态下,测量到的重力加速度可以用来计算设备相对于水平面的倾斜角度。
  2. 陀螺仪
    • 测量设备在X、Y、Z轴上的角速度。陀螺仪可以用于检测设备的旋转运动,比如快速转动或者缓慢旋转等。
    • 陀螺仪具有动态稳定性,但不具备静态稳定性。

2. 参数

ADC和数据存储

  • 16位ADC:MPU6050集成了16位的ADC,用于将模拟信号转换为数字信号,量化范围为-32768到32767。
  • 量化过程:ADC将模拟信号转换为数字信号,并以两个字节进行存储。

加速度计满量程选择:±2、±4、±8、±16(g)

陀螺仪满量程选择: ±250、±500、±1000、±2000(°/sec)

可配置的数字低通滤波器

  • 允许用户根据应用需求配置滤波器,滤除噪声和干扰。

可配置的时钟源

  • 支持多种时钟源,包括内部振荡器、外部参考时钟等。

采样率

  • 采样率可以通过配置寄存器设置,决定数据采集的频率。

I2C地址配置

  • I2C从机地址
    • 当AD0引脚接低电平(AD0=0):地址为0x68。
    • 当AD0引脚接高电平(AD0=1):地址为0x69。
    • 具体地址配置决定了在I2C总线上的唯一性,避免地址冲突。

2.1 量程选择

满量程选择

  • 剧烈运动:选择较大的满量程,确保测量范围足够大。
  • 平缓运动:选择较小的满量程,提升测量分辨率。

加速度计满量程示例

  • ±16g
    • 读取的ADC值为最大值32768时,对应实际加速度为16g。
    • ADC值为32768的一半(16384)时,对应加速度为8g。
  • ±2g
    • 读取的ADC值为最大值32768时,对应实际加速度为2g。
    • ADC值为32768的一半(16384)时,对应加速度为1g。

测量分辨率

  • 满量程越小,测量分辨率越高,测量越精细。
  • 满量程越大,测量范围越广。
  • ADC值与加速度值呈线性关系,可以通过乘一个系数从ADC值计算出实际加速度。

2.2 I2C从机地址配置

二进制地址转换为十六进制

  • 以从机地址1101000为例。
  • 把7位二进制数1101000转换为十六进制,即分割低4位和高3位:0110 1000,转换后为0x68

I2C时序中的地址格式

  • 在I2C通信时,需要发送7位从机地址1101000加上1位读写位。
  • 认为0x68是从机地址,需要将0x68左移1位,再加上读写位(0或1)。
  • 转换步骤:
    • 0x68左移1位:1101 0000(即0xD0)。
    • 再与读写位(0或1)进行或操作:(0x68 << 1) | 0(0x68 << 1) | 1

实际应用

  • 写操作时,从机地址为0xD0
  • 读操作时,从机地址为0xD1

3. 硬件电路

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

4. 框架图

5. 软件和硬件波形对比

软件I2C实现

  1. 波形特点:软件I2C的波形较为不规整,每个时钟周期和空闲时间都不一致。
  2. 操作特点:软件I2C时的引脚操作会有一定的延时,因此各个时钟周期的间隔和占空比都不均匀。

硬件I2C实现

  1. 波形特点:硬件I2C的波形更加规整,时钟周期和占空比非常一致。
  2. 操作特点:每个时钟周期后都有严格的延时,保证每个周期的时间相同。

6. 软件I2C读写MPU6050

6.1 程序整体构架

首先建立I2C通信层的.c和.h模块,再建立MPU6050.c, 最后是main.c

  • Main.c
    • 调用MPU6050初始化函数。
    • 循环读取数据并进行显示。
  • MPU6050.c
    • 基于I2C通信协议,设定设备地址,发送读写指令。
    • 配置寄存器,读取传感器数据。
  • I2C.c
    • 初始化GPIO。
    • 编写基本的I2C操作函数,包括起始条件、终止条件、发送/接收一个字节、发送/接收应答等。

6.2 一些需要注意的点:

起始和终止条件

  • 起始条件:在SCL高电平期间,SDA由高电平变为低电平,产生起始条件(Start Condition)。这表示一次I2C通信的开始。

  • 终止条件:在SCL高电平期间,SDA由低电平变为高电平,产生终止条件(Stop Condition)。这表示一次I2C通信的结束。

数据传输过程

  • 数据位传输:在SCL低电平期间,主机可以改变SDA的电平,即在SCL的每一个低电平周期内,主机将要传输的数据位放在SDA线上。

  • 数据位读取:在SCL高电平期间,从机读取SDA线上的数据。此时,SDA线上的电平表示当前传输的数据位。

应答位的发送和接收

  • 发送应答:在主机发送完一个字节数据后,从机会在下一个SCL高电平期间将SDA线拉低,表示已接收到数据(ACK)。

  • 接收应答:主机在发送完数据后,将SDA线释放为高电平,然后在SCL高电平期间读取SDA的电平,判断是否收到从机的应答。

I2C引脚配置

  • 开漏输出+弱上拉:I2C引脚配置为开漏输出,并启用弱上拉电阻。这意味着,当引脚输出高电平时,实际上是释放引脚,由上拉电阻将其拉高。当引脚输出低电平时,引脚被拉低。

接收Byte程序

  • 循环读取SDA:在接收数据时,主机会不断循环读取SDA引脚的电平。在SCL时钟的驱动下,从机会在SDA线上放置数据。
  • 数据有效性:由于从机会在SCL高电平期间改变SDA的电平,因此主机在读取SDA时,可以获得从机发送的数据。

6.3 MPU6050初始化配置

配置电源管理寄存器1:0000 0001

设备复位:值:0 含义:设备不复位。

睡眠模式:值:0 含义:解除睡眠。

循环模式:值:0 含义:不需要循环。

无关位:值:0

温度传感器失能:值:0 含义:温度传感器不失能。

时钟源选择:值:001 含义:选择X轴的陀螺仪时钟。

配置电源管理寄存器2:0x00

循环唤醒模式:值:00 含义:不需要循环唤醒模式。

待机位:值:每个轴的待机位全部给0。

电源管理寄存器1和2主要用于控制MPU6050的电源状态和工作模式。通过设置这些参数,可以确保MPU6050在最佳状态下运行,并且根据需要调整其功耗表现。

**采样率分频:**值:0x09 含义:10分频,8位决定了数据输出的快慢,值越小越快。

**配置寄存器:**寄存器值:0x06

  • 外部同步:全部给0,不需要。

  • 数字低通滤波器:110,最平滑的滤波。

陀螺仪配置寄存器:0x18

  1. 自测使能:值:0 含义:不自测使能。

  2. 满量程选择:值:11 含义:选择最大量程。

  3. 无关位:后三位无关。

加速度计配置寄存器:0x18

  1. 自测使能:值:000 含义:不自测使能。
  2. 满量程选择:值:11 含义:选择最大量程。
  3. 高通滤波器:不使用。

6.4 传感器模型

这里借用一张图片

  • 陀螺仪旋转检测

    • 陀螺仪绕Z轴旋转,陀螺仪Z轴会输出对应的角速度。
    • 图示中,三维空间的坐标轴X、Y、Z对应陀螺仪的三个方向。
    • 通过陀螺仪的测量,可以获得绕某一轴的旋转角速度信息,帮助理解物体的旋转状态。
  • 加速度计检测

    • 在正方体中放置一个小球,小球压在哪个面上就产生对应轴的输出。
    • 当前芯片水平放置,对应正方体的X轴、Y轴数据基本为0。
    • 小球在底面上,产生1个g的重力加速度,这里显示的数据是1943。
    • 1943代表Z轴方向的支持力,所以Z轴加速度为正。
  • 数据计算

    • 根据测量值1943和满量程32768(16位ADC),计算得出加速度的实际值。
    • 根据测量值1943和满量程32768(16位ADC),计算得出加速度的实际值。
    • 公式: 1943/32768 = Z/16g
    • 所以Z轴的加速度为0.95g。
  • 测量值比例公式

    • 读到的ADC值与满量程值之间的比例关系。
    • 公式: 读到的数据/32768 = X/满量程 (其中,满量程在16位系统中为-32768到32767)

7. 代码实现

软件I2C读写MPU6050

7.1 MyI2C.c

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

/*引脚配置层*/

/**
  * 函    数:I2C写SCL引脚电平
  * 参    数:BitValue 协议层传入的当前需要写入SCL的电平,范围0~1
  * 返 回 值:无
  * 注意事项:此函数需要用户实现内容,当BitValue为0时,需要置SCL为低电平,当BitValue为1时,需要置SCL为高电平
  */
void MyI2C_W_SCL(uint8_t BitValue)
{
	GPIO_WriteBit(GPIOB, GPIO_Pin_10, (BitAction)BitValue);		//根据BitValue,设置SCL引脚的电平
	Delay_us(10);												//延时10us,防止时序频率超过要求
}

/**
  * 函    数:I2C写SDA引脚电平
  * 参    数:BitValue 协议层传入的当前需要写入SDA的电平,范围0~0xFF
  * 返 回 值:无
  * 注意事项:此函数需要用户实现内容,当BitValue为0时,需要置SDA为低电平,当BitValue非0时,需要置SDA为高电平
  */
void MyI2C_W_SDA(uint8_t BitValue)
{
	GPIO_WriteBit(GPIOB, GPIO_Pin_11, (BitAction)BitValue);		//根据BitValue,设置SDA引脚的电平,BitValue要实现非0即1的特性
	Delay_us(10);												//延时10us,防止时序频率超过要求
}

/**
  * 函    数:I2C读SDA引脚电平
  * 参    数:无
  * 返 回 值:协议层需要得到的当前SDA的电平,范围0~1
  * 注意事项:此函数需要用户实现内容,当前SDA为低电平时,返回0,当前SDA为高电平时,返回1
  */
uint8_t MyI2C_R_SDA(void)
{
	uint8_t BitValue;
	BitValue = GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_11);		//读取SDA电平
	Delay_us(10);												//延时10us,防止时序频率超过要求
	return BitValue;											//返回SDA电平
}

/**
  * 函    数:I2C初始化
  * 参    数:无
  * 返 回 值:无
  * 注意事项:此函数需要用户实现内容,实现SCL和SDA引脚的初始化
  */
void MyI2C_Init(void)
{
	/*开启时钟*/
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);	//开启GPIOB的时钟
	
	/*GPIO初始化*/
	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);					//将PB10和PB11引脚初始化为开漏输出
	
	/*设置默认电平*/
	GPIO_SetBits(GPIOB, GPIO_Pin_10 | GPIO_Pin_11);			//设置PB10和PB11引脚初始化后默认为高电平(释放总线状态)
}

/*协议层*/

/**
  * 函    数:I2C起始
  * 参    数:无
  * 返 回 值:无
  */
void MyI2C_Start(void)
{
	MyI2C_W_SDA(1);							//释放SDA,确保SDA为高电平
	MyI2C_W_SCL(1);							//释放SCL,确保SCL为高电平
	MyI2C_W_SDA(0);							//在SCL高电平期间,拉低SDA,产生起始信号
	MyI2C_W_SCL(0);							//起始后把SCL也拉低,即为了占用总线,也为了方便总线时序的拼接
}

/**
  * 函    数:I2C终止
  * 参    数:无
  * 返 回 值:无
  */
void MyI2C_Stop(void)
{
	MyI2C_W_SDA(0);							//拉低SDA,确保SDA为低电平
	MyI2C_W_SCL(1);							//释放SCL,使SCL呈现高电平
	MyI2C_W_SDA(1);							//在SCL高电平期间,释放SDA,产生终止信号
}

/**
  * 函    数:I2C发送一个字节
  * 参    数:Byte 要发送的一个字节数据,范围:0x00~0xFF
  * 返 回 值:无
  */
void MyI2C_SendByte(uint8_t Byte)
{
	uint8_t i;
	for (i = 0; i < 8; i ++)				//循环8次,主机依次发送数据的每一位
	{
		MyI2C_W_SDA(Byte & (0x80 >> i));	//使用掩码的方式取出Byte的指定一位数据并写入到SDA线
		MyI2C_W_SCL(1);						//释放SCL,从机在SCL高电平期间读取SDA
		MyI2C_W_SCL(0);						//拉低SCL,主机开始发送下一位数据
	}
}

/**
  * 函    数:I2C接收一个字节
  * 参    数:无
  * 返 回 值:接收到的一个字节数据,范围:0x00~0xFF
  */
uint8_t MyI2C_ReceiveByte(void)
{
	uint8_t i, Byte = 0x00;					//定义接收的数据,并赋初值0x00,此处必须赋初值0x00,后面会用到
	MyI2C_W_SDA(1);							//接收前,主机先确保释放SDA,避免干扰从机的数据发送
	for (i = 0; i < 8; i ++)				//循环8次,主机依次接收数据的每一位
	{
		MyI2C_W_SCL(1);						//释放SCL,主机机在SCL高电平期间读取SDA
		if (MyI2C_R_SDA() == 1){Byte |= (0x80 >> i);}	//读取SDA数据,并存储到Byte变量
														//当SDA为1时,置变量指定位为1,当SDA为0时,不做处理,指定位为默认的初值0
		MyI2C_W_SCL(0);						//拉低SCL,从机在SCL低电平期间写入SDA
	}
	return Byte;							//返回接收到的一个字节数据
}

/**
  * 函    数:I2C发送应答位
  * 参    数:Byte 要发送的应答位,范围:0~1,0表示应答,1表示非应答
  * 返 回 值:无
  */
void MyI2C_SendAck(uint8_t AckBit)
{
	MyI2C_W_SDA(AckBit);					//主机把应答位数据放到SDA线
	MyI2C_W_SCL(1);							//释放SCL,从机在SCL高电平期间,读取应答位
	MyI2C_W_SCL(0);							//拉低SCL,开始下一个时序模块
}

/**
  * 函    数:I2C接收应答位
  * 参    数:无
  * 返 回 值:接收到的应答位,范围:0~1,0表示应答,1表示非应答
  */
uint8_t MyI2C_ReceiveAck(void)
{
	uint8_t AckBit;							//定义应答位变量
	MyI2C_W_SDA(1);							//接收前,主机先确保释放SDA,避免干扰从机的数据发送
	MyI2C_W_SCL(1);							//释放SCL,主机机在SCL高电平期间读取SDA
	AckBit = MyI2C_R_SDA();					//将应答位存储到变量里
	MyI2C_W_SCL(0);							//拉低SCL,开始下一个时序模块
	return AckBit;							//返回定义应答位变量
}

7.2 MyI2C.h

#ifndef __MYI2C_H
#define __MYI2C_H

void MyI2C_Init(void);
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

7.3 MPU6050.C

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

#define MPU6050_ADDRESS		0xD0		//MPU6050的I2C从机地址

/**
  * 函    数:MPU6050写寄存器
  * 参    数:RegAddress 寄存器地址,范围:参考MPU6050手册的寄存器描述
  * 参    数:Data 要写入寄存器的数据,范围:0x00~0xFF
  */
void MPU6050_WriteReg(uint8_t RegAddress, uint8_t Data)
{
	MyI2C_Start();						//I2C起始
	MyI2C_SendByte(MPU6050_ADDRESS);	//发送从机地址,读写位为0,表示即将写入
	MyI2C_ReceiveAck();					//接收应答
	MyI2C_SendByte(RegAddress);			//发送寄存器地址
	MyI2C_ReceiveAck();					//接收应答
	MyI2C_SendByte(Data);				//发送要写入寄存器的数据
	MyI2C_ReceiveAck();					//接收应答
	MyI2C_Stop();						//I2C终止
}

/**
  * 函    数:MPU6050读寄存器
  * 参    数:RegAddress 寄存器地址,范围:参考MPU6050手册的寄存器描述
  * 返 回 值:读取寄存器的数据,范围:0x00~0xFF
  */
uint8_t MPU6050_ReadReg(uint8_t RegAddress)
{
	uint8_t Data;
	
	MyI2C_Start();						//I2C起始
	MyI2C_SendByte(MPU6050_ADDRESS);	//发送从机地址,读写位为0,表示即将写入
	MyI2C_ReceiveAck();					//接收应答
	MyI2C_SendByte(RegAddress);			//发送寄存器地址
	MyI2C_ReceiveAck();					//接收应答
	
	MyI2C_Start();						//I2C重复起始
	MyI2C_SendByte(MPU6050_ADDRESS | 0x01);	//发送从机地址,读写位为1,表示即将读取
	MyI2C_ReceiveAck();					//接收应答
	Data = MyI2C_ReceiveByte();			//接收指定寄存器的数据
	MyI2C_SendAck(1);					//发送应答,给从机非应答,终止从机的数据输出
	MyI2C_Stop();						//I2C终止
	
	return Data;
}

/**
  * 函    数:MPU6050初始化
  * 参    数:无
  * 返 回 值:无
  */
void MPU6050_Init(void)
{
	MyI2C_Init();									//先初始化底层的I2C
	
	/*MPU6050寄存器初始化,需要对照MPU6050手册的寄存器描述配置,此处仅配置了部分重要的寄存器*/
	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
}

/**
  * 函    数:MPU6050获取ID号
  * 参    数:无
  * 返 回 值:MPU6050的ID号
  */
uint8_t MPU6050_GetID(void)
{
	return MPU6050_ReadReg(MPU6050_WHO_AM_I);		//返回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;						//数据拼接,通过输出参数返回
}

7.4 MPU6050.H

#ifndef __MPU6050_H
#define __MPU6050_H

void MPU6050_WriteReg(uint8_t RegAddress, uint8_t Data);
uint8_t MPU6050_ReadReg(uint8_t RegAddress);

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

#endif

7.5 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

7.6 main.c

#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);
	}
}
相关推荐
芋头莎莎5 小时前
STM32 51单片机设计半导体制冷片温控设计
stm32·嵌入式硬件·51单片机
ღ 金龍戲水 ღ7 小时前
蓝桥杯竞赛单片机组备赛【经验帖】
经验分享·单片机·蓝桥杯
搬砖的小码农_Sky7 小时前
单片机和FPGA有什么区别?
单片机·嵌入式硬件·fpga开发
折途9 小时前
拆解一下用了两年的三十多块的剃须刀
嵌入式硬件
BT-BOX10 小时前
STM32仿真proteus位带操作和keil增加头文件C文件
c语言·stm32·proteus
7yewh11 小时前
嵌入式硬件实战提升篇(一)-泰山派RK3566制作多功能小手机
linux·arm开发·驱动开发·嵌入式硬件·物联网·智能手机·硬件架构
@晓凡12 小时前
STM32编程遇到的问题随笔【一】
stm32·单片机·嵌入式硬件
虾球xz13 小时前
游戏引擎学习第11天
stm32·学习·游戏引擎
DevinLGT13 小时前
6Pin Type-C Pin脚定义:【图文讲解】
人工智能·单片机·嵌入式硬件
小A15914 小时前
STM32完全学习——系统时钟设置
stm32·嵌入式硬件·学习