江协科技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
相关推荐
腾视科技-AI4 小时前
腾视科技AIBOX双版本重磅发布!本地安全与全球适配,解锁视频智能新可能
大数据·人工智能·科技·安全·大模型·腾视科技·ai算力盒
逍遥~1424 小时前
什么是工业级算力?算盘科技的核心能力解析
网络·人工智能·科技
2601_960017625 小时前
速冻食品PLM选型指南:一半科技垂直落地实战版
科技
2401_890095615 小时前
武汉自动意志科技问题排查指南:先检查业务目标
科技·数据预处理·rag系统·武汉自动意志科技有限公司·ai办公自动化系统·知识库文档格式
CLK音视频广播设备6 小时前
河南川利卡科技集团圆满落地安徽宿州校园网络广播项目
网络·科技
科技每日热闻8 小时前
企业推进数字化转型等级国家认证该寻求什么支持?从贯标咨询到正式评价如何落地实施
科技
qq_161241359 小时前
超精密光学用CVD单晶金刚石:北睿科技的工艺路径探讨
人工智能·科技·半导体
测试狗科研平台10 小时前
电池材料表征、电芯制备与性能测试--测试狗先进能源中试服务
科技·测试工具·材料工程
云边云科技_云网融合10 小时前
混合云多云组网架构:跨云互联、公私融合、云边协同与专线替代全解析
网络·科技
数造科技10 小时前
政务数据治理实战:统一数据底座如何破解商事注册“重复填报”与数据孤岛
大数据·人工智能·科技·政务·ai-native