I2C诞生于上世纪80年代初,由飞利浦(现在的恩智浦NXP)为解决微控制器与外围芯片之间繁琐的连接问题而设计。
仅仅两根线——SCL(时钟线)和SDA(数据线),就能实现多设备间的双向通信
I2C通信协议可以用普通GPIO引脚进行软件模拟。
I2C接口主要用于通讯速率要求不高,以及多个器件之间通信的应用场景。

1. I2C介绍

1.1 特点

  • 双线制总线:I2C仅使用两条线——串行数据线(SDA)和串行时钟线(SCL)进行通信,有效降低了连接复杂性。
  • 多主多从:I2C支持多个主设备和多个从设备连接到同一总线上。每个设备都有唯一的地址。总线仲裁机制保证同一时刻只有一个主设备控制总线。
  • 不同的传输速率:I2C总线支持不同的速率模式,如标准模式(100kbps)、快速模式(400kbps)和高速模式(3.4Mbps)。
  • 同步通信:I2C是一种同步通信协议,数据传输由时钟信号(SCL)来控制(区别于UART异步通信)。
  • 简单的连接:I2C通信对硬件的要求比较低,只需两根线和上拉电阻。
  • 地址唯一:每个I2C设备都通过一个7位或10位的地址来识别(常用7位),主设备通过地址识别并选择具体的从设备进行通信。
  • 半双工通信:数据线为双向线,但在同一时刻只能单向传输数据。
  • 支持广播和点对点通信:可以向所有设备广播命令,也可以指定单个设备通信。
  • 阻塞传输:I2C支持阻塞传输机制,即主设备可以在传输过程中控制总线,防止其他设备发送数据。
  • 通信协议简单:包括起始信号、地址帧、读写位、应答位、数据帧、停止信号。
  • 应用广泛:由于其简单和灵活性,I2C被广泛应用于各种电子产品中,如传感器、LCD显示器、EEPROM等。
  • 总线仲裁和冲突检测:在多主模式下,I2C能够处理多个主设备同时尝试控制总线的情况。
  • 低功耗:I2C总线的设计使其成为低功耗的通信方式,适用于电池供电的设备。

物理连接,注意看5V和上拉电阻:
在这里插入图片描述

两个信号线特点:

这两条线都是 双向 的,并且采用 开漏(Open-Drain) 或 开集(Open-Collector) 输出。
当配置为开漏输出(Open-drain Output)时,单片机可以输出「低电平」(GPIO_PIN_RESET)或「高阻态」(GPIO_PIN_SET),高阻态下,相当于断开。这意味着任何设备都只能将信号线拉低到GND,但不能主动输出高电平。为了使信号线能呈现高电平,SCL和SDA线路上都必须连接一个 上拉电阻(Pull-up Resistor) 到VCC,且设备只能释放总线,让线通过外部上拉电阻被拉到高电平。

1.2 为什么必须使用上拉电阻

  • 保护电路:通过开漏结构,允许多个设备同时连接且不会因为某个设备输出高低电平冲突而损坏电路。
  • 线与(Wired-AND)逻辑: 当多个设备同时连接到总线上时,只要有一个设备将线路拉低,整个线路就呈现低电平。只有当所有设备都“释放”线路(即高阻态)时,线路才会在上拉电阻的作用下恢复到高电平。
  • 多主控仲裁: 如果两个主设备同时试图控制总线并发送数据,它们会监测SDA线。当一个主设备发送高电平(释放总线拉高电平)而另一个发送低电平(拉低总线)时,发送高电平的主设备会检测到SDA线与自己发送的电平不符,便会知道总线上存在冲突,并立即放弃对总线的控制,从而保证了数据传输的完整性。

1.3 I2C协议时序

在这里插入图片描述

  • 起始条件 (START): 主设备发起通信。SCL保持 高电平 期间,SDA从 高电平 变为 低电平

  • 停止条件 (STOP): 当SCL保持 高电平 期间,SDA从 低电平 跳变为 高电平。同样,只有主设备才能产生停止条件。
    在这里插入图片描述

  • 位数据传输: I²C对数据传输的时序有严格规定。在SCL为 高电平 期间,SDA上的数据必须保持稳定,不能有任何变化。SDA的电平变化(即数据位的翻转)只能在SCL为 低电平 时进行。每字节8位数据,最高位先发。
    在这里插入图片描述

  • 应答 (ACK) 与非应答 (NACK): 这是I²C通信中的“确认”与“拒绝”机制。

    • ACK (Acknowledge): 发送方每发送8位(一个字节)数据后,接收方会在第9个时钟周期将SDA线拉低,表示“我收到了,请继续!”。
    • NACK (Not Acknowledge): 接收方在第9个时钟周期保持SDA线为高电平,表示“我没收到”、“我忙着呢”、“数据不对劲”或者“我读完了,不用再发了”。这个NACK信号在主机读数据时尤为重要,它告诉从机“我不要更多数据了”。

