【STM32-学习笔记-8-】I2C通信

embedded/2025/1/15 14:46:22/

文章目录

  • I2C通信
    • Ⅰ、硬件电路
    • Ⅱ、IIC时序基本单元
      • ① 起始条件
      • ② 终止条件
      • ③ 发送一个字节
      • ④ 接收一个字节
      • ⑤ 发送应答
      • ⑥ 接收应答
    • Ⅲ、IIC时序
      • ① 指定地址写
      • ② 当前地址读
      • ③ 指定地址读
    • Ⅳ、MPU6050---6轴姿态传感器(软件I2C)
      • 1、模块内部电路
      • 2、寄存器地址
      • 3、软件模拟IIC
        • ①、MPU6050.c
        • ②、MPU6050.h
        • ③、MPU6050_Reg.h
    • Ⅴ、硬件IIC(I2C外设)
      • 1、I2C硬件外设
      • 2、I2C框图
      • 3、I2C基本结构
      • 4、主机发送
      • 5、主机接收
    • Ⅵ、配置I2C外设
      • 1、I2C函数
      • 2、I2C_InitTypeDef结构体参数
        • ①、I2C_ClockSpeed
        • ②、I2C_Mode
        • ③、I2C_DutyCycle
        • ④、I2C_OwnAddress1
        • ⑤、I2C_Ack
        • ⑥、I2C_AcknowledgedAddress
      • 3、I2C外设
        • ①、MPU6050.c

I2C通信

名称引脚双工时钟电平设备
I2CSCL、SDA半双工同步单端多设备
  • I2C(Inter IC Bus)是由Philips公司开发的一种通用数据总线

  • 两根通信线:SCL(Serial Clock)、SDA(Serial Data)

  • 同步,半双工

  • 带数据应答

  • 支持总线挂载多设备(一主多从、多主多从)

Ⅰ、硬件电路

  1. 所有I2C设备的SCL连在一起,SDA连在一起

  2. 设备的SCL和SDA均要配置成开漏输出模式

  3. SCL和SDA各添加一个上拉电阻,阻值一般为4.7KΩ左右,高电平驱动能力弱

image-20250104142118180

Ⅱ、IIC时序基本单元

① 起始条件

  • SCL高电平期间,SDA从高电平切换到低电平

image-20250104142341367

② 终止条件

  • SCL高电平期间,SDA从低电平切换到高电平

image-20250104142446909

③ 发送一个字节

  • SCL低电平期间,主机将数据位依次放到SDA线上(高位先行),然后释放SCL,从机将在SCL高电平期间读取数据位,所以SCL高电平期间SDA不允许有数据变化,依次循环上述过程8次,即可发送一个字节

image-20250104142940845

发送期间SCL与SDA只能由主机(STM32)控制

  • 最后一位为读写标志位(0:写;1:读)

