51单片机(九)驱动mpu6050

文章目录

mpu6050介绍

        MPU6050是一款流行的运动追踪传感器,它结合了3轴加速度计和3轴陀螺仪,能够提供全面的运动追踪能力。这种传感器特别适用于需要运动或方向检测的项目,如无人机、机器人和运动控制系统。

一、主要特性

(1)六轴运动追踪:MPU6050能够同时测量三个方向的加速度和三个方向的角速度,提供全面的运动追踪数据。
(2)I2C接口:它通过I2C(Inter-Integrated Circuit)总线与微控制器通信,这是一种常见的串行通信协议,允许多个设备通过两根线(数据线和时钟线)进行连接和通信。
(3)数字输出:所有测量数据都以数字形式提供,这意味着不需要额外的模拟到数字转换器(ADC)来处理信号。
(4)内置数字运动处理器(DMP):MPU6050内置的DMP可以处理复杂的运动检测算法,减轻主控制器的负担。-可编程的中断:支持可编程的中断功能,允许传感器在检测到特定运动事件时立即通知主控制器。
(5)电源管理:具有高效的电源管理系统,支持低功耗运行模式。

二、技术规格

(1)加速度计范围:±2g、±4g、±8g、±16g
(2)陀螺仪范围:±250、±500、±1000、±2000°/秒
(3)通信:I2C协议
(4)电源电压:2.3V至3.4V
(5)工作温度范围:-40°C至+85°C

三、应用领域

MPU6050广泛应用于需要运动或方向检测的领域,包括:

(1)无人机:用于稳定控制和导航。                
(2)机器人:提供平衡和运动控制。
(3)可穿戴设备:用于活动追踪和姿态检测。

mpu6050工作原理

        MPU6050的内部结构图如下:

        如图所示,mpu6050内置陀螺仪,通过六路adc采集加速度和加速度并通过i2c接口输出数据。详细的介绍将在以后的文章中展现。

mpu6050驱动代码(来自git)

mpu6050.c

#include "MPU6050.h"
#include "Soft_I2C.h"

void Delay1ms();		//@11.0592MHz
void MPU_Delay_Ms(uint16_t Milliseconds)	//
{
	while(Milliseconds--)
		Delay1ms();
}

//IIC连续写
//reg:要写入的寄存器地址
//len:要写入的长度
//buf:要写入的数据的首地址
//返回值:0,正常
//    其他,错误代码
uint8_t MPU_Write_Len(uint8_t reg, uint8_t len, uint8_t *buf)
{
	return i2c_mem_write(MPU_ADDR, reg, buf, len);
}

//IIC连续读
//reg:要读取的寄存器地址
//len:要读取的长度
//buf:读取到的数据存储区
//返回值:0,正常
//    其他,错误代码
uint8_t MPU_Read_Len(uint8_t reg, uint8_t len, uint8_t *buf)
{
	return i2c_mem_read(MPU_ADDR, reg, buf, len);
}

//IIC写一个字节 
//reg:寄存器地址
//Data:数据
//返回值:0,正常
//    其他,错误代码
uint8_t MPU_Write_Byte(uint8_t reg, uint8_t Data)
{
	return i2c_mem_write(MPU_ADDR, reg, &Data, 1);
}

//IIC读一个字节 
//reg:寄存器地址 
//返回值:读到的数据
uint8_t MPU_Read_Byte(uint8_t reg)
{
	uint8_t res;
	i2c_mem_read(MPU_ADDR, reg, &res, 1);
	return res;
}

//写入8位寄存器的一个位
uint8_t MPU_Write_Bit(uint8_t addr, uint8_t bitNum, uint8_t Data)
{
	return i2c_write_bit(MPU_ADDR, addr, bitNum, Data);
}

//写入8位寄存器的多个位
uint8_t MPU_Write_Bits(uint8_t addr, uint8_t bitStart, uint8_t length, uint8_t Data)
{
	return i2c_write_bits(MPU_ADDR, addr, bitStart, length, Data);
}

//读取一个位从8位器件的寄存器
uint8_t MPU_Read_Bit(uint8_t addr, uint8_t bitNum, uint8_t *Data)
{
	return i2c_read_bit(MPU_ADDR, addr, bitNum, Data);
}

//读取8位寄存器的多个位
uint8_t MPU_Read_Bits(uint8_t addr, uint8_t bitStart, uint8_t length, uint8_t *Data)
{
	return i2c_read_bits(MPU_ADDR, addr, bitStart, length, Data);
}


