news 2026/6/11 9:23:39

SPI通信协议深度解析:从寄存器操作到实战避坑指南

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
SPI通信协议深度解析:从寄存器操作到实战避坑指南

1. SPI通信协议核心原理与架构解析

SPI,全称Serial Peripheral Interface,即串行外设接口,是嵌入式系统领域应用最广泛的同步串行通信协议之一。它不像UART那样需要复杂的波特率协商,也不像I2C那样需要地址寻址,其核心魅力在于“简单粗暴”的高效。简单来说,你可以把它想象成一个高速的“旋转木马”:主设备(Master)控制着旋转的节奏(时钟SCK),数据像木马上的乘客一样,在主设备和从设备(Slave)之间同步、双向地交换。这种全双工、主从式的通信方式,使其在需要高速、实时数据交换的场景中,如Flash存储器读写、传感器数据采集、TFT屏幕驱动等,成为工程师的首选。

SPI的物理连接通常只需要四根线,但正是这四根线构成了其通信的骨架:

  • SCK (Serial Clock):串行时钟,由主设备产生,是所有数据收发的节拍器。
  • MOSI (Master Out Slave In):主设备输出,从设备输入,数据流出主设备的通道。
  • MISO (Master In Slave Out):主设备输入,从设备输出,数据流入主设备的通道。
  • SS/CS (Slave Select / Chip Select):从设备选择,低电平有效,主设备用它来“点名”要与哪个从设备对话。

其技术价值在于极低的协议开销和极高的数据传输效率。由于通信时序完全由硬件时钟同步,无需起始位、停止位或校验位,理论上时钟有多快,数据就能传多快。同时,其灵活的时钟相位(CPHA)和极性(CPOL)配置,使其能够适配市面上绝大多数SPI外设芯片的时序要求。接下来,我们将深入到寄存器层面,看看这些抽象的逻辑是如何在微控制器内部具体实现的。

1.1 SPI模块的核心:数据寄存器与状态机

要驾驭SPI,必须理解其核心——SPI数据寄存器(SPIDR)和与之联动的状态标志。很多初学者调不通SPI,问题往往就出在对这两个机制的理解不透彻上。

SPIDR:一个地址,双重身份在大多数MCU的SPI模块中,SPIDR是一个具有“双重人格”的寄存器。对程序员来说,你访问的是同一个内存地址(例如0x00040x0005,分别对应高8位和低8位,构成一个16位寄存器),但物理上,它背后连接着两个独立的缓冲区:发送数据寄存器接收数据寄存器

当你写入SPIDR时,数据实际上被放入了发送缓冲区。此时,如果发送器空闲(由SPTEF标志指示),数据会立即被加载到发送移位寄存器中,准备在SCK的驱动下,一位一位地从MOSI线移出。当你读取SPIDR时,你读取的是接收缓冲区里的内容,也就是最近一次从MISO线移入并组装好的完整数据。

这种“双缓冲”设计是SPI能够实现连续、高效传输的关键。它允许CPU在上一帧数据正在串行移位输出的同时,准备下一帧要发送的数据;同样,在上一帧数据还在移入的过程中,CPU可以读取之前已经接收完毕的数据。这就好比一个流水线,装填、加工、卸货可以同时进行,避免了等待。

SPIF与SPTEF:通信的“交通信号灯”如果说SPIDR是数据仓库,那么状态寄存器(SPISR)中的SPIF和SPTEF就是指挥交通的信号灯。

  • SPTEF (SPI Transmit Empty Flag):发送缓冲区空标志。当这个标志位被硬件置1时,就像一个绿灯,告诉你:“发送缓冲区空了,可以安全地写入下一字节数据了!” 如果你在SPTEF为0(缓冲区非空)时强行写入,可能会覆盖尚未发送的数据,导致通信错误。一个可靠的发送流程是:先查询SPTEF是否为1,如果是,则写入SPIDR;写入操作后,SPTEF通常会被硬件自动清零,直到数据从发送缓冲区转移到移位寄存器后再次置1。
  • SPIF (SPI Interrupt Flag):SPI传输完成中断标志。这是最重要的标志位。当一次完整的(例如8位或16位)数据帧从主设备移位到从设备,同时也从从设备移位回主设备后,硬件会将此标志置1。它宣告:“一次完整的双向数据交换已经完成,接收缓冲区里的数据已经就绪,可以读取了!”读取SPIF标志(通常通过读状态寄存器操作)并随后读取SPIDR数据,是清除SPIF标志的标准流程。

