STM32H7使用硬件I2C驱动MPU6050获得原始数据

开发平台

  • 野火STM32H750开发板
  • 板载的MPU6050

说在前面—关于I2C

I2C是一种双总线的通讯协议,关于I2C的资料其实网上有很多,而作为一名比较专业的嵌入式开发人员来讲,I2C、SPI、USART的时许应该是存在脑海中的(当然啦、针对偏硬件底层开发)。
那I2C到底长什么样子?没错就是如下图:在这里插入图片描述
这就是一段I2C的通讯时许。其实就是要包含SCL(时钟总线)、SDA(数据总线),以及起始信号、停止信号、应答信号和非应答信号。I2C可以通过GPIO进行时序模拟,也有MCU上自带有硬件I2C(都说ST的硬件I2C有BUG,但是我用到现在都没发现说有硬件BUG)。不管是模拟I2C还是硬件I2C,最终出来的信号都不会说偏离上图的时序的,因为规定就是规定,别人定制的协议就是这样传输。
有了I2C的使用基础,但是并不是每个I2C设备都是直接使用I2C,什么意思呢?举个例子就好了,现在有两个I2C设备,一个EEPROM,一个MPU6050。EEPROM的地址是0XA0,MPU6050的地址是0XD0。我们先写好一个单字节的写函数:

I2C_WriteByte(DEVICE_ADDR,REG_ADDR,DATA);

和一个单字节的读函数:

I2C_ReadBytte(DEVICE_ADDR,REG_ADDR,DATA);

在使用EEPROM的时候,由于EEPROM的读写一般使用页读写(因为比较快),而EEPROM的页读写就会将单字节读写的函数封装成页读写的函数。但使用MPU6050的时候,读写只是单字节的(当然,读最好是连续的读)。所以直接使用单字节读写函数即可。这就是设备与设备之间使用I2C的区别。所以你只需要明白I2C的基本读写、应答,I2C的使用基本上是没问题的,问题在于器件的使用,用I2C响什么位置写入或读出什么数据?最后得到什么功能?这才是使用I2C设备的问题所在。I2C设备一般会存在多个设备地址可选,这是电路设计问题,为的是预防设备地址冲突,这样就基本可以保证一个I2C设备就有一个设备地址。

关于MPU6050

MPU6050是常用测量角度等等的传感器,它多用于平衡车,飞控等等,需要快速且实时测量的事件。MPU6050支持I2C和SPI通讯,但一般都使用I2C(只因为节省引脚,肯定是!),I2C的速度能支持400K,SPI的速度能有20M,但实际上需要看MPU6050内陀螺仪与加速度计的配置。MPU6050内部带有温度(测芯片内部的温度,不能用作室外温度测量,很不准),陀螺仪和加速度计,顾名思义,就是测对应的物理量。

MPU6050的使用(具体查MOU6050寄存器手册):
1、唤醒MPU6050并选择时钟源----通过配置POWER MANAGEMENT 1寄存器。
在这里插入图片描述
2、配置MPU6050的滤波器—通过配置CONFIGURATION寄存器。
在这里插入图片描述
3、配置陀螺仪—通过配置GYROSCOPE CONFIGURATION寄存器。
在这里插入图片描述

4、配置加速度计–通过配置ACCELEROMETER CONFIGURATION寄存器。
在这里插入图片描述
5、MPU6050的ID读取----WHO AM I
在这里插入图片描述
至此,只要能读到MPU6050的ID,MPU6050基本可以正常读写了,剩下一些例如FIFO等的配置,可以看个人需求进行额外增加配置。

需要注意的点,MPU6050的原始数值,是有符号16位类型,因此关于数据读取的时候,需要使用short定义变量进行数据保存,否则你只有正值没有负值,这就不对了。

#include "mpu6050.h"



void MPU6050_Init(void)
{
	HAL_Delay(100);
	MPU6050_WriteByte(MPU6050_RA_PWR_MGMT_1,0X01);  //解除休眠模式
	MPU6050_WriteByte(MPU6050_RA_SMPLRT_DIV,0x07);	//配置陀螺仪采样率
	MPU6050_WriteByte(MPU6050_RA_CONFIG,	0x06);
	MPU6050_WriteByte(MPU6050_RA_ACCEL_CONFIG,0x01);//配置工作在16G模式下
	MPU6050_WriteByte(MPU6050_RA_GYRO_CONFIG,0x18);	//陀螺仪自检测量范围
	HAL_Delay(200);
}

/*
写数据到MPU6050里面
reg_add:寄存器地址
reg_dat:需要写入的数据
*/
void MPU6050_WriteByte(uint8_t reg_add,uint8_t reg_dat)
{
	//Sensors_I2C_WriteRegister(MPU6050_ADDRESS,reg_add,1,&reg_dat);
	I2C1_WriteByte(&reg_dat,MPU6050_ADDR,reg_add);
}

/*
读MPU6050数据
reg_add:寄存器地址
reg_dat:需要写入的数据
*/

void MPU6050_Read(uint8_t reg_add,unsigned char* Read,uint8_t num)
{
	I2C_READ(Read,MPU6050_ADDR,reg_add,num);
}

uint8_t MPU6050_ReadID(void)
{
	//unsigned char Re = 0;
  MPU6050_ReadData MPU6050_DARA;
  
	MPU6050_Read(MPU6050_ADDR_ID,&MPU6050_DARA.MPU6050_ID,1);
	if(MPU6050_DARA.MPU6050_ID != 0x68)
	{
		printf("MPU6050 dectected error!\r\n");
		return 0;
	}
	else
	{
		printf("MPU6050 ID = 0x%x\r\n",MPU6050_DARA.MPU6050_ID);
		return 1;
	}
}

void MPU6050_ACC_Read(short *accData)
{
	uint8_t buf[6];
    MPU6050_Read(MPU6050_ACC_OUT, buf, 6);
    accData[0] = (buf[0] << 8) | buf[1];
    accData[1] = (buf[2] << 8) | buf[3];
    accData[2] = (buf[4] << 8) | buf[5];
}

void MPU6050_Gyro_Read(short *gyroData)
{
	uint8_t buf[6];
    MPU6050_Read(MPU6050_GYRO_OUT,buf,6);
    gyroData[0] = (buf[0] << 8) | buf[1];
    gyroData[1] = (buf[2] << 8) | buf[3];
    gyroData[2] = (buf[4] << 8) | buf[5];

}
short MPU6050_GET_Angle(float x,float y,float z,uint8_t dir)
{
  float temp =0;
  float res = 0;
  switch(dir)
  {
  case 0:
    temp = sqrt((x*x + y*y))/z;
    res = atan(temp);
    break;
  case 1:
    temp = sqrt((y*y + z*z))/x;
    res = atan(temp);
    break;
  case 2:
    temp = sqrt((x*x + z*z))/y;
    res = atan(temp);
    break;
  
  }
  return (short)(res * 1800/3.14);
}

附上MPU6050的程序,I2C驱动自行实现即可,头文件中将寄存器都define了一遍,就不放上来了。

发布了45 篇原创文章 · 获赞 52 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/qq_42312125/article/details/101792686
今日推荐