//初始化MPU6050
//返回值:0,成功
//    其他,错误代码
uint8_t MPU_Init(void)
{
	uint8_t res;
	MPU_Write_Byte(MPU_PWR_MGMT1_REG, 0X80);	//复位MPU6050
	MPU_Delay_Ms(100);
	MPU_Write_Byte(MPU_PWR_MGMT1_REG, 0X00);	//唤醒MPU6050 
	MPU_Set_Gyro_Fsr(3);						//陀螺仪传感器,±2000dps
	MPU_Set_Accel_Fsr(0);						//加速度传感器,±2g
	MPU_Set_Rate(50);							//设置采样率50Hz
	MPU_Write_Byte(MPU_INT_EN_REG, 0X01);		//使能数据就绪中断
	MPU_Write_Byte(MPU_USER_CTRL_REG, 0X00);	//I2C主模式关闭
	MPU_Write_Byte(MPU_FIFO_EN_REG, 0X00);		//关闭FIFO
	MPU_Write_Byte(MPU_INTBP_CFG_REG, 0X80);	//INT引脚低电平有效
	res = MPU_Read_Byte(MPU_DEVICE_ID_REG);
	if (res == MPU_ADDR)//器件ID正确
	{
		MPU_Write_Byte(MPU_PWR_MGMT1_REG, 0X01);	//设置CLKSEL,PLL X轴为参考
		MPU_Write_Byte(MPU_PWR_MGMT2_REG, 0X00);	//加速度与陀螺仪都工作
		MPU_Set_Rate(200);							//设置采样率为200Hz
	}
	else
		return 1;
	return 0;
}

//设置MPU6050陀螺仪传感器满量程范围
//fsr:0,±250dps;1,±500dps;2,±1000dps;3,±2000dps
//返回值:0,设置成功
//    其他,设置失败 
uint8_t MPU_Set_Gyro_Fsr(uint8_t fsr)
{
	return MPU_Write_Byte(MPU_GYRO_CFG_REG, fsr << 3);//设置陀螺仪满量程范围  
}

//设置MPU6050加速度传感器满量程范围
//fsr:0,±2g;1,±4g;2,±8g;3,±16g
//返回值:0,设置成功
//    其他,设置失败 
uint8_t MPU_Set_Accel_Fsr(uint8_t fsr)
{
	return MPU_Write_Byte(MPU_ACCEL_CFG_REG, fsr << 3);//设置加速度传感器满量程范围  
}

//设置MPU6050的数字低通滤波器
//lpf:数字低通滤波频率(Hz)
//返回值:0,设置成功
//    其他,设置失败 
uint8_t MPU_Set_LPF(uint16_t lpf)
{
	uint8_t Data = 0;
	if (lpf >= 188)Data = 1;
	else if (lpf >= 98)Data = 2;
	else if (lpf >= 42)Data = 3;
	else if (lpf >= 20)Data = 4;
	else if (lpf >= 10)Data = 5;
	else Data = 6;
	return MPU_Write_Byte(MPU_CFG_REG, Data);//设置数字低通滤波器  
}

//设置MPU6050的采样率(假定Fs=1KHz)
//rate:4~1000(Hz)
//返回值:0,设置成功
//    其他,设置失败 
uint8_t MPU_Set_Rate(uint16_t rate)
{
	uint8_t Data;
	if (rate>1000)rate = 1000;
	if (rate<4)rate = 4;
	Data = 1000 / rate - 1;
	Data = MPU_Write_Byte(MPU_SAMPLE_RATE_REG, Data);	//设置数字低通滤波器
	return MPU_Set_LPF(rate / 2);	//自动设置LPF为采样率的一半
}

//得到温度值
//返回值:温度值(扩大了100倍)
short MPU_Get_Temperature(void)
{
	uint8_t buf[2];
	short raw;
	float temp;
	MPU_Read_Len(MPU_TEMP_OUTH_REG, 2, buf);
	raw = ((uint16_t)buf[0] << 8) | buf[1];
	temp = 36.53 + ((double)raw) / 340;
	return temp * 100;;
}