这里有一个极易出错的关键时序细节,也是手册中反复强调的:SPIF标志的清除与数据锁存。手册中的图13-9和图13-10清晰地展示了两种场景。简单来说,如果一次传输完成后,SPIF标志已经为1(表示数据A已在SPIDR中),而此时接收移位寄存器中又收到了新数据B,如果你没有及时读取数据A(即清除SPIF),那么数据B会暂存在移位寄存器中等待。如果你在第三帧数据传输开始之前清除了SPIF,数据B会被安全地锁存到SPIDR中。但如果你清除得太晚,在第三帧传输开始之后才操作,那么数据B就可能因为被新数据覆盖而丢失。因此,在中断服务程序或查询式程序中,及时响应并处理SPIF是保证数据不丢失的重中之重。

1.2 主从模式:角色与配置的本质区别

SPI通信严格区分主从角色,两者的行为和配置有本质不同,配置错误是导致通信失败的另一大常见原因。

主模式:主动的节奏控制者当SPI控制寄存器1(SPICR1)中的MSTR位被置1时,SPI模块进入主模式。此时:

  1. SCK引脚变为输出:主设备内部的可编程波特率发生器开始工作,产生时钟信号并驱动SCK线。
  2. MOSI引脚变为输出:主设备的数据由此发出。
  3. MISO引脚变为输入:用于接收从设备返回的数据。
  4. SS引脚功能可选
    • 如果配置为输出(通过MODFEN和SSOE位),它会在每次传输期间自动拉低以选中从设备,传输间隙拉高。这非常方便连接单个从设备。
    • 如果配置为输入(用于多主模式检测),则用于监测“模式错误”。当检测到另一个主设备试图驱动总线时,会触发MODF错误,强制本机转为从模式并释放总线,避免数据冲突。

从模式:被动的响应者当MSTR位为0时,模块处于从模式:

  1. SCK引脚变为输入:时钟完全由外部主设备提供,从设备必须严格遵循此时钟进行采样。
  2. MOSI引脚变为输入:接收来自主设备的数据。
  3. MISO引脚变为输出:但仅在SS引脚为低电平时才会被激活输出数据。当SS为高时,MISO引脚呈高阻态,这是实现多个从设备共享MISO线的关键。
  4. SS引脚是严格的输入:它是从设备的“使能”信号。在传输开始前,SS必须被主设备拉低,并保持低电平直至传输结束。如果在传输中SS意外变高,从设备会立即停止工作,进入空闲状态。

一个重要的配置禁忌:手册中特别用NOTE警告,在传输过程中(即SPIF未置起时),绝对不要更改CPOL、CPHA、MSTR等关键配置位。对于主设备,这会直接中止当前传输;对于从设备,这会破坏正在进行的传输,导致数据错误。所有配置都应在通信初始化阶段完成,并在通信过程中保持稳定。

2. 时钟相位与极性:破解时序兼容性的密码

SPI协议最灵活也最让人困惑的部分莫过于时钟相位(CPHA)和时钟极性(CPOL)的配置。这两位的组合,产生了四种不同的时钟模式(Mode 0-3),其目的是为了适配不同外设芯片对数据采样边沿的不同要求。

