[STM32]Day10-Part2硬件I2C读写MPU6050

I2C外设简介

STM32内部集成了硬件I2C收发电路,可以由硬件自动执行时钟生成、起始终止条件生成、应答位收发、数据收发等功能,减轻CPU的负担。

支持多主机模型。支持7位/10位地址模式。

支持不同的通讯速度,标准速度(高达100kHz),快速(高达400kHz)。

支持DMA

兼容SMBus协议

STM32F103C8T6硬件I2C资源:I2C1、I2C2

I2C框图

DATA REGISTER和数据移位寄存器是数据收发的核心部分。往SDA写数据时,把一个字节数据到DR,当移位寄存器没有数据正在移位时,数据从DR转运到移位寄存器同时置状态寄存器TXE为1,DR可以写入新值等待发送。从SDA读取数据时,数据逐位存进移位寄存器,收到完整一个字节数据后转运到DR,同时置标志位RXNE为1,等待读取数据。

I2C基本结构

使用硬件I2C时,SDA和SCL对应的GPIO口设置为复用开漏输出模式。复用是指GPIO的状态是由片上外设控制的。

主机发送与接收时序

主机发送时序

主机接收时序

软件/硬件波形图对比

硬件I2C读写MPU6050

在软件I2C基础上实现硬件I2C整体思路:配置I2C外设,对I2C2外设进行初始化 -> 控制外设电路,实现指定地址写的时序 -> 控制外设电路,实现指定地址读的时序

I2C2初始化:开启I2C2和GPIO时钟 -> 配置GPIO为复用开漏输出模式 -> 配置I2C -> 开启I2C

使用到的函数

c 复制代码
// 产生开始信号和停止信号
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);
uint8_t I2C_ReceiveData(I2C_TypeDef* I2Cx);
// 发送7位地址
void I2C_Send7bitAddress(I2C_TypeDef* I2Cx, uint8_t Address, uint8_t I2C_Direction);

// 检查EVx是否发生
ErrorStatus I2C_CheckEvent(I2C_TypeDef* I2Cx, uint32_t I2C_EVENT);

代码

c 复制代码
// MPU6050.c
#include "stm32f10x.h"                  // Device header
#include "MPU6050_Reg.h"

#define MPU6050_ADDRESS			0xD0

// 指定地址写
void MPU6050_WriteReg(uint8_t RegAddress, uint8_t Data)
{
	I2C_GenerateSTART(I2C2, ENABLE);
	while(I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_MODE_SELECT) != SUCCESS);
	
	I2C_Send7bitAddress(I2C2, MPU6050_ADDRESS, I2C_Direction_Transmitter);
	while(I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED) != SUCCESS);
	
	I2C_SendData(I2C2, RegAddress);
	while(I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_BYTE_TRANSMITTING) != SUCCESS);

	I2C_SendData(I2C2, Data);
	while(I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_BYTE_TRANSMITTED) != SUCCESS);

	I2C_GenerateSTOP(I2C2, ENABLE);
}

// 指定地址读
uint8_t MPU_6050_ReadReg(uint8_t RegAddress)
{	
	uint8_t Data;
	uint32_t TimeOut;
	
	TimeOut = 10000;
	
	I2C_GenerateSTART(I2C2, ENABLE);
	while(I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_MODE_SELECT) != SUCCESS) {
		TimeOut --;
		if(TimeOut == 0) {
			break;
		}
	}
	
	I2C_Send7bitAddress(I2C2, MPU6050_ADDRESS, I2C_Direction_Transmitter);
	while(I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED) != SUCCESS);
	
	I2C_SendData(I2C2, RegAddress);
	while(I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_BYTE_TRANSMITTED) != SUCCESS);
	
	I2C_GenerateSTART(I2C2, ENABLE);
	while(I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_MODE_SELECT) != SUCCESS);
	
	I2C_Send7bitAddress(I2C2, MPU6050_ADDRESS, I2C_Direction_Receiver);
	while(I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED) != SUCCESS);
	
	I2C_AcknowledgeConfig(I2C2, DISABLE);
	I2C_GenerateSTOP(I2C2, ENABLE);
	
	while(I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_BYTE_RECEIVED) != SUCCESS);
	Data = I2C_ReceiveData(I2C2);
	
	I2C_AcknowledgeConfig(I2C2, ENABLE);
	
	return Data;
}