//得到陀螺仪值(原始值)
//gx,gy,gz:陀螺仪x,y,z轴的原始读数(带符号)
//返回值:0,成功
//    其他,错误代码
uint8_t MPU_Get_Gyroscope(short *gx, short *gy, short *gz)
{
	uint8_t buf[6], res;
	res = MPU_Read_Len(MPU_GYRO_XOUTH_REG, 6, buf);
	if (res == 0)
	{
		*gx = ((uint16_t)buf[0] << 8) | buf[1];
		*gy = ((uint16_t)buf[2] << 8) | buf[3];
		*gz = ((uint16_t)buf[4] << 8) | buf[5];
	}
	return res;;
}

//得到加速度值(原始值)
//gx,gy,gz:陀螺仪x,y,z轴的原始读数(带符号)
//返回值:0,成功
//    其他,错误代码
uint8_t MPU_Get_Accelerometer(short *ax, short *ay, short *az)
{
	uint8_t buf[6], res;
	res = MPU_Read_Len(MPU_ACCEL_XOUTH_REG, 6, buf);
	if (res == 0)
	{
		*ax = ((uint16_t)buf[0] << 8) | buf[1];
		*ay = ((uint16_t)buf[2] << 8) | buf[3];
		*az = ((uint16_t)buf[4] << 8) | buf[5];
	}
	return res;;
}

mpu6050.h

#ifndef __MPU6050_H
#define __MPU6050_H

#include "stdint.h"


#define MPU_ACCEL_OFFS_REG		0X06	//accel_offs寄存器,可读取版本号,寄存器手册未提到
#define MPU_PROD_ID_REG			0X0C	//prod id寄存器,在寄存器手册未提到
#define MPU_SELF_TESTX_REG		0X0D	//自检寄存器X
#define MPU_SELF_TESTY_REG		0X0E	//自检寄存器Y
#define MPU_SELF_TESTZ_REG		0X0F	//自检寄存器Z
#define MPU_SELF_TESTA_REG		0X10	//自检寄存器A
#define MPU_SAMPLE_RATE_REG		0X19	//采样频率分频器
#define MPU_CFG_REG				0X1A	//配置寄存器
#define MPU_GYRO_CFG_REG		0X1B	//陀螺仪配置寄存器
#define MPU_ACCEL_CFG_REG		0X1C	//加速度计配置寄存器
#define MPU_MOTION_DET_REG		0X1F	//运动检测阀值设置寄存器
#define MPU_FIFO_EN_REG			0X23	//FIFO使能寄存器
#define MPU_I2CMST_CTRL_REG		0X24	//IIC主机控制寄存器
#define MPU_I2CSLV0_ADDR_REG	0X25	//IIC从机0器件地址寄存器
#define MPU_I2CSLV0_REG			0X26	//IIC从机0数据地址寄存器
#define MPU_I2CSLV0_CTRL_REG	0X27	//IIC从机0控制寄存器
#define MPU_I2CSLV1_ADDR_REG	0X28	//IIC从机1器件地址寄存器
#define MPU_I2CSLV1_REG			0X29	//IIC从机1数据地址寄存器
#define MPU_I2CSLV1_CTRL_REG	0X2A	//IIC从机1控制寄存器
#define MPU_I2CSLV2_ADDR_REG	0X2B	//IIC从机2器件地址寄存器
#define MPU_I2CSLV2_REG			0X2C	//IIC从机2数据地址寄存器
#define MPU_I2CSLV2_CTRL_REG	0X2D	//IIC从机2控制寄存器
#define MPU_I2CSLV3_ADDR_REG	0X2E	//IIC从机3器件地址寄存器
#define MPU_I2CSLV3_REG			0X2F	//IIC从机3数据地址寄存器
#define MPU_I2CSLV3_CTRL_REG	0X30	//IIC从机3控制寄存器
#define MPU_I2CSLV4_ADDR_REG	0X31	//IIC从机4器件地址寄存器
#define MPU_I2CSLV4_REG			0X32	//IIC从机4数据地址寄存器
#define MPU_I2CSLV4_DO_REG		0X33	//IIC从机4写数据寄存器
#define MPU_I2CSLV4_CTRL_REG	0X34	//IIC从机4控制寄存器
#define MPU_I2CSLV4_DI_REG		0X35	//IIC从机4读数据寄存器

#define MPU_I2CMST_STA_REG		0X36	//IIC主机状态寄存器
#define MPU_INTBP_CFG_REG		0X37	//中断/旁路设置寄存器
#define MPU_INT_EN_REG			0X38	//中断使能寄存器
#define MPU_INT_STA_REG			0X3A	//中断状态寄存器

