【STM32】详解使用STM32获取Mpu6050陀螺仪和加速度传感器数据(江科大学习笔记)

目录

I2C

起始条件:

终止条件:

 发送一个字节

接收一个字节

 接收发送应答

 代码

I2C

I2C.C

I2C.h

Mpu6050

Mpu6050.c

Mpu6050.h

Mpu6050Reg.h

main.c

结果


 

要想获取Mpu6050陀螺仪和加速度那就需要了解一下Mpu6050。Mpu6050使用的是I2C通讯

先了解一下

I2C

起始条件:

SCL高电平期间,SDA从高电平切换到低电平

终止条件:

SCL高电平期间,SDA从低电平切换到高电平

83095f8bf00246048403b6ef52deac98.png

 发送一个字节

7ee9d75606f84bd9a87d88ad49a8535a.png

接收一个字节

16491f9eb4774002805a50b77a8af6ca.png

 接收发送应答

2c257f3391344f648ed34a2e83bfa680.png

 代码

下来让我们用代码实现一下I2C通讯:

I2C

I2C.C

#include "stm32f10x.h"                  // Device header
#include "Delay.h"
void MyI2C_W_SCL(uint8_t  Bitvalue)//SCL电平,可以给这个函数0或1
{                                                        //设置引脚引脚后续可以改
	GPIO_WriteBit(GPIOB,GPIO_Pin_10,(BitAction)Bitvalue);//bitactiion就是一个枚举类型的变量,给1或0就可以拉低或拉高电平
	Delay_us(10);//延时10um
}
void MyI2C_W_SDA(uint8_t  Bitvalue)//SAD电平,可以给这个函数0或1
{                                                       //设置引脚引脚后续可以改
	GPIO_WriteBit(GPIOB,GPIO_Pin_11,(BitAction)Bitvalue);//bitactiion就是一个枚举类型的变量,表示这个位是高电平还是低电平
	Delay_us(10);//延时10um
}
//因为stm32读和写不是一个寄存器
uint8_t MyI2C_R_SDA(void)//读SDA
{
	uint8_t Bitvalue;
	Bitvalue = GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_11);/*函数 GPIO_ReadInputDataBit 读的是 GPIOx_IDR
读的是当 IO 口设置为输入状态时候的 IO 口电平状态值。*/
	Delay_us(10);//延时
	return Bitvalue;//返回值
}



void MyI2C_inite(void)//初始化引脚
{
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);//因为mpu6050接的是PB10和11脚
	
	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(GPIOA, GPIO_Pin_10 | GPIO_Pin_11);
	
}

void MyI2C_start(void)
{
	MyI2C_W_SDA(1);//先给这两条线的电平先释放
	MyI2C_W_SCL(1);

	MyI2C_W_SDA(0);//先拉底SDA再拉低SCL
	MyI2C_W_SCL(0);
}
void MyI2C_stop(void)
{
	
	MyI2C_W_SDA(0);//先拉低SDA确保他处于低电平
	MyI2C_W_SCL(1);//然后拉高SCL再拉高SDA终止通讯
	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));//取最高位向右移,与取最高位依次取出字节
	MyI2C_W_SCL(1);//释放SCL拉低SCL给它一个脉冲继续取下一个数据
	MyI2C_W_SCL(0);
	}
	
}
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高电平是读SCL低电平是写 
	if (MyI2C_R_SDA() == 1){Byte|=(0x80>>i);}
	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();//接收SDA的信号
	MyI2C_W_SCL(0);//进入下一个时序单位

	return AckBit;
	
}

I2C.h

#ifndef __MYI2C_H
#define __MYI2C_H

void MyI2C_inite(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);
 void Mpu6050_GetData(int16_t*AccX,int16_t*AccY,int16_t*AccZ,int16_t*GyroX,int16_t*GyroY,int16_t*GyroZ);
#endif

写好了i2c的通讯就可以来写mpu6050的代码

Mpu6050

Mpu6050.c

#include "stm32f10x.h"                 
#include "Mpu6050Reg.h"
#include "myi2c.h"
#include "Delay.h"
 
