STM32--10硬件读写MPU6050

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

#include "MPU6050_Reg.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);
	
	I2C_Send7bitAddress(I2C2,MPU6050_ADDRESS,I2C_Direction_Transmitter);
	MPU6050_WaitEvent(I2C2,I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED);
	
	I2C_SendData(I2C2,RegAddress);
	MPU6050_WaitEvent(I2C2,I2C_EVENT_MASTER_BYTE_TRANSMITTING);
	
	I2C_SendData(I2C2,Data);
	MPU6050_WaitEvent(I2C2,I2C_EVENT_MASTER_BYTE_TRANSMITTED);
	
	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);
	
	I2C_Send7bitAddress(I2C2,MPU6050_ADDRESS,I2C_Direction_Transmitter);
	MPU6050_WaitEvent(I2C2,I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED);
	
	I2C_SendData(I2C2,RegAddress);
	MPU6050_WaitEvent(I2C2,I2C_EVENT_MASTER_BYTE_TRANSMITTED);
	
	I2C_GenerateSTART(I2C2,ENABLE);
	MPU6050_WaitEvent(I2C2,I2C_EVENT_MASTER_MODE_SELECT);
	
	I2C_Send7bitAddress(I2C2,MPU6050_ADDRESS,I2C_Direction_Receiver);
	MPU6050_WaitEvent(I2C2,I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED);
	
	I2C_AcknowledgeConfig(I2C2,DISABLE);
	
	
	MPU6050_WaitEvent(I2C2,I2C_EVENT_MASTER_BYTE_RECEIVED);
	Data =I2C_ReceiveData(I2C2);
	
	I2C_GenerateSTOP(I2C2,ENABLE);
	
	I2C_AcknowledgeConfig(I2C2,ENABLE);
	
	
	
	
	return Data;
}
void MPU6050_Init(void)
{

	RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C2,ENABLE);
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);
	
	GPIO_InitTypeDef GPIO_InitStructure;
	GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF_OD;
	GPIO_InitStructure.GPIO_Pin=GPIO_Pin_10|GPIO_Pin_11;
	GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
	GPIO_Init(GPIOB,&GPIO_InitStructure);
	
	I2C_InitTypeDef I2C_InitStructure;
	I2C_InitStructure.I2C_Ack=I2C_Ack_Enable;
	I2C_InitStructure.I2C_AcknowledgedAddress=I2C_AcknowledgedAddress_7bit;
	I2C_InitStructure.I2C_ClockSpeed=100000;
	I2C_InitStructure.I2C_DutyCycle=I2C_DutyCycle_2;
	I2C_InitStructure.I2C_Mode=I2C_Mode_I2C;
	I2C_InitStructure.I2C_OwnAddress1=0X00;
	I2C_Init(I2C2,&I2C_InitStructure);
	
	I2C_Cmd(I2C2,ENABLE);
	
	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;
	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;
}

​

1.硬件I2C区别于软件I2C,我们不需要再操作SCL,SDA,只需要像操作其他外设那样配置好参数,至于电平的变换,硬件自己会做,不需要我们关注。

2.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;

}

}

}

硬件I2C用I2C_CheckEvent,检查事件是否完成,这里给他加了一个超时保护封装。

void MPU6050_WriteReg(uint8_t RegAddress,uint8_t Data)

{

I2C_GenerateSTART(I2C2,ENABLE);

MPU6050_WaitEvent(I2C2,I2C_EVENT_MASTER_MODE_SELECT);

I2C_Send7bitAddress(I2C2,MPU6050_ADDRESS,I2C_Direction_Transmitter);

MPU6050_WaitEvent(I2C2,I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED);

I2C_SendData(I2C2,RegAddress);

MPU6050_WaitEvent(I2C2,I2C_EVENT_MASTER_BYTE_TRANSMITTING);

I2C_SendData(I2C2,Data);

MPU6050_WaitEvent(I2C2,I2C_EVENT_MASTER_BYTE_TRANSMITTED);

I2C_GenerateSTOP(I2C2,ENABLE);

}

主机在写MPU6050时,除了开始和终止,和软件一样有三步,发送设备地址,发送寄存器地址,发送数据。