#define MPU_ACCEL_XOUTH_REG		0X3B	//加速度值,X轴高8位寄存器
#define MPU_ACCEL_XOUTL_REG		0X3C	//加速度值,X轴低8位寄存器
#define MPU_ACCEL_YOUTH_REG		0X3D	//加速度值,Y轴高8位寄存器
#define MPU_ACCEL_YOUTL_REG		0X3E	//加速度值,Y轴低8位寄存器
#define MPU_ACCEL_ZOUTH_REG		0X3F	//加速度值,Z轴高8位寄存器
#define MPU_ACCEL_ZOUTL_REG		0X40	//加速度值,Z轴低8位寄存器

#define MPU_TEMP_OUTH_REG		0X41	//温度值高八位寄存器
#define MPU_TEMP_OUTL_REG		0X42	//温度值低8位寄存器

#define MPU_GYRO_XOUTH_REG		0X43	//陀螺仪值,X轴高8位寄存器
#define MPU_GYRO_XOUTL_REG		0X44	//陀螺仪值,X轴低8位寄存器
#define MPU_GYRO_YOUTH_REG		0X45	//陀螺仪值,Y轴高8位寄存器
#define MPU_GYRO_YOUTL_REG		0X46	//陀螺仪值,Y轴低8位寄存器
#define MPU_GYRO_ZOUTH_REG		0X47	//陀螺仪值,Z轴高8位寄存器
#define MPU_GYRO_ZOUTL_REG		0X48	//陀螺仪值,Z轴低8位寄存器

#define MPU_I2CSLV0_DO_REG		0X63	//IIC从机0数据寄存器
#define MPU_I2CSLV1_DO_REG		0X64	//IIC从机1数据寄存器
#define MPU_I2CSLV2_DO_REG		0X65	//IIC从机2数据寄存器
#define MPU_I2CSLV3_DO_REG		0X66	//IIC从机3数据寄存器

#define MPU_I2CMST_DELAY_REG	0X67	//IIC主机延时管理寄存器
#define MPU_SIGPATH_RST_REG		0X68	//信号通道复位寄存器
#define MPU_MDETECT_CTRL_REG	0X69	//运动检测控制寄存器
#define MPU_USER_CTRL_REG		0X6A	//用户控制寄存器
#define MPU_PWR_MGMT1_REG		0X6B	//电源管理寄存器1
#define MPU_PWR_MGMT2_REG		0X6C	//电源管理寄存器2 
#define MPU_FIFO_CNTH_REG		0X72	//FIFO计数寄存器高八位
#define MPU_FIFO_CNTL_REG		0X73	//FIFO计数寄存器低八位
#define MPU_FIFO_RW_REG			0X74	//FIFO读写寄存器
#define MPU_DEVICE_ID_REG		0X75	//器件ID寄存器

//如果AD0脚(9脚)接地,IIC地址为0X68(不包含最低位).
//如果接V3.3,则IIC地址为0X69(不包含最低位).
#define MPU_ADDR				0X68	//此为7位地址

//因为模块AD0默认接GND,所以转为读写地址后,为0XD1和0XD0(如果接VCC,则为0XD3和0XD2)  
#define MPU_READ    0XD1
#define MPU_WRITE   0XD0

uint8_t MPU_Init(void); 													//初始化MPU6050
uint8_t MPU_Read_Len(uint8_t reg, uint8_t len, uint8_t *buf);				//IIC连续读 
uint8_t MPU_Write_Len(uint8_t reg, uint8_t len, uint8_t *buf);				//IIC连续写
uint8_t MPU_Write_Byte(uint8_t reg, uint8_t Data);							//IIC写一个字节
uint8_t MPU_Read_Byte(uint8_t reg);											//IIC读一个字节
uint8_t MPU_Write_Bit(uint8_t addr, uint8_t bitNum, uint8_t Data);			//写入8位寄存器的一个位
uint8_t MPU_Write_Bits(uint8_t addr, uint8_t bitStart, uint8_t length, uint8_t Data);//写入8位寄存器的多个位
uint8_t MPU_Read_Bit(uint8_t addr, uint8_t bitNum, uint8_t *Data);			//读取一个位从8位器件的寄存器
uint8_t MPU_Read_Bits(uint8_t addr, uint8_t bitStart, uint8_t length, uint8_t *Data);//读取8位寄存器的多个位

