【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通信
| 名称 | 引脚 | 双工 | 时钟 | 电平 | 设备 |
|---|---|---|---|---|---|
I2C | SCL、SDA | 半双工 | 同步 | 单端 | 多设备 |
I2C(Inter IC Bus)是由Philips公司开发的一种通用数据总线两根通信线:
SCL(Serial Clock)、SDA(Serial Data)同步,半双工
带数据应答
支持总线挂载多设备(一主多从、多主多从)
Ⅰ、硬件电路
所有I2C设备的SCL连在一起,SDA连在一起
设备的SCL和SDA均要配置成开漏输出模式
SCL和SDA各添加一个上拉电阻,阻值一般为4.7KΩ左右,高电平驱动能力弱

Ⅱ、IIC时序基本单元
① 起始条件
- SCL高电平期间,SDA从高电平切换到低电平
② 终止条件
- SCL高电平期间,SDA从低电平切换到高电平
③ 发送一个字节
- SCL低电平期间,主机将数据位依次放到SDA线上(高位先行),然后释放SCL,从机将在SCL高电平期间读取数据位,所以SCL高电平期间SDA不允许有数据变化,依次循环上述过程8次,即可发送一个字节
发送期间SCL与SDA只能由主机(STM32)控制
- 最后一位为读写标志位(0:写;1:读)
④ 接收一个字节
- SCL低电平期间,从机将数据位依次放到SDA线上(高位先行),然后释放SCL,主机将在SCL高电平期间读取数据位,所以SCL高电平期间SDA不允许有数据变化,依次循环上述过程8次,即可接收一个字节(主机在接收之前,需要释放SDA)
⑤ 发送应答
- 主机在接收完一个字节之后,在下一个时钟发送一位数据,(SDA)数据0表示应答,数据1表示非应答
⑥ 接收应答
- 主机在发送完一个字节之后,在下一个时钟接收一位数据,判断从机是否应答,数据0表示应答,数据1表示非应答(主机在接收之前,需要释放SDA)
Ⅲ、IIC时序
指定地址写单字节

指定地址写多字节

指定地址读单字节

指定地址读多字节

① 指定地址写
- 对于指定设备(Slave Address),在指定地址(Reg Address)下,写入指定数据(Data)
② 当前地址读
- 对于指定设备(Slave Address),在当前地址指针指示的地址下,读取从机数据(Data)
- 每一次的读写数据都会造成地址指针+1
③ 指定地址读
- 对于指定设备(Slave Address),在指定地址(Reg Address)下,读取从机数据(Data)
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从机地址:
1101000(AD0=0)1101001(AD0=1)
1、模块内部电路

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

2、寄存器地址


3、软件模拟IIC
可任意指定两个引脚,分别作为
IIC的SCL和SDA,本示例中使用的引脚为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框图


3、I2C基本结构

4、主机发送

5、主机接收

