I2C 外设知识体系:从基础到 STM32 硬件实现

news2025/7/23 17:34:40

文章目录

    • I2C外设简介
        • I2C 通信实现方式对比
          • 1. 软件模拟 I2C
          • 2. 硬件实现 I2C
        • STM32 I2C 外设核心功能
          • 1. 硬件特性
          • 2. 寄存器与引脚
      • I2C框图
        • 一、引脚接口
        • 二、数据处理模块
        • 三、时钟控制模块
        • 四、控制逻辑模块
        • 五、辅助功能
      • I2C基本结构
      • 主机发送
        • 一、7 位主发送序列
        • 二、10 位主发送序列
        • 三、关键事件(EV)说明
        • 四、注意事项
      • 主机接收
        • 一、7 位主接收序列
        • 二、10 位主接收序列
        • 三、关键事件(EV)说明
        • 四、注意事项
      • 软件/硬件波形对比
      • 硬件实现I2C使用MPU6050通信

I2C外设简介

I2C 通信实现方式对比
1. 软件模拟 I2C
  • 原理:通过手动翻转 GPIO 引脚电平,模拟 I2C 时序(时钟线 SCL 和数据线 SDA)。
    • 例:用软件控制 SCL 拉低 / 释放,逐位判断数据位并操作 SDA,生成通信波形。
  • 优势
    • 灵活性高,无需硬件支持,适用于简单场景。
    • 资源限制少,只需复制代码即可开辟多路 I2C 总线。
  • 局限
    • 依赖软件延时,时序精度较低(同步时序允许一定不规整)。
    • 占用 CPU 资源,不适合高频或复杂通信。
2. 硬件实现 I2C
  • 原理:通过单片机内置的 I2C 外设自动生成时序,软件只需配置寄存器。
    • 例:STM32 的 I2C 外设可自动处理起始 / 终止条件、时钟生成、数据收发、应答机制等。
  • 优势
    • 时序精准,效率高,释放 CPU 资源。
    • 支持完整协议特性(如多主机模型、DMA 传输、CRC 校验)。
  • 局限
    • 依赖硬件资源,引脚固定(如 STM32 I2C1 对应 PB6/PB7 或重映射引脚)。
    • 配置复杂度高于软件模拟(需理解寄存器和状态机)。
STM32 I2C 外设核心功能
1. 硬件特性
  • 集成收发电路:自动处理时序逻辑,软件通过操作寄存器(CR 控制寄存器、DR 数据寄存器、SR 状态寄存器)控制通信。
  • 多主机模型
    • 固定多主机:总线上有固定主机和从机,主机间需总线仲裁(如果多主设备同时发起通信)。
    • 可变多主机:设备可动态切换主从角色(STM32 采用此模型,默认从模式,需主动申请主机权限)。
  • 地址模式
    • 7 位地址:最常用(128 个地址,支持地址低位可配置)。
    • 10 位地址:扩展至 1024 个地址,通过两字节寻址(首字节高 5 位为标志位 “11110”)。
  • 通信速度
    • 标准模式:最高 100kHz,快速模式:最高 400kHz(同步时序允许非严格频率)。
  • 扩展功能:支持 DMA 传输(提升多字节收发效率)、兼容 SMBus 协议(系统管理总线)。
2. 寄存器与引脚
  • 引脚复用
    • I2C1:默认 PB6(SCL)、PB7(SDA),可重映射至 PB8/PB9。
    • I2C2:默认 PB10(SCL)、PB11(SDA)。
    • 注意:硬件 I2C 引脚固定,需配置为 “复用开漏输出” 模式(确保总线电平正确)。
  • 核心寄存器
    • 控制寄存器(CR):设置起始 / 终止条件、应答使能、主从模式等。
    • 数据寄存器(DR):存放待发送 / 已接收的数据,与移位寄存器配合实现逐位传输。
    • 状态寄存器(SR):包含标志位(如 SB 起始条件发送完成、ADDR 地址传输完成、TXE 发送寄存器空等),用于监测通信状态。

I2C框图

一、引脚接口
  • SDA(数据线):双向传输数据,通过 “数据控制” 模块与内部电路交互,支持开漏输出(需外接上拉电阻)。
  • SCL(时钟线):由 “时钟控制” 模块管理,用于同步数据传输,主机模式下生成时钟信号。
  • SMBALERT:用于 SMBus 协议的警报信号,连接至 “控制逻辑电路”,常规 I²C 通信中较少使用。
