stm32-软件I2C读写MPU6050(代码)

一、硬件电路

在这里插入图片描述

  • SCL引到了STM32的PB10号引脚,SDA引到了PB11号引脚
  • MPU605在SCL和SDA自带了两个上拉电阻,故不需要额外接上拉电阻

二、代码

1.MyI2C.c

#include "stm32f10x.h"                  // Device header
#include "Delay.h"

void MyI2C_W_SCL(uint8_t BitValue)  //写SCL
{
	GPIO_WriteBit(GPIOB,GPIO_Pin_10,(BitAction)BitValue);
	Delay_us(10);
}

void MyI2C_W_SDA(uint8_t BitValue)	//写SDA
{
	GPIO_WriteBit(GPIOB,GPIO_Pin_11,(BitAction)BitValue);
	Delay_us(10);
}

uint8_t MyI2C_R_SDA(void)  //读SDA
{
	uint8_t BitValue;
	BitValue=GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_11);
	Delay_us(10);
	return BitValue;
}

void MyI2C_Init(void)  //初始化
{
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
	
	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(GPIOB, GPIO_Pin_10 | GPIO_Pin_11);	//设置为高电平,处于空闲状态
}

void MyI2C_Start(void)  //开始条件
{
	MyI2C_W_SDA(1);	  //确保SDA释放后再释放SCL
	MyI2C_W_SCL(1);
	MyI2C_W_SDA(0);
	MyI2C_W_SCL(0);  //拉低时钟线,方便数据线上的数据变化(方便时序拼接)
}

void MyI2C_Stop(void)  //终止条件
{
	MyI2C_W_SDA(0);
	MyI2C_W_SCL(1);
	MyI2C_W_SDA(1);
}

void MyI2C_SendByte(uint8_t Byte)
{
	uint8_t i;
	for (i = 0; i < 8; i ++)
	{
		//趁着SCL是低电平,先把数据放在SDA上,再让SDA走一个时钟
		MyI2C_W_SDA(Byte & (0x80 >> i));  //高位在前
		MyI2C_W_SCL(1);
		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高电平,主机就可能读取数据
		if (MyI2C_R_SDA() == 1){Byte |= (0x80 >> i);}//高电平写1,低电平写0
		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_ReveiceAck(void)
{
	uint8_t AckBit;
	MyI2C_W_SDA(1);  //释放SDA线
	MyI2C_W_SCL(1);
	AckBit=MyI2C_R_SDA();
	MyI2C_W_SCL(0);  //方便拼接
	return AckBit;
}

2.MPU6050.c

#include "stm32f10x.h"                  // Device header
#include "MyI2C.h"
#include "MPU6050_Reg.h"

#define MPU6050_ADDRESS		0xD0

void MPU6050_WriteReg(uint8_t RegAddress,uint8_t Data)  //指定地址写
{
	MyI2C_Start();
	MyI2C_SendByte(MPU6050_ADDRESS);
	MyI2C_ReveiceAck();
	MyI2C_SendByte(RegAddress);
	MyI2C_ReveiceAck();
	MyI2C_SendByte(Data);
	MyI2C_ReveiceAck();
	MyI2C_Stop();
}

uint8_t MPU6050_ReadReg(uint8_t RegAddress)  //指定地址读
{
	uint8_t Data;
	MyI2C_Start();
	MyI2C_SendByte(MPU6050_ADDRESS);
	MyI2C_ReveiceAck();
	MyI2C_SendByte(RegAddress);
	MyI2C_ReveiceAck();
	
	MyI2C_Start();
	MyI2C_SendByte(MPU6050_ADDRESS|0x01);  //读写位改为1(表示读)
	MyI2C_ReveiceAck();
	Data=MyI2C_ReceiveByte();
	MyI2C_SendAck(1);  //产生非应答结束
	MyI2C_Stop();
	return Data;
}

void MPU6050_Init(void)  //初始化
{
	MyI2C_Init();
	MPU6050_WriteReg(MPU6050_PWR_MGMT_1,0x01);  //不复位,解除睡眠,不需要循环,温度传感器失能;选择陀螺仪时钟
	MPU6050_WriteReg(MPU6050_PWR_MGMT_2,0x00);  //无循环模式唤醒频率,后六位全给0,表示每个轴都不需要待机
	MPU6050_WriteReg(MPU6050_SMPLRT_DIV,0x09);  //10分频
	MPU6050_WriteReg(MPU6050_CONFIG,0x06);  //最后110,最平滑的数字低通滤波器
	MPU6050_WriteReg(MPU6050_GYRO_CONFIG,0x18);  
	//陀螺仪配置寄存器:前三位,自测使能,不自测;4,5位:满量程选择,11(最大量程);后三位无关位
	MPU6050_WriteReg(MPU6050_ACCEL_CONFIG, 0x18);
	//加速度计配置寄存器:自测000,满量程11,不用高通滤波器000
}

//获取数据(加速度计XYZ三个数据,陀螺仪传感器XYZ三个数据)
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);
	DataL=MPU6050_ReadReg(MPU6050_ACCEL_XOUT_L);
	*AccX=(DataH<<8)|DataL;
	
	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);
	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;
}

uint8_t MPU6050_GetID(void)
{
	return MPU6050_ReadReg(MPU6050_WHO_AM_I);
}

3.MPU6050_Reg.c

#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//加速度寄存器X轴的高8位
#define	MPU6050_ACCEL_XOUT_L	0x3C//加速度寄存器X轴的低8位
#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//陀螺仪寄存器x轴的高8位
#define	MPU6050_GYRO_XOUT_L		0x44//陀螺仪寄存器x轴的低8位
#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//电源管理寄存器1,地址是0x6B
#define	MPU6050_PWR_MGMT_2		0x6C//电源管理寄存器2,地址是0x6B
#define	MPU6050_WHO_AM_I		0x75
 
#endif

4.main.c

#include "stm32f10x.h"                  // Device header
#include "Delay.h"
#include "OLED.h"
#include "MPU6050.h"
 
uint8_t ID;
int16_t AX, AY, AZ, GX, GY, GZ;
 
int main(void)
{
	OLED_Init();
	MPU6050_Init();
	
	OLED_ShowString(1, 1, "ID:");
	ID = MPU6050_GetID();
	OLED_ShowHexNum(1, 4, ID, 2);
	
	while (1)
	{
		MPU6050_GetData(&AX, &AY, &AZ, &GX, &GY, &GZ);
		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);
	}
}
  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值