④ 接收一个字节

  • SCL低电平期间,从机将数据位依次放到SDA线上(高位先行),然后释放SCL,主机将在SCL高电平期间读取数据位,所以SCL高电平期间SDA不允许有数据变化,依次循环上述过程8次,即可接收一个字节(主机在接收之前,需要释放SDA

image-20250104143340792

⑤ 发送应答

  • 主机在接收完一个字节之后,在下一个时钟发送一位数据,(SDA)数据0表示应答,数据1表示非应答

image-20250104145540041

⑥ 接收应答

  • 主机在发送完一个字节之后,在下一个时钟接收一位数据,判断从机是否应答,数据0表示应答,数据1表示非应答(主机在接收之前,需要释放SDA

image-20250104145556162

Ⅲ、IIC时序

指定地址单字节

image-20250104185532597

指定地址多字节

image-20250104185611104

指定地址单字节

image-20250104185646816

指定地址多字节

image-20250104185723329

① 指定地址写

  • 对于指定设备(Slave Address),在指定地址(Reg Address)下,写入指定数据(Data)

image-20250104162847176

② 当前地址读

  • 对于指定设备(Slave Address),在当前地址指针指示的地址下,读取从机数据(Data)
    • 每一次的读写数据都会造成地址指针+1

image-20250104164032199

③ 指定地址读

  • 对于指定设备(Slave Address),在指定地址(Reg Address)下,读取从机数据(Data)

image-20250104164540158

  • Sr:重复起始条件(另启时序)

Ⅳ、MPU6050—6轴姿态传感器(软件I2C)

  • MPU6050是一个6轴姿态传感器,可以测量芯片自身X、Y、Z轴的加速度、角速度参数,通过数据融合,可进一步得到姿态角,常应用于平衡车、飞行器等需要检测自身姿态的场景

  • 3轴加速度计(Accelerometer):测量X、Y、Z轴的加速度

    • 静态稳定,动态不稳定
  • 3轴陀螺仪传感器(Gyroscope):测量X、Y、Z轴的角速度

    • 动态稳定,静态不稳定
  • 16位ADC采集传感器的模拟信号,量化范围:-32768~32767

  • 加速度计满量程选择:±2、±4、±8、±16(g)

  • 陀螺仪满量程选择: ±250、±500、±1000、±2000(°/sec)

  • 可配置的数字低通滤波器

  • 可配置的时钟源

  • 可配置的采样分频

  • I2C从机地址:

    • 1101000AD0=0
    • 1101001AD0=1

1、模块内部电路

image-20250104172907586

引脚功能
VCC、GND电源
SCL、SDAI2C通信引脚
XCL、XDA主机I2C通信引脚 (与扩展设备通信)
AD0从机地址最低位
INT中断信号输出

image-20250104173210431

2、寄存器地址

image-20250105164048416

请添加图片描述

3、软件模拟IIC

可任意指定两个引脚,分别作为IICSCLSDA,本示例中使用的引脚为PB10、PB11

  • SCL:PB10
  • SDA:PB11

MyI2C.c

#include "stm32f10x.h"                  // Device header
#include "Delay.h"/*
SCL:>PB10
SDA:>PB11
*/void MyI2C_W_SCL(char BitValue) {GPIO_WriteBit(GPIOB, GPIO_Pin_10, (BitAction)BitValue);Delay_us(10);
}
void MyI2C_W_SDA(char BitValue) {GPIO_WriteBit(GPIOB, GPIO_Pin_11, (BitAction)BitValue);Delay_us(10);
}
uint8_t MyI2C_R_SDA(void) {uint8_t BitValue = GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_11);Delay_us(10);return BitValue;
}//初始化IIC
void MyI2C_Init(void)
{RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);GPIO_InitTypeDef GPIO_InitStruct;GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_OD;//配置成开漏输出模式GPIO_InitStruct.GPIO_Pin = GPIO_Pin_10 | GPIO_Pin_11;GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOB, &GPIO_InitStruct);GPIO_SetBits(GPIOB, GPIO_Pin_10 | GPIO_Pin_11);//初始化为高电平(释放总线)
}//I2C开始函数(SCL高电平期间,SDA从高电平切换到低电平,最后拉低SCL)
//为了兼容重复起始条件,应将SDA置高放在SCL置高之前
void MyI2C_Start(void)
{MyI2C_W_SDA(1);MyI2C_W_SCL(1);MyI2C_W_SDA(0);MyI2C_W_SCL(0);
}//I2C终止函数(SCL高电平期间,SDA从低电平切换到高电平)
void MyI2C_Stop(void)
{MyI2C_W_SDA(0);MyI2C_W_SCL(1);MyI2C_W_SDA(1);
}//I2C发送一个字节
void MyI2C_SendByte(uint8_t Byte)
{uint8_t i = 0;for(i = 0;i < 8;i++) {MyI2C_W_SDA(Byte & (0x80 >> i));MyI2C_W_SCL(1);MyI2C_W_SCL(0);}
}//I2C接收一个字节
uint8_t MyI2C_ReceiveByte(void)
{uint8_t Byte = 0x00;uint8_t i = 0;MyI2C_W_SDA(1);//主机释放SDAfor(i = 0;i < 8;i++) {MyI2C_W_SCL(1);if(MyI2C_R_SDA() == 1) {//主机读取SDA		Byte |= (0x80 >> i);}MyI2C_W_SCL(0);}return Byte;
}//发送应答
void MyI2C_SendAck(char AckBit)
{MyI2C_W_SDA(AckBit);MyI2C_W_SCL(1);MyI2C_W_SCL(0);
}//接收应答
uint8_t MyI2C_ReceiveAck(void)
{MyI2C_W_SDA(1);//松手MyI2C_W_SCL(1);uint8_t Ack = MyI2C_R_SDA();MyI2C_W_SCL(0);return Ack;
}
①、MPU6050.c
#include "stm32f10x.h"                  // Device header
#include "MyIIC.h"
#include "MPU6050_Reg.h"
#include "MPU6050.h"#define MPU6050_ADDR 0xD0//从机地址+读写位//指定地址写
void MPU6050_WriteReg(uint8_t RegAddr, uint8_t Data)
{MyI2C_Start();					//开始MyI2C_SendByte(MPU6050_ADDR);	//指定从机MyI2C_ReceiveAck();				//接收应答(可处理)MyI2C_SendByte(RegAddr);		//指定地址MyI2C_ReceiveAck();				//接收应答(可处理)MyI2C_SendByte(Data);			//发送数据MyI2C_ReceiveAck();				//接收应答(可处理)MyI2C_Stop();					//停止
}//指定地址读
uint8_t MPU6050_ReadReg(uint8_t RegAddr)
{MyI2C_Start();					//开始MyI2C_SendByte(MPU6050_ADDR);	//指定从机--写MyI2C_ReceiveAck();	MyI2C_SendByte(RegAddr);		//指定地址MyI2C_ReceiveAck();MyI2C_Start();					//Sr重复起始MyI2C_SendByte(MPU6050_ADDR | 0x01);//指定从机--读MyI2C_ReceiveAck();uint8_t Data = MyI2C_ReceiveByte();MyI2C_SendAck(1);				//不给从机应答MyI2C_Stop();					//停止return Data;
}void MPU6050_Init(void)
{MyI2C_Init();MPU6050_WriteReg(MPU6050_PWR_MGMT_1, 0x01);//配置电源管理寄存器1,解除睡眠,选择x轴的时钟MPU6050_WriteReg(MPU6050_PWR_MGMT_2, 0x00);//配置电源管理寄存器2,六轴均不待机MPU6050_WriteReg(MPU6050_SMPLRT_DIV, 0x09);//采样率分频器:10分频MPU6050_WriteReg(MPU6050_CONFIG, 0x06);//滤波参数MPU6050_WriteReg(MPU6050_GYRO_CONFIG, 0x18);//陀螺仪最大量程MPU6050_WriteReg(MPU6050_ACCEL_CONFIG, 0x18);//加速度计最大量程
}void MPU6050_GetData(MPU_Data* pData)
{uint16_t Data_H, Data_L;//加速度计XData_H = MPU6050_ReadReg(MPU6050_ACCEL_XOUT_H);//读高位Data_L = MPU6050_ReadReg(MPU6050_ACCEL_XOUT_L);//读低位pData->AccX = (Data_H << 8) | Data_L;//拼接//加速度计YData_H = MPU6050_ReadReg(MPU6050_ACCEL_YOUT_H);Data_L = MPU6050_ReadReg(MPU6050_ACCEL_YOUT_L);pData->AccY = (Data_H << 8) | Data_L;//加速度计ZData_H = MPU6050_ReadReg(MPU6050_ACCEL_ZOUT_H);Data_L = MPU6050_ReadReg(MPU6050_ACCEL_ZOUT_L);pData->AccZ = (Data_H << 8) | Data_L;//陀螺仪XData_H = MPU6050_ReadReg(MPU6050_GYRO_XOUT_H);Data_L = MPU6050_ReadReg(MPU6050_GYRO_XOUT_L);pData->GyrX = (Data_H << 8) | Data_L;//陀螺仪YData_H = MPU6050_ReadReg(MPU6050_GYRO_YOUT_H);Data_L = MPU6050_ReadReg(MPU6050_GYRO_YOUT_L);pData->GyrY = (Data_H << 8) | Data_L;//陀螺仪ZData_H = MPU6050_ReadReg(MPU6050_GYRO_ZOUT_H);Data_L = MPU6050_ReadReg(MPU6050_GYRO_ZOUT_L);pData->GyrZ = (Data_H << 8) | Data_L;//温度Data_H = MPU6050_ReadReg(MPU6050_TEMP_OUT_H);Data_L = MPU6050_ReadReg(MPU6050_TEMP_OUT_L);pData->TEMP = (Data_H << 8) | Data_L;	
}uint8_t MPU6050_GetID(void)
{return MPU6050_ReadReg(MPU6050_WHO_AM_I);
}
②、MPU6050.h
#ifndef __MPU6050_H__
#define __MPU6050_H__
#include "stdint.h"
typedef struct {int16_t AccX;int16_t AccY;int16_t AccZ;int16_t GyrX;int16_t GyrY;int16_t GyrZ;int16_t TEMP;
}MPU_Data;void MPU6050_WriteReg(uint8_t RegAddr, uint8_t Data);//指定地址写
uint8_t MPU6050_ReadReg(uint8_t RegAddr);//指定地址读
void MPU6050_Init(void);
void MPU6050_GetData(MPU_Data* pData);
uint8_t MPU6050_GetID(void);#endif