二、数据处理模块
  • 数据寄存器(DATA REGISTER):存储待发送或已接收的字节数据,是软件与硬件交互的核心接口。
  • 数据移位寄存器:与数据寄存器协作,实现数据逐位发送(高位先行)或接收(高位先入)。发送时从数据寄存器获取数据,接收时将数据存入数据寄存器。
  • 比较器:将接收到的地址与 “自身地址寄存器”(单地址模式)或 “双地址寄存器”(双地址模式)对比,判断是否为目标设备地址,确保通信寻址准确。
  • 帧错误校验(PEC)计算:生成或校验帧错误校验码,用于数据完整性检查,结果存储于 “PEC 寄存器”,提升通信可靠性。
三、时钟控制模块
  • 时钟控制寄存器(CCR):配置时钟频率(如标准模式 100kHz、快速模式 400kHz)和相位,精确控制 SCL 的生成时序,确保通信同步。
四、控制逻辑模块
  • 控制寄存器(CR1 & CR2)
    • 设置工作模式(主 / 从、发送 / 接收)、触发起始 / 终止条件、使能应答(ACK)等关键操作。
    • 例如,主机发送时通过 CR1 设置 “START=1” 生成起始信号,从机通过地址寄存器响应寻址。
  • 状态寄存器(SR1 & SR2)
    • 实时反馈通信状态,如起始条件完成(SB 标志)、地址传输完成(ADDR 标志)、数据寄存器空(TXE 标志)等。
    • 软件通过查询这些标志位(或依赖中断)监控通信流程,确保时序正确。
  • 控制逻辑电路
    • 协调各模块工作,根据控制寄存器指令生成控制信号,触发中断和 DMA 请求。
    • 例如,数据传输完成时,向 CPU 发送中断;大批量数据传输时,发起 DMA 请求以减轻 CPU 负担。
五、辅助功能
  • 中断:当特定事件(如地址匹配、数据传输完成、应答失败)发生时,控制逻辑电路触发中断,通知 CPU 及时处理异常或继续后续操作。
  • DMA 请求与响应:支持直接内存访问,适用于大量数据收发场景,避免 CPU 频繁干预,提升系统效率

I2C基本结构

这个图是上面总线,进行简化之后的基本结构图,后面会根据这个图进行程序的编写。

主机发送

一、7 位主发送序列
  1. 起始条件(S):产生起始信号,触发 EV5(SB = 1),表示起始条件已发送。软件通过读状态寄存器 SR1 确认后,将 7 位从机地址(含写位)写入数据寄存器 DR,清除 EV5。
  2. 发送地址:地址通过 SDA 发送,从机应答(A)后触发 EV6(ADDR = 1),表示地址传输完成。软件读 SR1 后读 SR2,清除 EV6。
  3. 发送数据
    • 首次发送数据(如数据 1)前,触发 EV8_1(TxE = 1,移位寄存器空),软件将数据写入 DR。
    • 后续数据发送时,触发 EV8(TxE = 1,移位寄存器非空),每次数据写入 DR 后清除该事件。每个数据字节后等待从机应答(A)。
  4. 发送结束:最后一个数据(数据 N)发送后,触发 EV8_2(TxE = 1,BTF = 1),软件请求设置停止位(P)。硬件在产生停止条件时,自动清除 TxE 和 BTF 位。
二、10 位主发送序列
  1. 起始条件(S):同 7 位模式,触发 EV5(SB = 1),写帧头(10 位地址高 8 位,含写位)到 DR 清除。
  2. 发送帧头与地址
    • 帧头发送后,从机应答(A),触发 EV9(ADDR10 = 1),读 SR1 后写 10 位地址低 2 位到 DR 清除。
    • 地址低 2 位发送后,从机应答(A),触发 EV6(ADDR = 1),读 SR1 和 SR2 清除。
  3. 发送数据:与 7 位模式一致,通过 EV8_1EV8 事件逐字节发送数据,每个数据后等待应答(A)。
  4. 发送结束:同 7 位模式,触发 EV8_2 后设置停止位(P),结束传输。
