江协科技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
相关推荐
TMT星球2 小时前
康迪科技收购美国高端电动越野摩托车品牌,加速多品牌战略布局
科技
民乐团扒谱机2 小时前
【微科普】量子压缩光:突破噪声极限的 “超级光源”,量子科技的核心引擎
科技·量子计算·量子光学·压缩光·生物医疗与成像
科士威传动3 小时前
微型导轨的类型性能差异与场景适配需求
大数据·运维·人工智能·科技·机器人·自动化
Axis tech3 小时前
灵巧手遥操作:20自由度机械手高保真控制
科技
m0_591338916 小时前
day12江协科技 I2C
科技
千里念行客2406 小时前
映恩生物获纳入香港交易所科技100指数及富时全球股票指数中国小盘股成份股
科技·健康医疗
wanhengidc6 小时前
云计算环境中的数据安全防护策略
运维·服务器·科技·游戏·智能手机·云计算
屹立芯创ELEADTECH6 小时前
CoWoS、3D IC、Chiplet混战:先进封装的“技术路线之争“到底在争什么?
人工智能·科技·制造
智车科技6 小时前
泊车出海兑现技术红利,知行科技新获五泊车项目量产定点
大数据·人工智能·科技