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

文章目录

  • 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.rhkb.cn/news/1415.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

WINFORM - DevExpress -> devexpress版--报表(report)

devexpress report模板 1.安装devexpress(DevExpress 总结【安装、案例】_caoyanchao1的博客-CSDN博客_devexpress) 2.新建vs项目且添加standarReportDesigner控件 涛神设计器注意 3.运行后步骤 点击New Report DetailReport 涛神设计器checkbox(3.复选框只认boolean类型的 b…

亿道三防丨三防笔记本是什么意思?和普通笔记本的优势在哪里?

三防笔记本是什么意思&#xff1f;和普通笔记本的优势在哪里&#xff1f; 在现代社会中&#xff0c;笔记本电脑已经成为人们工作和生活中不可或缺的一部分。然而&#xff0c;在一些特殊行业或环境中&#xff0c;普通笔记本电脑由于其脆弱性和对环境条件的敏感性&#xff0c;往…

opencv的NLM去噪算法

NLM&#xff08;Non-Local Means&#xff09;去噪算法是一种基于图像块&#xff08;patch&#xff09;相似性的去噪方法。其基本原理是&#xff1a; 图像块相似性&#xff1a;算法首先定义了一个搜索窗口&#xff08;search window&#xff09;&#xff0c;然后在该窗口内寻找…

ElasticSearch在Windows环境搭建测试

引子 也持续关注大数据相关内容一段时间&#xff0c;大数据内容很多。想了下还是从目前项目需求侧出发&#xff0c;进行相关学习。Elasticsearch&#xff08;ES&#xff09;是位于 Elastic Stack&#xff08;ELK stack&#xff09; 核心的分布式搜索和分析引擎。Logstash 和 B…

Docker安装和卸载(centos)

Docker安装和卸载 一&#xff0c;已安装Docker&#xff0c;卸载Docker 1.方法一 sudo yum remove docker \docker-client \docker-client-latest \docker-common \docker-latest \docker-latest-logrotate \docker-logrotate \docker-engine​ 如果出现以下提示就证明没卸载…

《自动驾驶与机器人中的SLAM技术》ch8:基于 IESKF 的紧耦合 LIO 系统

目录 基于 IESKF 的紧耦合 LIO 系统 1 IESKF 的状态变量和运动过程 1.1 对名义状态变量的预测 1.2 对误差状态变量的预测及对协方差矩阵的递推 2 观测方程中的迭代过程 3 高维观测中的等效处理 4 NDT 和 卡尔曼滤波的联系 5 紧耦合 LIO 系统的主要流程 5.1 IMU 静止初始化 …

认识机器学习中的经验风险最小化准则

经验风险最小化准则的定义 经验风险最小化&#xff08;Empirical Risk Minimization&#xff0c;简称 ERM&#xff09;是机器学习中的一种基本理论框架&#xff0c;用于指导模型的训练过程。其核心思想是通过最小化训练数据上的损失函数来优化模型参数&#xff0c;从而提高模型…

使用Deepseek搭建类Cursor编辑器

使用Deepseek搭建类Cursor编辑器 Cursor想必大家都用过了&#xff0c;一个非常强大的AI编辑器&#xff0c;在代码编写上为我们省了不少事&#xff0c;但高昂的价格让我们望而却步&#xff0c;这篇文章教你在Visual Studio Code上搭建一个类Cursor的代码编辑器。 步骤其实非常…

SpringCloud系列教程:微服务的未来(十一)服务注册、服务发现、OpenFeign快速入门

本篇博客将通过实例演示如何在 Spring Cloud 中使用 Nacos 实现服务注册与发现&#xff0c;并使用 OpenFeign 进行服务间调用。你将学到如何搭建一个完整的微服务通信框架&#xff0c;帮助你快速开发可扩展、高效的分布式系统。 目录 前言 服务注册和发现 服务注册 ​编辑 …

【MySQL】SQL菜鸟教程(一)

1.常见命令 1.1 总览 命令作用SELECT从数据库中提取数据UPDATE更新数据库中的数据DELETE从数据库中删除数据INSERT INTO向数据库中插入新数据CREATE DATABASE创建新数据库ALTER DATABASE修改数据库CREATE TABLE创建新表ALTER TABLE变更数据表DROP TABLE删除表CREATE INDEX创建…

【Vue实战】Vuex 和 Axios 拦截器设置全局 Loading

目录 1. 效果图 2. 思路分析 2.1 实现思路 2.2 可能存在的问题 2.2.1 并发请求管理 2.2.2 请求快速响应和缓存带来的问题 3. 代码实现 4. 总结 1. 效果图 如下图所示&#xff0c;当路由变化或发起请求时&#xff0c;出现 Loading 等待效果&#xff0c;此时页面不可见。…

无源器件-电容

电容器件的参数 基本概念由中学大学物理或电路分析内容获得&#xff0c;此处不做过多分析。 电容的产量占全球电子元器件产品的40%以上。 单位&#xff1a;法拉 F&#xff1b;1F10^6uF&#xff1b;电路中常见的104电容就是10*10^4pF100nF0.1uF C为电容&#xff0c;Rp为绝缘电…

python实现自动登录12306抢票 -- selenium

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 python实现自动登录12306抢票 -- selenium 前言其实网上也出现了很多12306的代码&#xff0c;但是都不是最新的&#xff0c;我也是从网上找别人的帖子&#xff0c;看B站视频&…

Genymotion配套VirtualBox所在地址

在 Genymotion打开虚拟机前需要先打开VirtualBox中的虚拟机 C:\Program Files\Oracle\VirtualBox\VirtualBox.exe 再开启genymotion中的虚拟机开关

浅谈云计算06 | 云管理系统架构

云管理系统架构 一、云管理系统架构&#xff08;一&#xff09;远程管理系统&#xff08;二&#xff09;资源管理系统&#xff08;三&#xff09;SLA 管理系统&#xff08;四&#xff09;计费管理系统 二、安全与可靠性保障&#xff08;一&#xff09;数据安全防线&#xff08;…

泛目录和泛站有什么差别

啥是 SEO 泛目录&#xff1f; 咱先来说说 SEO 泛目录是啥。想象一下&#xff0c;你有一个巨大的图书馆&#xff0c;里面的书架上摆满了各种各样的书&#xff0c;每一本书都代表着一个网页。而 SEO 泛目录呢&#xff0c;就像是一个超级图书管理员&#xff0c;它的任务就是把这些…

WebScoket-服务器客户端双向通信

文章目录 1. 消息推送常用方式介绍2. WebSocket2.1 介绍2.2 客户端API2.3 服务端API 3. 总结 1. 消息推送常用方式介绍 轮询 浏览器以指定的时间间隔向服务器发出HTTP请求&#xff0c;服务器实时返回数据给浏览器。 长轮询 浏览器发出ajax请求&#xff0c;服务器端接收到请求…

uniapp 之 uni-forms校验提示【提交的字段[‘xxx‘]在数据库中并不存在】解决方案

目录 场景问题代码结果问题剖析解决方案 场景 uni-forms官方组件地址 使用uniapp官方提供的组件&#xff0c;某个表单需求&#xff0c;单位性质字段如果是高校&#xff0c;那么工作单位则是高校的下拉选择格式&#xff0c;单位性质如果是其他的类型&#xff0c;工作单位则是手动…

SOME/IP 协议详解——服务发现

文章目录 1. Introduction &#xff08;引言&#xff09;2. SOME/IP Service Discovery (SOME/IP-SD)2.1 General&#xff08;概述)2.2 SOME/IP-SD Message Format2.2.1 通用要求2.2.2 SOME/IP-SD Header2.2.3 Entry Format2.2.4 Options Format2.2.4.1 配置选项&#xff08;Co…

探秘 JMeter (Interleave Controller)交错控制器:解锁性能测试的隐藏密码

嘿&#xff0c;小伙伴们&#xff01;今天咱们要把 JMeter 里超厉害的 Interleave Controller&#xff08;交错控制器&#xff09;研究个透&#xff0c;让你从新手直接进阶成高手&#xff0c;轻松拿捏各种性能测试难题&#xff01; 一、Interleave Controller 深度剖析 所属家族…