Ⅵ、配置I2C外设
- 开启时钟:I2C外设和GPIO口的时钟
- 把I2C外设对应的GPIO口设置成复用开漏模式
- 配置I2C:结构体
- 使能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:
宏定义解释
I2C_Mode_I2C
- 描述:定义了标准的I2C模式。在这种模式下,I2C接口按照I2C协议的标准规范进行通信
I2C_Mode_SMBusDevice
- 描述:定义了SMBus(System Management Bus)设备模式。SMBus是一种基于I2C的协议,主要用于系统管理通信。在这种模式下,I2C接口按照SMBus协议进行通信,作为设备端
I2C_Mode_SMBusHost
- 描述:定义了SMBus主机模式。在这种模式下,I2C接口按照SMBus协议进行通信,作为主机端,可以控制通信过程
宏函数
IS_I2C_MODE(MODE)
- 描述:这是一个宏函数,用于检查给定的工作模式设置是否有效
- 参数:
MODE,代表I2C的工作模式设置- 功能:检查
MODE是否等于I2C_Mode_I2C、I2C_Mode_SMBusDevice或I2C_Mode_SMBusHost中的任一个- 返回值:如果
MODE有效,返回1(真),否则返回0(假)表格:
宏定义 值 描述 I2C_Mode_I2C 0x0000 标准I2C模式 I2C_Mode_SMBusDevice 0x0002 SMBus设备模式 I2C_Mode_SMBusHost 0x000A SMBus主机模式
宏函数 描述 IS_I2C_MODE(MODE) 检查MODE是否为有效的I2C工作模式设置
③、I2C_DutyCycle
I2C快速模式占空比
该参数可以是
@ref I2C_duty_cycle_in_fast_mode
@ref I2C_duty_cycle_in_fast_mode:
宏定义解释
I2C_DutyCycle_16_9
- 描述:定义了I2C快速模式下的占空比为16:9。在这种配置下,I2C的时钟周期被分为16个低电平时间和9个高电平时间。这种配置适用于大多数I2C设备
I2C_DutyCycle_2
- 描述:定义了I2C快速模式下的占空比为2:1。在这种配置下,I2C的时钟周期被分为2个低电平时间和1个高电平时间。这种配置适用于需要更快数据传输速率的场景
宏函数
IS_I2C_DUTY_CYCLE(CYCLE)
- 描述:这是一个宏函数,用于检查给定的占空比设置是否有效
- 参数:
CYCLE,代表I2C的占空比设置- 功能:检查
CYCLE是否等于I2C_DutyCycle_16_9或I2C_DutyCycle_2中的任一个- 返回值:如果
CYCLE有效,返回1(真),否则返回0(假)表格:
宏定义 值 描述 I2C_DutyCycle_16_9 0x4000 I2C快速模式占空比为16:9 I2C_DutyCycle_2 0xBFFF I2C快速模式占空比为2:1
宏函数 描述 IS_I2C_DUTY_CYCLE(CYCLE) 检查CYCLE是否为有效的I2C占空比设置
④、I2C_OwnAddress1
指定第一个设备自己的地址
- 支持7位或10位地址
⑤、I2C_Ack
启用或禁用应答
该参数可以是
@ref I2C_acknowledgement
@ref I2C_acknowledgement:
宏定义解释
I2C_Ack_Enable
- 描述:定义了启用I2C应答的宏。当设置为启用应答时,I2C设备会在接收到数据后发送一个ACK信号,表示数据已被成功接收
I2C_Ack_Disable
- 描述:定义了禁用I2C应答的宏。当设置为禁用应答时,I2C设备不会在接收到数据后发送ACK信号。这在某些特定的应用场景中可能有用,例如在某些数据传输协议中不需要应答信号
宏函数
IS_I2C_ACK_STATE(STATE)
- 描述:这是一个宏函数,用于检查给定的应答状态设置是否有效
- 参数:
STATE,代表I2C的应答状态设置- 功能:检查
STATE是否等于I2C_Ack_Enable或I2C_Ack_Disable中的任一个- 返回值:如果
STATE有效,返回1(真),否则返回0(假)表格:
宏定义 值 描述 I2C_Ack_Enable 0x0400 启用I2C应答 I2C_Ack_Disable 0x0000 禁用I2C应答
宏函数 描述 IS_I2C_ACK_STATE(STATE) 检查STATE是否为有效的I2C应答状态设置
⑥、I2C_AcknowledgedAddress
指定确认7位或10位地址
该参数可以是
@ref i2c_cogndged_address
@ref i2c_cogndged_address:
宏定义解释
I2C_AcknowledgedAddress_7bit
- 描述:定义了7位地址的应答配置。在I2C通信中,7位地址是最常见的地址格式,适用于大多数I2C设备。当设置为7位地址应答时,I2C设备将识别并应答7位地址
I2C_AcknowledgedAddress_10bit
- 描述:定义了10位地址的应答配置。10位地址提供了更大的地址空间,适用于需要更多设备地址的应用场景。当设置为10位地址应答时,I2C设备将识别并应答10位地址
宏函数
IS_I2C_ACKNOWLEDGE_ADDRESS(ADDRESS)
- 描述:这是一个宏函数,用于检查给定的应答地址设置是否有效
- 参数:
ADDRESS,代表I2C的应答地址设置- 功能:检查
ADDRESS是否等于I2C_AcknowledgedAddress_7bit或I2C_AcknowledgedAddress_10bit中的任一个- 返回值:如果
ADDRESS有效,返回1(真),否则返回0(假)表格:
宏定义 值 描述 I2C_AcknowledgedAddress_7bit 0x4000 7位地址应答 I2C_AcknowledgedAddress_10bit 0xC000 10位地址应答
宏函数 描述 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; } ... ...
相关文章:
【STM32-学习笔记-8-】I2C通信
文章目录 I2C通信Ⅰ、硬件电路Ⅱ、IIC时序基本单元① 起始条件② 终止条件③ 发送一个字节④ 接收一个字节⑤ 发送应答⑥ 接收应答 Ⅲ、IIC时序① 指定地址写② 当前地址读③ 指定地址读 Ⅳ、MPU6050---6轴姿态传感器(软件I2C)1、模块内部电路2、寄存器地…...
2025年1月17日(点亮三色LED)
系统信息: Raspberry Pi Zero 2W 系统版本: 2024-10-22-raspios-bullseye-armhf Python 版本:Python 3.9.2 已安装 pip3 支持拍摄 1080p 30 (1092*1080), 720p 60 (1280*720), 60/90 (640*480) 已安装 vim 已安装 git 学习目标:…...
ASP .NET Core 学习 (.NET 9)- 创建 API项目,并配置Swagger及API 分组或版本
本系列为个人学习 ASP .NET Core学习全过程记录,基于.NET 9 和 VS2022 ,实现前后端分离项目基础框架搭建和部署,以简单、易理解为主,注重页面美观度和后台代码简洁明了,可能不会使用过多的高级语法和扩展,后…...
mysql-5.7.18保姆级详细安装教程
本文主要讲解如何安装mysql-5.7.18数据库: 将绿色版安装包mysql-5.7.18-winx64解压后目录中内容如下图,该例是安装在D盘根目录。 在mysql安装目录中新建my.ini文件,文件内容及各配置项内容如下图,需要先将配置项【skip-grant-tab…...
RK3588平台开发系列讲解(NPU篇)NPU 驱动的组成
文章目录 一、NPU 驱动组成二、查询 NPU 驱动版本三、查询 rknn_server 版本四、查询 librknn_runtime 版本沉淀、分享、成长,让自己和他人都能有所收获!😄 一、NPU 驱动组成 NPU 驱动版本、rknn_server 版本、librknn_runtime 版本以及 RKNN Toolkit 版本的对应关系尤为重…...
ESP32学习笔记_FreeRTOS(6)——Event and Notification
摘要(From AI): 这篇博客详细介绍了 FreeRTOS 中的事件组和任务通知机制,讲解了事件组如何通过位操作实现任务间的同步与通信,以及任务如何通过通知机制进行阻塞解除和数据传递。博客提供了多个代码示例,展示了如何使用事件组和任务通知在多任…...
力扣-数组-350 两个数组的交集Ⅱ
解析 与刚刚的《两个数组的交集》一样,只是这道题允许重复,将上一题的set去除即可。 代码 class Solution { public:vector<int> intersect(vector<int>& nums1, vector<int>& nums2) {vector<int> res;int index1 …...
云原生第二次练习
1.判断192.168.1.0/24网络中,当前在线的ip有哪些,并编写脚本打印出来。 #!/bin/bash for ip in $(seq 1 254); doping -c 1 -W 1 "192.168.1.$ip" > /dev/null 2>&1if [ $? -eq 0 ]; thenecho "192.168.1.$ip is online&qu…...
SpringMVC复习笔记
文章目录 SpringMVC 概念和基本使用SpringMVC 简介SpringMVC 核心组件和调用流程SpringMVC 基本使用第一步:导入依赖第二步:Controller 层开发第三步:SpringMVC 配置类配置核心组件第四步:SpringMVC 环境搭建第五步:部…...
前端小案例——网页井字棋
前言:我们在学习完了HTML、CSS和JavaScript之后,就会想着使用这三个东西去做一些小案例,不过又没有什么好的案例让我们去练手,本篇文章就提供里一个案例——网页井字棋。 ✨✨✨这里是秋刀鱼不做梦的BLOG ✨✨✨想要了解更多内容可…...
ComfyUI-PromptOptimizer:文生图提示优化节点
ComfyUI-PromptOptimizer 是 ComfyUI 的一个自定义节点,旨在优化文本转图像模型的提示。它将用户输入的提示转换为更详细、更多样化、更生动的描述,使其更适合生成高质量的图像。无需本地模型。 1、功能 提示优化:优化用户输入的提示以生成…...
AudioGPT全新的 音频内容理解与生成系统
AudioGPT全新的 音频内容理解与生成系统 ChatGPT、GPT-4等大型语言模型 (LLM) 在语言理解、生成、交互和推理方面表现出的非凡能力,引起了学界和业界的极大关注,也让人们看到了LLM在构建通用人工智能 (AGI) 系统方面的潜力。 现有的GPT模型具有极高的语言生成能力,是目前最…...
thinkphp6 + redis实现大数据导出excel超时或内存溢出问题解决方案
redis下载安装(window版本) 参考地址:https://blog.csdn.net/Ci1693840306/article/details/144214215 php安装redis扩展 参考链接:https://blog.csdn.net/jianchenn/article/details/106144313 解决思路:࿰…...
Hexo + NexT + Github搭建个人博客
文章目录 一、 安装二、配置相关项NexT config更新主题主题样式本地实时预览常用命令 三、主题设置1.侧边栏2.页脚3.帖子发布字数统计 4.自定义自定义页面Hexo 的默认页面自定义 404 页自定义样式 5.杂项搜索服务 四、第三方插件NexT 自带插件评论系统阅读和访问人数统计 五、部…...
使用Sum计算Loss和解决梯度累积(Gradient Accumulation)的Bug
使用Sum计算Loss和解决梯度累积的Bug 学习 https://unsloth.ai/blog/gradient:Bugs in LLM Training - Gradient Accumulation Fix 这篇文章的记录。 在深度学习训练过程中,尤其是在大批量(large batch)训练中,如何高…...
基于本地消息表实现分布式事务
假设我们有一个电商系统,包含订单服务和库存服务。当用户下单时,需要在订单服务中创建订单,同时在库存服务中扣减库存。这是一个典型的分布式事务场景,我们需要保证这两个操作要么都成功,要么都失败,以保证数据的最终一致性。 项目结构: 订单服务(Order Service)库存服务(Inv…...
Web3与加密技术的结合:增强个人隐私保护的未来趋势
随着互联网的快速发展,个人隐私和数据安全问题越来越受到关注。Web3作为新一代互联网架构,凭借其去中心化的特性,为个人隐私保护提供了全新的解决方案。而加密技术则是Web3的重要组成部分,进一步增强了隐私保护的能力。本文将探讨…...
广播网络实验
1 实验内容 1、构建星性拓扑下的广播网络,实现hub各端口的数据广播,验证网络的连通性并测试网络效率 2、构建环形拓扑网络,验证该拓扑下结点广播会产生数据包环路 2 实验流程与结果分析 2.1 实验环境 ubuntu、mininet、xterm、wireshark、iperf 2.2 实验方案与结果分析…...
Vscode——SSH连接不上的一种解决办法
一、完整报错: > @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ > IT IS POSSIBLE THAT SOMEONE IS DOING SOMETHING NASTY! > Someone could be eavesdropping on you right now (man-in-the...
ChatGPT大模型极简应用开发-目录
引言 要理解 ChatGPT,了解其背后的 Transformer 架构和 GPT 技术一路的演进则变得非常必要。 ChatGPT 背后的 LLM 技术使普通人能够通过自然语言完成过去只能由程序员通过编程语言实现的任务,这是一场巨大的变革。然而,人类通常容易高估技术…...
wordpress后台更新后 前端没变化的解决方法
使用siteground主机的wordpress网站,会出现更新了网站内容和修改了php模板文件、js文件、css文件、图片文件后,网站没有变化的情况。 不熟悉siteground主机的新手,遇到这个问题,就很抓狂,明明是哪都没操作错误&#x…...
Unity3D中Gfx.WaitForPresent优化方案
前言 在Unity中,Gfx.WaitForPresent占用CPU过高通常表示主线程在等待GPU完成渲染(即CPU被阻塞),这表明存在GPU瓶颈或垂直同步/帧率设置问题。以下是系统的优化方案: 对惹,这里有一个游戏开发交流小组&…...
江苏艾立泰跨国资源接力:废料变黄金的绿色供应链革命
在华东塑料包装行业面临限塑令深度调整的背景下,江苏艾立泰以一场跨国资源接力的创新实践,重新定义了绿色供应链的边界。 跨国回收网络:废料变黄金的全球棋局 艾立泰在欧洲、东南亚建立再生塑料回收点,将海外废弃包装箱通过标准…...
【android bluetooth 框架分析 04】【bt-framework 层详解 1】【BluetoothProperties介绍】
1. BluetoothProperties介绍 libsysprop/srcs/android/sysprop/BluetoothProperties.sysprop BluetoothProperties.sysprop 是 Android AOSP 中的一种 系统属性定义文件(System Property Definition File),用于声明和管理 Bluetooth 模块相…...
高防服务器能够抵御哪些网络攻击呢?
高防服务器作为一种有着高度防御能力的服务器,可以帮助网站应对分布式拒绝服务攻击,有效识别和清理一些恶意的网络流量,为用户提供安全且稳定的网络环境,那么,高防服务器一般都可以抵御哪些网络攻击呢?下面…...
OPenCV CUDA模块图像处理-----对图像执行 均值漂移滤波(Mean Shift Filtering)函数meanShiftFiltering()
操作系统:ubuntu22.04 OpenCV版本:OpenCV4.9 IDE:Visual Studio Code 编程语言:C11 算法描述 在 GPU 上对图像执行 均值漂移滤波(Mean Shift Filtering),用于图像分割或平滑处理。 该函数将输入图像中的…...
学校时钟系统,标准考场时钟系统,AI亮相2025高考,赛思时钟系统为教育公平筑起“精准防线”
2025年#高考 将在近日拉开帷幕,#AI 监考一度冲上热搜。当AI深度融入高考,#时间同步 不再是辅助功能,而是决定AI监考系统成败的“生命线”。 AI亮相2025高考,40种异常行为0.5秒精准识别 2025年高考即将拉开帷幕,江西、…...
IP如何挑?2025年海外专线IP如何购买?
你花了时间和预算买了IP,结果IP质量不佳,项目效率低下不说,还可能带来莫名的网络问题,是不是太闹心了?尤其是在面对海外专线IP时,到底怎么才能买到适合自己的呢?所以,挑IP绝对是个技…...
A2A JS SDK 完整教程:快速入门指南
目录 什么是 A2A JS SDK?A2A JS 安装与设置A2A JS 核心概念创建你的第一个 A2A JS 代理A2A JS 服务端开发A2A JS 客户端使用A2A JS 高级特性A2A JS 最佳实践A2A JS 故障排除 什么是 A2A JS SDK? A2A JS SDK 是一个专为 JavaScript/TypeScript 开发者设计的强大库ÿ…...
Linux nano命令的基本使用
参考资料 GNU nanoを使いこなすnano基础 目录 一. 简介二. 文件打开2.1 普通方式打开文件2.2 只读方式打开文件 三. 文件查看3.1 打开文件时,显示行号3.2 翻页查看 四. 文件编辑4.1 Ctrl K 复制 和 Ctrl U 粘贴4.2 Alt/Esc U 撤回 五. 文件保存与退出5.1 Ctrl …...