实际数据 = 转换后的值 32768 ∗ 选择的量程 实际数据 = \frac{转换后的值 }{32768}*选择的量程 实际数据=32768转换后的值选择的量程

③、MPU6050_Reg.h

常用寄存器

#ifndef __MPU6050_REG_H__
#define __MPU6050_REG_H__
//#define	寄存器名称	地址#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	//加速度计X轴高字节
#define	MPU6050_ACCEL_XOUT_L	0x3C	//加速度计X轴低字节
#define	MPU6050_ACCEL_YOUT_H	0x3D	//加速度计Y轴高字节
#define	MPU6050_ACCEL_YOUT_L	0x3E	//加速度计Y轴低字节
#define	MPU6050_ACCEL_ZOUT_H	0x3F	//加速度计Z轴高字节
#define	MPU6050_ACCEL_ZOUT_L	0x40	//加速度计Z轴低字节
#define	MPU6050_TEMP_OUT_H		0x41	//温度高字节
#define	MPU6050_TEMP_OUT_L		0x42	//温度低字节
#define	MPU6050_GYRO_XOUT_H		0x43	//陀螺仪X轴高字节
#define	MPU6050_GYRO_XOUT_L		0x44	//陀螺仪X轴低字节
#define	MPU6050_GYRO_YOUT_H		0x45	//陀螺仪Y轴高字节
#define	MPU6050_GYRO_YOUT_L		0x46	//陀螺仪Y轴低字节
#define	MPU6050_GYRO_ZOUT_H		0x47	//陀螺仪Z轴高字节
#define	MPU6050_GYRO_ZOUT_L		0x48	//陀螺仪Z轴低字节#define	MPU6050_PWR_MGMT_1		0x6B	//电源管理1
#define	MPU6050_PWR_MGMT_2		0x6C	//电源管理2
#define	MPU6050_WHO_AM_I		0x75	//设备ID#endif