uint8_t MPU_Set_Gyro_Fsr(uint8_t fsr);
uint8_t MPU_Set_Accel_Fsr(uint8_t fsr);
uint8_t MPU_Set_LPF(uint16_t lpf);
uint8_t MPU_Set_Rate(uint16_t rate);

int16_t MPU_Get_Temperature(void);
uint8_t MPU_Get_Gyroscope(int16_t *gx, int16_t *gy, int16_t *gz);
uint8_t MPU_Get_Accelerometer(int16_t *ax, int16_t *ay, int16_t *az);

#define MPU_Refresh() MPU_Write_Byte(MPU_PWR_MGMT1_REG, 0X00)	//唤醒MPU6050 

void MPU_Delay_Ms(uint16_t Milliseconds);						//

#endif

iic.c

#include "Soft_I2C.h"

#define I2C_TIMEOUT_TIMES 100	//超时倍数

//延时 用于等待应答时的超时判断 
void i2c_timeout_delay(void)	
{

}

void i2c_delay()	//每步的间隔 用于等待电平稳定和控制通讯速率
{

}

//SCL拉高 
void I2C_SCL_H(void)
{
	I2C_SCL = 1;
}

//SCL拉低 
void I2C_SCL_L(void)
{
	I2C_SCL = 0;
}

//SDA拉高 
void I2C_SDA_H(void)
{
	I2C_SDA = 1;
}

//SDA拉低 
void I2C_SDA_L(void)
{
	I2C_SDA = 0;
}

//读取SDA 
uint8_t I2C_SDA_Read(void)
{
	return I2C_SDA;
}

/*******************************************************************************
* 函 数 名       : i2c_start
* 函数功能		 : 产生I2C起始信号
* 输    入       : 无
* 输    出    	 : 无
*******************************************************************************/
void i2c_start(void)
{
	I2C_SDA_H();
    I2C_SCL_H();
    i2c_delay();

    I2C_SDA_L();	//当SCL为高电平时,SDA由高变为低
    i2c_delay();
    I2C_SCL_L();	//钳住I2C总线,准备发送或接收数据
}

/*******************************************************************************
* 函 数 名         : i2c_stop
* 函数功能		   : 产生I2C停止信号
* 输    入         : 无
* 输    出         : 无
*******************************************************************************/
void i2c_stop(void)
{
	I2C_SDA_L();
    I2C_SCL_H();
    i2c_delay();

    I2C_SDA_H();	//当SCL为高电平时,SDA由低变为高
    i2c_delay();
}

/*******************************************************************************
* 函 数 名         : i2c_ack
* 函数功能		   : 产生ACK应答
* 输    入         : 无
* 输    出         : 无
*******************************************************************************/
void i2c_ack(void)
{
    I2C_SCL_L();
    I2C_SDA_L();	//SDA为低电平
    i2c_delay();

    I2C_SCL_H();
    i2c_delay();
    I2C_SCL_L();
	I2C_SDA_H();	
}

/*******************************************************************************
* 函 数 名         : i2c_nack
* 函数功能		   : 产生NACK非应答
* 输    入         : 无
* 输    出         : 无
*******************************************************************************/
void i2c_nack(void)
{
    I2C_SCL_L();
    I2C_SDA_H();	//SDA为高电平
    i2c_delay();

    I2C_SCL_H();
    i2c_delay();
    I2C_SCL_L();
}

/*******************************************************************************
* 函 数 名         : i2c_wait_ack
* 函数功能		   : 等待应答信号到来
* 输    入         : 无
* 输    出         : 1,接收应答失败
        			 0,接收应答成功
*******************************************************************************/
uint8_t i2c_wait_ack(void)
{
    uint16_t time_temp = 0;

    I2C_SCL_H();
    i2c_delay();
    while(I2C_SDA_Read())				//等待SDA为低电平
    {
        time_temp++;
		i2c_timeout_delay();
        if(time_temp > I2C_TIMEOUT_TIMES)	//超时则强制结束I2C通信
        {
            i2c_stop();
            return 1;
        }
    }
    I2C_SCL_L();
    return 0;
}

