Hardware IIC communication and source code instructions (code transferable version)

This article inherits from the software IIC communication, so the basic part is not detailed, only how to use the source code is explained.

Taking the MPU6050 as an example, it is first necessary to initialize the hardware IIC communication hardware initialization.

The code is as follows: (the comments are explained in detail)

#include "stm32f10x.h" // Device header
#include "MPU6050_Reg.h"

#define MPU6050_ADDRESS 0xD0 //Slave address + write

//delay function
void IIC_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;
}
}
}


//IIC communication hardware peripheral initialization.
void IIC_Hade_Init(void)
{
RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C2, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
\t
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);
\t
I2C_InitTypeDef I2C_InitStructure;
I2C_InitStructure.I2C_Mode = I2C_Mode_I2C;
I2C_InitStructure.I2C_ClockSpeed = 50000;
I2C_InitStructure.I2C_DutyCycle = I2C_DutyCycle_2;
I2C_InitStructure.I2C_Ack = I2C_Ack_Enable;
I2C_InitStructure.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit;
I2C_InitStructure.I2C_OwnAddress1 = 0x00;
I2C_Init(I2C2, &I2C_InitStructure);
\t
I2C_Cmd(I2C2, ENABLE);
\t
}

Next, specify the address read and specify address write functions.

//Parameter 1: The address of the corresponding register of the data to be written. Parameter 2: The data to be written. Parameter 3: Corresponding slave address (including writing)
//Function: configure the data of the specified register, and then configure the function of the module
void IIC_WriteReg(uint8_t RegAddress, uint8_t Data, uint8_t Slave_ADDRESS)
{
I2C_GenerateSTART(I2C2, ENABLE);
IIC_WaitEvent(I2C2, I2C_EVENT_MASTER_MODE_SELECT);
\t
I2C_Send7bitAddress(I2C2, Slave_ADDRESS, I2C_Direction_Transmitter);
IIC_WaitEvent(I2C2, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED);
\t
I2C_SendData(I2C2, RegAddress);
IIC_WaitEvent(I2C2, I2C_EVENT_MASTER_BYTE_TRANSMITTING);
\t
I2C_SendData(I2C2, Data);
IIC_WaitEvent(I2C2, I2C_EVENT_MASTER_BYTE_TRANSMITTED);
\t
I2C_GenerateSTOP(I2C2, ENABLE);
}

//Parameter 1: The address of the register to be read. Parameter 2: The corresponding slave address (including writing) Return value: The return value is the data stored on the read register.
//Function: Read the data on the specified register.
uint8_t IIC_ReadReg(uint8_t RegAddress, uint8_t Slave_ADDRESS)
{
uint8_t Data;
\t
I2C_GenerateSTART(I2C2, ENABLE);
IIC_WaitEvent(I2C2, I2C_EVENT_MASTER_MODE_SELECT);
\t
I2C_Send7bitAddress(I2C2, Slave_ADDRESS, I2C_Direction_Transmitter);
IIC_WaitEvent(I2C2, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED);
\t
I2C_SendData(I2C2, RegAddress);
IIC_WaitEvent(I2C2, I2C_EVENT_MASTER_BYTE_TRANSMITTED);
\t
I2C_GenerateSTART(I2C2, ENABLE);
IIC_WaitEvent(I2C2, I2C_EVENT_MASTER_MODE_SELECT);
\t
I2C_Send7bitAddress(I2C2, Slave_ADDRESS, I2C_Direction_Receiver);
IIC_WaitEvent(I2C2, I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED);
\t
I2C_AcknowledgeConfig(I2C2, DISABLE);
I2C_GenerateSTOP(I2C2, ENABLE);
\t
IIC_WaitEvent(I2C2, I2C_EVENT_MASTER_BYTE_RECEIVED);
Data = I2C_ReceiveData(I2C2);
\t
I2C_AcknowledgeConfig(I2C2, ENABLE);
\t
return Data;
}

Then use the above code to initialize the function of MPU6050.

//MPU6050 function initialization.
void MPU6050_Init(void)
{
IIC_WriteReg(MPU6050_PWR_MGMT_1, 0x01, MPU6050_ADDRESS);
IIC_WriteReg(MPU6050_PWR_MGMT_2, 0x00, MPU6050_ADDRESS);
IIC_WriteReg(MPU6050_SMPLRT_DIV, 0x09, MPU6050_ADDRESS);
IIC_WriteReg(MPU6050_CONFIG, 0x06, MPU6050_ADDRESS);
IIC_WriteReg(MPU6050_GYRO_CONFIG, 0x18, MPU6050_ADDRESS);
IIC_WriteReg(MPU6050_ACCEL_CONFIG, 0x18, MPU6050_ADDRESS);
\t
}

