【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.mzph.cn/bicheng/68102.shtml

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

相关文章

Android SDK下载安装(图文详解)

安装完sdk&#xff0c;就可以直接使用adb命令了&#xff0c;我们做app自动化测试&#xff0c;也需要sdk环境的依赖。 1. 下载Android SDK 网盘下载地址&#xff1a;https://pan.quark.cn/s/8398e52cefc9 官网下载地址&#xff1a;https://www.androiddevtools.cn/ &#xff08;…

农业移动式水肥一体机全面解析:开启精准农业新篇章

在当今科技飞速发展的时代&#xff0c;农业领域也迎来了众多创新设备&#xff0c;农业移动式水肥一体机便是其中的佼佼者。它正悄然改变着传统的农业灌溉与施肥模式&#xff0c;为实现精准农业提供了强有力的支持。 一、什么是农业移动式水肥一体机 农业移动式水肥一体机&…

2008-2020年各省社会消费品零售总额数据

2008-2020年各省社会消费品零售总额数据 1、时间&#xff1a;2008-2020年 2、来源&#xff1a;国家统计局、统计年鉴 3、指标&#xff1a;行政区划代码、地区、年份、社会消费品零售总额 4、范围&#xff1a;31省 5、指标解释&#xff1a;社会消费品零售总额指企业&#x…

江科大STM32入门——读写备份寄存器(BKP)实时时钟(RTC)笔记整理

wx&#xff1a;嵌入式工程师成长日记 https://mp.weixin.qq.com/s/hDk7QaXP8yfYIj1gUhtMrw?token1051786482&langzh_CNhttps://mp.weixin.qq.com/s/hDk7QaXP8yfYIj1gUhtMrw?token1051786482&langzh_CN RTC是一个独立的定时器&#xff0c;BKP并不能完全掉电不丢失&am…

GitLab CI/CD使用runner实现自动化部署前端Vue2 后端.Net 7 Zr.Admin项目

1、查看gitlab版本 建议安装的runner版本和gitlab保持一致 2、查找runner 执行 yum list gitlab-runner --showduplicates | sort -r 找到符合gitlab版本的runner&#xff0c;我这里选择 14.9.1版本 如果执行出现找不到下载源&#xff0c;添加官方仓库 执行 curl -L &quo…

HTML5 Canvas实现的跨年烟花源代码

以下是一份基于HTML5 Canvas实现的跨年烟花源代码: <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml">…

MySQL解压版(保姆级教程)

文章目录 1. 下载MySQL2. 解压压缩包3. 添加环境变量4. 创建配置文件5. 启动管理员模式下的CMD6. 重启mysql7. 检查服务是否成功启动8. 可能遇见的错误&#x1f3af; 数据目录未正确初始化&#x1f3af; MySQL服务已存在但路径错误&#x1f3af; 端口被占用&#x1f3af; MySQL…

mysql 快速转为 sqlalchemy 模型 文件

资料 1.mysql数据表自动导为python sqlalchemy可操作对象 - JKYO - 博客园 2. 复制 show create table xxx 丢给 gpt 处理 过程 1.下载 pip install sqlacodegen 2.修改源文件 /sqlacodegen/main.py 我使用的是 miniconda &#xff0c;地址是&#xff1a; C:\ProgramDat…

人工智能实验(四)-A*算法求解迷宫寻路问题实验

零、A*算法学习参考资料 1.讲解视频 A*寻路算法详解 #A星 #启发式搜索_哔哩哔哩_bilibili 2.A*算法学习网站 A* 算法简介 一、实验目的 熟悉和掌握A*算法实现迷宫寻路功能&#xff0c;要求掌握启发式函数的编写以及各类启发式函数效果的比较。 二、实验要求 同课本 附录…

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

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

Github配置ssh key,密钥配对错误怎么解决?

解决密钥配对的方案如下&#xff1a; 方法一、最有效的方案&#xff1a;重新配置&#xff0c;验证 SSH 密钥是否已添加到 GitHub 确保您的 SSH 密钥已经正确添加到了 GitHub 账户中。您可以打开命令行控制台&#xff08;cmd/powerShell都可以&#xff09;&#xff0c;按照以下…