Ⅴ、硬件IIC(I2C外设)

1、I2C硬件外设

  • STM32内部集成了硬件I2C收发电路,可以由硬件自动执行时钟生成、起始终止条件生成、应答位收发、数据收发等功能,减轻CPU的负担

  • 支持多主机模型

  • 支持7位/10位地址模式

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

  • 支持DMA

  • 兼容SMBus协议

  • STM32F103C8T6 硬件I2C资源:I2C1、I2C2

2、I2C框图

image-20250107202309431

image-20250107203426140

3、I2C基本结构

image-20250107203509030

4、主机发送

image-20250107205015755

5、主机接收

image-20250107205024938

Ⅵ、配置I2C外设

  1. 开启时钟:I2C外设和GPIO口的时钟
  2. 把I2C外设对应的GPIO口设置成复用开漏模式
  3. 配置I2C:结构体
  4. 使能I2C

1、I2C函数

// 重置指定的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的DMA功能
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);
// 生成I2C的停止信号
void I2C_GenerateSTOP(I2C_TypeDef* I2Cx, FunctionalState NewState);// 配置I2C的应答使能
void I2C_AcknowledgeConfig(I2C_TypeDef* I2Cx, FunctionalState NewState);// 配置I2C的第二个地址
void I2C_OwnAddress2Config(I2C_TypeDef* I2Cx, uint8_t Address);
// 开启或关闭I2C的双地址模式
void I2C_DualAddressCmd(I2C_TypeDef* I2Cx, FunctionalState NewState);
// 开启或关闭I2C的通用呼叫模式
void I2C_GeneralCallCmd(I2C_TypeDef* I2Cx, FunctionalState NewState);// 开启或关闭I2C的中断
void I2C_ITConfig(I2C_TypeDef* I2Cx, uint16_t I2C_IT, FunctionalState NewState);// 通过I2C发送数据
void I2C_SendData(I2C_TypeDef* I2Cx, uint8_t Data);
// 通过I2C接收数据
uint8_t I2C_ReceiveData(I2C_TypeDef* I2Cx);// 发送I2C的7位地址和方向
void I2C_Send7bitAddress(I2C_TypeDef* I2Cx, uint8_t Address, uint8_t I2C_Direction);// 读取I2C寄存器的值
uint16_t I2C_ReadRegister(I2C_TypeDef* I2Cx, uint8_t I2C_Register);// 发送I2C软件复位信号
void I2C_SoftwareResetCmd(I2C_TypeDef* I2Cx, FunctionalState NewState);// 配置I2C的NACK位置
void I2C_NACKPositionConfig(I2C_TypeDef* I2Cx, uint16_t I2C_NACKPosition);// 配置I2C的SMBus警报
void I2C_SMBusAlertConfig(I2C_TypeDef* I2Cx, uint16_t I2C_SMBusAlert);// 开启或关闭I2C的PEC传输
void I2C_TransmitPEC(I2C_TypeDef* I2Cx, FunctionalState NewState);
// 配置I2C的PEC位置
void I2C_PECPositionConfig(I2C_TypeDef* I2Cx, uint16_t I2C_PECPosition);
// 开启或关闭I2C的PEC计算
void I2C_CalculatePEC(I2C_TypeDef* I2Cx, FunctionalState NewState);
// 获取I2C的PEC值
uint8_t I2C_GetPEC(I2C_TypeDef* I2Cx);// 开启或关闭I2C的ARP功能
void I2C_ARPCmd(I2C_TypeDef* I2Cx, FunctionalState NewState);// 开启或关闭I2C的时钟拉伸功能
void I2C_StretchClockCmd(I2C_TypeDef* I2Cx, FunctionalState NewState);// 配置I2C的快速模式占空比
void I2C_FastModeDutyCycleConfig(I2C_TypeDef* I2Cx, uint16_t I2C_DutyCycle);//检查I2C事件是否发生
ErrorStatus I2C_CheckEvent(I2C_TypeDef* I2Cx, uint32_t I2C_EVENT);
//获取I2C最后一个发生的事件
uint32_t I2C_GetLastEvent(I2C_TypeDef* I2Cx);//获取I2C标志状态
FlagStatus I2C_GetFlagStatus(I2C_TypeDef* I2Cx, uint32_t I2C_FLAG);
//清除I2C标志。
void I2C_ClearFlag(I2C_TypeDef* I2Cx, uint32_t I2C_FLAG);//获取I2C中断状态。
ITStatus I2C_GetITStatus(I2C_TypeDef* I2Cx, uint32_t I2C_IT);
//清除I2C中断待处理位。
void I2C_ClearITPendingBit(I2C_TypeDef* I2Cx, uint32_t I2C_IT);

