STM32学习笔记(江协科技)-----硬件I2C实战(MPU6050)

STM32的I2C外设:

可以由硬件自动执行时钟生成、起始终止条件生成、应答位收发,数据收发等功能。

支持多主机模型,支持7/10位地址,支持DMA

STM32F103C8T6的I2C资源:I2C1,I2C2。

引脚分配:

PB10:I2C2_SCL                           PB11:I2C2_SDA

PB6:I2C1_SCL                             PB7:I2C2_SDA

操作顺序:


1. 在I2C_CR2寄存器中设定该模块的输入时钟以产生正确的时序
2.配置时钟控制寄存器
3. 配置上升时间寄存器
4.编程I2C_CR1寄存器启动外设
5. 置I2C_CR1寄存器中的START位为1,产生起始条件

代码实现:

#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);//开始时序
	
	//等待EV5事件(可参考上文图245);等不到(SUCCESS)就一直空循环,等到就跳出循环,执行下一步;
	I2C_Send7bitAddress(I2C2,MPU6050_ADDRESS,I2C_Direction_Transmitter);//发送从机地址(点名从机)
	//I2C2,从机地址,读写位置0(发送);
	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事件,当发送最后一个字节后,应等待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事件(可参考上文图245);等不到(SUCCESS)就一直空循环,等到就跳出循环,执行下一步;
	I2C_Send7bitAddress(I2C2,MPU6050_ADDRESS,I2C_Direction_Transmitter);//发送从机地址(点名从机)
	//I2C2,从机地址,读写位置0(发送);
	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);//接收,读写位置1(接收)
	MPU6050_WaitEvent(I2C2,I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED);//等待EV6事件;
	I2C_AcknowledgeConfig(I2C2,DISABLE);//不给应答,ACK置0;
	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是APB1的外设,所以用APB1
	
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);
	//GPIO是APB2的外设,所以用APB2
	GPIO_InitTypeDef GPIO_InitStructure;//初始化GPIO
	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;//初始化I2C2
	I2C_InitStructure.I2C_Ack = I2C_Ack_Enable;//是否给应答
	I2C_InitStructure.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit;//响应7位地址
	I2C_InitStructure.I2C_ClockSpeed = 50000;//时钟频率:50KHZ
	I2C_InitStructure.I2C_DutyCycle = I2C_DutyCycle_2;
	//占空比 低:高 = 2:1;
	//因为I2C总线采用上拉电阻,是弱上拉,弹回高电平速度比拉低电平速度慢,所以要给低电平更多资源
	//让数据有足够的时间放到SDA总线上
	I2C_InitStructure.I2C_Mode = I2C_Mode_I2C;
	I2C_InitStructure.I2C_OwnAddress1 = 0x00;//STM32作从机时的地址,暂时不用
	I2C_Init(I2C2,&I2C_InitStructure);
	
	I2C_Cmd(I2C2,ENABLE);//使能I2C2;
	
	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_ReadID(void)//获取ID号
{
	return MPU6050_ReadReg(MPU6050_WHO_AM_I);
}

void MPU6050_ReadData(int16_t *AccX, int16_t *AccY, int16_t *AccZ, 
					  int16_t *GyroX, int16_t *GyroY, int16_t *GyroZ)
{//获取数据(6个int16_t的数据)
	*AccX = (MPU6050_ReadReg(MPU6050_ACCEL_XOUT_H) << 8)
			| MPU6050_ReadReg(MPU6050_ACCEL_XOUT_L);
	
	*AccY = (MPU6050_ReadReg(MPU6050_ACCEL_YOUT_H) << 8)
			| MPU6050_ReadReg(MPU6050_ACCEL_YOUT_L);
	
	*AccZ = (MPU6050_ReadReg(MPU6050_ACCEL_ZOUT_H) << 8)
			| MPU6050_ReadReg(MPU6050_ACCEL_ZOUT_L);
	
	*GyroX = (MPU6050_ReadReg(MPU6050_GYRO_XOUT_H) << 8)
			| MPU6050_ReadReg(MPU6050_GYRO_XOUT_L);
	
	*GyroY = (MPU6050_ReadReg(MPU6050_GYRO_YOUT_H) << 8)
			| MPU6050_ReadReg(MPU6050_GYRO_YOUT_L);
	
	*GyroZ = (MPU6050_ReadReg(MPU6050_GYRO_ZOUT_H) << 8)
			| MPU6050_ReadReg(MPU6050_GYRO_ZOUT_L);
}

  • 4
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值