当前位置:   article > 正文

STM32入门笔记12_04_硬件I2C读写MPU6050_stm32 cubermx 实现 硬件i2c对mpu6050的操作

stm32 cubermx 实现 硬件i2c对mpu6050的操作

I2C通信外设

I2C外设简介

  • STM32内部集成了硬件I2C收发电路,可以由硬件自动执行时钟生成、起始终止条件生成、应答位收发、数据收发等功能,减轻CPU的负担
  • 支持多主机模型
  • 支持7位/10位地址模式
  • 支持不同的通讯速度,标准速度(100kHz),快速(400kHz)
  • 支持DMA
  • 兼容SMBus协议
  • STM32F103C8T6硬件I2C资源: I2C1、I2C2

I2C框图

在这里插入图片描述

SDA线控制

在这里插入图片描述

  • 发送模式: 当发送寄存器空时(TXE), 单片机将数据写入数据寄存器(DATA REGISTER), 当数据移位寄存器为空时, 数据从数据寄存器转入数据移位寄存器, 再通过数据移位寄存器一位位输出
  • 接收模式: 数据一位位被送到数据移位寄存器中, 移位寄存器再把数据一位位送到数据寄存器中(DATA REGISTER), 当接收寄存器非空时(RXNE), 单片机就可以将数据寄存器中的数据读出

单片机从模式控制(了解)

在这里插入图片描述

  • 报错误校验(PEC) 用于提高通信的可靠性,使用CRC-8算法
  • 当stm32主机属于从模式时,可以通过自身地址寄存器和双地址寄存器为stm32自定义地址

SCL线控制

在这里插入图片描述

  • 控制寄存器用于配置硬件电路

    • CR1

在这里插入图片描述

  • CR2

在这里插入图片描述

  • 状态寄存器可以读取电路的信息

    • SR1

在这里插入图片描述

  • SR2

    在这里插入图片描述

  • 时钟控制寄存器用于配置时钟信号

    • CCR

在这里插入图片描述

  • 具体翻阅STM32F10xxx参考手册

I2C基本结构

在这里插入图片描述

时序图

主机发送

在这里插入图片描述

主机接收

在这里插入图片描述

软件硬件波形对比(了解)

在这里插入图片描述

程序设计

根据主机发送和主机接收的时序图重写 MPU6050_WriteReg()MPU6050_ReadReg()

I2C的配置结构体意义见注释

I2C常用函数介绍

  • void I2C_Init(I2C_TypeDef* I2Cx, I2C_InitTypeDef* I2C_InitStruct);

    • 用于配置I2C
  • void I2C_Cmd(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);

    • 控制是否有应答
  • void I2C_SendData(I2C_TypeDef I2Cx, uint8_t Data);*

    • 发送数据
  • void I2C_Send7bitAddress(I2C_TypeDef* I2Cx, uint8_t Address, uint8_t I2C_Direction);

    • 用于寻找从机地址
  • ErrorStatus I2C_CheckEvent(I2C_TypeDef I2Cx, uint32_t I2C_EVENT)*

    • 状态检测函数,用于检查I2C通讯过程中产生的事件
  • FlagStatus I2C_GetFlagStatus(I2C_TypeDef* I2Cx, uint32_t I2C_FLAG);

    • 状态检测函数,用于获取状态寄存器中的标志位

main.c

