I2C(Inter-Integrated Circuit)总线是一种由NXP(原PHILIPS)公司开发的两线式串行总线,用于连接微控制器及其外围设备。多用于主控制器和从器件间的主从通信,在小数据量场合使用,传输距离短,任意时刻只能有一个主机等特性。
串行的 8 位双向数据传输位速率在标准模式下可达 100kbit/s,快速模式下可达 400kbit/s,高速模式下可达 3.4Mbit/s。
I2C是一个多主机的总线,每个设备既可以当主控器或被控器,又可作为发送器或接收器,一条总线上可以有多个主机,但同一时刻只允许一个主机工作。
?MPU6050是一个6轴姿态传感器,可以测量芯片自身X、Y、Z轴的加速度、角速度参数,通过数据融合,可进一步得到姿态角,常应用于平衡车、飞行器等需要检测自身姿态的场景
?3轴加速度计(Accelerometer):测量X、Y、Z轴的加速度
?3轴陀螺仪传感器(Gyroscope):测量X、Y、Z轴的角速度
/**
* @brief Initializes the I2Cx peripheral according to the specified
* parameters in the I2C_InitStruct.
* @param I2Cx: where x can be 1 or 2 to select the I2C peripheral.
* @param I2C_InitStruct: pointer to a I2C_InitTypeDef structure that
* contains the configuration information for the specified I2C peripheral.
* @retval None
*/
void I2C_Init(I2C_TypeDef* I2Cx, I2C_InitTypeDef* I2C_InitStruct)
功能:
根据 I2C_InitStruct 中指定的参数初始化外设 I2Cx 寄存器
参数:
I2Cx:x 可以是 1 或者 2,来选择 I2C 外设
I2C_InitStruct:指向结构 I2C_InitTypeDef 的指针,包含了外设 GPIO 的配置信息
返回值:
无
/**
* @brief I2C Init structure definition
*/
typedef struct
{
uint32_t I2C_ClockSpeed; /*!< Specifies the clock frequency.
This parameter must be set to a value lower than 400kHz */
uint16_t I2C_Mode; /*!< Specifies the I2C mode.
This parameter can be a value of @ref I2C_mode */
uint16_t I2C_DutyCycle; /*!< Specifies the I2C fast mode duty cycle.
This parameter can be a value of @ref I2C_duty_cycle_in_fast_mode */
uint16_t I2C_OwnAddress1; /*!< Specifies the first device own address.
This parameter can be a 7-bit or 10-bit address. */
uint16_t I2C_Ack; /*!< Enables or disables the acknowledgement.
This parameter can be a value of @ref I2C_acknowledgement */
uint16_t I2C_AcknowledgedAddress; /*!< Specifies if 7-bit or 10-bit address is acknowledged.
This parameter can be a value of @ref I2C_acknowledged_address */
}I2C_InitTypeDef;
I2C_Mode
/** @defgroup I2C_mode
* @{
*/
#define I2C_Mode_I2C ((uint16_t)0x0000)
#define I2C_Mode_SMBusDevice ((uint16_t)0x0002)
#define I2C_Mode_SMBusHost ((uint16_t)0x000A)
I2C_DutyCycle
/** @defgroup I2C_duty_cycle_in_fast_mode
* @{
*/
#define I2C_DutyCycle_16_9 ((uint16_t)0x4000) /*!< I2C fast mode Tlow/Thigh = 16/9 */
#define I2C_DutyCycle_2 ((uint16_t)0xBFFF) /*!< I2C fast mode Tlow/Thigh = 2 */
I2C_OwnAddress1
I2C_Ack
/** @defgroup I2C_acknowledgement
* @{
*/
#define I2C_Ack_Enable ((uint16_t)0x0400)
#define I2C_Ack_Disable ((uint16_t)0x0000)
I2C_AcknowledgedAddress
/** @defgroup I2C_acknowledged_address
* @{
*/
#define I2C_AcknowledgedAddress_7bit ((uint16_t)0x4000)
#define I2C_AcknowledgedAddress_10bit ((uint16_t)0xC000)
/**
* @brief Enables or disables the specified I2C peripheral.
* @param I2Cx: where x can be 1 or 2 to select the I2C peripheral.
* @param NewState: new state of the I2Cx peripheral.
* This parameter can be: ENABLE or DISABLE.
* @retval None
*/
void I2C_Cmd(I2C_TypeDef* I2Cx, FunctionalState NewState)
功能:
使能或者失能 I2C 外设
参数:
I2Cx:x 可以是 1 或者 2,来选择 I2C 外设
NewState: 外设 I2Cx 的新状态,这个参数可以取:ENABLE 或者 DISABLE
返回值:
无
/**
* @brief Generates I2Cx communication START condition.
* @param I2Cx: where x can be 1 or 2 to select the I2C peripheral.
* @param NewState: new state of the I2C START condition generation.
* This parameter can be: ENABLE or DISABLE.
* @retval None.
*/
void I2C_GenerateSTART(I2C_TypeDef* I2Cx, FunctionalState NewState)
功能:
产生 I2Cx 传输 START 条件
参数:
I2Cx:x 可以是 1 或者 2,来选择 I2C 外设
NewState: I2Cx START 条件的新状态, 这个参数可以取:ENABLE 或者 DISABLE
返回值:
无
/**
* @brief Generates I2Cx communication STOP condition.
* @param I2Cx: where x can be 1 or 2 to select the I2C peripheral.
* @param NewState: new state of the I2C STOP condition generation.
* This parameter can be: ENABLE or DISABLE.
* @retval None.
*/
void I2C_GenerateSTOP(I2C_TypeDef* I2Cx, FunctionalState NewState)
功能:
产生 I2Cx 传输 STOP 条件
参数:
I2Cx:x 可以是 1 或者 2,来选择 I2C 外设
NewState: I2Cx STOP 条件的新状态, 这个参数可以取:ENABLE 或者 DISABLE
返回值:
无
/**
* @brief Enables or disables the specified I2C acknowledge feature.
* @param I2Cx: where x can be 1 or 2 to select the I2C peripheral.
* @param NewState: new state of the I2C Acknowledgement.
* This parameter can be: ENABLE or DISABLE.
* @retval None.
*/
void I2C_AcknowledgeConfig(I2C_TypeDef* I2Cx, FunctionalState NewState)
功能:
使能或者失能指定 I2C 的应答功能
参数:
I2Cx:x 可以是 1 或者 2,来选择 I2C 外设
NewState: I2Cx 应答的新状态, 这个参数可以取:ENABLE 或者 DISABLE
返回值:
无
/**
* @brief Sends a data byte through the I2Cx peripheral.
* @param I2Cx: where x can be 1 or 2 to select the I2C peripheral.
* @param Data: Byte to be transmitted..
* @retval None
*/
void I2C_SendData(I2C_TypeDef* I2Cx, uint8_t Data)
功能:
通过外设 I2Cx 发送一个数据
参数:
I2Cx:x 可以是 1 或者 2,来选择 I2C 外设
Data: 待发送的数据
返回值:
无
/**
* @brief Returns the most recent received data by the I2Cx peripheral.
* @param I2Cx: where x can be 1 or 2 to select the I2C peripheral.
* @retval The value of the received data.
*/
uint8_t I2C_ReceiveData(I2C_TypeDef* I2Cx)
功能:
返回通过 I2Cx 最近接收的数据
参数:
I2Cx:x 可以是 1 或者 2,来选择 I2C 外设
返回值:
接收到的字
/**
* @brief Transmits the address byte to select the slave device.
* @param I2Cx: where x can be 1 or 2 to select the I2C peripheral.
* @param Address: specifies the slave address which will be transmitted
* @param I2C_Direction: specifies whether the I2C device will be a
* Transmitter or a Receiver. This parameter can be one of the following values
* @arg I2C_Direction_Transmitter: Transmitter mode
* @arg I2C_Direction_Receiver: Receiver mode
* @retval None.
*/
void I2C_Send7bitAddress(I2C_TypeDef* I2Cx, uint8_t Address, uint8_t I2C_Direction)
功能:
向指定的从 I2C 设备传送地址字
参数:
I2Cx:x 可以是 1 或者 2,来选择 I2C 外设
Address: 待传输的从 I2C 地址
I2C_Direction:设置指定的 I2C 设备工作为发射端还是接收端
返回值:
无
/**
* @brief Checks whether the last I2Cx Event is equal to the one passed
* as parameter.
* @param I2Cx: where x can be 1 or 2 to select the I2C peripheral.
* @param I2C_EVENT: specifies the event to be checked.
* This parameter can be one of the following values:
* @arg I2C_EVENT_SLAVE_TRANSMITTER_ADDRESS_MATCHED : EV1
* @arg I2C_EVENT_SLAVE_RECEIVER_ADDRESS_MATCHED : EV1
* @arg I2C_EVENT_SLAVE_TRANSMITTER_SECONDADDRESS_MATCHED : EV1
* @arg I2C_EVENT_SLAVE_RECEIVER_SECONDADDRESS_MATCHED : EV1
* @arg I2C_EVENT_SLAVE_GENERALCALLADDRESS_MATCHED : EV1
* @arg I2C_EVENT_SLAVE_BYTE_RECEIVED : EV2
* @arg (I2C_EVENT_SLAVE_BYTE_RECEIVED | I2C_FLAG_DUALF) : EV2
* @arg (I2C_EVENT_SLAVE_BYTE_RECEIVED | I2C_FLAG_GENCALL) : EV2
* @arg I2C_EVENT_SLAVE_BYTE_TRANSMITTED : EV3
* @arg (I2C_EVENT_SLAVE_BYTE_TRANSMITTED | I2C_FLAG_DUALF) : EV3
* @arg (I2C_EVENT_SLAVE_BYTE_TRANSMITTED | I2C_FLAG_GENCALL) : EV3
* @arg I2C_EVENT_SLAVE_ACK_FAILURE : EV3_2
* @arg I2C_EVENT_SLAVE_STOP_DETECTED : EV4
* @arg I2C_EVENT_MASTER_MODE_SELECT : EV5
* @arg I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED : EV6
* @arg I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED : EV6
* @arg I2C_EVENT_MASTER_BYTE_RECEIVED : EV7
* @arg I2C_EVENT_MASTER_BYTE_TRANSMITTING : EV8
* @arg I2C_EVENT_MASTER_BYTE_TRANSMITTED : EV8_2
* @arg I2C_EVENT_MASTER_MODE_ADDRESS10 : EV9
*
* @note: For detailed description of Events, please refer to section
* I2C_Events in stm32f10x_i2c.h file.
*
* @retval An ErrorStatus enumeration value:
* - SUCCESS: Last event is equal to the I2C_EVENT
* - ERROR: Last event is different from the I2C_EVENT
*/
ErrorStatus I2C_CheckEvent(I2C_TypeDef* I2Cx, uint32_t I2C_EVENT)
功能:
检查指定的I2C的标志
参数:
I2Cx:x 可以是 1 或者 2,来选择 I2C 外设
I2C_Event:待检查的事件
返回值:
ErrorStatus 枚举值:
SUCCESS:最近一次 I2C 事件是 I2C_Event
ERROR:最近一次 I2C 事件不是 I2C_Event
MPU6050.h
#ifndef __MPU6050_H__
#define __MPU6050_H__
#include "mpu6050.h"
#include "stm32f10x.h"
#define MPU6050_ADDRESS 0xD0
#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
void MPU6050_WriteReg(uint8_t regAddr, uint8_t data);
uint8_t MPU6050_ReadReg(uint8_t regAddr);
void MPU6050_init(void);
uint8_t MPU6050_getId(void);
void MPU6050_getData(int16_t *AccX, int16_t *AccY, int16_t *AccZ,
int16_t *GyroX, int16_t *GyroY, int16_t *GyroZ);
#endif /*__MPU6050_H__*/
MPU6050.c
#include "mpu6050.h"
void MPU6050_WaitEvent(I2C_TypeDef* I2Cx, uint32_t I2C_EVENT)
{
uint32_t timeout;
timeout = 100000;
while(I2C_CheckEvent(I2Cx, I2C_EVENT) != SUCCESS)
{
timeout--;
if (0 == timeout)
{
break;
}
}
}
void MPU6050_WriteReg(uint8_t regAddr, uint8_t data)
{
//发送起始条件
I2C_GenerateSTART(I2C2, ENABLE);
MPU6050_WaitEvent(I2C2, I2C_EVENT_MASTER_MODE_SELECT);
//发送7位地址
I2C_Send7bitAddress(I2C2, MPU6050_ADDRESS, I2C_Direction_Transmitter);
MPU6050_WaitEvent(I2C2, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED);
//发送寄存器地址
I2C_SendData(I2C2, regAddr);
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 regAddr)
{
uint8_t data = 0;
//发送起始条件
I2C_GenerateSTART(I2C2, ENABLE);
MPU6050_WaitEvent(I2C2, I2C_EVENT_MASTER_MODE_SELECT);
//发送7位地址
I2C_Send7bitAddress(I2C2, MPU6050_ADDRESS, I2C_Direction_Transmitter);
MPU6050_WaitEvent(I2C2, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED);
//发送寄存器地址
I2C_SendData(I2C2, regAddr);
MPU6050_WaitEvent(I2C2, I2C_EVENT_MASTER_BYTE_TRANSMITTED);
//发送起始条件
I2C_GenerateSTART(I2C2, ENABLE);
MPU6050_WaitEvent(I2C2, I2C_EVENT_MASTER_MODE_SELECT);
//发送7位地址
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;
}
void MPU6050_init(void)
{
GPIO_InitTypeDef GPIO_InitStruct;
I2C_InitTypeDef I2C_InitStruct;
//I2C初始化
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C2, ENABLE);
//PB10 PB11
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF_OD;
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_11 | GPIO_Pin_10;
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB, &GPIO_InitStruct);
I2C_InitStruct.I2C_Mode = I2C_Mode_I2C;
I2C_InitStruct.I2C_ClockSpeed = 50000;
I2C_InitStruct.I2C_DutyCycle = I2C_DutyCycle_2;
I2C_InitStruct.I2C_Ack = I2C_Ack_Enable;
I2C_InitStruct.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit;
I2C_InitStruct.I2C_OwnAddress1 = 0x00;
I2C_Init(I2C2, &I2C_InitStruct);
//使能I2C
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;
}
main.c
#include "stm32f10x.h"
#include "delay.h"
#include "oled.h"
#include "mpu6050.h"
int main(void)
{
uint8_t data = 0;
int16_t AX, AY, AZ, GX, GY, GZ;
//初始化
OLED_Init();
MPU6050_init();
data = MPU6050_getId();
OLED_ShowString(1, 1, "ID: ");
OLED_ShowHexNum(1, 5, data, 3);
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);
}
return 0;
}