江协科技10-3软件I2C读写MPU6050

因为我们的读写操作都是依靠SCL和SDA的电平变化来达成的,所以直接封装好,然后再进行操作

不多bb,直接看代码吧

main.c

cpp 复制代码
#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);
	}
}

myl2C.c

cpp 复制代码
#include "stm32f10x.h"                  // Device header
#include "Delay.h"

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

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

uint8_t MyI2C_R_SDA(void)
{
	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);
}
//还记得吗怎么开始的,即SCL和SDA都是高电平,然后SDA先变为低电平然后SCL再变为低电平
void MyI2C_Start(void)
{
	MyI2C_W_SDA(1);
	MyI2C_W_SCL(1);
	MyI2C_W_SDA(0);
	MyI2C_W_SCL(0);
}


//还记得怎么停止的吗,此时SCL已经变为低电平了(由于是数据的跳变),由于SDA为数据位,不管其为高低电平
//先将其置为低电平,然后SCL变为高电平,然后SDA开始跳变为高电平
void MyI2C_Stop(void)
{
	MyI2C_W_SDA(0);
	MyI2C_W_SCL(1);
	MyI2C_W_SDA(1);
}
//对于SDA来说由于有电平的跳变,所以在开始和结束的时候,都要将其给规整到合适的位置

//发送数据,主机先将数据放到SDA上去,然后在由低电平跳跃到高电平,然后从机会接收数据,然后SCL关闭
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);
		MyI2C_W_SCL(0);
	}
}
//由于是从高位开始发送数据,所以先从0x80开始去调用位置
//这个是怎么理解的(Byte & (0x80 >> i),就是取一个二进制位,然后在主机控制SCL高低电平,从机在高电平处取位
//比如你有个二进制位数10101010   这里有个10000000即(0x80)
//将两者按位置与即10101010
//             即 10000000
//很明显就只能得到了你这个二进制数据的高位即1

//对于接收的流程,说白了就是主机读取从机数据的流程
//就是从机将数据放在SDA线上,然后主机从低电平变为高电平
//然后此时从机将数据发送给主机,然后主机变为低电平,此时从机继续准备数据
//MyI2C_W_SDA(1);图中有一行这个代码是什么意思呢
//就是从机没有主动权将数据放在SDA上,只有当主机将SDA给释放了,才能有这个机会
uint8_t MyI2C_ReceiveByte(void)
{
	uint8_t i, Byte = 0x00;
	MyI2C_W_SDA(1);
	for (i = 0; i < 8; i ++)
	{
		MyI2C_W_SCL(1);
		if (MyI2C_R_SDA()){Byte |= (0x80 >> i);}
		//这段代码很简单,如果此时读取的数据是1,则对byte进行或操作
		//如果此时读取的数据是0,则此时输入0
		MyI2C_W_SCL(0);
	}
	return Byte;
}
//当主机读取到从机的数据后,就会给从机发送信号,自己读取到了
//AckBit=1,表示从机继续发,AckBit=0,表示从机别发了
//然后继续主机控制SCL高电平,然后从机获取信息,然后主机控制高电平
void MyI2C_SendAck(uint8_t AckBit)
{
	MyI2C_W_SDA(AckBit);
	MyI2C_W_SCL(1);
	MyI2C_W_SCL(0);
}
//当从机收到主机的数据后的反应,还是和之前所说的一样,从机是没有主动权的
//当从机想要在SDA上发送数据,只有一条路,就是主机先释放SDA
//所以可以看到主机先释放了SDA,然后主机高电平,从机告诉主机是否继续,然后主机控制SCL为低电平
uint8_t MyI2C_ReceiveAck(void)
{
	uint8_t AckBit;
	MyI2C_W_SDA(1);
	MyI2C_W_SCL(1);
	AckBit = MyI2C_R_SDA();
	MyI2C_W_SCL(0);
	return AckBit;
}

myi2c.h

cpp 复制代码
#ifndef __MYI2C_H
#define __MYI2C_H

void MyI2C_Init(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);

#endif

mpu6050.c

cpp 复制代码
#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_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();
	MyI2C_SendByte(MPU6050_ADDRESS);
	MyI2C_ReceiveAck();
	MyI2C_SendByte(RegAddress);
	MyI2C_ReceiveAck();
	
	MyI2C_Start();
	MyI2C_SendByte(MPU6050_ADDRESS | 0x01);
	MyI2C_ReceiveAck();
	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);
	MPU6050_WriteReg(MPU6050_SMPLRT_DIV, 0x09);
	MPU6050_WriteReg(MPU6050_CONFIG, 0x06);
	MPU6050_WriteReg(MPU6050_GYRO_CONFIG, 0x18);
	MPU6050_WriteReg(MPU6050_ACCEL_CONFIG, 0x18);
}

uint8_t MPU6050_GetID(void)
{
	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);
	DataL = MPU6050_ReadReg(MPU6050_ACCEL_XOUT_L);
	*AccX = (DataH << 8) | DataL;
	//通过mpu6050自动读取陀螺仪等等的位置信息
	//然后传输到我们定义的函数里面
	
	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;
}

mpu6050.h

cpp 复制代码
#ifndef __MPU6050_H
#define __MPU6050_H

void MPU6050_WriteReg(uint8_t RegAddress, uint8_t Data);
uint8_t MPU6050_ReadReg(uint8_t RegAddress);

void MPU6050_Init(void);
uint8_t MPU6050_GetID(void);
void MPU6050_GetData(int16_t *AccX, int16_t *AccY, int16_t *AccZ, 
						int16_t *GyroX, int16_t *GyroY, int16_t *GyroZ);

#endif
相关推荐
Deepoch20 小时前
Deepoc具身模型:景区服务机器人的智能中枢
人工智能·科技·机器人·景区·具身模型·deepoc·景区机器人
云器科技21 小时前
数美科技的数百TB大数据平台实践:从“1天响应“到“定义即可查”
大数据·科技·ai·数据平台·湖仓平台
泰迪智能科技0121 小时前
泰迪智能科技案例库 | 交通运输行业项目案例合集
科技
changyunkeji1 天前
电缆输送机,高质量产品助力行业快速发展
经验分享·科技
雷焰财经1 天前
构筑数字文化新生态:iBox的融合创新与产业赋能之路
科技
北京耐用通信1 天前
从“电缆束缚”到“光纤自由”:耐达讯自动化Profibus总线光纤中继器在化工通信的跨越式升级
人工智能·科技·物联网·自动化·信息与通信
WX131695189981 天前
是德科技53230A安捷伦53220A 53210A频率计
科技·信息与通信·射频工程
RFID舜识物联网1 天前
高校实验室智能化升级:RFID技术革新化学试剂管理
大数据·人工智能·科技·物联网·安全
科士威传动1 天前
支撑座固定端刚性约束与浮动端热补偿的差异化应用
科技·机器人·自动化·制造
新启航光学频率梳1 天前
高铁制动盘冷却深孔孔深光学3D轮廓测量-激光频率梳3D轮廓技术
科技·3d·制造