#include "stm32f10x.h" 
#include "delay.h"
#include "OLED.h"
#include "MPU6050.h"
uint8_t ID;
int main(void)
{
	OLED_Init();
	MPU6050_Init();
	OLED_ShowString(1, 1, "ID:");
	ID = MPU6050_GetID();
	OLED_ShowHexNum(1, 4, ID, 2);
	MPU6050_DataTypeDef MPU6050_DataStructure;
	while(1)
	{
		// 读取数据
		MPU6050_GetData(&MPU6050_DataStructure);
		// 显示数据
		OLED_ShowSignedNum(2, 1, MPU6050_DataStructure.AccX, 5);
		OLED_ShowSignedNum(3, 1, MPU6050_DataStructure.AccY, 5);
		OLED_ShowSignedNum(4, 1, MPU6050_DataStructure.AccZ, 5);
		OLED_ShowSignedNum(2, 8, MPU6050_DataStructure.GyroX, 5);
		OLED_ShowSignedNum(3, 8, MPU6050_DataStructure.GyroY, 5);
		OLED_ShowSignedNum(4, 8, MPU6050_DataStructure.GyroZ, 5);
	}
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26

MPU6050.c

#include "stm32f10x.h"
#include "MPU6050_SEG.h"

#define MPU_ADDRESS 0xD0

/*
 *  等待事件 带超时退出机制 
 *  将while与I2C_CheckEvent封装在一起
 */
void MPU6050_WaitEvent(I2C_TypeDef* I2Cx, uint32_t I2C_EVENT)
{
	uint32_t Timeout=50000;
	while(Timeout && (I2C_CheckEvent(I2Cx, I2C_EVENT) != SUCCESS))
	{
		Timeout --;
	}
}

/*
 *  往指定地址写入指定数据
 */
void MPU6050_WriteReg(uint8_t RegAddress, uint8_t Data)
{
	// 起始条件
	I2C_GenerateSTART(I2C2, ENABLE);
	// 等待 EV5
	MPU6050_WaitEvent(I2C2, I2C_EVENT_MASTER_MODE_SELECT);
	// 呼叫设备(MPU6050)
	I2C_Send7bitAddress(I2C2, MPU_ADDRESS, I2C_Direction_Transmitter);
	// 等待 EV6
	MPU6050_WaitEvent(I2C2, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED);
	// 寻找写入地址
	I2C_SendData(I2C2, RegAddress);
	// 等待EV8
	MPU6050_WaitEvent(I2C2, I2C_EVENT_MASTER_BYTE_TRANSMITTING);
	// 写入数据
	I2C_SendData(I2C2, Data);
	// 等待EV8_2
	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);	// 等待 EV5
	
	I2C_Send7bitAddress(I2C2, MPU_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, MPU_ADDRESS, I2C_Direction_Receiver); // 呼叫设备 读
	MPU6050_WaitEvent(I2C2, I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED); // 等待 EV6
	
	I2C_AcknowledgeConfig(I2C2, DISABLE);  // 关闭应答
	I2C_GenerateSTOP(I2C2, ENABLE);		// 终止条件
	
	MPU6050_WaitEvent(I2C2, I2C_EVENT_MASTER_BYTE_RECEIVED);  // 等待EV7
	Data = I2C_ReceiveData(I2C2); // 接收数据

	I2C_AcknowledgeConfig(I2C2, ENABLE);  // 开启应答
	return Data;
}

/*
 *  配置MPU6050
 */
void MPU6050_Init(void)
{
	// I2C初始化
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C2, ENABLE);
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
	
	// GPIO
	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
	I2C_InitTypeDef I2C_InitStructure;
	I2C_InitStructure.I2C_Ack=I2C_Ack_Enable;  // 有应答
	I2C_InitStructure.I2C_ClockSpeed=50000;  // 400 kHz以下  100 kHz以上为快速通讯
	I2C_InitStructure.I2C_DutyCycle=I2C_DutyCycle_2;  // 低电平比高电平2:1 仅在快速通讯生效  
	I2C_InitStructure.I2C_Mode=I2C_Mode_I2C;
	I2C_InitStructure.I2C_AcknowledgedAddress=I2C_AcknowledgedAddress_7bit; 
    // 从模式下 stm32作为从机的地址所占位数	
	I2C_InitStructure.I2C_OwnAddress1=0x00;  // 从模式下stm32作为从机的地址
	I2C_Init(I2C2, &I2C_InitStructure);
	// 开启I2C2
	I2C_Cmd(I2C2, ENABLE);
	
	MPU6050_WriteReg(PWR_MGMT_1, 0x01);
	MPU6050_WriteReg(PWR_MGMT_2, 0x00);
	MPU6050_WriteReg(SMPLRT_DIV, 0x09);
	MPU6050_WriteReg(CONFIG, 0x06);
	MPU6050_WriteReg(GYRO_CONFIG, 0x18);
	MPU6050_WriteReg(ACCEL_CONFIG, 0x18);
}
/*
 * 获取ID号
 */