Then read the device number and read the data function.

//Read the device ID number.
uint8_t MPU6050_GetID(void)
{
return IIC_ReadReg(MPU6050_WHO_AM_I, MPU6050_ADDRESS);
}

//Read the data on the six-axis data register.
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;
\t
DataH = IIC_ReadReg(MPU6050_ACCEL_XOUT_H, MPU6050_ADDRESS);
DataL = IIC_ReadReg(MPU6050_ACCEL_XOUT_L, MPU6050_ADDRESS);
*AccX = (DataH << 8) | DataL;
\t
DataH = IIC_ReadReg(MPU6050_ACCEL_YOUT_H, MPU6050_ADDRESS);
DataL = IIC_ReadReg(MPU6050_ACCEL_YOUT_L, MPU6050_ADDRESS);
*AccY = (DataH << 8) | DataL;
\t
DataH = IIC_ReadReg(MPU6050_ACCEL_ZOUT_H, MPU6050_ADDRESS);
DataL = IIC_ReadReg(MPU6050_ACCEL_ZOUT_L, MPU6050_ADDRESS);
*AccZ = (DataH << 8) | DataL;
\t
DataH = IIC_ReadReg(MPU6050_GYRO_XOUT_H, MPU6050_ADDRESS);
DataL = IIC_ReadReg(MPU6050_GYRO_XOUT_L, MPU6050_ADDRESS);
*GyroX = (DataH << 8) | DataL;
\t
DataH = IIC_ReadReg(MPU6050_GYRO_YOUT_H, MPU6050_ADDRESS);
DataL = IIC_ReadReg(MPU6050_GYRO_YOUT_L, MPU6050_ADDRESS);
*GyroY = (DataH << 8) | DataL;
\t
DataH = IIC_ReadReg(MPU6050_GYRO_ZOUT_H, MPU6050_ADDRESS);
DataL = IIC_ReadReg(MPU6050_GYRO_ZOUT_L, MPU6050_ADDRESS);
*GyroZ = (DataH << 8) | DataL;
}

The overall IIC.C of the above code is as follows:

#include "stm32f10x.h" // Device header
#include "MPU6050_Reg.h"

#define MPU6050_ADDRESS 0xD0 //Slave address + write

//delay function
void IIC_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;
}
}
}

//Parameter 1: The address of the corresponding register of the data to be written. Parameter 2: The data to be written. Parameter 3: Corresponding slave address (including writing)
//Function: configure the data of the specified register, and then configure the function of the module
void IIC_WriteReg(uint8_t RegAddress, uint8_t Data, uint8_t Slave_ADDRESS)
{
I2C_GenerateSTART(I2C2, ENABLE);
IIC_WaitEvent(I2C2, I2C_EVENT_MASTER_MODE_SELECT);
\t
I2C_Send7bitAddress(I2C2, Slave_ADDRESS, I2C_Direction_Transmitter);
IIC_WaitEvent(I2C2, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED);
\t
I2C_SendData(I2C2, RegAddress);
IIC_WaitEvent(I2C2, I2C_EVENT_MASTER_BYTE_TRANSMITTING);
\t
I2C_SendData(I2C2, Data);
IIC_WaitEvent(I2C2, I2C_EVENT_MASTER_BYTE_TRANSMITTED);
\t
I2C_GenerateSTOP(I2C2, ENABLE);
}

//Parameter 1: The address of the register to be read. Parameter 2: The corresponding slave address (including writing) Return value: The return value is the data stored on the read register.
//Function: Read the data on the specified register.
uint8_t IIC_ReadReg(uint8_t RegAddress, uint8_t Slave_ADDRESS)
{
uint8_t Data;
\t
I2C_GenerateSTART(I2C2, ENABLE);
IIC_WaitEvent(I2C2, I2C_EVENT_MASTER_MODE_SELECT);
\t
I2C_Send7bitAddress(I2C2, Slave_ADDRESS, I2C_Direction_Transmitter);
IIC_WaitEvent(I2C2, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED);
\t
I2C_SendData(I2C2, RegAddress);
IIC_WaitEvent(I2C2, I2C_EVENT_MASTER_BYTE_TRANSMITTED);
\t
I2C_GenerateSTART(I2C2, ENABLE);
IIC_WaitEvent(I2C2, I2C_EVENT_MASTER_MODE_SELECT);
\t
I2C_Send7bitAddress(I2C2, Slave_ADDRESS, I2C_Direction_Receiver);
IIC_WaitEvent(I2C2, I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED);
\t
I2C_AcknowledgeConfig(I2C2, DISABLE);
I2C_GenerateSTOP(I2C2, ENABLE);
\t
IIC_WaitEvent(I2C2, I2C_EVENT_MASTER_BYTE_RECEIVED);
Data = I2C_ReceiveData(I2C2);
\t
I2C_AcknowledgeConfig(I2C2, ENABLE);
\t
return Data;
}

