STM32学习-20240905-IC通信协议

一、I2C简介

使用电阻构成弱上拉,避免了电路的短路,输入和输出不用切换。

二、MPU6050

融入读写位从机地址位0xD0

三、软件I2C

#include "stm32f10x.h"                  // Device header
#include "MyI2C.h"
#include "MPU6050Reg.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);//给1表示接下来不需要数据了
	MyI2C_Stop();//数据传输结束
	return Data;
}




void MPU6050_Init(void)
{
	MyI2C_Init();
	MPU6050_WriteReg(MPU6050_PWR_MGMT_1, 0x01);//初始化电源管理寄存器1
	MPU6050_WriteReg(MPU6050_PWR_MGMT_2, 0x00);//初始化电源管理寄存器2
	MPU6050_WriteReg(MPU6050_SMPLRT_DIV, 0x09);//初始化分频模块,10分频
	MPU6050_WriteReg(MPU6050_CONFIG, 0x06);//外部同步给0,6为平滑滤波
	MPU6050_WriteReg(MPU6050_GYRO_CONFIG, 0x18);//配置陀螺仪
	MPU6050_WriteReg(MPU6050_ACCEL_CONFIG, 0x18);//加速度计寄存器
}

uint8_t MPU6050_GetID(void)
{
	return MPU6050_ReadReg(MPU6050_WHO_AM_I);//读取ID号
}
	

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_ACCEL_YOUT_H);
	DataL = MPU6050_ReadReg(MPU6050_ACCEL_YOUT_L);
	*GyroY = (DataH << 8) | DataL;
	
	DataH = MPU6050_ReadReg(MPU6050_ACCEL_ZOUT_H);
	DataL = MPU6050_ReadReg(MPU6050_ACCEL_ZOUT_L);
	*GyroZ = (DataH << 8) | DataL;
}

MPU6050寄存器定义

#ifndef __MPU6050Reg_H
#define __MPU6050Reg_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
#define	MPU6050_ACCEL_XOUT_L	0x3C
#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
#define	MPU6050_GYRO_XOUT_L		0x44
#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
#define	MPU6050_PWR_MGMT_2		0x6C
#define	MPU6050_WHO_AM_I		0x75

#endif

四、硬件I2C

EV5为标志位,状态寄存器不需要手动清除;检测到EV8表示可以继续发送数据了。

1.硬件I2C相应库函数

void I2C_DeInit(I2C_TypeDef* I2Cx);//I2C恢复初始配置函数
void I2C_Init(I2C_TypeDef* I2Cx, I2C_InitTypeDef* I2C_InitStruct);//I2C初始化函数
void I2C_StructInit(I2C_InitTypeDef* I2C_InitStruct);//I2C机构体初始化函数
void I2C_Cmd(I2C_TypeDef* I2Cx, FunctionalState NewState);//I2C启动函数

void I2C_DMACmd(I2C_TypeDef* I2Cx, FunctionalState NewState);//I2C配合DMA启动函数
void I2C_DMALastTransferCmd(I2C_TypeDef* I2Cx, FunctionalState NewState);//I2C转运启动

void I2C_GenerateSTART(I2C_TypeDef* I2Cx, FunctionalState NewState);//产生起始条件,控制数据传输开始
void I2C_GenerateSTOP(I2C_TypeDef* I2Cx, FunctionalState NewState);//产生停止条件,控制传输结束

void I2C_AcknowledgeConfig(I2C_TypeDef* I2Cx, FunctionalState NewState);//配置CR1的ACK位,即应答位,收到一个字节后是否应答。

void I2C_SendData(I2C_TypeDef* I2Cx, uint8_t Data);//DR寄存器,数据写入DR自动发送,

uint8_t I2C_ReceiveData(I2C_TypeDef* I2Cx);//接收数据,读取DR数据作为返回值

void I2C_Send7bitAddress(I2C_TypeDef* I2Cx, uint8_t Address, uint8_t I2C_Direction);//发送7位地址的专用函数。

ErrorStatus I2C_CheckEvent(I2C_TypeDef* I2Cx, uint32_t I2C_EVENT);//读取I2C的状态函数

uint32_t I2C_GetLastEvent(I2C_TypeDef* I2Cx);

FlagStatus I2C_GetFlagStatus(I2C_TypeDef* I2Cx, uint32_t I2C_FLAG);

void I2C_ClearFlag(I2C_TypeDef* I2Cx, uint32_t I2C_FLAG);//清除中断标志
ITStatus I2C_GetITStatus(I2C_TypeDef* I2Cx, uint32_t I2C_IT);//夺取中断状态
void I2C_ClearITPendingBit(I2C_TypeDef* I2Cx, uint32_t I2C_IT);//清除中断标志位

2.硬件I2C代码

#include "stm32f10x.h"                  // Device header
#include "MPU6050Reg.h"
#define MPU6050_ADDRESS     0xD0

void MPU6050_WaitEvent(I2C_TypeDef* I2Cx, uint32_t I2C_EVENT)
{
	uint32_t Timeout;
	Timeout = 10000;
	while (I2C_CheckEvent(I2Cx, I2C_EVENT) != SUCCESS)
	{
		Timeout --;
		if (Timeout == 0)
		{
			break;//跳出循环
		}
	}
}