uint8_t MPU6050_GetID(void)
{
	return MPU6050_ReadReg(WHO_AM_I);
}
/*
 *  获取MPU6050数据
 */
void MPU6050_GetData(MPU6050_DataTypeDef * MPU_DataStructure)
{
	uint16_t Data_H, Data_L;  // 高位数据和低位数据
	Data_H = MPU6050_ReadReg(ACCEL_XOUT_H);
	Data_L = MPU6050_ReadReg(ACCEL_XOUT_L);
	MPU_DataStructure->AccX=(Data_H<<8) | Data_L;
	
	Data_H = MPU6050_ReadReg(ACCEL_YOUT_H);
	Data_L = MPU6050_ReadReg(ACCEL_YOUT_L);
	MPU_DataStructure->AccY=(Data_H<<8) | Data_L;
	
	Data_H = MPU6050_ReadReg(ACCEL_ZOUT_H);
	Data_L = MPU6050_ReadReg(ACCEL_ZOUT_L);
	MPU_DataStructure->AccZ=(Data_H<<8) | Data_L;
	
	Data_H = MPU6050_ReadReg(GYRO_XOUT_H);
	Data_L = MPU6050_ReadReg(GYRO_XOUT_L);
	MPU_DataStructure->GyroX=(Data_H<<8) | Data_L;
	
	Data_H = MPU6050_ReadReg(GYRO_YOUT_H);
	Data_L = MPU6050_ReadReg(GYRO_YOUT_L);
	MPU_DataStructure->GyroY=(Data_H<<8) | Data_L;
	
	Data_H = MPU6050_ReadReg(GYRO_ZOUT_H);
	Data_L = MPU6050_ReadReg(GYRO_ZOUT_L);
	MPU_DataStructure->GyroZ=(Data_H<<8) | Data_L;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147

MPU6050.h

#ifndef __MPU6050_H
#define __MPU6050_H
#include "MPU6050_REG.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(MPU6050_DataTypeDef * MPU_DataStructure);
#endif

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

MPU6050_REG.h

#ifndef __MPU6050_REG_H
#define __MPU6050_REG_H
// 寄存器地址
#define SMPLRT_DIV 				0x19
#define CONFIG					0x1A
#define GYRO_CONFIG 			0x1B
#define ACCEL_CONFIG 			0x1C
#define ACCEL_XOUT_H 			0x3B
#define ACCEL_XOUT_L 			0x3C
#define ACCEL_YOUT_H 			0x3D
#define ACCEL_YOUT_L 			0x3E
#define ACCEL_ZOUT_H 			0x3F
#define ACCEL_ZOUT_L 			0x40
#define TEMP_OUT_H 				0x41
#define	TEMP_OUT_L				0x42
#define	GYRO_XOUT_H				0x43
#define	GYRO_XOUT_L				0x44
#define	GYRO_YOUT_H				0x45
#define	GYRO_YOUT_L				0x46
#define	GYRO_ZOUT_H				0x47
#define	GYRO_ZOUT_L				0x48

#define	PWR_MGMT_1				0x6B
#define	PWR_MGMT_2				0x6C
#define	WHO_AM_I				0x75

/*
 *  MPU6050数据结构体
 */
typedef struct
{
	int16_t AccX;
	int16_t AccY;
	int16_t AccZ;
	int16_t GyroX;
	int16_t GyroY;
	int16_t GyroZ;
} MPU6050_DataTypeDef;

#endif

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41

参考资料

【STM32入门教程-2023持续更新中】

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/小蓝xlanll/article/detail/462405
推荐阅读
相关标签
  

闽ICP备14008679号