void MPU6050_Init(void)
{
	// 开启时钟
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C2, 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_Mode = I2C_Mode_I2C;
	I2C_InitStructure.I2C_ClockSpeed = 50000;		// 时钟频率
	I2C_InitStructure.I2C_DutyCycle = I2C_DutyCycle_2;			// 时钟频率大于100kHz下才有用
	I2C_InitStructure.I2C_Ack = I2C_Ack_Enable;			// 应答位配置
	I2C_InitStructure.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit;		// STM32作为从机时地址位数
	I2C_InitStructure.I2C_OwnAddress1 = 0x00;		// 设置作为从机时的地址
	I2C_Init(I2C2, &I2C_InitStructure);
	
	// 开启I2C
	I2C_Cmd(I2C2, ENABLE);
	
	// 配置电源管理寄存器1,解除睡眠模式
	MPU6050_WriteReg(MPU6050_PWR_MGMT_1, 0x01);
	
	// 配置电源管理寄存器2
	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 MPU_6050_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 = MPU_6050_ReadReg(MPU6050_ACCEL_XOUT_H);
	DataL = MPU_6050_ReadReg(MPU6050_ACCEL_XOUT_L);
	*AccX = (DataH << 8) | DataL;
	
	DataH = MPU_6050_ReadReg(MPU6050_ACCEL_YOUT_H);
	DataL = MPU_6050_ReadReg(MPU6050_ACCEL_YOUT_L);
	*AccY = (DataH << 8) | DataL;
	
	DataH = MPU_6050_ReadReg(MPU6050_ACCEL_ZOUT_H);
	DataL = MPU_6050_ReadReg(MPU6050_ACCEL_ZOUT_L);
	*AccZ = (DataH << 8) | DataL;
	
	DataH = MPU_6050_ReadReg(MPU6050_GYRO_XOUT_H);
	DataL = MPU_6050_ReadReg(MPU6050_GYRO_XOUT_L);
	*GyroX = (DataH << 8) | DataL;
	
	DataH = MPU_6050_ReadReg(MPU6050_GYRO_YOUT_H);
	DataL = MPU_6050_ReadReg(MPU6050_GYRO_YOUT_L);
	*GyroY = (DataH << 8) | DataL;
	
	DataH = MPU_6050_ReadReg(MPU6050_GYRO_ZOUT_H);
	DataL = MPU_6050_ReadReg(MPU6050_GYRO_ZOUT_L);
	*GyroZ = (DataH << 8) | DataL;
}

// main.c
#include "stm32f10x.h"                  // Device header
#include "OLED_Hardware.h"
#include "MPU6050.h"

int16_t AX, AY, AZ, GX, GY, GZ;

int main(void)
{
	OLED_Init_H();
	MPU6050_Init();
	
	OLED_ShowString_H(1, 1, "ID:");
	OLED_ShowNum_H(1, 4, MPU6050_GetID(), 2);

	while(1)
	{
		MPU6050_GetData(&AX, &AY, &AZ, &GX, &GY, &GZ);
		OLED_ShowSignedNum_H(2, 1, AX, 5);
		OLED_ShowSignedNum_H(3, 1, AY, 5);
		OLED_ShowSignedNum_H(4, 1, AZ, 5);
		OLED_ShowSignedNum_H(2, 8, GX, 5);
		OLED_ShowSignedNum_H(3, 8, GX, 5);
		OLED_ShowSignedNum_H(4, 8, GX, 5);
	}
}
相关推荐
泡泡糖的中文规格书2 小时前
精准解读 UMW DS18B20:一份经过深度校对的数字温度传感器中文手册
嵌入式硬件·规格说明书·硬件设计·中文数据手册
纳祥科技2 小时前
NX699,内置精度±5%晶振的lightning苹果PD快充12W
单片机·手机·音视频
点灯小铭3 小时前
基于单片机的图书馆座位管理系统设计与实现
单片机·嵌入式硬件·毕业设计·课程设计·期末大作业
清风6666663 小时前
基于单片机的两路PWM信号输出及频率占空比相位差调节系统
单片机·嵌入式硬件·毕业设计·课程设计·期末大作业
LeoZY_3 小时前
CH347应用 USB转JTAG功能之:probe-rs搭配CH347下载MCU命令全指南
单片机·嵌入式硬件·mcu·开源·github
Zyed3 小时前
[STM32]Day11-软件实现SPI读写W25Q64
stm32·单片机·嵌入式硬件
普中科技3 小时前
【普中STM32F1xx开发攻略--标准库版】-- 第 48 章 FATFS 文件系统实验
stm32·单片机·嵌入式硬件·文件系统·开发板·fatfs·普中科技
振南的单片机世界3 小时前
中央对齐PWM:边沿对齐EMI大,中央对齐更安静
arm开发·stm32·单片机·嵌入式硬件
清风6666663 小时前
基于51单片机的电阻测量仪设计
单片机·嵌入式硬件·毕业设计·51单片机·课程设计·期末大作业