Java基础知识(六) -- 常用类

1.包装类 1.1 概述 Java提供了两个类型系统&#xff0c;基本类型与引用类型&#xff0c;使用基本类型在于效率&#xff0c;但当使用只针对对象设计的API或新特性(例如泛型)&#xff0c;那么基本数据类型的数据就需要用包装类来包装。 序号基本数据类型包装类&#xff08;java…

fbx 环境搭建

python 3.7 3.8 版本支持 https://github.com/Shiiho11/FBX-Python-SDK-for-Python3.x 只有python3.7 https://www.autodesk.com/developer-network/platform-technologies/fbx-sdk-2020-3 scipy安装&#xff1a; python安装scipy_scipy1.2.1库怎么安装-CSDN博客 smpl 2 fbx…

【Linux】深入理解文件系统(超详细)

目录 一.磁盘 1-1 磁盘、服务器、机柜、机房 &#x1f4cc;补充&#xff1a; &#x1f4cc;通常网络中用高低电平&#xff0c;磁盘中用磁化方向来表示。以下是具体说明&#xff1a; &#x1f4cc;如果有一块磁盘要进行销毁该怎么办&#xff1f; 1-2 磁盘存储结构 ​编辑…

【硬件介绍】Type-C接口详解

一、Type-C接口概述 Type-C接口特点&#xff1a;以其独特的扁头设计和无需区分正反两面的便捷性而广受欢迎。这种设计大大提高了用户的使用体验&#xff0c;避免了传统USB接口需要多次尝试才能正确插入的问题。Type-C接口内部结构&#xff1a;内部上下两排引脚的设计虽然可能不…

Linux第二课:LinuxC高级 学习记录day02

2.4、shell中的特殊字符 2.4.4、命令置换符 或者 $() 反引号&#xff1a;esc下面的按键&#xff0c;英文状态下直接按 功能&#xff1a;将一个命令的输出作为另一个命令的参数 echo 不会认为hostname是一个命令 加上 之后&#xff0c;先执行hostname&#xff0c;拿到主机名…

图生生AI描述生图:一句话生成蛇年海报素材

2025年春晚吉祥物“巳升升”的亮相&#xff0c;引发了广泛讨论。其整体造型参考甲骨文中的“巳”字&#xff0c;以青绿色为主调&#xff0c;象征春意盎然、蓬勃生机。从头部轮廓、脸颊螺旋形状到五官设计&#xff0c;都蕴含着丰富的传统文化元素。巳升升的亮相&#xff0c;春节…

如何提高自动化测试覆盖率和效率

用ChatGPT做软件测试 在现代软件开发中&#xff0c;自动化测试已经成为保证软件质量的重要手段。然而&#xff0c;在实践中&#xff0c;自动化测试的覆盖率和效率常常受到限制&#xff0c;导致潜在缺陷未能及时发现或测试资源浪费。因此&#xff0c;提升自动化测试的覆盖率和效…

OpenCV相机标定与3D重建(54)解决透视 n 点问题(Perspective-n-Point, PnP)函数solvePnP()的使用

操作系统&#xff1a;ubuntu22.04 OpenCV版本&#xff1a;OpenCV4.9 IDE:Visual Studio Code 编程语言&#xff1a;C11 算法描述 根据3D-2D点对应关系找到物体的姿态。 cv::solvePnP 是 OpenCV 库中的一个函数&#xff0c;用于解决透视 n 点问题&#xff08;Perspective-n-Po…

KMP前缀表 ≈ find() 函数——28.找出字符串中第一个匹配项的下标【力扣】

class Solution { public: //得到前缀表void getNext(int *next,string needle){int j0;for(int i1;i<needle.size();i){while(j>0 && needle[j]!needle[i]) jnext[j-1];//**j>0**>j0是出口if(needle[i]needle[j]) j;next[i]j;//若写入if中&#xff0c;则该…