传输的数据帧结构:
在这里插入图片描述

写入流程如下,比较简单,先写地址,再写数据即可:

MasterSlave发送Start信号(SDA高->>低,SCL高)发送从设备地址 + 写位(R/W=0)发送ACK发送寄存器地址(8位)发送ACK发送数据字节(8位)发送ACK发送Stop信号(SDA低->>高,SCL高)MasterSlave

读取一个地址的数据流程稍显复杂,因为中间会经历一次写/读的转换:

主设备 (Master)从设备 (Slave)发送Start信号(SDA高->>低,SCL高)发送从设备地址 + 写位(R/W=0)发送ACK发送寄存器地址(8位)发送ACK发送重复Start信号(Repeated Start)发送从设备地址 + 读位(R/W=1)发送ACK发送数据字节(8位)发送NACK(读取结束)发送Stop信号(SDA低->>高,SCL高)主设备 (Master)从设备 (Slave)

REPEATED START (重复起始条件): 这是读操作的精髓!在不发送STOP信号的情况下,主机再次发送一个START信号。这个操作非常关键,它允许主机在不释放总线的情况下,改变数据传输方向(从写变为读)。
简单来说读过程就是主机发送写请求将要读的地址告知从机,然后再发送读请求,从机开始回复数据。
这两个时序图是符合I2C标准的,EEPROM需符合该标准。

1.4 I2C多主机的仲裁机制

I2C是支持多主机通信的,多主机通信必须有仲裁机制,保证某个主机通信的完整性。

多主机同时发送起始信号时,通过监测SDA线电平实现位级仲裁。
主机发送1时发现SDA线为0时,会停止发送,等待下次机会。如果线为1,即使有其他主机在发送,也认为不冲突,等待下个位时再检测

1.5 时钟拉伸

什么是时钟拉伸?
在I2C通信中,SCL线由主机控制时钟信号。
有时从机处理数据较慢,不能马上准备好下一位数据。
从机可以主动拉低SCL线(即拉伸时钟),阻止主机继续产生时钟上升沿,从而延长当前时钟周期。
主机必须等待SCL释放(变高),才能继续通信。

2. 代码实践

使用野火-指南者F103进行测试,读写EEPROM。

2.1 硬件原理图

可以看到,SCL和SDA分别对应PB6和PB7,对应I2C1。
在这里插入图片描述

从设备地址:
高 4 位固定为:1010 b;
按照我们此处的连接,A0/A1/A2 均为 0,所以 EEPROM 的 7 位设备地址是:1010 000b ,即 0x50。

2.2 MX配置

在这里插入图片描述

  • Master Features(主机特性)

    • I2C Speed Mode:Fast Mode
      表示I2C总线速度模式为“快速模式”,通信速率最高可达400kHz。
      这里只支持Standard Mode(100kHz)、Fast Mode(400kHz)。
    • I2C Clock Speed (Hz):400000
      主机产生的I2C时钟频率,单位赫兹。这里为400kHz,符合Fast Mode标准。
    • Fast Mode Duty Cycle:Duty cycle Tlow/Thigh = 2
      指时钟信号中低电平和高电平的占空比比值。
      例如:Tlow = 2 × Thigh,意味着时钟低电平持续时间是高电平的两倍。默认即可。
  • Slave Features(从机特性)

    • Clock No Stretch Mode:Disabled
      “时钟不拉伸模式”禁用。禁用此选项表示允许从机拉伸时钟。
      在I2C协议中,从机可以通过拉低SCL线“拉伸时钟”来延长时钟周期,给自己时间处理数据。

    • Primary Address Length Selection:7-bit
      从机主地址使用7位地址模式。
      I2C支持7位和10位地址两种寻址方式,这里选择7位地址。

    • Dual Address Acknowledged:Disabled
      禁用双地址应答功能。从机只响应一个主地址,若启用则可以设置两个不同地址响应。

    • Primary Slave Address:0x50,即上面确定的EEPROM从机地址。

    • General Call Address Detection:Disabled
      禁用“通用呼叫”地址检测。
      通用呼叫地址(0x00)是主机向所有从机广播的地址,启用此功能时从机会响应通用呼叫。