/*******************************************************************************
* 函 数 名         : i2c_write_byte
* 函数功能		   : I2C发送一个字节
* 输    入         : dat:发送一个字节
* 输    出         : 无
*******************************************************************************/
void i2c_write_byte(uint8_t dat)
{
    uint8_t i = 0;

    I2C_SCL_L();
    for(i = 0; i<8; i++)	//循环8次将一个字节传出,先传高再传低位
    {
        if((dat & 0x80) > 0)
            I2C_SDA_H();
        else
            I2C_SDA_L();
        dat <<= 1;
        i2c_delay();
        I2C_SCL_H();
        i2c_delay();
        I2C_SCL_L();
        i2c_delay();
    }
}

/*******************************************************************************
* 函 数 名         : i2c_read_byte
* 函数功能		   : I2C读一个字节
* 输    入         : ack = 1时,发送ACK,ack = 0,发送nACK
* 输    出         : 应答或非应答
*******************************************************************************/
uint8_t i2c_read_byte(uint8_t ack)
{
    uint8_t i = 0, receive = 0;

    for(i = 0; i < 8; i++ )	//循环8次将一个字节读出,先读高再传低位
    {
        I2C_SCL_L();
        i2c_delay();
        I2C_SCL_H();
        receive <<= 1;
        if(I2C_SDA_Read())
			receive++;
        i2c_delay();
    }
    if (!ack)
        i2c_nack();
    else
        i2c_ack();

    return receive;
}

/*******************************************************************************
* 函 数 名         : i2c_mem_write
* 函数功能		   : I2C对指定器件、指定寄存器连续写入
* 输    入         : 器件地址、器件寄存器地址、待输入数据首地址、待输入数据长度
* 输    出         : 0: 成功 1:失败
*******************************************************************************/
uint8_t i2c_mem_write(uint8_t DevAddress, uint8_t MemAddress, uint8_t *pData, uint16_t Len)
{
	i2c_start();
	i2c_write_byte(DevAddress << 1);
	if(i2c_wait_ack())
		return 1;
	i2c_write_byte(MemAddress);
	if(i2c_wait_ack())
		return 1;
	while(Len--)
	{
		i2c_write_byte(*pData++);
		if(i2c_wait_ack())
			return 1;
	}
	i2c_stop();
	return 0;
}

/*******************************************************************************
* 函 数 名         : i2c_mem_read
* 函数功能		   : I2C对指定器件、指定寄存器连续读取
* 输    入         : 器件地址、器件寄存器地址、数据缓冲区首地址、数据长度
* 输    出         : 0: 成功 1:失败
*******************************************************************************/
uint8_t i2c_mem_read(uint8_t DevAddress, uint8_t MemAddress, uint8_t *pBuffer, uint16_t Len)
{				  
    i2c_start();  
	i2c_write_byte(DevAddress << 1);		//发送写命令	   
	if(i2c_wait_ack())
		return 1;
    i2c_write_byte(MemAddress); 			//发送字地址  
	if(i2c_wait_ack())
		return 1;   
	i2c_start();  	 	   
	i2c_write_byte(DevAddress << 1 | 1); 	//进入接收模式         			   
	if(i2c_wait_ack())
		return 1;
	while(Len--)
	{
		*pBuffer++ = i2c_read_byte(Len!=0);	//读取字节	
	}
    i2c_stop();								//产生一个停止条件  
	return 0;
}

/**写入8位寄存器的一个位。
* @参数 DevAddress	I2C从器件地址
* @参数 addr    	I2C从器件内部地址
* @参数 bitNum  	写入的比特位(0-7)
* @参数 data    	写入数据
* @返回值 返回状态 (0=成功)
*/
uint8_t i2c_write_bit(uint8_t DevAddress, uint8_t addr, uint8_t bitNum, uint8_t Data)
{
	uint8_t b;
	if (!i2c_mem_read(DevAddress, addr, &b, 1))
	{
		b = (Data != 0) ? (b | (1 << bitNum)) : (b & ~(1 << bitNum));
		return i2c_mem_write(DevAddress, addr, &b, 1);	//写入数据
	}
	else
		return 1;
}

