目录
一、介绍
MPU6050是一款集成了三轴陀螺仪、三轴加速度计、温度传感器及 DMP 数字运动处理器的六轴运动传感器,可通过 I2C 接口测量物体三维加速度并直接解算姿态;它具备高度集成、体积小巧、低功耗、性能稳定、成本低廉、开发简单的优点,还能减轻主控芯片运算负担;常被用于无人机飞控、平衡小车、智能穿戴、手机姿态识别、等体感设备,是入门和实用度极高的主流六轴传感器

以下是MPU6050陀螺仪的参数:
|-------|-----------------------|
| 型号 | MPU6050 |
| 工作电压 | DC 3.3~5V |
| 通信接口 | I2C |
| 主芯片 | MPU6050 |
| 芯片内置 | 16bit AD转换器,16位数据输出 |
| 工作温度 | -40~+85℃ |
| 陀螺仪范围 | ±250 500 1000 2000°/s |
| 全量程范围 | ±2/±4/±8/±16 g |
(资料分享见文末)
二、传感器原理
1.尺寸图

2.引脚描述
|--------|--------------|
| 引脚 | 描述 |
| VCC | 3.3-5V |
| GND | 地 |
| SDA | I2C串行时钟线 |
| SCL | I2C串行数据线 |
| XDA | 连接其他设备的主机数据口 |
| XCL | 给I2C设备提供主时钟 |
| AD0 | I2C器件地址选择位 |
| INT | 中断引脚 |
三、程序设计
1.使用STM32F103C8T6读取陀螺仪数据、加速度数据
2.将读取得到的数据同时在OLED上显示
|-------------|-----|
| MPU6050_SCL | PA0 |
| MPU6050_SDA | PA1 |
| OLED_SCL | PB6 |
| OLED_SDA | PB7 |
| 串口 | 串口1 |
main.c文件
cpp
#include "stm32f10x.h"
#include "led.h"
#include "usart.h"
#include "delay.h"
#include "oled.h"
#include "MPU6050.h"
/*****************辰哥单片机设计******************
STM32
* 文件 : MPU6050实验
* 版本 : V1.0
* 日期 : 2026.3.10
* MCU : STM32F103C8T6
* 接口 : 见代码
* IP账号 : 辰哥单片机设计(同BILIBILI|抖音|快手|小红书|CSDN|公众号|视频号等)
* 作者 : 辰哥
* 工作室 : 异方辰电子工作室
* 官方网站 : www.yfcdz.cn
**********************BEGIN***********************/
uint8_t ID; //定义用于存放ID号的变量
int16_t AX, AY, AZ, GX, GY, GZ; //定义用于存放各个数据的变量
uint8_t fall_status;
int main(void)
{
SystemInit();//配置系统时钟为72M
delay_init(72);
LED_Init();
LED_On();
MPU6050_Init(); //MPU6050初始化
USART1_Config();//串口初始化
OLED_Init(); // OLED初始化
printf("Start \n");
delay_ms(1000);
//OLED_ShowString(1, 1, "ID:"); //显示静态字符串
ID = MPU6050_GetID(); //获取MPU6050的ID号
while (1)
{
//加速度
OLED_ShowString(0,0,"X",16,1);
OLED_ShowString(0,16,"Y",16,1);
OLED_ShowString(0,32,"Z",16,1);
//陀螺仪
OLED_ShowString(64,0,"X",16,1);
OLED_ShowString(64,16,"Y",16,1);
OLED_ShowString(64,32,"Z",16,1);
MPU6050_GetData(&AX, &AY, &AZ, &GX, &GY, &GZ);
OLED_ShowintNum(12, 0, AX, 5, 16, 1);
OLED_ShowintNum(12, 16, AY, 5, 16, 1);
OLED_ShowintNum(12, 32, AZ, 5, 16, 1);
OLED_ShowintNum(76, 0, GX, 5, 16, 1);
OLED_ShowintNum(76, 16, GY, 5, 16, 1);
OLED_ShowintNum(76, 32, GZ, 5, 16, 1);
//OLED_ShowChinese(16,48,0,16,1);
OLED_ShowChinese(0,48,0,16,1);
OLED_ShowChinese(16,48,1,16,1);
OLED_ShowChinese(32,48,2,16,1);
OLED_ShowChinese(48,48,3,16,1);
OLED_ShowChar(64,48,':',16,1);
fall_status = MPU6050_CheckFall();
if(fall_status)
{
OLED_ShowChinese(94,48,0,16,1); // 显示"是"
printf("Fall detected! \n");
LED_Off();
}
else
{
OLED_ShowChinese(94,48,1,16,1); // 显示"否"
LED_On();
}
OLED_Refresh();
// delay_ms(100); // 检测间隔100ms,平衡响应速度和防抖
}
}
MPU6050.c文件
cpp
#include "MPU6050.h"
#include "math.h"
#include "stdlib.h"
/*****************辰哥单片机设计******************
STM32
* 文件 : MPU6050实验
* 版本 : V1.0
* 日期 : 2026.3.10
* MCU : STM32F103C8T6
* 接口 : 见代码
* IP账号 : 辰哥单片机设计(同BILIBILI|抖音|快手|小红书|CSDN|公众号|视频号等)
* 作者 : 辰哥
* 工作室 : 异方辰电子工作室
* 官方网站 : www.yfcdz.cn
**********************BEGIN***********************/
#define XY_ACC_THRESH 1800
#define FALL_DEBOUNCE_CNT 1 // 防抖次数:连续1次超过阈值即判定(值越大越稳定,越小越灵敏)
#define FALL_CHECK_INTERVAL 100 // 检测间隔(ms)
static uint8_t fall_detect_cnt = 0; // 静态变量:连续异常计数(仅本文件可见)
/************************ 软件I2C底层驱动函数实现 ************************/
// I2C写SCL引脚电平(BitValue=1:拉高,0:拉低)
void MPU6050_W_SCL(uint8_t BitValue)
{
// 设置SCL引脚电平(开漏输出模式,拉高=释放总线,拉低=强制输出低)
GPIO_WriteBit(MPU6050_I2C_PORT, MPU6050_I2C_SCL_PIN, (BitAction)BitValue);
delay_us(10); // 延时10us:保证I2C时序稳定(软件I2C必须加延时)
}
// I2C写SDA引脚电平(BitValue=1:拉高,0:拉低)
void MPU6050_W_SDA(uint8_t BitValue)
{
GPIO_WriteBit(MPU6050_I2C_PORT, MPU6050_I2C_SDA_PIN, (BitAction)BitValue);
delay_us(10); // 延时10us:保证I2C时序稳定
}
// I2C读SDA引脚电平(返回:1=高电平,0=低电平)
uint8_t MPU6050_R_SDA(void)
{
uint8_t BitValue;
// 读取SDA引脚当前电平(输入模式)
BitValue = GPIO_ReadInputDataBit(MPU6050_I2C_PORT, MPU6050_I2C_SDA_PIN);
delay_us(10); // 延时10us:保证采样稳定
return BitValue;
}
// I2C引脚初始化(配置为开漏输出)
void MPU6050_IIC_Init(void)
{
// 1. 使能GPIO端口时钟
RCC_APB2PeriphClockCmd(MPU6050_I2C_CLK, ENABLE);
// 2. 配置GPIO引脚参数
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_OD; // 开漏输出(I2C标准模式)
GPIO_InitStructure.GPIO_Pin = MPU6050_I2C_SCL_PIN | MPU6050_I2C_SDA_PIN; // SCL+SDA引脚
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; // 输出速率50MHz
GPIO_Init(MPU6050_I2C_PORT, &GPIO_InitStructure); // 应用配置
// 3. 初始化时将SCL/SDA拉高(I2C总线空闲状态)
GPIO_SetBits(MPU6050_I2C_PORT, MPU6050_I2C_SCL_PIN | MPU6050_I2C_SDA_PIN);
}
// 发送I2C起始信号(时序:SCL高时,SDA从高拉低)
void MPU6050_Start(void)
{
MPU6050_W_SDA(1); // SDA先拉高
MPU6050_W_SCL(1); // SCL拉高(总线空闲)
MPU6050_W_SDA(0); // SDA拉低(起始信号)
MPU6050_W_SCL(0); // SCL拉低(准备发送数据)
}
// 发送I2C停止信号(时序:SCL高时,SDA从低拉高)
void MPU6050_Stop(void)
{
MPU6050_W_SDA(0); // SDA先拉低
MPU6050_W_SCL(1); // SCL拉高
MPU6050_W_SDA(1); // SDA拉高(停止信号)
}
// I2C发送1字节数据(参数Byte:要发送的字节,高位先行)
void MPU6050_SendByte(uint8_t Byte)
{
uint8_t i;
// 循环发送8位(高位到低位)
for (i = 0; i < 8; i++)
{
// 1. 输出当前位(Byte & 0x80:取最高位)
MPU6050_W_SDA(!!(Byte & (0x80 >> i)));
// 2. SCL拉高(从机采样数据)
MPU6050_W_SCL(1);
// 3. SCL拉低(准备发送下一位)
MPU6050_W_SCL(0);
}
}
// I2C接收1字节数据(返回:接收到的字节,高位先行)
uint8_t MPU6050_ReceiveByte(void)
{
uint8_t i, Byte = 0x00;
MPU6050_W_SDA(1); // 释放SDA总线(由从机控制)
// 循环接收8位(高位到低位)
for (i = 0; i < 8; i++)
{
MPU6050_W_SCL(1); // SCL拉高(从机输出数据)
// 读取当前位并写入Byte(左移累加)
if(MPU6050_R_SDA()) Byte |= (0x80 >> i);
MPU6050_W_SCL(0); // SCL拉低(准备接收下一位)
}
return Byte;
}
// 发送I2C应答位(参数AckBit:0=应答,1=非应答)
void MPU6050_SendAck(uint8_t AckBit)
{
MPU6050_W_SDA(AckBit); // 输出应答位(0=拉低,1=拉高)
MPU6050_W_SCL(1); // SCL拉高(从机采样应答)
MPU6050_W_SCL(0); // SCL拉低
}
// 接收I2C应答位(返回:0=从机应答,1=从机非应答)
uint8_t MPU6050_ReceiveAck(void)
{
uint8_t AckBit;
MPU6050_W_SDA(1); // 释放SDA总线
MPU6050_W_SCL(1); // SCL拉高(读取应答)
AckBit = MPU6050_R_SDA(); // 读取应答位
MPU6050_W_SCL(0); // SCL拉低
return AckBit;
}
/************************ MPU6050核心功能函数实现 ************************/
#define MPU6050_ADDR 0xD0 // MPU6050的I2C设备地址(0x68 << 1,左移1位含读写位)
// 写MPU6050寄存器(参数:RegAddress=寄存器地址,Data=要写入的数据)
void MPU6050_WriteReg(uint8_t RegAddress, uint8_t Data)
{
MPU6050_Start(); // 1. 发送起始信号
MPU6050_SendByte(MPU6050_ADDR); // 2. 发送设备写地址(0xD0=写)
MPU6050_ReceiveAck(); // 3. 等待从机应答
MPU6050_SendByte(RegAddress); // 4. 发送寄存器地址
MPU6050_ReceiveAck(); // 5. 等待从机应答
MPU6050_SendByte(Data); // 6. 发送要写入的数据
MPU6050_ReceiveAck(); // 7. 等待从机应答
MPU6050_Stop(); // 8. 发送停止信号
}
// 读MPU6050寄存器(参数:RegAddress=寄存器地址;返回:读取到的数据)
uint8_t MPU6050_ReadReg(uint8_t RegAddress)
{
uint8_t Data;
MPU6050_Start(); // 1. 发送起始信号
MPU6050_SendByte(MPU6050_ADDR); // 2. 发送设备写地址(先写寄存器地址)
MPU6050_ReceiveAck(); // 3. 等待从机应答
MPU6050_SendByte(RegAddress); // 4. 发送寄存器地址
MPU6050_ReceiveAck(); // 5. 等待从机应答
MPU6050_Start(); // 6. 重新发送起始信号(切换为读模式)
MPU6050_SendByte(MPU6050_ADDR|0x01); // 7. 发送设备读地址(0xD1=读)
MPU6050_ReceiveAck(); // 8. 等待从机应答
Data = MPU6050_ReceiveByte(); // 9. 接收寄存器数据
MPU6050_SendAck(1); // 10. 发送非应答(结束接收)
MPU6050_Stop(); // 11. 发送停止信号
return Data;
}
// MPU6050初始化(配置:唤醒传感器、加速度/陀螺仪量程、采样率)
void MPU6050_Init(void)
{
MPU6050_IIC_Init(); // 1. 初始化I2C引脚
// 2. 唤醒MPU6050(电源管理寄存器1:0x00=使用内部8MHz时钟,唤醒)
MPU6050_WriteReg(MPU6050_PWR_MGMT_1, 0x00);
// 3. 设置采样率分频(采样率=1000/(1+9)=100Hz)
MPU6050_WriteReg(MPU6050_SMPLRT_DIV, 0x09);
// 4. 配置低通滤波(0x00=256Hz,无滤波)
MPU6050_WriteReg(MPU6050_CONFIG, 0x00);
// 5. 配置陀螺仪量程(0x18=±2000°/s,最大量程)
MPU6050_WriteReg(MPU6050_GYRO_CONFIG, 0x18);
// 6. 配置加速度计量程(0x18=±16g,最大量程)
MPU6050_WriteReg(MPU6050_ACCEL_CONFIG, 0x18);
}
// 获取MPU6050的ID号(返回:0x68=正常,其他值=通信异常)
uint8_t MPU6050_GetID(void)
{
// 读取WHO_AM_I寄存器(默认值0x68)
return MPU6050_ReadReg(MPU6050_WHO_AM_I);
}
// 获取加速度/陀螺仪原始数据
// 参数说明:
// AccX/AccY/AccZ:输出加速度计原始值(±16g量程下,1LSB=2048 LSB/g)
// GyroX/GyroY/GyroZ:输出陀螺仪原始值(±2000°/s量程下,1LSB=16.4 LSB/(°/s))
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位数据
// 读取加速度计X轴数据(高8位+低8位拼接为16位有符号数)
DataH = MPU6050_ReadReg(MPU6050_ACCEL_XOUT_H);
DataL = MPU6050_ReadReg(MPU6050_ACCEL_XOUT_L);
*AccX = (DataH << 8) | DataL;
// 读取加速度计Y轴数据
DataH = MPU6050_ReadReg(MPU6050_ACCEL_YOUT_H);
DataL = MPU6050_ReadReg(MPU6050_ACCEL_YOUT_L);
*AccY = (DataH << 8) | DataL;
// 读取加速度计Z轴数据
DataH = MPU6050_ReadReg(MPU6050_ACCEL_ZOUT_H);
DataL = MPU6050_ReadReg(MPU6050_ACCEL_ZOUT_L);
*AccZ = (DataH << 8) | DataL;
// 读取陀螺仪X轴数据
DataH = MPU6050_ReadReg(MPU6050_GYRO_XOUT_H);
DataL = MPU6050_ReadReg(MPU6050_GYRO_XOUT_L);
*GyroX = (DataH << 8) | DataL;
// 读取陀螺仪Y轴数据
DataH = MPU6050_ReadReg(MPU6050_GYRO_YOUT_H);
DataL = MPU6050_ReadReg(MPU6050_GYRO_YOUT_L);
*GyroY = (DataH << 8) | DataL;
// 读取陀螺仪Z轴数据
DataH = MPU6050_ReadReg(MPU6050_GYRO_ZOUT_H);
DataL = MPU6050_ReadReg(MPU6050_GYRO_ZOUT_L);
*GyroZ = (DataH << 8) | DataL;
}
/************************ 摔倒检测核心函数 ************************/
// 返回值:1=检测到摔倒,0=正常
uint8_t MPU6050_CheckFall(void)
{
int16_t ax, ay; // 临时存储X/Y轴加速度值
uint32_t xy_acc_sum; // X+Y轴加速度绝对值之和(避免正负抵消)
uint8_t fall_flag = 0; // 摔倒标志(0=正常,1=摔倒)
// 1. 获取当前X、Y轴加速度数据(Z轴/陀螺仪传0,无需读取)
MPU6050_GetData(&ax, &ay, 0, 0, 0, 0);
// 2. 计算X+Y轴加速度绝对值之和(abs():取绝对值,避免正负抵消)
xy_acc_sum = abs(ax) + abs(ay);
// 3. 摔倒判定逻辑
if (xy_acc_sum > XY_ACC_THRESH) // 超过阈值=异常
{
fall_detect_cnt++; // 连续异常计数+1
// 连续异常次数达到防抖阈值=判定为摔倒
if (fall_detect_cnt >= FALL_DEBOUNCE_CNT)
{
fall_flag = 1; // 设置摔倒标志
fall_detect_cnt = 0; // 重置计数(避免重复触发)
}
}
else // 未超过阈值=正常
{
fall_detect_cnt = 0; // 重置异常计数
fall_flag = 0; // 清除摔倒标志
}
return fall_flag; // 返回判定结果
}
MPU6050.h文件
cpp
#ifndef __MPU6050_H
#define __MPU6050_H
#include "stm32f10x.h"
#include "delay.h"
/*****************辰哥单片机设计******************
STM32
* 文件 : MPU6050实验
* 版本 : V1.0
* 日期 : 2026.3.10
* MCU : STM32F103C8T6
* 接口 : 见代码
* IP账号 : 辰哥单片机设计(同BILIBILI|抖音|快手|小红书|CSDN|公众号|视频号等)
* 作者 : 辰哥
* 工作室 : 异方辰电子工作室
* 官方网站 : www.yfcdz.cn
**********************BEGIN***********************/
/************************ 软件I2C引脚配置宏 ************************/
#define MPU6050_I2C_PORT GPIOA // I2C总线使用的GPIO端口
#define MPU6050_I2C_SCL_PIN GPIO_Pin_0 // SCL时钟引脚
#define MPU6050_I2C_SDA_PIN GPIO_Pin_1 // SDA数据引脚
#define MPU6050_I2C_CLK RCC_APB2Periph_GPIOA // I2C端口对应的时钟
/************************ MPU6050寄存器地址定义 ************************/
#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 // 加速度计X轴高8位数据寄存器
#define MPU6050_ACCEL_XOUT_L 0x3C // 加速度计X轴低8位数据寄存器
#define MPU6050_ACCEL_YOUT_H 0x3D // 加速度计Y轴高8位数据寄存器
#define MPU6050_ACCEL_YOUT_L 0x3E // 加速度计Y轴低8位数据寄存器
#define MPU6050_ACCEL_ZOUT_H 0x3F // 加速度计Z轴高8位数据寄存器
#define MPU6050_ACCEL_ZOUT_L 0x40 // 加速度计Z轴低8位数据寄存器
#define MPU6050_TEMP_OUT_H 0x41 // 温度传感器高8位数据寄存器
#define MPU6050_TEMP_OUT_L 0x42 // 温度传感器低8位数据寄存器
#define MPU6050_GYRO_XOUT_H 0x43 // 陀螺仪X轴高8位数据寄存器
#define MPU6050_GYRO_XOUT_L 0x44 // 陀螺仪X轴低8位数据寄存器
#define MPU6050_GYRO_YOUT_H 0x45 // 陀螺仪Y轴高8位数据寄存器
#define MPU6050_GYRO_YOUT_L 0x46 // 陀螺仪Y轴低8位数据寄存器
#define MPU6050_GYRO_ZOUT_H 0x47 // 陀螺仪Z轴高8位数据寄存器
#define MPU6050_GYRO_ZOUT_L 0x48 // 陀螺仪Z轴低8位数据寄存器
#define MPU6050_PWR_MGMT_1 0x6B // 电源管理寄存器1(唤醒传感器、选择时钟源)
#define MPU6050_PWR_MGMT_2 0x6C // 电源管理寄存器2(禁用轴)
#define MPU6050_WHO_AM_I 0x75 // 设备ID寄存器(默认值0x68,用于校验通信)
/************************ I2C底层驱动函数声明(软件模拟I2C) ************************/
void MPU6050_IIC_Init(void); // I2C引脚初始化(配置为开漏输出)
void MPU6050_Start(void); // 发送I2C起始信号(SCL高时SDA拉低)
void MPU6050_Stop(void); // 发送I2C停止信号(SCL高时SDA拉高)
void MPU6050_SendByte(uint8_t Byte); // I2C发送1字节数据(高位先行)
uint8_t MPU6050_ReceiveByte(void); // I2C接收1字节数据(高位先行)
void MPU6050_SendAck(uint8_t AckBit); // 发送应答位(0=应答,1=非应答)
uint8_t MPU6050_ReceiveAck(void); // 接收从机应答位
/************************ MPU6050功能函数声明 ************************/
void MPU6050_WriteReg(uint8_t RegAddress, uint8_t Data); // 写MPU6050寄存器(指定地址写入1字节)
uint8_t MPU6050_ReadReg(uint8_t RegAddress); // 读MPU6050寄存器(指定地址读取1字节)
void MPU6050_Init(void); // MPU6050初始化(配置量程、采样率、唤醒)
uint8_t MPU6050_GetID(void); // 获取MPU6050的ID号(校验通信是否正常)
// 获取加速度/陀螺仪原始数据(输出:AccX/Y/Z=加速度值,GyroX/Y/Z=陀螺仪值)
void MPU6050_GetData(int16_t *AccX, int16_t *AccY, int16_t *AccZ,
int16_t *GyroX, int16_t *GyroY, int16_t *GyroZ);
uint8_t MPU6050_CheckFall(void); // 摔倒检测函数(返回:1=摔倒,0=正常)
#endif // __MPU6050_H 头文件结束
四、实验效果