三、关键事件(EV)说明
  • EV5(SB = 1):起始条件发送完成,读 SR1 后写地址 / 帧头到 DR 清除。
  • EV6(ADDR = 1):地址传输完成(含应答),读 SR1 和 SR2 清除。
  • EV8_1(TxE = 1):移位寄存器空,写 DR 准备发送数据。
  • EV8(TxE = 1):数据寄存器空,写 DR 清除,确保数据连续发送。
  • EV8_2(TxE = 1,BTF = 1):最后一字节发送完成,请求停止条件,硬件自动清除相关位。
  • EV9(ADDR10 = 1):10 位地址帧头发送完成,读 SR1 后写地址低 2 位到 DR 清除。
四、注意事项
  1. SCL 拉长:EV5、EV6、EV9、EV8_1、EV8_2 事件会拉长 SCL 低电平,直至软件完成对应操作(如写 DR、读寄存器)。
  2. EV8 操作时序:EV8 的软件序列(写 DR)必须在当前字节传输结束前完成,避免时序错误

主机接收

一、7 位主接收序列
  1. 起始条件(S):产生起始信号,触发 EV5(SB = 1)。软件读状态寄存器 SR1 后,将 7 位从机地址(含读位)写入数据寄存器 DR,清除 EV5。
  2. 发送地址:地址通过 SDA 发送,从机应答(A)后触发 EV6(ADDR = 1)。软件读 SR1 后读 SR2,清除 EV6。
  3. 接收数据
    • 接收第一个数据(如数据 1)时,无对应事件标志(EV6_1 仅适用于接收 1 字节场景,在 EV6 后清除应答和停止条件产生位)。
    • 后续数据接收时,触发 EV7(RxNE = 1),表示数据寄存器非空,软件读 DR 清除该事件。
  4. 接收结束:最后一个数据(数据 N)接收时,触发 EV7_1(RxNE = 1)。软件读 DR 后,设置 ACK = 0(非应答)和 STOP 请求,结束通信。
二、10 位主接收序列
  1. 起始条件(S):同 7 位模式,触发 EV5(SB = 1),写 10 位地址帧头(高 8 位,含读位)到 DR 清除。
  2. 发送帧头与地址
    • 帧头发送后,从机应答(A),触发 EV9(ADDR10 = 1)。软件读 SR1 后,写 10 位地址低 2 位到 DR 清除。
    • 地址低 2 位发送后,从机应答(A),触发 EV6(ADDR = 1)。软件读 SR1 和 SR2 清除。若需继续接收,设置 CR2 的 START = 1,产生重复起始条件(Sr)。
  3. 接收数据:重复起始条件后,发送帧头(触发 EV6),后续数据接收同 7 位模式,通过 EV7 事件逐字节读取数据。
  4. 接收结束:同 7 位模式,最后一个数据触发 EV7_1,软件设置 ACK = 0STOP 请求,硬件生成停止条件,结束传输。
三、关键事件(EV)说明
  • EV5(SB = 1):起始条件发送完成,读 SR1 后写地址 / 帧头到 DR 清除。
  • EV6(ADDR = 1):地址传输完成(含应答),读 SR1 和 SR2 清除。10 位模式下,该事件后若需继续接收,设置 START = 1
  • EV7(RxNE = 1):数据寄存器非空,读 DR 清除,用于常规数据接收。
  • EV7_1(RxNE = 1):最后一字节数据接收,读 DR 后设置 ACK = 0STOP,结束通信。
  • EV9(ADDR10 = 1):10 位地址帧头发送完成,读 SR1 后写地址低 2 位到 DR 清除。
四、注意事项
  • EV6_1 特殊处理:仅适用于接收 1 字节场景,在 EV6 后需手动清除应答和停止条件产生位。
  • 10 位模式重复起始:若需连续接收,在 EV6 后设置 START = 1,重新生成起始条件,继续通信。

软件/硬件波形对比

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

硬件实现I2C使用MPU6050通信

//MPU6050.c 

#include "stm32f10x.h"                  // Device header
#include "MPU6050Reg.h" 
#define MPU6050_Address 0xD0

