文章目录
1. MPU6050
1.1 运动学概念
1.2 工作原理
2. 参数
2.1 量程选择
2.2 I2C从机地址配置
3. 硬件电路
4. 框架图
5. 软件和硬件波形对比
6. 软件I2C读写MPU6050
6.1 程序整体构架
6.2 一些需要注意的点:
6.3 MPU6050初始化配置
6.4 传感器模型
7. 代码实现
7.1 MyI2C.c
7.2 MyI2C.h
7.3 MPU6050.C
7.4 MPU6050.H
7.5 MPU6050_Reg.h
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 工作原理
- 加速度计:
- 在X、Y、Z轴方向上测量加速度。通过检测重力加速度,可以推断出设备的倾斜角度。例如,在一个静止状态下,测量到的重力加速度可以用来计算设备相对于水平面的倾斜角度。
- 陀螺仪:
- 测量设备在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实现
- 波形特点:软件I2C的波形较为不规整,每个时钟周期和空闲时间都不一致。
- 操作特点:软件I2C时的引脚操作会有一定的延时,因此各个时钟周期的间隔和占空比都不均匀。
硬件I2C实现
- 波形特点:硬件I2C的波形更加规整,时钟周期和占空比非常一致。
- 操作特点:每个时钟周期后都有严格的延时,保证每个周期的时间相同。
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
-
自测使能:值:0 含义:不自测使能。
-
满量程选择:值:11 含义:选择最大量程。
-
无关位:后三位无关。
加速度计配置寄存器:0x18
- 自测使能:值:000 含义:不自测使能。
- 满量程选择:值:11 含义:选择最大量程。
- 高通滤波器:不使用。
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);
}
}