2.3 代码生成

在i2c.c中创建了下面的关键代码:

  hi2c1.Instance = I2C1;hi2c1.Init.ClockSpeed = 400000;hi2c1.Init.DutyCycle = I2C_DUTYCYCLE_2;hi2c1.Init.OwnAddress1 = 0;hi2c1.Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT;hi2c1.Init.DualAddressMode = I2C_DUALADDRESS_DISABLE;hi2c1.Init.OwnAddress2 = 0;hi2c1.Init.GeneralCallMode = I2C_GENERALCALL_DISABLE;hi2c1.Init.NoStretchMode = I2C_NOSTRETCH_DISABLE;if (HAL_I2C_Init(&hi2c1) != HAL_OK){Error_Handler();}

【注意】这里`hi2c1.Init.OwnAddress1和OwnAddress2都被设置为了0,这两个是给主设备即STM32本身设置地址,一般只需要设置OwnAddress1即可,且只需要保证和EEPROM从设备地址不一样即可。
如果MX中设置为0x50,这个OwnAddress1最低位为读写位,实际代码中赋的值是0x50左移一位,即0xA0。

2.4 读写操作

为了简化验证,读写函数都放到main.c中了。

#define EE_ADDR (0x50 << 1)                //注意要左移一位
#define EEPROM_PAGE_SIZE     8             // AT24C02页大小8字节
#define EEPROM_MAX_TRIALS    100
#define EEPROM_TIMEOUT       1000          // I2C操作超时时间(ms)
//I2C写入一段连续缓存
int EE_I2C_WriteBuffer(uint16_t memAddress, uint8_t *pData, uint16_t size)
{//AT24C02的页大小为8字节,即一次写操作最多写入8字节(一个页)。//当写入数据超过一页大小时,地址会自动回绕(wrap-around),覆盖这一页内的前面字节,导致数据错乱。//因此,写入buffer时必须分块写,每块最大8字节,且不能"跨页"写。//每次写入后需等待写周期完成(约5~10 ms)//写入的地址可以是任意的,但为了保证不跨页,也得分多次写入。比如写入地址05,写4个字节,那么05 06 07写前三个字节,08单独写最后一个字节。HAL_StatusTypeDef status;uint16_t bytesWritten = 0;while (bytesWritten < size) {// 计算当前地址所在页剩余空间(这两句覆盖了写入地址在页中间和页头两种情况)uint8_t page_offset = memAddress % EEPROM_PAGE_SIZE;uint8_t page_space = EEPROM_PAGE_SIZE - page_offset;// 本次写入长度,不能超过页剩余空间,也不能超过剩余数据长度uint16_t write_len = (size - bytesWritten) < page_space ? (size - bytesWritten) : page_space;// 执行写操作 &pData[bytesWritten]相当于pData + bytesWrittenstatus = HAL_I2C_Mem_Write(&hi2c1,EE_ADDR,memAddress,I2C_MEMADD_SIZE_8BIT,&pData[bytesWritten],write_len,EEPROM_TIMEOUT);if (status != HAL_OK) {return -1;}// 等待写完成// 关键步骤1, 等待总线空闲,传输完成。因为上一步写入是异步操作while(HAL_I2C_GetState(&hi2c1) != HAL_I2C_STATE_READY){}// 关键步骤2, 等待EE内部写入FLASH完成while(HAL_I2C_IsDeviceReady(&hi2c1, EE_ADDR, EEPROM_MAX_TRIALS, EEPROM_TIMEOUT) == HAL_TIMEOUT){}//关键步骤3, 再次确认I2C总线空闲while(HAL_I2C_GetState(&hi2c1) != HAL_I2C_STATE_READY){}// 更新地址和已写入字节数memAddress += write_len;bytesWritten += write_len;}return 0;
}//I2C读取一段数据缓存
int EE_I2C_ReadBuffer(uint8_t *pbuffer, uint16_t addrRead, uint16_t readByteNum)
{//读操作没有页限制,可以一次读取任意长度数据。HAL_StatusTypeDef stat = HAL_I2C_Mem_Read(&hi2c1, EE_ADDR, addrRead, I2C_MEMADD_SIZE_8BIT, pbuffer, readByteNum, 1000);if (stat != HAL_OK){return -1;}return 0;
}

写入时的注意事项已经在代码中添加了。这里再强调一遍:

  • AT24C02的页大小为8字节,即一次写操作最多写入8字节(一个页)。
  • 当写入数据超过一页大小时,地址会自动回绕(wrap-around),覆盖这一页内的前面字节,导致数据错乱。
  • 因此,写入buffer时必须分块写,每块最大8字节,且不能"跨页"写。
  • 每次写入后需等待写周期完成(约5~10 ms)
  • 写入的地址可以是任意的,但为了保证不跨页,也得分多次写入。比如写入地址05,写4个字节,那么05 06 07写前三个字节,08单独写最后一个字节。 读取非常简单。
	//I2C写入测试uint8_t buffer[10] = {1,2,3,4,5,6,7,8,9,10};EE_I2C_WriteBuffer(5, buffer, sizeof(buffer)); //写入起始地址在页中间uint8_t buffer_r[10];EE_I2C_ReadBuffer(buffer_r, 5, sizeof(buffer));

测试通过。

DMA写入和串口DMA写入很类似,也是在中断中判定写入完成再可以写下一个。

3. 经验总结

本节上往上信息的摘录总结。

3.1 上拉电阻问题

- 阻值过大: 如果上拉电阻阻值过大,SCL和SDA线从低电平恢复到高电平的时间会变长(RC充电时间常数)。在高波特率(比如400kHz甚至1MHz)下,这可能导致信号上升沿缓慢,违反I²C的时序要求,从而导致通信失败或数据错误。
- 阻值过小: 如果上拉电阻阻值过小,当设备将线路拉低时,流过上拉电阻的电流会过大。这可能超过设备I/O引脚的灌电流能力,甚至可能损坏设备。
- 选型: 上拉电阻的阻值通常在1kΩ到10kΩ之间。具体选择多少,取决于总线电容(连接的设备数量、PCB走线长度)、工作电压和通信速率。一般来说,速率越高,总线电容越大,上拉电阻就需要越小。经验法则是先从4.7kΩ或2.2kΩ开始尝试。

I2C上升时间主要由RC时间常数决定,上拉电阻 * 总线电容,成反比关系。
在这里插入图片描述

先用4.7kΩ作为起点测试。
如果出现信号上升慢、通信不稳定,尝试减小阻值到2.2kΩ或1kΩ。
如果功耗过大或信号电平偏低,尝试增大阻值。
结合示波器测试信号波形,确保满足I2C时序。

3.2 地址错误

这是最常见的错误之一。
- 7位 vs 8位地址: 很多数据手册提供的是7位从机地址,但有些I²C驱动或库函数要求你传入8位地址(即7位地址左移1位,并包含读写位)。务必仔细阅读数据手册和驱动文档,确认传入的地址格式是否正确。
- 地址冲突: 如果总线上有两个从设备使用了相同的地址,那么通信就会混乱。
- 设备未上电/未初始化: 从设备没有正确上电或没有完成初始化,自然不会响应I²C地址。

3.3 ACK/NACK问题

传输中途出现NACK,通常意味着从机没有正确响应。
- 原因: 可能是地址错误(从机根本没收到地址)、从机正忙(内部操作未完成)、从机未正常工作(硬件故障)、或者数据格式不正确导致从机无法解析。
- 调试: 使用逻辑分析仪查看NACK发生在哪个字节之后,这能帮助你定位问题。

3.4 总线被锁死

这是I²C的“僵尸模式”。当某个设备在I²C传输过程中突然复位、掉电或出现异常,它可能将SDA线永久拉低,导致整个I²C总线被“锁死”,任何通信都无法进行。

  • 解决方法: 主机可以尝试发送9个时钟脉冲(在SCL线上产生9个时钟周期,但不关心SDA),让从机完成当前字节传输并释放SDA线。如果SDA线仍然被拉低,则可能需要复位从设备或整个系统。有些I²C控制器有硬件复位总线的功能。

3.5 逻辑分析仪

调试I²C问题的“上帝视角”!如果你在I²C通信上遇到了“玄学”问题,一个逻辑分析仪(哪怕是几十块钱的USB逻辑分析仪)都能帮你“拨云见日”。它能清晰地捕获SCL和SDA上的波形,并自动解析出START/STOP、地址、数据和ACK/NACK,让你一目了然地看到通信的每一个细节,是定位时序问题、数据错误、ACK/NACK异常的终极神器。但是必要的时候(上升下降时间、波形电平)还是需要使用示波器进行波形抓取。

3.6 速度受限

相较于SPI(串行外设接口)等协议,I²C的速度较慢。常见的标准模式为100kbps,快速模式为400kbps,高速模式可达3.4Mbps,但仍不如SPI快。对于需要高速数据传输的应用(如显示屏),I²C可能不是最佳选择。

3.7 距离受限

由于总线电容效应,I²C的通信距离有限,通常仅限于同一块PCB板内或短距离连接。长距离传输需要额外的总线缓冲器或转换芯片。

3.8协议开销

每个字节的数据传输都需要一个额外的ACK/NACK位,这增加了协议的开销。在传输大量小数据包时,效率会受到一定影响。

3.9 布线考虑:

• 尽量保持SCL和SDA走线平行、等长
• 避免与高速信号或电源走线并行
• 加入适当的去耦电容

3.10 I²C支持多主控吗?如何实现仲裁?

A: I²C支持多主控。当多个主设备同时尝试控制总线时,I²C通过“时钟同步”和“数据仲裁”机制来解决冲突。
• 时钟同步: 多个主设备会同步它们的SCL信号,只要有一个主设备拉低SCL,SCL就保持低电平。
• 数据仲裁: 这是关键。当一个主设备发送高电平(释放SDA)而另一个主设备发送低电平(拉低SDA)时,发送高电平的主设备会检测到SDA线与自己发送的电平不符。它会立即意识到总线冲突,并主动放弃对总线的控制,进入监听模式。这种“谁先拉低谁赢”的机制保证了数据传输的完整性。

3.11 如何为我的I2C总线选择合适的上拉电阻值?

A: 这是一个权衡。阻值太大,拉高电流小,信号上升时间长,高速率下会出问题;阻值太小,灌电流大,可能超出GPIO引脚的承受能力,且功耗增加。一个经验法则是:对于100kbps速率,使用4.7kΩ;对于400kbps速率,使用1.8kΩ到2.2kΩ。最科学的方法是根据总线电容、电压和速率,查阅I2C官方规范(UM10204)中的公式进行计算。

3.12 为什么I²C总线会被锁死?如何避免和解决?

A: I²C总线锁死通常发生在从设备在通信过程中异常复位、掉电或程序跑飞,导致SDA线被永久拉低。因为I²C是线与逻辑,SDA被拉低后,总线就无法恢复高电平,所有通信都会停止。

  1. 确保从设备的电源稳定,软件逻辑健壮,避免死循环或异常中断。
  2. 软件复位: 主机尝试发送9个时钟脉冲(在SCL上产生9个时钟,不关心SDA),让从机有机会释放SDA。
  3. 硬件复位: 如果软件复位无效,可能需要通过控制从设备的复位引脚来强制复位从设备。
  4. 总线复位: 某些I²C控制器有硬件总线复位功能,可以直接复位I²C总线状态。
  5. 电源复位: 最“暴力”但有效的方法是给从设备断电再上电。

3.13 我的从设备总是返回NACK,最快的排查步骤是什么?

A: 遵循“由硬到软”原则:

  1. 测电压: 确认从设备VCC和GND都已正确连接。
  2. 查上拉: 确认SCL和SDA上拉电阻存在且阻值合适。
  3. 核对地址: 用i2cdetect或逻辑分析仪确认你代码中的地址和设备实际地址是否一致(注意7位/8位格式)。
  4. 简化总线: 只保留一个主机和一个从机,排除其他设备的干扰。
  5. 检查时序: 用逻辑分析仪检查你的START信号、时钟频率和时序是否符合规范。

3.14 什么是“时钟拉伸”(Clock Stretching),它有什么用?

A: “时钟拉伸”是I2C协议中一个非常重要的特性。它允许从设备在需要更多时间处理数据时(比如正在进行一次内部ADC转换),主动将SCL线拉低,从而“暂停”时钟。主机检测到SCL被拉低后,会耐心等待,直到从机处理完任务并释放SCL线,通信才会继续。这赋予了从设备一定的主动权,确保了在主快从慢的情况下数据不会丢失,大大增强了系统的健壮性。

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

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

相关文章

WPF 监控CPU、内存性能

本段代码是一个封装的用户控件<UserControl x:Class"YF_Frame.PerformanceMonitor"xmlns"http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:x"http://schemas.microsoft.com/winfx/2006/xaml"xmlns:mc"http://schemas.…

Rust学习笔记(四)|结构体与枚举(面向对象、模式匹配)

本篇文章包含的内容1 结构体1.1 定义和初始化结构体1.2 Tuple Struct1.3 结构体方法&#xff08;Rust 面向对象&#xff09;1.4 关联函数2 枚举2.1 定义和使用枚举2.2 将数据附加到枚举的变体中2.3 Option 枚举2.4 模式匹配2.4.1 match语句2.4.2 if let语句1 结构体 1.1 定义和…

C++——分布式

文章目录一、什么是分布式&#xff1f;核心特点为什么需要分布式&#xff1f;分布式 vs 集中式常见分布式场景挑战与难点二、 简述下CAP理论2.1 简述2.2 详细三、 简述下分布式中的2PC2.1 详细3.2 简述三 、简述下Raft协议3.1 详细3.2 简述四 grpc框架4.1 RPC&#xff08;Remot…

Redis面试精讲 Day 20:Redis大规模部署性能调优

【Redis面试精讲 Day 20】Redis大规模部署性能调优 开篇 欢迎来到"Redis面试精讲"系列第20天&#xff01;今天我们将深入探讨Redis在大规模部署场景下的性能调优策略&#xff0c;这是高级工程师和架构师面试必考的核心知识点。本文将从操作系统配置、Redis参数调优…

[微服务]ELK Stack安装与配置全指南

目录 一、ELK相关介绍 1.1 什么是ELK Stack 1.2 ELK核心组件与功能 1.3 ELK优势 1.4 ES数据库结构对比SqlServer 二、安装ELK 2.1 window安装 2.2 Docker下环境搭建 2.2.1 安装7.16.3版本ElasticSearch 2.2.2 安装7.16.3版本Kibana : 2.2.3 安装8.0.0版本ElasticSea…

java项目怎么实现用户行为分析、漏斗转化、数据可视化报表。

在 Java 项目中实现用户行为分析、漏斗转化和数据可视化报表是一个系统性的工作&#xff0c;需要从数据采集、存储、分析到展示的完整链路设计。以下是一个可行的实现方案&#xff1a;1. 整体架构设计建议采用分层架构&#xff1a;数据采集层&#xff1a;收集用户行为数据数据存…

缓存元数据损坏操作步骤(lvmcache修复)

现象为:机械盘丢失cvol-cmeta卷如图所示,lvm逻辑卷中缺失缓存的lvm,这边以只读cache为例日志现象报错信息为:lvmcache_cvol failed manual repair required!lvmcache_cvol failed: manual repair required! 这类报错&#xff0c;本质上是 LVM cache 池&#xff08;cache-pool&…

使用CMAKE-GUI生成Visual Studio项目

使用CMAKE-GUI生成Visual Studio项目第一种&#xff0c;如果我们想把以Cmake构建的项目移植VS上&#xff0c;就可以使用Cmake来生成.sln文件 准备生成的目录文件先准备好我们要打包的源代码等文件&#xff08;放在resource下&#xff09;使用cmake-gui工具来构建&#xff08;命…

20道DOM相关前端面试题

DOM 相关面试题及答案 什么是 DOM&#xff1f;DOM 树的结构是怎样的&#xff1f; DOM&#xff08;文档对象模型&#xff0c;Document Object Model&#xff09;是 HTML/XML 文档的编程接口&#xff0c;将文档结构化为树形节点集合&#xff0c;允许程序动态访问和修改文档内容、…

CVE-2021-4300漏洞复现

Adminer是一个PHP编写的开源数据库管理工具&#xff0c;支持MySQL、MariaDB、PostgreSQL、SQLite、MS SQL、Oracle、Elasticsearch、MongoDB等数据库。在其版本1.12.0到4.6.2之间存在一处因为MySQL LOAD DATA LOCAL导致的文件读取漏洞。 一、伪造服务器 利用mysql-fake-serve…

【LeetCode题解】LeetCode 35. 搜索插入位置

【题目链接】 35. 搜索插入位置 【题目描述】 【题解】 通过题目可以知道这是一道经典的二分查找的题目&#xff0c;对于二分查找的题目&#xff0c;根据需要查找的两个边界点&#xff0c;分为两个不同的模板&#xff0c;如下图所示。 这道题要求在数组中查找目标值并返回其索…

RK3568 NPU RKNN(五):RKNN-ToolKit-lite2板端推理

文章目录1、前言2、目标3、安装RKNN-ToolKit-lite23.1、安装环境3.2、安装RKNN-ToolKit-lite23.3、验证4、完整的测试程序5、运行测试程序6、程序拆解7、总结1、前言 本文仅记录本人学习过程&#xff0c;不具备教学指导意义。 2、目标 之前提到过&#xff0c;RKNN-Toolkit2-…

二分查找。。

1 二分查找二分查找前提是数组有序。先令&#xff0c;left 0 , right 7mid (right left) / 2;如果mid的值大于要查找的值&#xff0c;则right mid - 1&#xff1b;如果小于&#xff0c;left mid 1&#xff1b;如果mid的值等于要查找的值&#xff0c;查找成功。重复步骤2…

Spring Ai 如何配置以及如何搭建

Spring Ai 如何配置以及如何搭建 解释什么是Spring ai 首先&#xff0c;我们用Spring ai 其实不是去了解他的LLM,以及底层用的一些东西&#xff0c;Spring AI,提供给我们的其实是对各种大模型快速调用&#xff0c;提供了大模型API的作用&#xff0c;Spring AI 的核心定位是提…

FCC认证三星XR头显加速全球量产,微美全息AI+AR技术引领智能眼镜硬件创新

据悉&#xff0c;三星(SSNGY.US)XR头显Project Moohan目前已获得美国FCC认证&#xff0c;FCC认证表明该款头显即将上市&#xff0c;之前三星财报会议也表明确认将于今年年底推出XR头显。此前有报道称&#xff0c;该设备将采用索尼旗舰级 OLEDoS 显示屏&#xff0c;像素密度高达…

洛谷P1595讲解(加强版)+错排讲解

前言接我原先的文章&#xff0c;因为一场考试&#xff0c;让我对这道题记忆深刻注&#xff1a;&#xff08;因为那道题&#xff0c;所以80分&#xff09;正文1.分析题目题目&#xff1a;某人写了 n 封信和 n 个信封&#xff0c;如果所有的信都装错了信封。求所有信都装错信封共…

提升化工制造质量的 7 种方法

尽管化工制造属于制造业的一个子类别&#xff0c;但它是一个广泛的范畴&#xff0c;涵盖了基础化学品、树脂和合成纤维、农药和化肥、涂料和粘合剂&#xff0c;甚至消费类化合物&#xff08;如肥皂和清洁化学品&#xff09;等所有领域。尽管这些细分领域差异巨大&#xff0c;但…

从“数据垄断”到“全民共建”:Dataparts如何重构智能时代的数据流通规则?

从“数据垄断”到“全民共建”&#xff1a;Dataparts如何重构智能时代的数据流通规则&#xff1f;在杭州某科技园区的会议室里&#xff0c;一场关于“AI大模型训练数据”的讨论正在激烈进行。某头部AI企业的技术总监指着屏幕上的“对话场景零件库”说&#xff1a;“过去我们花3…

31 HTB Union 机器 - 中等难度

第一阶段 侦查nmap扫描oxdfparrot$ nmap -p- --min-rate 10000 -oA scans/nmap-alltcp 10.10.11.128 Starting Nmap 7.80 ( https://nmap.org ) at 2021-11-19 08:29 EST Nmap scan report for 10.10.11.128 Host is up (0.092s latency). Not shown: 65534 filtered ports POR…

【数据分享】上市公司创新韧性数据(2007-2023)

数据介绍核心看点&#xff1a; 在复杂多变的市场环境中&#xff0c;企业如何通过创新维持竞争力&#xff1f;创新韧性是衡量企业在外部冲击下保持创新活力的关键指标。本文分享2007-2023年上市公司创新韧性数据&#xff0c;为研究企业抗风险能力提供核心支持。数据概览数据名称…