2、I2C_InitTypeDef结构体参数

①、I2C_ClockSpeed

时钟频率—该参数必须设置为低于400kHz的值

②、I2C_Mode

I2C模式

  • 该参数可以是@ref I2C_mode

  • @ref I2C_mode

    • 宏定义解释

      1. I2C_Mode_I2C
        • 描述:定义了标准的I2C模式。在这种模式下,I2C接口按照I2C协议的标准规范进行通信
      2. I2C_Mode_SMBusDevice
        • 描述:定义了SMBus(System Management Bus)设备模式。SMBus是一种基于I2C的协议,主要用于系统管理通信。在这种模式下,I2C接口按照SMBus协议进行通信,作为设备端
      3. I2C_Mode_SMBusHost
        • 描述:定义了SMBus主机模式。在这种模式下,I2C接口按照SMBus协议进行通信,作为主机端,可以控制通信过程

      宏函数

      1. IS_I2C_MODE(MODE)
        • 描述:这是一个宏函数,用于检查给定的工作模式设置是否有效
        • 参数MODE,代表I2C的工作模式设置
        • 功能:检查MODE是否等于I2C_Mode_I2CI2C_Mode_SMBusDeviceI2C_Mode_SMBusHost中的任一个
        • 返回值:如果MODE有效,返回1(真),否则返回0(假)

      表格:

      宏定义描述
      I2C_Mode_I2C0x0000标准I2C模式
      I2C_Mode_SMBusDevice0x0002SMBus设备模式
      I2C_Mode_SMBusHost0x000ASMBus主机模式
      宏函数描述
      IS_I2C_MODE(MODE)检查MODE是否为有效的I2C工作模式设置
③、I2C_DutyCycle

I2C快速模式占空比

  • 该参数可以是@ref I2C_duty_cycle_in_fast_mode

  • @ref I2C_duty_cycle_in_fast_mode

    • 宏定义解释

      1. I2C_DutyCycle_16_9
        • 描述:定义了I2C快速模式下的占空比为16:9。在这种配置下,I2C的时钟周期被分为16个低电平时间和9个高电平时间。这种配置适用于大多数I2C设备
      2. I2C_DutyCycle_2
        • 描述:定义了I2C快速模式下的占空比为2:1。在这种配置下,I2C的时钟周期被分为2个低电平时间和1个高电平时间。这种配置适用于需要更快数据传输速率的场景

      宏函数

      1. IS_I2C_DUTY_CYCLE(CYCLE)
        • 描述:这是一个宏函数,用于检查给定的占空比设置是否有效
        • 参数CYCLE,代表I2C的占空比设置
        • 功能:检查CYCLE是否等于I2C_DutyCycle_16_9I2C_DutyCycle_2中的任一个
        • 返回值:如果CYCLE有效,返回1(真),否则返回0(假)

      表格:

      宏定义描述
      I2C_DutyCycle_16_90x4000I2C快速模式占空比为16:9
      I2C_DutyCycle_20xBFFFI2C快速模式占空比为2:1
      宏函数描述
      IS_I2C_DUTY_CYCLE(CYCLE)检查CYCLE是否为有效的I2C占空比设置
