STM32 I2C硬件通信(标准库)详解

目录

 一丶I2C简介

二丶读写过程

(一)发送过程

(二)接收数据

 三丶库函数

四丶代码部分及解析(使用了MPU6050观察实验现象)

(一)I2C及MPU6050初始化部分

(二)主函数部分


      一丶I2C简介

(1)由两条总线控制:一条双向串行数据线(SDA) ,一条串行时钟线 (SCL)。SDA用来发送数据,SCL用于数据收发同步。
(2)I2C总线上可挂在多个 I2C通讯的设备
(3)每个连接到总线的设备都有一个独立的地址,主机可以利用这个地址进行不同设备之间的访问。
(4)总线通过上拉电阻接到电源。当 I2C 设备空闲时,输出高阻态,而当所有设备都空闲,都输出高阻态,上拉电阻将总线拉成高电平。
(5)多个主机同时使用总线时,为了防止数据冲突,会利用仲裁方式决定由哪个设备占用总线。

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

(7)同步,半双工

二丶读写过程

(1)发送过程

(2)接收数据

 三丶库函数

(1)void I2C_Init(I2C_TypeDef* I2Cx, I2C_InitTypeDef* I2C_InitStruct);

          初始化I2C 

(2)void I2C_Cmd(I2C_TypeDef* I2Cx, FunctionalState NewState);

         使能I2C

(3)void I2C_Cmd(I2C_TypeDef* I2Cx, FunctionalState NewState);
         void I2C_DMACmd(I2C_TypeDef* I2Cx, FunctionalState NewState);

         配合DMA使用

(4)void I2C_GenerateSTART(I2C_TypeDef* I2Cx, FunctionalState NewState);
         void I2C_GenerateSTOP(I2C_TypeDef* I2Cx, FunctionalState NewState);

         起始条件和终止条件

(5)void I2C_AcknowledgeConfig(I2C_TypeDef* I2Cx, FunctionalState NewState); 

收到一个字节后是否给从机应答  

 (6)void I2C_OwnAddress2Config(I2C_TypeDef* I2Cx, uint8_t Address);

          设置主机地址(STM32当从机使用时配置)

(7)void I2C_SendData(I2C_TypeDef* I2Cx, uint8_t Data);
         uint8_t I2C_ReceiveData(I2C_TypeDef* I2Cx);

         发送数据和接收数据

(8)void I2C_Send7bitAddress(I2C_TypeDef* I2Cx, uint8_t Address, uint8_t I2C_Direction);

         发送从机地址(当然I2C_SendData也可以发送)

(9)I2C_CheckEvent(I2C_TypeDef* I2Cx, uint32_t I2C_EVENT);

          检查应答位

四丶代码部分及解析(使用了MPU6050观察实验现象)

(一)I2C及MPU6050初始化部分

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

#define MPU6050_ADDRESS		0xD0



void MPU6050_Init(void)
{
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C2, ENABLE);    //开启GPIO时钟
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);   //开启I2C时钟
	
	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);                  //初始化GPIO
	
	I2C_InitTypeDef I2C_InitStructure;
	I2C_InitStructure.I2C_Mode = I2C_Mode_I2C;              //I2C模式
	I2C_InitStructure.I2C_ClockSpeed = 50000;               //传输速度,最大不能超过400KHZ
	I2C_InitStructure.I2C_DutyCycle = I2C_DutyCycle_2;      //时钟占空比
	I2C_InitStructure.I2C_Ack = I2C_Ack_Enable;             //主机是否设置应答
	I2C_InitStructure.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit;  //主机地址位数  7位或10位
	I2C_InitStructure.I2C_OwnAddress1 = 0x00;               //主机地址(当STM32位从机时)
	I2C_Init(I2C2, &I2C_InitStructure);
	
	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);
}



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);
	
	I2C_Send7bitAddress(I2C2, MPU6050_ADDRESS, I2C_Direction_Transmitter);
	MPU6050_WaitEvent(I2C2, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED);
	
	I2C_SendData(I2C2, RegAddress);
	MPU6050_WaitEvent(I2C2, I2C_EVENT_MASTER_BYTE_TRANSMITTED);       //此上与发送数据相同
	
	I2C_GenerateSTART(I2C2, ENABLE);
	MPU6050_WaitEvent(I2C2, I2C_EVENT_MASTER_MODE_SELECT);            
	
	I2C_Send7bitAddress(I2C2, MPU6050_ADDRESS, I2C_Direction_Receiver);
	MPU6050_WaitEvent(I2C2, I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED);      //检测EV6(接收模式)
	
	I2C_AcknowledgeConfig(I2C2, DISABLE);                                  //主机给从机应答位A
	I2C_GenerateSTOP(I2C2, ENABLE);                                        //接收数据时需要提前发送终止位
	
	MPU6050_WaitEvent(I2C2, I2C_EVENT_MASTER_BYTE_RECEIVED);               //检测EV7
	Data = I2C_ReceiveData(I2C2);
	
	I2C_AcknowledgeConfig(I2C2, ENABLE);
	
	return Data;
}

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;
}

(二)主函数部分

#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();
	MPU6050_Init();
	
	OLED_ShowString(1, 1, "ID:");
	ID = MPU6050_GetID();
	OLED_ShowHexNum(1, 4, ID, 2);
	
	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);
	}
}

注:指定地址读时需要重复一段指定地址写的部分(即用蓝色圈出的部分)

补充:

欧拉⾓:飞机与XYZ轴的夹⾓,反应了飞机的姿态,侧仰,上倾,下倾; 获得欧拉⾓需要多个数据,常⽤的数据融合算法:互补滤波、卡尔曼滤波等 MPU6050 XCL和SDA是扩展使⽤,通常是外接磁⼒计或者⽓压计

 

物联沃分享整理
物联沃-IOTWORD物联网 » STM32 I2C硬件通信(标准库)详解

发表评论