//超时等待函数 ,防止函数意外卡死
void MPU6050_WaitEvent(I2C_TypeDef* I2Cx, uint32_t I2C_EVENT)
{
	uint16_t Timeout = 10000;
	while(I2C_CheckEvent(I2Cx, I2C_EVENT) != SUCCESS)
	{
		Timeout--;
		if(Timeout == 0)
		{
			break;
		}
	}
}
//指定位置读
uint8_t MPU6050_ReadReg(uint8_t RegAddress)
{
	uint8_t data;
//	//起始位
//	MyI2C_Start();
//	MyI2C_SendByte(MPU6050_Address);
//	//接收应答位
//	MyI2C_ReadAck();
//	//发送寄存器地址
//	MyI2C_SendByte(RegAddress);
//	MyI2C_ReadAck();
//	
//	//因为又要设置读写,所以要重启起始位
//	MyI2C_Start();
//	//发送从机地址,因为是读数据所以地址最后的读写位为1
//	MyI2C_SendByte(MPU6050_Address | 0x01);
//	//接收应答位
//	MyI2C_ReadAck();
//	data = MyI2C_ReadByte();
//	//发送应答位 表示要停止
//	MyI2C_SendAck(1);
//	MyI2C_End();
	
	//将上面的软件I2c转化为对应的硬件I2c
	I2C_GenerateSTART(I2C2, ENABLE);
	//等待EV5事件 从机转化为主机
	MPU6050_WaitEvent(I2C2, I2C_EVENT_MASTER_MODE_SELECT);
	
	//发送从机地址位
	I2C_Send7bitAddress(I2C2, MPU6050_Address, I2C_Direction_Transmitter);
	//不用接收应答位,发送接收都会自动接收应答位
	//等待EV6事件  转换为发送模式
	MPU6050_WaitEvent(I2C2, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED);
	
	//不用等待EV8_1事件,就是告诉可以往数据寄存器发送数据了 发送寄存器地址
	I2C_SendData(I2C2, RegAddress);
	//等待EV8事件  等待字节转移完成
	MPU6050_WaitEvent(I2C2, I2C_EVENT_MASTER_BYTE_TRANSMITTING);
	
	//重启起始位
	I2C_GenerateSTART(I2C2, ENABLE);
	//等待EV5事件 从机转化为主机
	MPU6050_WaitEvent(I2C2, I2C_EVENT_MASTER_MODE_SELECT);
	
	//发送要从机地址
	I2C_Send7bitAddress(I2C2, MPU6050_Address, I2C_Direction_Receiver);
	//不用接收应答位,发送接收都会自动接收应答位
	//等待EV6事件  转换为接收模式
	MPU6050_WaitEvent(I2C2, I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED);
	//因为是接收一个字节所以要发送接收最后一个字节之前要配置应答位,因为接收完数据就晚了
	I2C_AcknowledgeConfig(I2C2, DISABLE);
	I2C_GenerateSTOP(I2C2, ENABLE);
	
	//等待EV7事件  等待数据接收完成
	MPU6050_WaitEvent(I2C2, I2C_EVENT_MASTER_BYTE_RECEIVED);
	//读取数据
	data = I2C_ReceiveData(I2C2);
	
	//完成之后再重新将标志位 设置为ENABLE 因为默认为使能,改为默认可以兼容在进行其他操作
	I2C_AcknowledgeConfig(I2C2, ENABLE);
	return data;
}
//指定地址写
void MPU6050_WriteReg(uint8_t RegAddress, uint8_t Data)
{
//	//起始位
//	MyI2C_Start();
//	MyI2C_SendByte(MPU6050_Address);
//	//接收应答位
//	MyI2C_ReadAck();
//	//发送寄存器地址
//	MyI2C_SendByte(RegAddress);
//	MyI2C_ReadAck();
//	//发送数据
//	MyI2C_SendByte(Data);
//	MyI2C_ReadAck();
//	//停止位
//	MyI2C_End();
	
	//将上面的软件I2c转化为对应的硬件I2c
	I2C_GenerateSTART(I2C2, ENABLE);
	//等待EV5事件 从机转化为主机
	MPU6050_WaitEvent(I2C2, I2C_EVENT_MASTER_MODE_SELECT);
	
	//发送从机地址位
	I2C_Send7bitAddress(I2C2, MPU6050_Address, I2C_Direction_Transmitter);
	//不用接收应答位,发送接收都会自动接收应答位
	//等待EV6事件  转换为发送模式
	MPU6050_WaitEvent(I2C2, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED);
	
	//不用等待EV8_1事件,就是告诉可以往数据寄存器发送数据了 发送寄存器地址
	I2C_SendData(I2C2, RegAddress);
	//等待EV8事件  等待字节转移完成
	MPU6050_WaitEvent(I2C2, I2C_EVENT_MASTER_BYTE_TRANSMITTING);
	
	//发送寄存器要写入的数据
	I2C_SendData(I2C2, Data);
	//等待EV8_2事件  等待字节转移完成
	MPU6050_WaitEvent(I2C2, I2C_EVENT_MASTER_BYTE_TRANSMITTED);
	
	
	//产生结束位
	I2C_GenerateSTOP(I2C2, ENABLE);
}

