【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 技术使普通人能够通过自然语言完成过去只能由程序员通过编程语言实现的任务,这是一场巨大的变革。然而,人类通常容易高估技术…...

手游刚开服就被攻击怎么办?如何防御DDoS?
开服初期是手游最脆弱的阶段,极易成为DDoS攻击的目标。一旦遭遇攻击,可能导致服务器瘫痪、玩家流失,甚至造成巨大经济损失。本文为开发者提供一套简洁有效的应急与防御方案,帮助快速应对并构建长期防护体系。 一、遭遇攻击的紧急应…...

树莓派超全系列教程文档--(61)树莓派摄像头高级使用方法
树莓派摄像头高级使用方法 配置通过调谐文件来调整相机行为 使用多个摄像头安装 libcam 和 rpicam-apps依赖关系开发包 文章来源: http://raspberry.dns8844.cn/documentation 原文网址 配置 大多数用例自动工作,无需更改相机配置。但是,一…...

Unity3D中Gfx.WaitForPresent优化方案
前言 在Unity中,Gfx.WaitForPresent占用CPU过高通常表示主线程在等待GPU完成渲染(即CPU被阻塞),这表明存在GPU瓶颈或垂直同步/帧率设置问题。以下是系统的优化方案: 对惹,这里有一个游戏开发交流小组&…...

中南大学无人机智能体的全面评估!BEDI:用于评估无人机上具身智能体的综合性基准测试
作者:Mingning Guo, Mengwei Wu, Jiarun He, Shaoxian Li, Haifeng Li, Chao Tao单位:中南大学地球科学与信息物理学院论文标题:BEDI: A Comprehensive Benchmark for Evaluating Embodied Agents on UAVs论文链接:https://arxiv.…...
Objective-C常用命名规范总结
【OC】常用命名规范总结 文章目录 【OC】常用命名规范总结1.类名(Class Name)2.协议名(Protocol Name)3.方法名(Method Name)4.属性名(Property Name)5.局部变量/实例变量(Local / Instance Variables&…...

定时器任务——若依源码分析
分析util包下面的工具类schedule utils: ScheduleUtils 是若依中用于与 Quartz 框架交互的工具类,封装了定时任务的 创建、更新、暂停、删除等核心逻辑。 createScheduleJob createScheduleJob 用于将任务注册到 Quartz,先构建任务的 JobD…...

Mac软件卸载指南,简单易懂!
刚和Adobe分手,它却总在Library里给你写"回忆录"?卸载的Final Cut Pro像电子幽灵般阴魂不散?总是会有残留文件,别慌!这份Mac软件卸载指南,将用最硬核的方式教你"数字分手术"࿰…...
OpenLayers 分屏对比(地图联动)
注:当前使用的是 ol 5.3.0 版本,天地图使用的key请到天地图官网申请,并替换为自己的key 地图分屏对比在WebGIS开发中是很常见的功能,和卷帘图层不一样的是,分屏对比是在各个地图中添加相同或者不同的图层进行对比查看。…...

GC1808高性能24位立体声音频ADC芯片解析
1. 芯片概述 GC1808是一款24位立体声音频模数转换器(ADC),支持8kHz~96kHz采样率,集成Δ-Σ调制器、数字抗混叠滤波器和高通滤波器,适用于高保真音频采集场景。 2. 核心特性 高精度:24位分辨率,…...
Pinocchio 库详解及其在足式机器人上的应用
Pinocchio 库详解及其在足式机器人上的应用 Pinocchio (Pinocchio is not only a nose) 是一个开源的 C 库,专门用于快速计算机器人模型的正向运动学、逆向运动学、雅可比矩阵、动力学和动力学导数。它主要关注效率和准确性,并提供了一个通用的框架&…...