一、I2C简介
使用电阻构成弱上拉,避免了电路的短路,输入和输出不用切换。
二、MPU6050
融入读写位从机地址位0xD0
三、软件I2C
#include "stm32f10x.h" // Device header
#include "MyI2C.h"
#include "MPU6050Reg.h"
#define MPU6050_ADDRESS 0xD0
void MPU6050_WriteReg(uint8_t RegAddress, uint8_t Data)//指定地址写
{
MyI2C_Start();//开始传输标志
MyI2C_SendByte(MPU6050_ADDRESS);//发送外设地址确定是否连接
MyI2C_ReceiveAck();//接受确定收到标志位
MyI2C_SendByte(RegAddress);//发送指定地址
MyI2C_ReceiveAck();//接受确定收到标志位
MyI2C_SendByte(Data);//发送数据
MyI2C_ReceiveAck();//接受确定收到标志位
MyI2C_Stop();//数据传输结束
}
uint8_t MPU6050_ReadReg(uint8_t RegAddress)//指定地址读
{
uint8_t Data;
MyI2C_Start();//开始传输标志
MyI2C_SendByte(MPU6050_ADDRESS);//发送外设写地址确定是否连接
MyI2C_ReceiveAck();//接受确定收到标志位
MyI2C_SendByte(RegAddress);//发送指定地址
MyI2C_ReceiveAck();//接受确定收到标志位,这之前代码确定要读的地址
MyI2C_Start();//开始传输标志
MyI2C_SendByte(MPU6050_ADDRESS | 0x01);//发送读地址
MyI2C_ReceiveAck();//接受确定收到标志位
Data = MyI2C_ReceiveByte();//收到从机数据
MyI2C_SendAck(1);//给1表示接下来不需要数据了
MyI2C_Stop();//数据传输结束
return Data;
}
void MPU6050_Init(void)
{
MyI2C_Init();
MPU6050_WriteReg(MPU6050_PWR_MGMT_1, 0x01);//初始化电源管理寄存器1
MPU6050_WriteReg(MPU6050_PWR_MGMT_2, 0x00);//初始化电源管理寄存器2
MPU6050_WriteReg(MPU6050_SMPLRT_DIV, 0x09);//初始化分频模块,10分频
MPU6050_WriteReg(MPU6050_CONFIG, 0x06);//外部同步给0,6为平滑滤波
MPU6050_WriteReg(MPU6050_GYRO_CONFIG, 0x18);//配置陀螺仪
MPU6050_WriteReg(MPU6050_ACCEL_CONFIG, 0x18);//加速度计寄存器
}
uint8_t MPU6050_GetID(void)
{
return MPU6050_ReadReg(MPU6050_WHO_AM_I);//读取ID号
}
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_ACCEL_YOUT_H);
DataL = MPU6050_ReadReg(MPU6050_ACCEL_YOUT_L);
*GyroY = (DataH << 8) | DataL;
DataH = MPU6050_ReadReg(MPU6050_ACCEL_ZOUT_H);
DataL = MPU6050_ReadReg(MPU6050_ACCEL_ZOUT_L);
*GyroZ = (DataH << 8) | DataL;
}
MPU6050寄存器定义
#ifndef __MPU6050Reg_H
#define __MPU6050Reg_H
#define MPU6050_SMPLRT_DIV 0x19
#define MPU6050_CONFIG 0x1A
#define MPU6050_GYRO_CONFIG 0x1B
#define MPU6050_ACCEL_CONFIG 0x1C
#define MPU6050_ACCEL_XOUT_H 0x3B
#define MPU6050_ACCEL_XOUT_L 0x3C
#define MPU6050_ACCEL_YOUT_H 0x3D
#define MPU6050_ACCEL_YOUT_L 0x3E
#define MPU6050_ACCEL_ZOUT_H 0x3F
#define MPU6050_ACCEL_ZOUT_L 0x40
#define MPU6050_TEMP_OUT_H 0x41
#define MPU6050_TEMP_OUT_L 0x42
#define MPU6050_GYRO_XOUT_H 0x43
#define MPU6050_GYRO_XOUT_L 0x44
#define MPU6050_GYRO_YOUT_H 0x45
#define MPU6050_GYRO_YOUT_L 0x46
#define MPU6050_GYRO_ZOUT_H 0x47
#define MPU6050_GYRO_ZOUT_L 0x48
#define MPU6050_PWR_MGMT_1 0x6B
#define MPU6050_PWR_MGMT_2 0x6C
#define MPU6050_WHO_AM_I 0x75
#endif
四、硬件I2C
EV5为标志位,状态寄存器不需要手动清除;检测到EV8表示可以继续发送数据了。
1.硬件I2C相应库函数
void I2C_DeInit(I2C_TypeDef* I2Cx);//I2C恢复初始配置函数
void I2C_Init(I2C_TypeDef* I2Cx, I2C_InitTypeDef* I2C_InitStruct);//I2C初始化函数
void I2C_StructInit(I2C_InitTypeDef* I2C_InitStruct);//I2C机构体初始化函数
void I2C_Cmd(I2C_TypeDef* I2Cx, FunctionalState NewState);//I2C启动函数
void I2C_DMACmd(I2C_TypeDef* I2Cx, FunctionalState NewState);//I2C配合DMA启动函数
void I2C_DMALastTransferCmd(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);//配置CR1的ACK位,即应答位,收到一个字节后是否应答。
void I2C_SendData(I2C_TypeDef* I2Cx, uint8_t Data);//DR寄存器,数据写入DR自动发送,
uint8_t I2C_ReceiveData(I2C_TypeDef* I2Cx);//接收数据,读取DR数据作为返回值
void I2C_Send7bitAddress(I2C_TypeDef* I2Cx, uint8_t Address, uint8_t I2C_Direction);//发送7位地址的专用函数。
ErrorStatus I2C_CheckEvent(I2C_TypeDef* I2Cx, uint32_t I2C_EVENT);//读取I2C的状态函数
uint32_t I2C_GetLastEvent(I2C_TypeDef* I2Cx);
FlagStatus I2C_GetFlagStatus(I2C_TypeDef* I2Cx, uint32_t I2C_FLAG);
void I2C_ClearFlag(I2C_TypeDef* I2Cx, uint32_t I2C_FLAG);//清除中断标志
ITStatus I2C_GetITStatus(I2C_TypeDef* I2Cx, uint32_t I2C_IT);//夺取中断状态
void I2C_ClearITPendingBit(I2C_TypeDef* I2Cx, uint32_t I2C_IT);//清除中断标志位
2.硬件I2C代码
#include "stm32f10x.h" // Device header
#include "MPU6050Reg.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);//等待EV5事件,确认开始成功
I2C_Send7bitAddress(I2C2, MPU6050_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_TRANSMITTING);//等待EV8事件确定数据发送完成
I2C_SendData(I2C2, Data);//发送具体的数据
MPU6050_WaitEvent(I2C2, I2C_EVENT_MASTER_BYTE_TRANSMITTED);//最后一个字节发送完毕,
//等待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事件,确认开始成功
I2C_Send7bitAddress(I2C2, MPU6050_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, MPU6050_ADDRESS, I2C_Direction_Receiver);//发送从机地址
MPU6050_WaitEvent(I2C2, I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED);//等待EV6事件,确认地址发送完毕
I2C_AcknowledgeConfig(I2C2, DISABLE);//接收一个字节时要在接收到数据之前ACK置零,Stop置一
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的时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);//开启IO口时钟
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_OD;//开漏输出模式
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10 | GPIO_Pin_11;
GPIO_Init(GPIOB, &GPIO_InitStructure);
I2C_InitTypeDef I2C2_InitStructure;
I2C2_InitStructure.I2C_Mode = I2C_Mode_I2C; //选择I2C
I2C2_InitStructure.I2C_Ack = I2C_Ack_Enable;
I2C2_InitStructure.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit;
I2C2_InitStructure.I2C_ClockSpeed = 50000;//配置I2C时钟频率
I2C2_InitStructure.I2C_DutyCycle = I2C_DutyCycle_2;//时钟占空比,在100kHz以上才有用
I2C2_InitStructure.I2C_OwnAddress1 = 0x00;
I2C_Init(I2C2, &I2C2_InitStructure);
I2C_Cmd(I2C2, ENABLE);
MPU6050_WriteReg(MPU6050_PWR_MGMT_1, 0x01);//初始化电源管理寄存器1
MPU6050_WriteReg(MPU6050_PWR_MGMT_2, 0x00);//初始化电源管理寄存器2
MPU6050_WriteReg(MPU6050_SMPLRT_DIV, 0x09);//初始化分频模块,10分频
MPU6050_WriteReg(MPU6050_CONFIG, 0x06);//外部同步给0,6为平滑滤波
MPU6050_WriteReg(MPU6050_GYRO_CONFIG, 0x18);//配置陀螺仪
MPU6050_WriteReg(MPU6050_ACCEL_CONFIG, 0x18);//加速度计寄存器
}
uint8_t MPU6050_GetID(void)
{
return MPU6050_ReadReg(MPU6050_WHO_AM_I);//读取ID号
}
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_ACCEL_YOUT_H);
DataL = MPU6050_ReadReg(MPU6050_ACCEL_YOUT_L);
*GyroY = (DataH << 8) | DataL;
DataH = MPU6050_ReadReg(MPU6050_ACCEL_ZOUT_H);
DataL = MPU6050_ReadReg(MPU6050_ACCEL_ZOUT_L);
*GyroZ = (DataH << 8) | DataL;
}