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也不能说准,以后有设备再排查吧

相关推荐
糖糖单片机设计3 小时前
基于STM32的鱼缸水质检测系统
stm32·单片机·嵌入式硬件
HRTOS3 小时前
HRTOS 4.0 正式发布:Driver Library 基础外设驱动模块介绍
驱动开发·单片机·嵌入式硬件·51单片机
染予3 小时前
20个点位下发该如何正常操作?
单片机·嵌入式硬件
wuyk5554 小时前
从零吃透 MQTT 通信|第 5 章 MQTT 心跳保活机制深度优化,断线检测与智能自动重连
c语言·开发语言·stm32·学习
jianqiang.xue4 小时前
ESP-IDF保姆级入门23|MQTT物联网通信全解:发布订阅模式/QoS等级/遗嘱消息/主题设计/断线重连,掌握工业级标准消息通信
stm32·单片机·mcu·物联网·51单片机·iot
HRTOS5 小时前
HRTOS 4.0 Driver Library:03_Sensor 传感器驱动
驱动开发·单片机·嵌入式硬件·51单片机
youcans_5 小时前
【嵌入式软件AI编程】01. 基于 STM32/Claude Code的AI编程
stm32·mcu·嵌入式·ai编程·claude code
小麦嵌入式5 小时前
FPGA入门(十一):受控线性序列机 UART 发送升级
stm32·单片机·嵌入式硬件·mcu·fpga开发·硬件工程
jianqiang.xue6 小时前
ESP-IDF保姆级入门29|FreeRTOS任务管理与调度全解:任务创建/状态切换/优先级调度/双核负载均衡/实时性优化,掌握嵌入式多任务编程核心
stm32·单片机·mcu·物联网·51单片机·iot