④、I2C_OwnAddress1

指定第一个设备自己的地址

  • 支持7位或10位地址
⑤、I2C_Ack

启用或禁用应答

  • 该参数可以是@ref I2C_acknowledgement

  • @ref I2C_acknowledgement

    • 宏定义解释

      1. I2C_Ack_Enable
        • 描述:定义了启用I2C应答的宏。当设置为启用应答时,I2C设备会在接收到数据后发送一个ACK信号,表示数据已被成功接收
      2. I2C_Ack_Disable
        • 描述:定义了禁用I2C应答的宏。当设置为禁用应答时,I2C设备不会在接收到数据后发送ACK信号。这在某些特定的应用场景中可能有用,例如在某些数据传输协议中不需要应答信号

      宏函数

      1. IS_I2C_ACK_STATE(STATE)
        • 描述:这是一个宏函数,用于检查给定的应答状态设置是否有效
        • 参数STATE,代表I2C的应答状态设置
        • 功能:检查STATE是否等于I2C_Ack_EnableI2C_Ack_Disable中的任一个
        • 返回值:如果STATE有效,返回1(真),否则返回0(假)

      表格:

      宏定义描述
      I2C_Ack_Enable0x0400启用I2C应答
      I2C_Ack_Disable0x0000禁用I2C应答
      宏函数描述
      IS_I2C_ACK_STATE(STATE)检查STATE是否为有效的I2C应答状态设置
⑥、I2C_AcknowledgedAddress

指定确认7位或10位地址

  • 该参数可以是@ref i2c_cogndged_address

  • @ref i2c_cogndged_address

    • 宏定义解释

      1. I2C_AcknowledgedAddress_7bit
        • 描述:定义了7位地址的应答配置。在I2C通信中,7位地址是最常见的地址格式,适用于大多数I2C设备。当设置为7位地址应答时,I2C设备将识别并应答7位地址
      2. I2C_AcknowledgedAddress_10bit
        • 描述:定义了10位地址的应答配置。10位地址提供了更大的地址空间,适用于需要更多设备地址的应用场景。当设置为10位地址应答时,I2C设备将识别并应答10位地址

      宏函数

      1. IS_I2C_ACKNOWLEDGE_ADDRESS(ADDRESS)
        • 描述:这是一个宏函数,用于检查给定的应答地址设置是否有效
        • 参数ADDRESS,代表I2C的应答地址设置
        • 功能:检查ADDRESS是否等于I2C_AcknowledgedAddress_7bitI2C_AcknowledgedAddress_10bit中的任一个
        • 返回值:如果ADDRESS有效,返回1(真),否则返回0(假)

      表格:

      宏定义描述
      I2C_AcknowledgedAddress_7bit0x40007位地址应答
      I2C_AcknowledgedAddress_10bit0xC00010位地址应答
      宏函数描述
      IS_I2C_ACKNOWLEDGE_ADDRESS(ADDRESS)检查ADDRESS是否为有效的I2C应答地址设置

3、I2C外设