CPOL:时钟的空闲状态

  • CPOL = 0:SCK时钟线在空闲状态(即两次传输之间,SS为高时)为低电平
  • CPOL = 1:SCK时钟线在空闲状态为高电平。 CPOL本身不改变数据传输的边沿关系,它只是决定了时钟信号的初始基线。你可以把它看作决定了“旋转木马”在等待时是停在底部(低电平)还是顶部(高电平)。

CPHA:数据采样的时刻这才是决定数据稳定性的核心。

  • CPHA = 0:数据在第一个时钟边沿被采样。对于CPOL=0,第一个边沿是上升沿;对于CPOL=1,第一个边沿是下降沿。
  • CPHA = 1:数据在第二个时钟边沿被采样。对于CPOL=0,第二个边沿是下降沿;对于CPOL=1,第二个边沿是上升沿。

更直观的理解是看数据输出变化的时刻。在SPI中,数据总是在时钟的某个边沿发生变化,在另一个边沿被采样。一个通用的经验法则是:数据总是在采样边沿的相反边沿发生变化,以确保在采样时刻数据是稳定的。

模式选择实战指南通常,外设芯片的数据手册会明确要求SPI模式。例如,很多NOR Flash芯片使用Mode 0 (CPOL=0, CPHA=0) 或 Mode 3 (CPOL=1, CPHA=0)。你需要严格匹配主从设备的模式。

  • Mode 0 (CPOL=0, CPHA=0):时钟空闲低,数据在第一个上升沿采样。这是最常见的一种模式。在SS有效后,第一个数据位(MSB或LSB)会立即出现在MOSI/MISO线上,等待半个SCK周期后,第一个上升沿到来进行采样。
  • Mode 1 (CPOL=0, CPHA=1):时钟空闲低,数据在第二个下降沿采样。第一个上升沿用于从设备准备数据(输出到MISO),主设备在随后的下降沿采样。
  • Mode 2 (CPOL=1, CPHA=0):时钟空闲高,数据在第一个下降沿采样。
  • Mode 3 (CPOL=1, CPHA=1):时钟空闲高,数据在第二个上升沿采样。

如何配置?以S12系列MCU为例,通过设置SPICR1寄存器中的CPOL和CPHA位即可。务必记住,主设备和从设备的这两个配置必须完全一致,否则采样到的将全是乱码。

3. 寄存器级操作与通信流程实现

理解了原理,我们进入实战环节,看看如何通过操作S12系列MCU的SPI寄存器,完成一次完整的通信。这里我们以主模式、8位数据传输、Mode 0为例。

3.1 SPI模块初始化配置

在开始任何通信之前,必须对SPI模块进行正确的初始化。以下是一个典型的配置序列:

// 假设SPI基地址为 SPI0_BASE_PTR #define SPI0CR1 (*(volatile unsigned char*)(SPI0_BASE_PTR + 0x00)) #define SPI0CR2 (*(volatile unsigned char*)(SPI0_BASE_PTR + 0x01)) #define SPI0BR (*(volatile unsigned char*)(SPI0_BASE_PTR + 0x02)) #define SPI0SR (*(volatile unsigned char*)(SPI0_BASE_PTR + 0x03)) #define SPI0DR (*(volatile unsigned char*)(SPI0_BASE_PTR + 0x04)) // 8位访问低字节 void SPI_Master_Init(void) { // 1. 首先禁用SPI (SPE=0),以便安全配置其他寄存器 SPI0CR1 = 0x00; // 2. 配置波特率寄存器 (SPI0BR) // 假设总线时钟为25MHz,目标SPI时钟为1.25MHz // 波特率除数 = (SPPR+1) * 2^(SPR+1) // 设置 SPPR[2:0] = 001b (SPPR=1), SPR[2:0] = 100b (SPR=4) // 除数 = (1+1) * 2^(4+1) = 2 * 32 = 64 // 波特率 = 25MHz / 64 ≈ 390.625kHz (注意:与目标有差异,需根据手册表格13-7选择最接近值) // 查阅手册表13-7,为简化,我们选择SPPR=0, SPR=4, 除数=2^(4+1)=32, 波特率=25MHz/32=781.25kHz SPI0BR = 0x04; // SPR2=0, SPR1=0, SPR0=0, SPPR2=0, SPPR1=0, SPPR0=0? 不对。 // 正确配置:SPPR[2:0]为预分频位,SPR[2:0]为主分频位。寄存器位定义需查手册。 // 假设位定义如下:Bit7:SPPR2, Bit6:SPPR1, Bit5:SPPR0, Bit2:SPR2, Bit1:SPR1, Bit0:SPR0 // 设置SPPR=0 (000b), SPR=4 (100b) -> SPI0BR = 0b00000 100 = 0x04 SPI0BR = 0x04; // 生成781.25kHz时钟 // 3. 配置控制寄存器2 (SPI0CR2) SPI0CR2 = 0x00; // 默认值:双向模式禁用,模式错误使能,等待模式停止SPI, 8位传输 // 4. 配置控制寄存器1 (SPI0CR1) - 核心配置 // Bit7: SPIE=0 (先禁用中断,采用查询方式) // Bit6: SPE=1 (使能SPI模块) // Bit5: SPTIE=0 (发送中断禁用) // Bit4: MSTR=1 (主模式) // Bit3: CPOL=0 (时钟极性,低电平空闲) // Bit2: CPHA=0 (时钟相位,第一个边沿采样) // Bit1: SSOE=1 (SS引脚作为输出,自动管理) // Bit0: LSBFE=0 (MSB先传输) SPI0CR1 = 0x5C; // 二进制 0101 1100 // 初始化完成,SPI模块已使能,SS输出引脚自动变为高电平(空闲) }

注意:波特率的计算需要仔细对照数据手册中的表格和公式。错误的波特率设置可能导致通信不稳定或完全失败。上述代码中的位赋值仅为示例,实际开发中必须根据你所使用的具体MCU型号的参考手册中的寄存器位定义进行精确配置。

3.2 查询式数据收发流程

初始化完成后,就可以进行数据收发了。查询方式是最基础、最可靠的方法。