#define    MPU6050_ADDRESS    0XD0 

void MPU6050_WriteReg(uint8_t RegAddress, uint8_t Data)//写入地址和写入数据
{
	MyI2C_start();//打开I2C通讯
	MyI2C_SendByte(MPU6050_ADDRESS);//从机地址+读写位,0是写,1读
	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);//从机地址
	MyI2C_ReceiveAck();//返回一个应答位,接收回应
	MyI2C_SendByte(RegAddress);//发送指定寄存器
	MyI2C_ReceiveAck();//返回一个应答位,接收回应
	
	MyI2C_start();//打开I2C通讯
	MyI2C_SendByte(MPU6050_ADDRESS | 0x01);//从机地址+读写位,0是写,1读
	MyI2C_ReceiveAck();//返回一个应答位,接收回应
	Data = MyI2C_ReceiveByte();//读取信息存储到data
	MyI2C_SendAck(1);//1不给从机应答,0给从机应答.
	MyI2C_stop();//停止通讯
	
	return Data;//返回值
}

void Mpu6050_Init(void)//mpu6050初始化
{
	MyI2C_inite();//初始化I2C通讯
	MPU6050_WriteReg(MPU6050_PWR_MGMT_1, 0x01);//陀螺仪时钟
	MPU6050_WriteReg(MPU6050_PWR_MGMT_2, 0x00);//六个轴均不待机
	MPU6050_WriteReg(MPU6050_SMPLRT_DIV, 0x09);//采样率分频   10分频   值越小越快
	MPU6050_WriteReg(MPU6050_CONFIG, 0x06);//配置寄存器
	MPU6050_WriteReg(MPU6050_GYRO_CONFIG, 0x18);//陀螺仪配置寄存器
	MPU6050_WriteReg(MPU6050_ACCEL_CONFIG, 0x18);//加速度计配置寄存器
}

uint8_t Mpu6050_GetID(void)//获取mpu6050ID号
{
	return MPU6050_ReadReg(MPU6050_WHO_AM_I);
}

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);//读取加速度X,Y,Z轴高八位和低八位
	DataL = MPU6050_ReadReg(MPU6050_ACCEL_XOUT_L);
	*AccX = (DataH << 8) | DataL;//获取16位存入指针
	
	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);//读取陀螺仪X,Y,Z轴高八位和低八位
	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;
}

Mpu6050.h

#ifndef _Mpu6050_H
#define _Mpu6050_H

void Mpu6050_WriteReg(uint8_t RegAddress,uint8_t Data); //指定地址写寄存器
uint8_t Mpu6050_ReadReg(uint8_t RegAddress);
uint8_t Mpu6050_GetID(void);
void Mpu6050_Init(void);
void Mpu6050_GetData(int16_t*AccX,int16_t*AccY,int16_t*AccZ,int16_t*GyroX,int16_t*GyroY,int16_t*GyroZ);

#endif

还需要Mpu6050的寄存器地址

Mpu6050Reg.h

#ifndef _Mpu6050Reg_H//宏定义mpu6050的寄存器
#define _Mpu6050Reg_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

实现把Mpu6050数据显示到oled屏幕上

main.c

#include "stm32f10x.h"                  
#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
	//显示内容mpu6050的ID号
	OLED_ShowString(1, 1, "ID:");
	ID = Mpu6050_GetID();//获取ID号
	OLED_ShowHexNum(1, 4, ID, 2);
	
	while (1)
	{
		Mpu6050_GetData(&AX, &AY, &AZ, &GX, &GY, &GZ);//获取AX到GZ的值
		//显示加速度计和陀螺仪到OLED
		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);
	}
}

结果

8d362a76886b4981978de54276bbac2c.jpeg

参考视视频:

【STM32入门教程-2023持续更新中-哔哩哔哩】 https://b23.tv/mVJHA3h

 

 

 

物联沃分享整理
物联沃-IOTWORD物联网 » 【STM32】详解使用STM32获取Mpu6050陀螺仪和加速度传感器数据(江科大学习笔记)

发表评论