I2C_EVENT_MASTER_MODE_SELECT:STM32被选为主机

I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED:STM32被选为主机且处于发送模式

I2C_EVENT_MASTER_BYTE_TRANSMITTING:STM32被选为主机且正在发送数据

I2C_EVENT_MASTER_BYTE_TRANSMITTED:STM32被选为主机且发送数据完成

uint8_t MPU6050_ReadReg(uint8_t RegAddress)

{

uint8_t Data;

I2C_GenerateSTART(I2C2,ENABLE);

MPU6050_WaitEvent(I2C2,I2C_EVENT_MASTER_MODE_SELECT);

I2C_Send7bitAddress(I2C2,MPU6050_ADDRESS,I2C_Direction_Transmitter);

MPU6050_WaitEvent(I2C2,I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED);

I2C_SendData(I2C2,RegAddress);

MPU6050_WaitEvent(I2C2,I2C_EVENT_MASTER_BYTE_TRANSMITTED);

I2C_GenerateSTART(I2C2,ENABLE);

MPU6050_WaitEvent(I2C2,I2C_EVENT_MASTER_MODE_SELECT);

I2C_Send7bitAddress(I2C2,MPU6050_ADDRESS,I2C_Direction_Receiver);

MPU6050_WaitEvent(I2C2,I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED);

I2C_AcknowledgeConfig(I2C2,DISABLE);

I2C_GenerateSTOP(I2C2,ENABLE);

MPU6050_WaitEvent(I2C2,I2C_EVENT_MASTER_BYTE_RECEIVED);

Data =I2C_ReceiveData(I2C2);

I2C_AcknowledgeConfig(I2C2,ENABLE);

return Data;

}

读寄存器的流程是开始I2C通信,发送设备地址(写),发送寄存器地址,重新开始,发送设备地址(读),关闭应答,结束I2C通信,等待数据接收,后存入Data,打开应答

I2C开始后,无论读写都要先发送地址,把指针放到寄存器的位置上,在读的时候,需要重新开启,改变方向为读.

由于我们这里每次都只读一个字节,所以在找到地址后,需要关闭应答,不然它默认是开启应答,MPU6050还会继续发送,

谁接收数据谁发送应答,在读的时候,MPU6050发送数据,STM32接收,所以是STM32发送还要不要继续接收的应答.

一定是先关应答,后读数,如果反过来,读完数了,再关应答,从机下一组数已经到了,主机却不想要了,会导致主机从机的状态机不一致,混乱。

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);

Delay_ms(100);

}

每隔100ms做一次取数显示,其实取数加显示应该是30ms左右,我试过10ms,结果是数不动了,有时候还全是0,这里不知道为什么,deepseek也不能说准,以后有设备再排查吧

相关推荐
Zw-awa8 小时前
协议是人为约定:同一个字节能有三种意思
stm32
国科安芯13 小时前
83 倍:ASC0108S 在推挽和开漏之间,差的不是速度,是回程
单片机·嵌入式硬件·架构·电平转换·抗辐射
国科安芯17 小时前
从遥控到自治:ASP4644S2B支撑星载电源健康管理与容错配电
网络·单片机·嵌入式硬件·安全·dcdc·低轨卫星·商业航天
rhythm-ring17 小时前
《汽车热管理系统:电子水泵单线PWM双向诊断机制》
单片机·嵌入式硬件·汽车
Dev_XH20 小时前
【成品设计】基于物联网的车间安全生产监控系统设计
stm32·单片机·嵌入式硬件·物联网
xiebs_1 天前
【无标题】111
单片机
元器件BOM超人1 天前
GD32E230C8T6 兆易创新Cortex-M23超值型MCU解析:规格参数、替代选型与常见问题
单片机·嵌入式硬件
LONGZHIQIN1 天前
STM32学习笔记
笔记·stm32·学习·arm
StarsGreen1 天前
Android 启动流程详解
android·linux·单片机·嵌入式硬件
en.en..1 天前
AFE:模拟前端,模拟世界通往 MCU 的信号桥梁
单片机·嵌入式硬件