①、MPU6050.c
#include "stm32f10x.h"                  // Device header
#include "MPU6050_Reg.h"
#include "MPU6050.h"#define MPU6050_ADDR 0xD0//从机地址+读写位//指定地址写
void MPU6050_WriteReg(uint8_t RegAddr, uint8_t Data)
{I2C_GenerateSTART(I2C2, ENABLE);//起始条件while(I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_MODE_SELECT) == !SUCCESS);//判断是否产生EV5事件I2C_Send7bitAddress(I2C2, MPU6050_ADDR, I2C_Direction_Transmitter);//指定从机地址while(I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED) == !SUCCESS);//等待事件EV6I2C_SendData(I2C2, RegAddr);//指定地址while(I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_BYTE_TRANSMITTING) == !SUCCESS);//等待事件EV8I2C_SendData(I2C2, Data);//发送数据while(I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_BYTE_TRANSMITTED) == !SUCCESS);//等待事件EV8_2I2C_GenerateSTOP(I2C2, ENABLE);//停止条件	
}//指定地址读
uint8_t MPU6050_ReadReg(uint8_t RegAddr)
{I2C_GenerateSTART(I2C2, ENABLE);//起始条件while(I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_MODE_SELECT) == !SUCCESS);//判断是否产生EV5事件I2C_Send7bitAddress(I2C2, MPU6050_ADDR, I2C_Direction_Transmitter);//指定从机地址while(I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED) == !SUCCESS);//等待事件发送EV6I2C_SendData(I2C2, RegAddr);//指定地址while(I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_BYTE_TRANSMITTED) == !SUCCESS);//等待事件EV8_2I2C_GenerateSTART(I2C2, ENABLE);//重复起始条件while(I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_MODE_SELECT) == !SUCCESS);//判断是否产生EV5事件I2C_Send7bitAddress(I2C2, MPU6050_ADDR, I2C_Direction_Receiver);//指定从机--读while(I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED) == !SUCCESS);//等待事件接收EV6//接收之前要提前设置ACK=0和STOP请求I2C_AcknowledgeConfig(I2C2, DISABLE);//设置ACK=0I2C_GenerateSTOP(I2C2, ENABLE);//STOP请求while(I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_BYTE_RECEIVED) == !SUCCESS);//等待事件接收EV7uint8_t Data = I2C_ReceiveData(I2C2);I2C_AcknowledgeConfig(I2C2, ENABLE);return Data;
}void MPU6050_Init(void)
{//初始化I2CRCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C2, ENABLE);RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);GPIO_InitTypeDef GPIO_InitStruct;GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF_OD;GPIO_InitStruct.GPIO_Pin = GPIO_Pin_10 | GPIO_Pin_11;GPIO_InitStruct.GPIO_Speed =GPIO_Speed_50MHz;GPIO_Init(GPIOB, &GPIO_InitStruct);I2C_InitTypeDef I2C_InitStruct;I2C_InitStruct.I2C_ClockSpeed = 100000;//100kHz的时钟频率I2C_InitStruct.I2C_Mode = I2C_Mode_I2C;I2C_InitStruct.I2C_DutyCycle = I2C_DutyCycle_16_9;//仅快速适用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_Cmd(I2C2, ENABLE);MPU6050_WriteReg(MPU6050_PWR_MGMT_1, 0x01);//配置电源管理寄存器1,解除睡眠,选择x轴的时钟MPU6050_WriteReg(MPU6050_PWR_MGMT_2, 0x00);//配置电源管理寄存器2,六轴均不待机MPU6050_WriteReg(MPU6050_SMPLRT_DIV, 0x09);//采样率分频器:10分频MPU6050_WriteReg(MPU6050_CONFIG, 0x06);//滤波参数MPU6050_WriteReg(MPU6050_GYRO_CONFIG, 0x18);//陀螺仪最大量程MPU6050_WriteReg(MPU6050_ACCEL_CONFIG, 0x18);//加速度计最大量程
}void MPU6050_GetData(MPU_Data* pData)
{...
}uint8_t MPU6050_GetID(void)
{...
}

实现超时退出