/**写入8位寄存器的多个位。
* @参数 DevAddress	I2C从器件地址
* @参数 addr     I2C从器件内部地址
* @参数 bitStart 第一位的写入位置(0-7)
* @参数 length   写的比特数(不超过8)
* @参数 Data     写入数据
* @返回值 返回状态 (0=成功)
*/
uint8_t i2c_write_bits(uint8_t DevAddress, uint8_t addr, uint8_t bitStart, uint8_t length, uint8_t Data)
{
	//      010 要写入的值
	// 76543210 比特位
	//    xxx   args: bitStart=4, length=3
	// 00011100 掩码字节
	// 10101111 原始值(样本)
	// 10100011 原始值 & ~掩码
	// 10101011 掩码 | 原始值
	uint8_t b, mask = 0;
	if (!i2c_mem_read(DevAddress, addr, &b, 1))
	{
		mask = (((1 << length) - 1) << (bitStart - length + 1));	//掩码
		Data <<= (bitStart - length + 1);	//把写入的数据移动到位
		Data &= mask;
		b &= ~(mask);
		b |= Data;

		return i2c_mem_write(DevAddress, addr, &b, 1);	//写入数据
	}
	else
		return 1;
}
/**读取一个位从8位器件的寄存器。
* @参数 DevAddress	I2C从器件地址
* @参数 addr    I2C从器件内部地址
* @参数 bitNum  位的位置来读取(0-7)
* @参数 *data   数据存储地址
* @返回值(0=成功)
*/
uint8_t i2c_read_bit(uint8_t DevAddress, uint8_t addr, uint8_t bitNum, uint8_t *Data)
{
	uint8_t b;
	if (!i2c_mem_read(DevAddress, addr, &b, 1))
	{
		*Data = b & (1 << bitNum);
		return 0;
	}
	else
	{
		return 1;
	}
}
/**读取8位寄存器的多个位。
* @参数 DevAddress	I2C从器件地址
* @参数 addr    I2C从器件内部地址
* @参数 bitStart第一位的位置读取(0-7)
* @参数 length  位读取@参数长度数(不超过8)
* @参数 *data   数据存储地址(即'101'任何bitStart位置读取将等于0X05)
* @返回值(0=成功)
*/
uint8_t i2c_read_bits(uint8_t DevAddress, uint8_t addr, uint8_t bitStart, uint8_t length, uint8_t *Data)
{
	// 01101001 读取字节
	// 76543210 比特位
	//    xxx   args: bitStart=4, length=3
	//    010   masked
	//   -> 010 shifted
	uint8_t b, mask = 0;
	if (!i2c_mem_read(DevAddress, addr, &b, 1))
	{

		mask = ((1 << length) - 1) << (bitStart - length + 1);
		b &= mask;
		b >>= (bitStart - length + 1);
		*Data = b;
		return 0;
	}
	else
		return 1;
}

i2c.h

#ifndef SOFT_I2C_H_
#define SOFT_I2C_H_

#include <reg52.h>
#include "stdint.h"

//定义I2C控制脚
sbit I2C_SCL = P3^4;				//SCL时钟线
sbit I2C_SDA = P3^5;				//SDA数据线

//I2C所有操作函数				 
void i2c_start(void);				//发送I2C开始信号
void i2c_stop(void);	  			//发送I2C停止信号
uint8_t i2c_wait_ack(void); 		//I2C等待ACK信号
void i2c_ack(void);					//I2C发送ACK信号
void i2c_nack(void);				//I2C不发送ACK信号

void i2c_write_byte(uint8_t txd);	//I2C发送一个字节
uint8_t i2c_read_byte(uint8_t ack);	//I2C读取一个字节
uint8_t i2c_mem_write(uint8_t DevAddress, uint8_t MemAddress, uint8_t *pData, uint16_t Len);	//I2C对指定器件、指定寄存器连续写入
uint8_t i2c_mem_read(uint8_t DevAddress, uint8_t MemAddress, uint8_t *pBuffer, uint16_t Len);	//I2C对指定器件、指定寄存器连续读取
uint8_t i2c_write_bit(uint8_t DevAddress, uint8_t addr, uint8_t bitNum, uint8_t Data);			//写入8位寄存器的一个位
uint8_t i2c_write_bits(uint8_t DevAddress, uint8_t addr, uint8_t bitStart, uint8_t length, uint8_t Data);//写入8位寄存器的多个位
uint8_t i2c_read_bit(uint8_t DevAddress, uint8_t addr, uint8_t bitNum, uint8_t *Data);			//读取一个位从8位器件的寄存器
uint8_t i2c_read_bits(uint8_t DevAddress, uint8_t addr, uint8_t bitStart, uint8_t length, uint8_t *Data);//读取8位寄存器的多个位

#endif

总结

        mpu6050资料众多,使用方便,适用于多种应用场景,传统的51单片机受限于i2c读取速率,实时性不一定符合应用需求,建议用32位单片机。

好耶,又水了一篇

  • 5
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 5
    评论
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值