uint8_t MPU6050_GetID(void)
{
	return MPU6050_ReadReg(MPU6050_WHO_AM_I);
}
void MPU6050_Init(void)
{
//	MyI2C_Init();
	
	//硬件I2C初始化代码
	//1. 开启时钟
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C2, ENABLE);
	
	//2.配置gpio口 10 11 为复用开漏
	//初始化gpioinit参数中的结构体
	GPIO_InitTypeDef GPIO_InitStructure;
	//将gpio口设置为推挽输出
	GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF_OD;
	//初始化两个端口
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10 | GPIO_Pin_11;
	GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
	GPIO_Init(GPIOB,&GPIO_InitStructure);
	
	// 3. 初始化I2c
	I2C_InitTypeDef I2C_InitStruct;
	//开启应答位
	I2C_InitStruct.I2C_Ack = I2C_Ack_Enable;
	I2C_InitStruct.I2C_ClockSpeed = 50000;
	//占空比 2 比 1 其实都差不多
	I2C_InitStruct.I2C_DutyCycle = I2C_DutyCycle_2;
	I2C_InitStruct.I2C_Mode = I2C_Mode_I2C;
	//应答地址,这里是主机所以不重要
	I2C_InitStruct.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit;
	//是主机随便设置地址就可以了,不和其他硬件重合就可以了
	I2C_InitStruct.I2C_OwnAddress1 = 0x00;
	I2C_Init(I2C2, &I2C_InitStruct);
	
	//开启I2c总开关
	I2C_Cmd(I2C2, ENABLE);
	
	//配置相关的寄存器
	//电源管理寄存器 时钟选择陀螺仪x时钟
	MPU6050_WriteReg(MPU6050_PWR_MGMT_1, 0x01);
	//电源管理寄存器2 配置待机模式,都不待机
	MPU6050_WriteReg(MPU6050_PWR_MGMT_2, 0x00);
	//配置分频系数,值越小越快
	MPU6050_WriteReg(MPU6050_SMPLRT_DIV, 0x09);
	//配置寄存器 滤波模式 最平滑的滤波 0x06
	MPU6050_WriteReg(MPU6050_CONFIG, 0x06);
	//陀螺仪配置寄存器 选择最大量程 11 
	MPU6050_WriteReg(MPU6050_GYRO_CONFIG, 0x18);
	//加速度计配置寄存器 最大量程
	MPU6050_WriteReg(MPU6050_ACCEL_CONFIG, 0x18);
	
}
//经过上面寄存器的配置,数据都存在了寄存器中,直接设置读取寄存器的函数
void MPU6050_GetData(int16_t *AccX, int16_t *AccY, int16_t *AccZ,
							int16_t *GyroX, int16_t *GyroY, int16_t *GyroZ)
{
	uint8_t DataH, DataL;
	DataH = MPU6050_ReadReg(MPU6050_ACCEL_XOUT_H);
	DataL = MPU6050_ReadReg(MPU6050_ACCEL_XOUT_L);
	*AccX = DataH << 8 | DataL;
	
	DataH = MPU6050_ReadReg(MPU6050_ACCEL_YOUT_H);
	DataL = MPU6050_ReadReg(MPU6050_ACCEL_YOUT_L);
	*AccY = DataH << 8 | DataL;
	
	DataH = MPU6050_ReadReg(MPU6050_ACCEL_ZOUT_H);
	DataL = MPU6050_ReadReg(MPU6050_ACCEL_ZOUT_L);
	*AccZ = DataH << 8 | DataL;
	
	DataH = MPU6050_ReadReg(MPU6050_GYRO_XOUT_H);
	DataL = MPU6050_ReadReg(MPU6050_GYRO_XOUT_L);
	*GyroX = DataH << 8 | DataL;
	
	DataH = MPU6050_ReadReg(MPU6050_GYRO_YOUT_H);
	DataL = MPU6050_ReadReg(MPU6050_GYRO_YOUT_L);
	*GyroY = DataH << 8 | DataL;
	
	
	DataH = MPU6050_ReadReg(MPU6050_GYRO_ZOUT_H);
	DataL = MPU6050_ReadReg(MPU6050_GYRO_ZOUT_H);
	*GyroZ = DataH << 8 | DataL;
	
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2402245.html

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

相关文章

文件索引:数组、二叉树、二叉排序树、平衡树、红黑树、B树、B+树

参考链接&#xff1a;https://www.bilibili.com/video/BV1mY4y1W7pS 数据结构可视化工具&#xff1a;https://www.cs.usfca.edu/~galles/visualization/Algorithms.html 问题引出&#xff1a;一般是什么原因导致从磁盘查找数据效率低&#xff1f; 通过索引来更快的查询数据&a…

《仿盒马》app开发技术分享-- 商品搜索页(顶部搜索bar热门搜索)(端云一体)

开发准备 随着开发功能的逐渐深入&#xff0c;我们的应用逐渐趋于完善&#xff0c;现在我们需要继续在首页给没有使用按钮以及组件添加对应的功能&#xff0c;这一节我们要实现的功能是商品搜索页面&#xff0c;这个页面我们从上到下开始实现功能&#xff0c;首先就是一个搜索…

Tensorborad

一、tensorboard的基本操作 1.1 发展历史 TensorBoard 是 TensorFlow 生态中的官方可视化工具&#xff08;也可无缝集成 PyTorch&#xff09;&#xff0c;用于实时监控训练过程、可视化模型结构、分析数据分布、对比实验结果等。它通过网页端交互界面&#xff0c;将枯燥的训练…

工业自动化DeviceNET从站转Ethernet/IP主站网关赋能冶金行业工业机器人高效运行

在冶金行业高速发展的当下&#xff0c;对生产效率与精度的要求不断攀升。工业机器人凭借其精准、高效的特性&#xff0c;在钻孔、铣削、切割、弯曲、冲压等加工工艺中广泛应用。然而&#xff0c;不同设备间的通信协议差异常成为制约系统协同的瓶颈。JH-DVN-EIP疆鸿智能DeviceNE…

开源数据库MySQL 与 PostgreSQL的巅峰对决。

MySQL 与 PostgreSQL 是两大主流开源关系型数据库&#xff0c;其核心差异主要体现在架构设计、功能特性、性能优化及适用场景上。结合最新技术对比和行业实践&#xff0c;以下为深度解析&#xff1a; &#x1f9e0; ​​一、架构与设计哲学​​ ​​维度​​​​PostgreSQL​​…

从 LeetCode 到日志匹配:一行 Swift 实现规则识别

文章目录 摘要描述题解答案题解代码分析示例测试及结果时间复杂度空间复杂度总结 摘要 在开发中我们经常遇到“模式匹配”的问题&#xff0c;比如日志分类、用户意图识别、甚至是在一些权限系统中做规则映射判断。这类问题的本质是判断两个结构是否具有一致的对应关系。LeetCo…

前端js获取当前经纬度(H5/pc/mac/window都可用)

前端JS获取当前位置的经纬度&#xff08;H5/PC/mac/window都可用&#xff0c;亲测&#xff01;&#xff09;&#xff0c;效果如下。 完整代码如下&#xff1a; <!-- 用原生api获取经纬度&#xff0c;转化为百度经纬度与服务端交互&#xff0c; 只支持https&#xff01; --&g…

Meta计划借助AI实现广告创作全自动化

每周跟踪AI热点新闻动向和震撼发展 想要探索生成式人工智能的前沿进展吗&#xff1f;订阅我们的简报&#xff0c;深入解析最新的技术突破、实际应用案例和未来的趋势。与全球数同行一同&#xff0c;从行业内部的深度分析和实用指南中受益。不要错过这个机会&#xff0c;成为AI领…

AI编程规范失控?三大策略用Cursor Rules精准约束

​在 AI 编程时代,如何让助手精准理解您的项目规范?当团队协作时,如何确保每位开发者生成的代码风格统一?Cursor Rules 正是您需要的终极解决方案——它如同一位永不疲倦的架构师,通过预设规则控制 AI 的每一次代码生成、重构与补全行为。 本教程将带您深入 Cursor Rules…

4.大语言模型预备数学知识

大语言模型预备数学知识 复习一下在大语言模型中用到的矩阵和向量的运算&#xff0c;及概率统计和神经网络中常用概念。 矩阵的运算 矩阵 矩阵加减法 条件&#xff1a;行数列数相同的矩阵才能做矩阵加减法 数值与矩阵的乘除法 矩阵乘法 条件&#xff1a;矩阵A的列数 矩阵…

免费开源Umi-OCR,离线使用,批量精准!

Umi-OCR&#xff08;Windows端&#xff09; Umi-OCR 是一款在 GitHub 上开源的免费 OCR 识别软件&#xff0c;它最大的亮点就是免费、开源、支持批量处理&#xff0c;而且识别准确度很高。这款软件不需要联网就能用&#xff0c;非常值得推荐&#xff01; 在 OCR 识别功能方面&…

NLP驱动网页数据分类与抽取实战

一、性能瓶颈点&#xff1a;数据抽取中的「三座大山」 在使用NLP技术进行网页商品数据抽取时&#xff0c;很多工程师会遇到如下三类瓶颈&#xff1a; 1. 请求延迟高&#xff1a;目标站点反爬机制灵敏&#xff0c;普通请求频繁被封。2. 结构解析慢&#xff1a;HTML结构复杂&am…

阿里云ACP云计算备考笔记 (3)——云存储RDS

目录 第一章 云存储概览 1、云存储通用知识 ① 发展历史 ② 云存储的优势 2、云存储分类 3、文件存储业务场景 第二章 块存储 1、块存储分类 2、云盘的优势 3、创建云盘 4、管理数据盘 ① 格式化数据盘 ② 挂载数据盘 ③ 通过 API 挂载云盘 5、管理系统盘 ① 更…

仓颉语言---Socket编程

一、什么是Socket编程&#xff1f; 1.定义 Socket&#xff08;套接字&#xff09;可以被理解为网络上两个进程之间通信的端点。它是网络通信的抽象表示&#xff0c;封装了底层网络协议的复杂性&#xff0c;为应用程序提供了一个简单统一的接口。 Socket 编程是一种网络编程范式…

【Java EE初阶 --- 多线程(初阶)】多线程的实现案例

乐观学习&#xff0c;乐观生活&#xff0c;才能不断前进啊&#xff01;&#xff01;&#xff01; 我的主页&#xff1a;optimistic_chen 我的专栏&#xff1a;c语言 &#xff0c;Java 欢迎大家访问~ 创作不易&#xff0c;大佬们点赞鼓励下吧~ 文章目录 前言单例模式实现单例模式…

制作一款打飞机游戏64:关卡设计

今天我想完成第一个音乐循环的关卡设计。 初始设置 首先&#xff0c;我要删除所有之前创建的敌人和“大脑”&#xff08;可能指敌人的行为模式或AI&#xff09;。我不想保留它们&#xff0c;我要从零开始&#xff0c;重新创建敌人。但我会保留精灵&#xff08;游戏中的角色或…

Python趣学篇:用Pygame打造绚烂流星雨动画

名人说&#xff1a;路漫漫其修远兮&#xff0c;吾将上下而求索。—— 屈原《离骚》 创作者&#xff1a;Code_流苏(CSDN)&#xff08;一个喜欢古诗词和编程的Coder&#x1f60a;&#xff09; 专栏介绍&#xff1a;《Python星球日记》 目录 一、项目简介与效果展示二、技术栈与核…

山西省第十八届职业院校技能大赛 网络建设与运维赛项 样题

山西省第十八届职业院校技能大赛 网络建设与运维赛项 &#xff08;学生组&#xff09; 样题 2024 年 11 月 xx 日 2 赛题说明 一、竞赛项目简介 “网络建设与运维”竞赛共分为模块一&#xff1a;网络理论测试与网络 运维&#xff1b;模块二&#xff1a; 网络建设与调试&a…

Python----目标检测(训练YOLOV8网络)

一、数据集标注 在已经采集的数据中&#xff0c;使用labelImg进行数据集标注&#xff0c;标注后的txt与原始 图像文件同名且在同一个文件夹&#xff08;data&#xff09;即可。 二、制作数据集 在data目录的同目录下&#xff0c;新建dataset目录&#xff0c;以存放制作好的YOLO…

构建 MCP 服务器:第一部分 — 资源入门

什么是模型上下文协议? 模型上下文协议(MCP) 是Claude等大型语言模型 (LLM) 与外部数据和功能安全交互的标准化方式。您可以将其想象成一个平视显示器,或者 AI 的 USB 端口——它提供了一个通用接口,允许任何兼容 MCP 的 LLM 连接到您的数据和工具。 MCP 提供了一个集中式协…