#include "stm32f10x.h"                  // Device header
#include "MPU6050_Reg.h"
#include "MPU6050.h"#define MPU6050_ADDR 0xD0//从机地址+读写位//封装MPU6050_WaitEvent函数,实现超时退出
void MPU6050_WaitEvent(I2C_TypeDef* I2Cx, uint32_t I2C_EVENT)
{uint32_t Timeout = 10000;while(I2C_CheckEvent(I2Cx, I2C_EVENT) == !SUCCESS){Timeout--;if(Timeout == 0){//错误处理break;}}
}//指定地址写
void MPU6050_WriteReg(uint8_t RegAddr, uint8_t Data)
{I2C_GenerateSTART(I2C2, ENABLE);//起始条件MPU6050_WaitEvent(I2C2, I2C_EVENT_MASTER_MODE_SELECT);//判断是否产生EV5事件I2C_Send7bitAddress(I2C2, MPU6050_ADDR, I2C_Direction_Transmitter);//指定从机地址MPU6050_WaitEvent(I2C2, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED);//等待事件EV6I2C_SendData(I2C2, RegAddr);//指定地址MPU6050_WaitEvent(I2C2, I2C_EVENT_MASTER_BYTE_TRANSMITTING);//等待事件EV8I2C_SendData(I2C2, Data);//发送数据MPU6050_WaitEvent(I2C2, I2C_EVENT_MASTER_BYTE_TRANSMITTED);//等待事件EV8_2I2C_GenerateSTOP(I2C2, ENABLE);//停止条件	
}//指定地址读
uint8_t MPU6050_ReadReg(uint8_t RegAddr)
{I2C_GenerateSTART(I2C2, ENABLE);//起始条件MPU6050_WaitEvent(I2C2, I2C_EVENT_MASTER_MODE_SELECT);//判断是否产生EV5事件I2C_Send7bitAddress(I2C2, MPU6050_ADDR, I2C_Direction_Transmitter);//指定从机地址MPU6050_WaitEvent(I2C2, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED);//等待事件发送EV6I2C_SendData(I2C2, RegAddr);//指定地址MPU6050_WaitEvent(I2C2, I2C_EVENT_MASTER_BYTE_TRANSMITTED);//等待事件EV8_2I2C_GenerateSTART(I2C2, ENABLE);//重复起始条件MPU6050_WaitEvent(I2C2, I2C_EVENT_MASTER_MODE_SELECT);//判断是否产生EV5事件I2C_Send7bitAddress(I2C2, MPU6050_ADDR, I2C_Direction_Receiver);//指定从机--读MPU6050_WaitEvent(I2C2, I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED);//等待事件接收EV6//接收之前要提前设置ACK=0和STOP请求I2C_AcknowledgeConfig(I2C2, DISABLE);//设置ACK=0I2C_GenerateSTOP(I2C2, ENABLE);//STOP请求MPU6050_WaitEvent(I2C2, I2C_EVENT_MASTER_BYTE_RECEIVED);//等待事件接收EV7uint8_t Data = I2C_ReceiveData(I2C2);I2C_AcknowledgeConfig(I2C2, ENABLE);return Data;
}
... ...

http://www.ppmy.cn/embedded/154124.html

相关文章

计算机视觉算法实战——步态识别(主页有源码)

✨个人主页欢迎您的访问 ✨期待您的三连 ✨ ✨个人主页欢迎您的访问 ✨期待您的三连 ✨ ✨个人主页欢迎您的访问 ✨期待您的三连✨ ​ ​​​​​​​​​​​​​​​​​​ 1. 步态识别简介✨✨ 步态识别&#xff08;Gait Recognition&#xff09;是计算机视觉领域中的一个…

Spring Cloud Alibaba - Nacos理论面试总结-未完结

临时实例和永久实例 临时实例和永久实例在 Nacos 中是一个非常非常重要的概念 之所以说它重要&#xff0c;主要是因为我在读源码的时候发现&#xff0c;临时实例和永久实例在底层的许多实现机制是完全不同的 临时实例 临时实例在注册到注册中心之后仅仅只保存在服务端内部一…

MySQL(高级特性篇) 06 章——索引的数据结构

一、为什么使用索引 索引是存储引擎用于快速找到数据记录的一种数据结构&#xff0c;就好比一本教科书的目录部分&#xff0c;通过目录找到对应文章的页码&#xff0c;便可快速定位到需要的文章。MySQL中也是一样的道理&#xff0c;进行数据查找时&#xff0c;首先查看查询条件…

赤店商城系统点餐小程序多门店分销APP共享股东h5源码saas账号独立版全插件全开源

代码介绍 后端编程语言采用&#xff1a;PHP yii2.0框架 前端代码采用&#xff1a;UNIAPP框架环境要求 推荐选择服务器配置&#xff1a;2核4G内存3M带宽 linux操作系统 控制面板&#xff1a;宝塔面板 运行环境&#xff1a;PHP7.2MYSQL5.7 赤店商城系统是一款集点餐小程序、多门…

计算机视觉算法实战——吸烟人员检测

✨个人主页欢迎您的访问 ✨期待您的三连 ✨ ✨个人主页欢迎您的访问 ✨期待您的三连 ✨ ✨个人主页欢迎您的访问 ✨期待您的三连✨ ​​​​​​ ​​​​​​​​​​​​ ​​​​​ 1. 领域介绍✨✨ 计算机视觉是人工智能的一个重要分支&#xff0c;旨在通过算法让计算机…

网络精英赛模拟练习

1、 会话侦听与劫持技术属于&#xff08;&#xff09;技术。 &#xff08;单选题&#xff0c;1分&#xff09; A. 密码分析还原 B. 协议漏洞渗透 C. 应用漏洞分析与渗透 D. DOS攻击 回答正确(得分: 1分) 正确答案 B 解析 会话侦听与劫持技术属于协议漏洞渗透技术。 2、 溢…

模型压缩 --学习记录1

模型压缩 --学习记录1 一、模型压缩的定义二 、模型量化技术2.1、线性量化 - 对称线性量化对称线性量化的过程Step 1&#xff1a;确定量化范围&#xff08;range&#xff09;Step 2&#xff1a;计算缩放因子&#xff08;scale&#xff09;Step 3&#xff1a;执行量化 对称线性量…

STC89C51与AT89C51芯片区别深度剖析

目录 一、引言 二、芯片概述 &#xff08;一&#xff09;STC89C51 &#xff08;二&#xff09;AT89C51 三、性能对比 &#xff08;一&#xff09;主频 &#xff08;二&#xff09;存储器 &#xff08;三&#xff09;I/O端口 &#xff08;四&#xff09;定时器/计数器 …