void MPU6050_WriteReg(uint8_t RegAddress, uint8_t Data)//指定地址写
{
	I2C_GenerateSTART(I2C2, ENABLE);//开始
	MPU6050_WaitEvent(I2C2, I2C_EVENT_MASTER_MODE_SELECT);//等待EV5事件,确认开始成功
	
	I2C_Send7bitAddress(I2C2, MPU6050_ADDRESS, I2C_Direction_Transmitter);//发送地址
	MPU6050_WaitEvent(I2C2, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED);//等待EV6事件,确认地址发送完毕
		
	I2C_SendData(I2C2, RegAddress);//发送特定的寄存器地址
	MPU6050_WaitEvent(I2C2, I2C_EVENT_MASTER_BYTE_TRANSMITTING);//等待EV8事件确定数据发送完成
		
	I2C_SendData(I2C2, Data);//发送具体的数据
	MPU6050_WaitEvent(I2C2, I2C_EVENT_MASTER_BYTE_TRANSMITTED);//最后一个字节发送完毕,
																			//等待EV8_2事件,确定发送结束
	I2C_GenerateSTOP(I2C2, ENABLE);//发送完毕,停止发送
}

uint8_t MPU6050_ReadReg(uint8_t RegAddress)//指定地址读
{
	uint8_t Data;
	
	I2C_GenerateSTART(I2C2, ENABLE);//开始
	MPU6050_WaitEvent(I2C2, I2C_EVENT_MASTER_MODE_SELECT);//等待EV5事件,确认开始成功
	
	I2C_Send7bitAddress(I2C2, MPU6050_ADDRESS, I2C_Direction_Transmitter);//发送从机地址
	MPU6050_WaitEvent(I2C2, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED);//等待EV6事件,确认地址发送完毕
	
	I2C_SendData(I2C2, RegAddress);//发送特定的寄存器地址
	MPU6050_WaitEvent(I2C2, I2C_EVENT_MASTER_BYTE_TRANSMITTED);//等待EV8_2事件确定数据发送完成
	
	I2C_GenerateSTART(I2C2, ENABLE);//重开始,准备接收数据
	MPU6050_WaitEvent(I2C2, I2C_EVENT_MASTER_MODE_SELECT);//等待EV5事件,确认开始成功
	
	I2C_Send7bitAddress(I2C2, MPU6050_ADDRESS, I2C_Direction_Receiver);//发送从机地址
	MPU6050_WaitEvent(I2C2, I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED);//等待EV6事件,确认地址发送完毕
	
	I2C_AcknowledgeConfig(I2C2, DISABLE);//接收一个字节时要在接收到数据之前ACK置零,Stop置一
	I2C_GenerateSTOP(I2C2, ENABLE);
	
	MPU6050_WaitEvent(I2C2, I2C_EVENT_MASTER_BYTE_RECEIVED);//等待EV7事件,确认数据接收完毕
	Data = I2C_ReceiveData(I2C2);
	
	I2C_AcknowledgeConfig(I2C2, ENABLE);//恢复默认ACK为1,回复应答
	
	return Data;
}




void MPU6050_Init(void)
{
//	MyI2C_Init();
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C2, ENABLE);//开启I2C2的时钟
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);//开启IO口时钟
	
	GPIO_InitTypeDef GPIO_InitStructure;
 	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_OD;//开漏输出模式
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10 | GPIO_Pin_11;
 	GPIO_Init(GPIOB, &GPIO_InitStructure);

	I2C_InitTypeDef I2C2_InitStructure;
	I2C2_InitStructure.I2C_Mode = I2C_Mode_I2C;	//选择I2C
	I2C2_InitStructure.I2C_Ack = I2C_Ack_Enable;
	I2C2_InitStructure.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit;
	I2C2_InitStructure.I2C_ClockSpeed = 50000;//配置I2C时钟频率
	I2C2_InitStructure.I2C_DutyCycle = I2C_DutyCycle_2;//时钟占空比,在100kHz以上才有用
	I2C2_InitStructure.I2C_OwnAddress1 = 0x00;
	I2C_Init(I2C2, &I2C2_InitStructure);
	
	I2C_Cmd(I2C2, ENABLE);
	
	
	MPU6050_WriteReg(MPU6050_PWR_MGMT_1, 0x01);//初始化电源管理寄存器1
	MPU6050_WriteReg(MPU6050_PWR_MGMT_2, 0x00);//初始化电源管理寄存器2
	MPU6050_WriteReg(MPU6050_SMPLRT_DIV, 0x09);//初始化分频模块,10分频
	MPU6050_WriteReg(MPU6050_CONFIG, 0x06);//外部同步给0,6为平滑滤波
	MPU6050_WriteReg(MPU6050_GYRO_CONFIG, 0x18);//配置陀螺仪
	MPU6050_WriteReg(MPU6050_ACCEL_CONFIG, 0x18);//加速度计寄存器
}

uint8_t MPU6050_GetID(void)
{
	return MPU6050_ReadReg(MPU6050_WHO_AM_I);//读取ID号
}
	

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_ACCEL_YOUT_H);
	DataL = MPU6050_ReadReg(MPU6050_ACCEL_YOUT_L);
	*GyroY = (DataH << 8) | DataL;
	
	DataH = MPU6050_ReadReg(MPU6050_ACCEL_ZOUT_H);
	DataL = MPU6050_ReadReg(MPU6050_ACCEL_ZOUT_L);
	*GyroZ = (DataH << 8) | DataL;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值