//IIC communication hardware peripheral initialization.
void IIC_Hade_Init(void)
{
RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C2, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
\t
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);
\t
I2C_InitTypeDef I2C_InitStructure;
I2C_InitStructure.I2C_Mode = I2C_Mode_I2C;
I2C_InitStructure.I2C_ClockSpeed = 50000;
I2C_InitStructure.I2C_DutyCycle = I2C_DutyCycle_2;
I2C_InitStructure.I2C_Ack = I2C_Ack_Enable;
I2C_InitStructure.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit;
I2C_InitStructure.I2C_OwnAddress1 = 0x00;
I2C_Init(I2C2, &I2C_InitStructure);
\t
I2C_Cmd(I2C2, ENABLE);
\t
}

//MPU6050 function initialization.
void MPU6050_Init(void)
{
IIC_WriteReg(MPU6050_PWR_MGMT_1, 0x01, MPU6050_ADDRESS);
IIC_WriteReg(MPU6050_PWR_MGMT_2, 0x00, MPU6050_ADDRESS);
IIC_WriteReg(MPU6050_SMPLRT_DIV, 0x09, MPU6050_ADDRESS);
IIC_WriteReg(MPU6050_CONFIG, 0x06, MPU6050_ADDRESS);
IIC_WriteReg(MPU6050_GYRO_CONFIG, 0x18, MPU6050_ADDRESS);
IIC_WriteReg(MPU6050_ACCEL_CONFIG, 0x18, MPU6050_ADDRESS);
\t
}

//Read the device ID number.
uint8_t MPU6050_GetID(void)
{
return IIC_ReadReg(MPU6050_WHO_AM_I, MPU6050_ADDRESS);
}

//Read the data on the six-axis data register.
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;
\t
DataH = IIC_ReadReg(MPU6050_ACCEL_XOUT_H, MPU6050_ADDRESS);
DataL = IIC_ReadReg(MPU6050_ACCEL_XOUT_L, MPU6050_ADDRESS);
*AccX = (DataH << 8) | DataL;
\t
DataH = IIC_ReadReg(MPU6050_ACCEL_YOUT_H, MPU6050_ADDRESS);
DataL = IIC_ReadReg(MPU6050_ACCEL_YOUT_L, MPU6050_ADDRESS);
*AccY = (DataH << 8) | DataL;
\t
DataH = IIC_ReadReg(MPU6050_ACCEL_ZOUT_H, MPU6050_ADDRESS);
DataL = IIC_ReadReg(MPU6050_ACCEL_ZOUT_L, MPU6050_ADDRESS);
*AccZ = (DataH << 8) | DataL;
\t
DataH = IIC_ReadReg(MPU6050_GYRO_XOUT_H, MPU6050_ADDRESS);
DataL = IIC_ReadReg(MPU6050_GYRO_XOUT_L, MPU6050_ADDRESS);
*GyroX = (DataH << 8) | DataL;
\t
DataH = IIC_ReadReg(MPU6050_GYRO_YOUT_H, MPU6050_ADDRESS);
DataL = IIC_ReadReg(MPU6050_GYRO_YOUT_L, MPU6050_ADDRESS);
*GyroY = (DataH << 8) | DataL;
\t
DataH = IIC_ReadReg(MPU6050_GYRO_ZOUT_H, MPU6050_ADDRESS);
DataL = IIC_ReadReg(MPU6050_GYRO_ZOUT_L, MPU6050_ADDRESS);
*GyroZ = (DataH << 8) | DataL;
}

The corresponding IIC.H file is as follows:

#ifndef __MPU6050_H
#define __MPU6050_H

void IIC_WriteReg(uint8_t RegAddress, uint8_t Data, uint8_t Slave_ADDRESS);
uint8_t IIC_ReadReg(uint8_t RegAddress, uint8_t Slave_ADDRESS);

void IIC_Hade_Init(void);
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

main.c is as follows:

#include "stm32f10x.h" // Device header
#include "Delay.h"
#include "OLED.h"
#include "MPU6050.h"

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

int main(void)
{
OLED_Init();
IIC_Hade_Init();
MPU6050_Init();
\t
OLED_ShowString(1, 1, "ID:");
ID = MPU6050_GetID();
OLED_ShowHexNum(1, 4, ID, 2);
\t
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);
}
}