unsigned char SPI_Master_TransmitByte(unsigned char txData) { unsigned char rxData = 0; // 1. 等待发送缓冲区为空 (SPTEF == 1) while(!(SPI0SR & 0x20)); // 假设SPTEF是状态寄存器的Bit5 // 2. 将待发送数据写入SPI数据寄存器,启动传输 SPI0DR = txData; // 3. 等待接收完成 (SPIF == 1) while(!(SPI0SR & 0x80)); // 假设SPIF是状态寄存器的Bit7 // 4. 读取状态寄存器(清除SPIF标志),然后读取接收到的数据 rxData = SPI0DR; // 读SPI0DR会清除SPIF标志 return rxData; }

这段代码的每一个等待循环都至关重要。第一个循环确保不会覆盖尚未送出的数据;第二个循环确保我们读取的是本次交换完成的、稳定的数据。SPI0DR的读取操作一举两得:既获取了数据,也完成了清除SPIF标志的硬件序列。

3.3 中断驱动实现

对于需要高效率或非阻塞通信的场景,中断方式是更好的选择。你需要配置中断服务程序(ISR)。

volatile unsigned char spiTxBuffer[32]; volatile unsigned char spiRxBuffer[32]; volatile unsigned char spiTxIndex = 0; volatile unsigned char spiRxIndex = 0; volatile unsigned char spiTransferCount = 0; void SPI_IRQ_Handler(void) { unsigned char status = SPI0SR; // 1. 处理发送中断 (SPTEF) if(status & 0x20) { // SPTEF标志置位 if(spiTxIndex < spiTransferCount) { SPI0DR = spiTxBuffer[spiTxIndex++]; // 填充下一个数据,自动清除SPTEF } else { // 所有数据已发送完毕,可在此禁用发送中断或进行其他标记 // SPI0CR1 &= ~0x20; // 例如,清除SPTIE位禁用发送中断 } } // 2. 处理接收完成中断 (SPIF) if(status & 0x80) { // SPIF标志置位 spiRxBuffer[spiRxIndex++] = SPI0DR; // 读取数据,自动清除SPIF // 检查是否接收完成 if(spiRxIndex >= spiTransferCount) { // 完成接收,通知主程序或进行后续处理 } } // 3. 处理模式错误中断 (MODF) - 错误处理 if(status & 0x40) { // 假设MODF是Bit6 // 读状态寄存器 // 写控制寄存器1以清除MODF标志(根据手册要求) SPI0CR1 = SPI0CR1; // 进行错误恢复,例如重新初始化SPI SPI_Master_Init(); } } // 主程序中启动一次中断驱动的传输 void Start_SPI_Transfer(unsigned char *txData, unsigned char *rxBuffer, unsigned char length) { // 复制数据到发送缓冲区 for(unsigned char i=0; i<length; i++) { spiTxBuffer[i] = txData[i]; } spiTxIndex = 0; spiRxIndex = 0; spiTransferCount = length; // 使能SPI发送中断和接收中断 SPI0CR1 |= 0xA0; // 设置SPIE和SPTIE位 // 手动触发第一次发送:如果发送缓冲区为空,直接写入第一个数据启动传输 if(SPI0SR & 0x20) { SPI0DR = spiTxBuffer[spiTxIndex++]; } }

在中断服务程序中,处理多个中断标志的顺序很重要。通常先处理发送(SPTEF),再处理接收(SPIF),因为填充发送数据可以驱动下一次传输。同时,必须处理MODF错误,否则在多主环境或SS配置错误时,系统可能挂起。

4. 高级功能与实战避坑指南

掌握了基本操作后,一些高级功能和细节决定了项目的稳定性和可靠性。

4.1 双向模式与引脚复用

当系统引脚资源紧张时,SPI的双向模式(Bidirectional Mode)非常有用。通过设置SPICR2寄存器的SPC0位,可以将全双工的四线模式变为半双工的两线模式。

  • 主模式下:MOSI引脚变为MOMI(主输入输出)引脚,MISO引脚不再被SPI模块使用,可释放为通用IO。
  • 从模式下:MISO引脚变为SISO(从输入输出)引脚,MOSI引脚被释放。

此时,数据方向由BIDIROE位控制。需要特别注意:在双向模式下,一次只能在一个方向上传输数据,你需要通过软件控制BIDIROE位来切换方向,这增加了协议的复杂性。除非引脚真的不够用,否则建议优先使用标准的四线全双工模式。

4.2 低功耗模式下的SPI行为

在电池供电的设备中,低功耗设计是关键。SPI模块在MCU进入等待(Wait)或停止(Stop)模式时的行为需要特别关注。

  • 等待模式(Wait):由SPICR2中的SPISWAI位控制。
    • SPISWAI = 0:CPU进入等待模式,SPI模块继续正常运行。适用于从设备需要持续与主设备通信的场景。
    • SPISWAI = 1:CPU进入等待模式,SPI时钟停止,模块进入低功耗状态。对于从设备,这是一个危险配置!如果主设备在此期间继续发送时钟和数据,从设备的移位寄存器会继续工作,但接收完成中断(SPIF)不会产生,数据也不会从移位寄存器复制到SPIDR。直到退出等待模式,可能会发生数据覆盖或丢失。手册明确警告,从设备在等待或停止模式下,正在接收移位寄存器中的数据会丢失。
  • 停止模式(Stop):模块时钟关闭,SPI完全冻结。从设备需依赖外部主设备在唤醒后重新同步。

避坑建议:对于从设备,如果预期主设备会持续通信,应避免在通信期间进入会使SPI核心关闭的低功耗模式,或者设计好唤醒后的同步与错误恢复机制。

4.3 多从设备连接与SS管理

SPI总线可以挂载多个从设备,通常有两种连接方式:

  1. 独立片选(CS):每个从设备使用主设备一个独立的GPIO作为片选。这是最推荐的方式,软件控制简单,各个从设备完全独立。
  2. 菊花链(Daisy-Chain):所有从设备的MISO和MOSI依次串联,共用一套SCK和SS。数据像通过一个长的移位寄存器一样依次通过所有设备。这种方式节省GPIO,但软件协议复杂,且所有设备必须支持这种模式。

关于SS输出的一个关键点:当主设备配置了SS输出(SSOE=1, MODFEN=1)时,其SS引脚会在每次传输时自动产生低电平脉冲。这非常方便连接单个从设备。但绝对不能用这个自动产生的SS信号去同时控制多个从设备!因为所有从设备会在同一时间被选中,它们的MISO输出会发生冲突。连接多个从设备时,必须使用独立的GPIO手动控制每个从设备的SS引脚。

4.4 常见问题排查速查表

在实际调试中,SPI通信失败的现象五花八门。下面这个表格整理了最常见的问题、可能的原因及排查步骤,你可以像查字典一样快速定位问题。

现象可能原因排查步骤
完全无数据/无波形1. SPI模块未使能(SPE=0)
2. 主模式下SS配置错误(如配置为输入且被拉低)
3. 引脚复用功能未正确映射到SPI
4. 时钟源或波特率配置错误,导致SCK频率为0或极高
1. 检查SPICR1的SPE位是否为1。
2. 用示波器或逻辑分析仪检查SCK、MOSI、SS引脚是否有信号。检查SS引脚配置,若为输入且被意外拉低,主设备会因模式错误转为从模式。
3. 确认MCU的引脚控制寄存器,将相关引脚功能设置为SPI而非GPIO。
4. 检查波特率寄存器计算值,用示波器测量实际SCK频率是否符合预期。
主设备能发送,但从设备无响应/主设备收不到数据1. 主从设备时钟模式(CPOL/CPHA)不匹配
2. 从设备SS引脚未正确拉低或时序不对
3. 从设备MISO引脚未使能输出(SS为高时高阻)
4. 硬件连接错误(如MOSI与MISO接反)
1.这是最常见原因!双盲测试:用逻辑分析仪同时抓取主设备的MOSI和从设备的MISO。如果主设备发送的数据波形正确,但从设备MISO无输出,问题大概率在从设备配置或SS。如果从设备有输出但主设备采样不对,则是时钟模式问题。
2. 测量从设备SS引脚,确保在传输全程保持低电平,且满足手册要求的最小建立时间。
3. 确认从设备在SS有效时,其MISO引脚驱动能力正常。
4. 仔细核对原理图,确保MOSI接MOSI,MISO接MISO。
数据错位(如字节反了)数据传输位序(LSBFE)配置错误检查主从设备的LSBFE(或类似)配置位。大多数设备是MSB先行,但有些传感器可能是LSB先行。必须保持一致。
通信一段时间后出错/卡死1. 状态标志处理不当,导致数据覆盖或丢失(尤其是SPIF)
2. 中断服务程序中未清除中断标志
3. 在传输过程中修改了配置寄存器
4. 缓冲区溢出(在高速或连续传输时)
1. 严格遵循“等SPTEF再写,等SPIF再读”的流程。在中断服务中,确保读取SPIDR以清除SPIF。
2. 确认中断标志的清除方式(是读状态寄存器还是读数据寄存器)。
3.绝对禁止在通信中更改CPOL、CPHA、MSTR等位。
4. 提高CPU处理优先级,或使用DMA进行SPI数据传输。
多从设备系统中,某个设备干扰总线未被选中的从设备MISO未进入高阻态确保所有SPI从设备的MISO引脚在不被选中(SS为高)时处于高阻态。检查从设备芯片的使能逻辑。可以在MISO总线上加弱上拉电阻。

调试SPI,逻辑分析仪是你的最佳伙伴。它能同时捕获SCK、MOSI、MISO、SS四路信号,直观地展示时钟边沿与数据位的对应关系,一眼就能看出时钟模式是否正确、数据是否对齐、SS时序是否合规。不要只依赖打印调试信息。

最后,分享一个我调试高速SPI Flash时的深刻教训:当时为了追求极限速度,将SPI时钟设到了系统时钟的二分频。结果发现写入的数据偶尔会出错。用逻辑分析仪抓取波形后发现,在连续写入长数据时,SCK波形在后期出现了轻微的畸变。原因是长走线、高频率下的信号完整性出了问题。解决方案:一是降低波特率;二是在SCK和MOSI线上串联一个小电阻(如22欧姆)以减小振铃;三是优化PCB布局,缩短SPI走线长度。嵌入式开发中,软件配置的尽头是硬件特性,永远不要忽视物理世界的约束。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/6/11 9:23:26

如何彻底销毁硬盘数据:DBAN数据擦除工具终极指南

如何彻底销毁硬盘数据&#xff1a;DBAN数据擦除工具终极指南 【免费下载链接】dban Unofficial fork of DBAN. 项目地址: https://gitcode.com/gh_mirrors/db/dban 还在担心旧电脑硬盘中的敏感数据泄露吗&#xff1f;DBAN&#xff08;Dariks Boot and Nuke&#xff09;是…

作者头像 李华
网站建设 2026/6/11 9:23:25

通用jsonResult封装返回结果(boolean方法也可以通过这个返回的)

文章目录JsonResult类的代码JsonResult类的代码-简版(不要errorCode)(推荐)io流中的jsonResult工具类成功成功的情况下如何封装失败失败的情况下的封装(手动封装)失败情况下的code&#xff0c;message半自动封装失败情况下抛异常让全局异常处理器处理如何判定成功和失败(succes…

作者头像 李华
网站建设 2026/6/11 9:23:18

Java数组中查找元素的方法

Java数组中查找元素的方法 要恰饭的嘛~ 2020-08-15 20:43:51 29 收藏 分类专栏&#xff1a; Java 文章标签&#xff1a; java索引数据结构 版权 Arrays类的binarySearch()方法&#xff0c;可以使用二分搜索法来搜索指定的数组。该方法返回要搜索元素的索引值。binarySearc…

作者头像 李华
网站建设 2026/6/11 9:23:14

那些年,我们写过的低级BUG,警钟长鸣

又一个低级的生产BUG if(newDto.getStoreName().equals(oldDto.getStoreName()) &&newDto.getStoreCode().equals(oldDto.getStoreCode()) &&newDto.getGoodsName().equals(oldDto.getGoodsName()) &&newDto.getGoodsSpec().equals(oldDto.getGoodsSpe…

作者头像 李华
网站建设 2026/6/11 9:23:12

Koikatu HF Patch终极指南:200+插件与完整翻译体验一键解锁

Koikatu HF Patch终极指南&#xff1a;200插件与完整翻译体验一键解锁 【免费下载链接】KK-HF_Patch Automatically translate, uncensor and update Koikatu! and Koikatsu Party! 项目地址: https://gitcode.com/gh_mirrors/kk/KK-HF_Patch 还在为《恋活&#xff01;》…

作者头像 李华
网站建设 2026/6/11 9:23:09

MC9S08JS16嵌入式开发实战:从USB集成到低功耗设计

1. 项目概述与芯片定位在嵌入式开发领域&#xff0c;选型往往是项目成功的第一步。面对市场上琳琅满目的微控制器&#xff0c;工程师们常常需要在性能、成本、功耗和集成度之间寻找最佳平衡点。对于许多需要USB连接、成本敏感且对实时性有一定要求的应用——比如自定义的HID设备…

作者头像 李华