STM32驱动W25Q64 SPI Flash实战:从硬件连接到代码实现

1. 项目缘起与整体设计思路

1.1 为什么选 SPI Flash 作为存储方案

做过嵌入式项目的人大概都有这种体会:MCU 自带的 Flash 空间永远不够用。以 STM32F103C8T6 为例,64KB 的 Flash 里塞完协议栈、驱动和业务逻辑,能留给数据存储的空间往往只剩几 KB。一旦需要记录日志、保存配置参数、缓存传感器数据,或者做字库、图片素材的存储,片内 Flash 就捉襟见肘了。

这时候外挂一颗 SPI Flash 是最经济实惠的选择。W25Q64 这颗芯片在圈子里几乎是“标配”级别的存在——8MB 容量(64Mbit)、SPI 接口、SOP8 封装、单价便宜、货源充足,随便一个电子市场或者网购平台都能买到。它支持标准 SPI、Dual SPI 和 Quad SPI 三种模式,标准 SPI 下最高时钟能跑到 80MHz(STM32F103 的 SPI1 最高 36MHz,SPI2 最高 18MHz,所以实际跑不到那么高),对于绝大多数中小规模的数据存储需求完全够用。

我这次做的项目是一个数据采集终端,需要每隔几秒记录一次传感器读数,同时保存设备配置参数和一段开机提示音音频数据。片内 Flash 显然扛不住这种持续写入,所以选了 W25Q64 作为外部存储。整个方案的核心就是:STM32F103 通过 SPI 接口驱动 W25Q64,实现扇区擦除、页写入、数据读取、状态轮询等完整操作。

1.2 硬件连接与引脚规划

先看硬件接线。W25Q64 是 SOP8 封装,8 个引脚各有分工:

引脚编号名称功能说明STM32 连接
1CS片选,低电平有效PA4(软件控制)
2DO(IO1)数据输出(MISO)PA6(SPI1_MISO)
3WP(IO2)写保护,低有效接 3.3V(禁用保护)
4GND地GND
5DI(IO0)数据输入(MOSI)PA7(SPI1_MOSI)
6CLK时钟PA5(SPI1_SCK)
7HOLD(IO3)保持,低有效接 3.3V(禁用保持)
8VCC电源3.3V

这里有几个细节值得展开说。WP 和 HOLD 引脚我直接拉高禁用了,因为项目里不需要硬件写保护和暂停传输功能,拉高是最省事的做法。如果你要做数据安全要求高的场景,WP 可以接到 MCU 的 GPIO 上,通过软件控制写保护状态。CS 片选我用的是 PA4 普通 GPIO 而不是 SPI 硬件 NSS,原因是硬件 NSS 在多从机场景下管理起来很麻烦,软件控制更灵活,想什么时候拉低就什么时候拉低。

SPI1 挂在 APB2 总线上,时钟源是 72MHz。配置分频系数为 4,得到 18MHz 的 SPI 时钟。为什么不分频到 36MHz?因为 W25Q64 虽然标称支持 80MHz,但实际布线如果走线较长或者没有做好阻抗匹配,高速下容易出错。18MHz 是个稳妥的选择,实测下来读写都很稳定,速度也够用。

1.3 软件架构分层设计

软件层面我分了三层:底层 SPI 驱动、W25Q64 驱动、应用层接口。

底层 SPI 驱动负责初始化 SPI1 外设、配置 GPIO、实现字节收发函数。这一层跟具体 Flash 芯片无关,换成其他 SPI 设备也能复用。

W25Q64 驱动层封装了芯片的所有操作指令,包括读 ID、写使能、扇区擦除、页写入、数据读取、状态寄存器读取等。每个操作都对应 W25Q64 的一条指令码,比如 0x03 是读数据、0x02 是页写入、0x20 是扇区擦除。这一层向上提供简洁的函数接口,应用层不需要关心底层时序细节。

应用层就是具体的业务逻辑了,比如“保存配置参数到 Flash 地址 0x000000”、“从 Flash 地址 0x001000 读取 100 字节数据”这种调用。

这样分层的好处是:换 MCU 平台时只需要改底层 SPI 驱动,换 Flash 型号时只需要改驱动层,应用层代码基本不动。我在另一个项目里把 MCU 从 STM32F103 换到 GD32F103,底层 SPI 驱动改了几行寄存器配置就搞定了,上层完全没动。

2. W25Q64 核心机制与关键细节解析

2.1 存储结构与地址映射

W25Q64 的 8MB 空间不是随便写的,它有一套严格的层级结构:

  • 页(Page):256 字节,这是写入操作的最小单位。一次页写入最多写 256 字节,超过这个范围会“回卷”到页首覆盖之前的数据。
  • 扇区(Sector):4KB,由 16 个页组成。这是擦除操作的最小单位。Flash 的特性是只能把 1 写成 0,不能把 0 写成 1,所以写入前必须先擦除,擦除后整个扇区变成 0xFF。
  • 块(Block):64KB,由 16 个扇区组成。块擦除指令一次擦 64KB,适合大批量数据清除。
  • 整片(Chip):8MB,整片擦除指令会把所有数据清空,耗时较长(典型值 20 秒左右)。

地址范围从 0x000000 到 0x7FFFFF,共 8M 字节。计算方式很简单:扇区号 × 4096 = 扇区起始地址。比如第 3 个扇区的起始地址是 3 × 4096 = 12288 = 0x3000。

这里有个容易踩的坑:很多人以为可以像 RAM 一样随意写任意地址,结果发现写进去的数据不对。原因就是没有先擦除。Flash 的写入操作只能把 bit 从 1 变 0,如果目标地址之前写过数据(有些 bit 已经是 0),直接写入会导致数据错误。所以任何写入操作之前,必须确保目标区域已经被擦除。

2.2 SPI 通信时序与模式选择

W25Q64 支持 SPI 模式 0(CPOL=0,CPHA=0)和模式 3(CPOL=1,CPHA=1)。这两种模式的区别在于时钟空闲电平和采样边沿:

  • 模式 0:时钟空闲为低电平,数据在上升沿采样,下降沿变化。
  • 模式 3:时钟空闲为高电平,数据在下降沿采样,上升沿变化。

我选的是模式 0,这也是最常用的配置。STM32 的 SPI_CR1 寄存器中,CPOL 位设为 0,CPHA 位设为 0,就是模式 0。

数据传输的基本流程是:拉低 CS → 发送指令码 → 发送地址(如果需要)→ 发送/接收数据 → 拉高 CS。注意 CS 必须在整个传输过程中保持低电平,如果在传输中途拉高,W25Q64 会认为本次操作结束,后续数据全部丢弃。

SPI 的时钟频率设置也有讲究。W25Q64 的数据手册标明,标准读指令(0x03)最高支持 50MHz,快速读指令(0x0B)最高支持 80MHz。但实际使用中要考虑 PCB 走线质量。我一般建议初次调试时先用低速(比如 4.5MHz,分频系数 16),确认通信正常后再逐步提高频率。如果高速下出现数据错误,优先检查走线是否过长、是否有干扰源。

2.3 状态寄存器与忙判断

W25Q64 内部有一个状态寄存器(Status Register),其中 bit0 是 BUSY 位。当芯片正在执行擦除或写入操作时,BUSY 位为 1;操作完成后自动变为 0。

这个机制非常重要。因为擦除和写入不是瞬间完成的——扇区擦除典型耗时 45ms,最大 400ms;页写入典型耗时 0.7ms,最大 3ms。如果在 BUSY 期间发送新指令,芯片会忽略该指令,导致操作失败。

所以每次擦除或写入之后,必须轮询状态寄存器直到 BUSY 位清零,才能进行下一步操作。轮询的方式是发送 0x05 指令读取状态寄存器,判断 bit0 是否为 0。

void W25Q64_WaitBusy(void) { uint8_t status; do { W25Q64_CS_Low(); SPI_ReadWriteByte(0x05); // 读状态寄存器指令 status = SPI_ReadWriteByte(0xFF); W25Q64_CS_High(); } while (status & 0x01); // bit0 为 1 表示忙 }

这段代码看起来简单,但有个细节:每次读取状态都要重新拉低 CS 再拉高,不能在一次 CS 低电平期间连续读。因为 W25Q64 的指令解析是以 CS 下降沿为起点的,连续读需要重新发起指令。

3. 完整实操流程与代码实现

3.1 SPI 底层驱动初始化

先配置 GPIO 和 SPI1 外设。PA5(SCK)、PA7(MOSI)配置为复用推挽输出,PA6(MISO)配置为浮空输入,PA4(CS)配置为通用推挽输出。

void SPI1_Init(void) { GPIO_InitTypeDef GPIO_InitStructure; SPI_InitTypeDef SPI_InitStructure; RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_SPI1, ENABLE); // SCK PA5, MOSI PA7 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5 | GPIO_Pin_7; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOA, &GPIO_InitStructure); // MISO PA6 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; GPIO_Init(GPIOA, &GPIO_InitStructure); // CS PA4 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; GPIO_Init(GPIOA, &GPIO_InitStructure); GPIO_SetBits(GPIOA, GPIO_Pin_4); // CS 默认拉高 SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex; SPI_InitStructure.SPI_Mode = SPI_Mode_Master; SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b; SPI_InitStructure.SPI_CPOL = SPI_CPOL_Low; SPI_InitStructure.SPI_CPHA = SPI_CPHA_1Edge; SPI_InitStructure.SPI_NSS = SPI_NSS_Soft; SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_4; // 18MHz SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB; SPI_InitStructure.SPI_CRCPolynomial = 7; SPI_Init(SPI1, &SPI_InitStructure); SPI_Cmd(SPI1, ENABLE); }

字节收发函数是底层核心,用查询方式实现:

uint8_t SPI_ReadWriteByte(uint8_t txData) { uint8_t retry = 0; while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) == RESET) { retry++; if (retry > 200) return 0; } SPI_I2S_SendData(SPI1, txData); retry = 0; while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_RXNE) == RESET) { retry++; if (retry > 200) return 0; } return SPI_I2S_ReceiveData(SPI1); }

这里的 retry 超时机制是必要的。如果 SPI 外设配置有误或者硬件连接有问题,没有超时的话程序会死循环卡在这里。我调试时就遇到过 MISO 虚焊导致 RXNE 永远不置位的情况,加了超时后至少能返回错误值,方便定位问题。

3.2 读取芯片 ID 验证通信

上电后第一件事是读芯片 ID,确认通信正常。W25Q64 的 JEDEC ID 是 0xEF4017(厂商 ID 0xEF,设备 ID 0x4017)。

uint32_t W25Q64_ReadID(void) { uint32_t id = 0; W25Q64_CS_Low(); SPI_ReadWriteByte(0x9F); // 读 JEDEC ID 指令 id |= SPI_ReadWriteByte(0xFF) << 16; id |= SPI_ReadWriteByte(0xFF) << 8; id |= SPI_ReadWriteByte(0xFF); W25Q64_CS_High(); return id; }

如果读回来是 0xFFFFFF 或者 0x000000,说明通信有问题。0xFFFFFF 通常是 MISO 一直高电平(没接或虚焊),0x000000 通常是 MISO 一直低电平(短路或 CS 没拉低)。正常应该读到 0xEF4017。

3.3 扇区擦除操作

擦除是写入的前提。以扇区擦除(4KB)为例:

void W25Q64_SectorErase(uint32_t addr) { W25Q64_WriteEnable(); // 写使能 W25Q64_WaitBusy(); W25Q64_CS_Low(); SPI_ReadWriteByte(0x20); // 扇区擦除指令 SPI_ReadWriteByte((addr >> 16) & 0xFF); SPI_ReadWriteByte((addr >> 8) & 0xFF); SPI_ReadWriteByte(addr & 0xFF); W25Q64_CS_High(); W25Q64_WaitBusy(); // 等待擦除完成 }

写使能指令(0x06)是必须的。W25Q64 在执行任何擦除或写入操作前,都要求先发送写使能指令,否则操作会被忽略。这是芯片的安全机制,防止误操作。写使能状态在每次擦除/写入完成后自动清除,所以每次操作前都要重新发送。

3.4 页写入与数据读取

页写入一次最多 256 字节,且不能跨页。如果写入地址是 0x0000F0,写 200 字节,那么前 16 字节写到页 0 的末尾,剩下 184 字节会回卷到页 0 的开头覆盖之前的数据。所以写入前要计算好地址和长度。

void W25Q64_PageWrite(uint32_t addr, uint8_t *buf, uint16_t len) { if (len > 256) len = 256; // 限制单次最多 256 字节 W25Q64_WriteEnable(); W25Q64_WaitBusy(); W25Q64_CS_Low(); SPI_ReadWriteByte(0x02); // 页写入指令 SPI_ReadWriteByte((addr >> 16) & 0xFF); SPI_ReadWriteByte((addr >> 8) & 0xFF); SPI_ReadWriteByte(addr & 0xFF); for (uint16_t i = 0; i < len; i++) { SPI_ReadWriteByte(buf[i]); } W25Q64_CS_High(); W25Q64_WaitBusy(); }

读取就简单多了,不需要写使能,也不需要等待忙状态:

void W25Q64_ReadData(uint32_t addr, uint8_t *buf, uint32_t len) { W25Q64_CS_Low(); SPI_ReadWriteByte(0x03); // 读数据指令 SPI_ReadWriteByte((addr >> 16) & 0xFF); SPI_ReadWriteByte((addr >> 8) & 0xFF); SPI_ReadWriteByte(addr & 0xFF); for (uint32_t i = 0; i < len; i++) { buf[i] = SPI_ReadWriteByte(0xFF); } W25Q64_CS_High(); }

读数据指令支持连续读取,地址会自动递增,可以一次读任意长度(只要不超过芯片容量)。这是 W25Q64 很方便的一个特性,读大块数据时不需要分段。

3.5 跨页写入的封装处理

实际应用中经常需要写入超过 256 字节的数据,比如保存一个 1KB 的配置结构体。这时候需要封装一个跨页写入函数:

void W25Q64_BufferWrite(uint32_t addr, uint8_t *buf, uint32_t len) { uint16_t pageRemain = 256 - (addr % 256); // 当前页剩余空间 if (len <= pageRemain) { W25Q64_PageWrite(addr, buf, len); } else { W25Q64_PageWrite(addr, buf, pageRemain); W25Q64_BufferWrite(addr + pageRemain, buf + pageRemain, len - pageRemain); } }

这个递归写法很简洁,逻辑是:先写满当前页剩余空间,然后递归处理剩余数据。注意调用这个函数之前,目标区域必须已经擦除过。

4. 常见问题排查与避坑经验

4.1 读写失败的典型原因

调试 W25Q64 时遇到的问题五花八门,我整理了一个速查表:

现象可能原因排查方法
读 ID 返回 0xFFFFFFMISO 未连接或虚焊万用表测 PA6 到 W25Q64 引脚 2 的通断
读 ID 返回 0x000000CS 未拉低或 MISO 短路检查 PA4 电平,检查 MISO 是否对地短路
写入后读回数据不对未擦除就写入确认写入前执行了扇区擦除
擦除后读回全 0x00擦除指令未生效检查写使能指令是否发送成功
高速下数据偶发错误SPI 时钟过快或走线干扰降低分频系数,检查走线长度
写入操作被忽略BUSY 期间发送指令确保每次操作后轮询状态寄存器

4.2 写使能遗漏的隐蔽问题

写使能遗漏是最难排查的问题之一,因为它的表现是“有时候能写,有时候不能写”。原因是写使能状态在每次擦除/写入后自动清除,如果代码里只在初始化时发送了一次写使能,后续操作就会随机失败。

我的做法是把写使能封装成独立函数,在每次擦除和写入前都调用一次。虽然多了一次 SPI 传输,但可靠性大大提升。这点开销相对于擦除的几十毫秒来说完全可以忽略。

4.3 电源噪声导致的数据损坏

W25Q64 在擦除和写入时电流会有较大波动,如果电源滤波不好,可能导致操作失败甚至数据损坏。我在 PCB 上靠近 W25Q64 的 VCC 引脚放了一个 100nF 陶瓷电容和一个 10uF 钽电容,问题就解决了。

另外,如果系统中有大功率器件(比如电机、继电器)和 Flash 共用电源,建议给 Flash 单独加一个 LDO 或者用磁珠隔离。我有个项目里 Flash 和电机共用 3.3V,电机启动时 Flash 写入必失败,后来加了磁珠和电容才稳定。

4.4 数据掉电保护的实用技巧

Flash 写入过程中如果掉电,可能导致数据损坏。对于关键配置参数,我通常采用“双备份 + 校验”的策略:在 Flash 里分配两个扇区,交替写入配置数据,每个扇区末尾加一个 CRC 校验值。读取时先读扇区 A,CRC 校验通过就用 A 的数据;不通过就读扇区 B,用 B 的数据。这样即使一个扇区在写入时掉电损坏,另一个扇区仍然可用。

这个策略的代价是占用双倍空间和写入时间,但对于配置参数这种不常写、但丢了很麻烦的数据来说,完全值得。

4.5 SPI 时钟相位配置错误的排查

如果 SPI 模式配置错误(CPOL/CPHA 不匹配),表现是读 ID 返回乱码或者固定值。排查方法是先用示波器看 SCK 和 MOSI 的波形,确认时钟空闲电平和数据变化边沿是否符合预期。没有示波器的话,可以尝试四种模式组合,看哪种能读到正确的 ID。

我个人的经验是:W25Q64 用模式 0 和模式 3 都能正常工作,但模式 0 更常见。如果模式 0 不行,先检查硬件连接,而不是急着换模式。

5. 性能优化与进阶用法

5.1 提高读取速度的几种手段

标准读指令(0x03)在 18MHz 时钟下,理论最大读取速度是 18Mbps ÷ 8 = 2.25MB/s。实际因为指令和地址开销,有效速度会低一些。如果觉得不够快,有几个优化方向:

第一,提高 SPI 时钟。STM32F103 的 SPI1 最高 36MHz,如果 PCB 走线质量好,可以试试分频系数 2。我实测在短走线(小于 5cm)的情况下,36MHz 读取稳定。

第二,使用快速读指令(0x0B)。这个指令支持更高的时钟频率(80MHz),但需要额外发送一个 dummy 字节。在 18MHz 下提升不明显,但在 36MHz 以上会有帮助。

第三,使用 Dual SPI 模式。W25Q64 支持用两根数据线同时传输,理论速度翻倍。但 STM32F103 的 SPI 外设不支持 Dual 模式,需要软件模拟,实现起来比较复杂,一般项目用不上。

5.2 扇区管理与磨损均衡

Flash 的每个扇区都有擦写寿命限制,W25Q64 标称 10 万次擦写。如果频繁擦写同一个扇区,很快就会损坏。对于需要频繁记录数据的场景(比如日志),需要做磨损均衡。

最简单的磨损均衡是“轮询写入”:把多个扇区组成一个环,每次写入下一个扇区,写满一圈后擦除最早的扇区。这样每个扇区的擦写次数就被平均了。实现时需要一个指针记录当前写入位置,掉电后指针要能恢复,所以指针本身也要存在 Flash 里,并且要定期更新。

更复杂的方案是加入文件系统,比如 LittleFS 或 SPIFFS,它们内置了磨损均衡和掉电保护。如果项目允许引入文件系统,这是最省心的做法。

5.3 批量数据写入的优化

如果需要写入大量数据(比如几 MB 的音频文件),逐页写入效率很低,因为每次都要等待 BUSY 清零。优化方法是使用连续页写入模式:W25Q64 支持在一次 CS 低电平期间连续写入多个页,只要地址连续且不跨页边界。这样可以减少 CS 切换和状态轮询的开销。

不过要注意,连续页写入时如果中间某页写入失败,后面的数据也会受影响。所以对于关键数据,还是建议逐页写入并校验。

6. 项目总结与个人体会

这套 W25Q64 驱动我已经在三个项目里复用了,从数据采集终端到音频播放器,再到配置参数存储,表现都很稳定。整个方案的核心其实就三点:SPI 底层驱动要健壮(加超时、加错误处理)、擦除写入流程要严格(写使能、等忙、先擦后写)、应用层要做好掉电保护和磨损均衡。

踩过的坑也不少。最开始调试时读 ID 一直返回 0xFFFFFF,查了半天发现是 MISO 引脚虚焊;后来写入数据偶尔出错,发现是忘记在每次写入前发写使能;再后来长时间运行后数据丢失,发现是电源噪声导致擦除失败。这些问题在数据手册里都不会写,只有实际做过才会遇到。

如果你正准备用 W25Q64 做项目,我的建议是:先用低速 SPI 把读写擦除流程跑通,确认数据正确后再逐步提高时钟频率;每次擦除和写入后都轮询状态寄存器,不要偷懒用延时代替;关键数据一定要做备份和校验,Flash 掉电损坏的概率比你想象的高。

这个驱动后续还可以扩展的方向包括:接入 LittleFS 文件系统实现真正的文件管理、增加 Quad SPI 支持提升速度、实现后台擦除功能避免阻塞主循环。等我有空再折腾这些,到时候再写一篇分享。

相关新闻

如何用 Jasna 自动修复 VR180 视频:从分眼处理到投影选择的完整新手教程

如何用 Jasna 自动修复 VR180 视频:从分眼处理到投影选择的完整新手教程

如何用 Jasna 自动修复 VR180 视频&#xff1a;从分眼处理到投影选择的完整新手教程 【免费下载链接】jasna Video restoration tool 项目地址: https://gitcode.com/GitHub_Trending/ja/jasna Jasna 是一款面向 GPU 的视频修复工具&#xff0c;内置 VR180 自动修复能力…

2026/10/21 2:02:39 阅读更多 →
gamdl:Apple Music 无损下载工具完全指南,一键收藏歌曲与 4K 音乐视频

gamdl:Apple Music 无损下载工具完全指南,一键收藏歌曲与 4K 音乐视频

gamdl&#xff1a;Apple Music 无损下载工具完全指南&#xff0c;一键收藏歌曲与 4K 音乐视频 【免费下载链接】gamdl A command-line app for downloading Apple Music songs, music videos and post videos. 项目地址: https://gitcode.com/GitHub_Trending/ga/gamdl …

2026/10/21 2:02:39 阅读更多 →
Django数据可视化实践:超市销售系统全流程开发与热词分析

Django数据可视化实践:超市销售系统全流程开发与热词分析

毕业设计做到一半才意识到"选对题"比“写代码”重要得多——这是我在带几个应届生做完整套毕设流程后最深的体会。今天这篇想好好拆解一个很有代表性的题目&#xff1a;基于PythonDjango的超市销售系统&#xff0c;以及其中数据可视化模块的具体实现。这个选题好在哪…

2026/10/21 2:01:38 阅读更多 →

最新新闻

Quartz动态设置并发数量

Quartz动态设置并发数量

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/21 2:48:00 阅读更多 →
AI Agent ROI评估指南:从成本结构到收益测算全解析

AI Agent ROI评估指南:从成本结构到收益测算全解析

1. 先别急着算账&#xff0c;想清楚AI Agent的ROI和传统IT项目有什么不同这两年不少公司都开始折腾AI Agent&#xff0c;有的把它接到客服系统&#xff0c;有的让它帮着写代码&#xff0c;还有的用它处理合同和报表。但当你真坐下来算这笔账时&#xff0c;会发现一个尴尬的问题…

2026/10/21 2:48:00 阅读更多 →
基于卷积神经网络的食物图像识别实战:从ResNet迁移学习到部署

基于卷积神经网络的食物图像识别实战:从ResNet迁移学习到部署

简介&#xff1a;基于卷积神经网络的食物图像识别项目完整代码与数据包&#xff0c;面向具备Python基础并希望实践CNN图像分类的开发者与学习者。资源围绕TensorFlow与tf.keras构建食物识别模型&#xff0c;涵盖数据预处理、网络定义、训练评估与预测全流程&#xff0c;并引入迁…

2026/10/21 2:48:00 阅读更多 →
SECS-II/HSMS调试工具实战:从协议原理到模拟器应用

SECS-II/HSMS调试工具实战:从协议原理到模拟器应用

简介&#xff1a;面向半导体制造与MES系统集成场景&#xff0c;这份SECS-II HSMS调试工具模拟器适合设备工程师、上位机开发人员使用。它可模拟客户端与服务端&#xff0c;用于验证自定义程序是否符合SECS-II通信标准&#xff0c;减少现场联调时的错误与返工。压缩包为rar格式&…

2026/10/21 2:48:00 阅读更多 →
eNSP校园网拓扑设计实战:VLAN划分、DHCP配置与静态路由全解析

eNSP校园网拓扑设计实战:VLAN划分、DHCP配置与静态路由全解析

简介&#xff1a;面向计算机网络期末设计、课程设计及eNSP仿真练习的完整项目资料包&#xff0c;围绕某中学校园网络拓扑设计展开。方案包含网络拓扑选型、综合布线系统规划、教学楼/行政楼/宿舍接入设计&#xff0c;以及VLAN划分、IP地址分配、路由协议配置等模拟配置要点&…

2026/10/21 2:48:00 阅读更多 →
思科模拟器6.2:从安装到避坑的完整实战指南

思科模拟器6.2:从安装到避坑的完整实战指南

简介&#xff1a;这是一份思科模拟器6.2安装包&#xff0c;官方名称为Packet Tracer&#xff0c;面向网络技术学习者、思科认证考生以及开展网络实验教学的教师。软件以图形化方式搭建虚拟网络环境&#xff0c;可模拟路由器、交换机、无线接入点、防火墙等设备&#xff0c;支持…

2026/10/21 2:47:00 阅读更多 →

日新闻

统一内存+量化:锐龙AI Max PRO 400如何本地跑320B大模型

统一内存+量化:锐龙AI Max PRO 400如何本地跑320B大模型

这段时间硬件圈和AI圈都在传一个事&#xff1a;AMD锐龙AI Max PRO 400系列把最高192GB统一内存搬进了PC形态的产品里&#xff0c;按宣传口径&#xff0c;本地跑320B参数的大家伙不再是纸面概念。我第一反应倒不是“内存真大”&#xff0c;而是这话背后的含金量——它把过去只能…

2026/10/21 0:00:11 阅读更多 →
AI助手深度使用体验:对话质量、长文本处理与指令遵循如何留住用户

AI助手深度使用体验:对话质量、长文本处理与指令遵循如何留住用户

1. 从“封号重开”这个行为说起&#xff1a;用户到底在追求什么“封号重开”这四个字&#xff0c;放在任何产品语境里都带着一股决绝的味道。一个账号从零开始积累使用记录、调教偏好、沉淀工作流&#xff0c;背后是大量的时间和精力成本。正常情况下&#xff0c;没有人愿意主动…

2026/10/21 0:00:11 阅读更多 →
ROS中YOLOv3工程落地:通信同步、坐标变换与性能调优

ROS中YOLOv3工程落地:通信同步、坐标变换与性能调优

1. 为什么在ROS里硬刚YOLOv3不是“炫技”&#xff0c;而是工程落地的必经之路我第一次在某高校机器人实验室看到那台搭载Jetson TX2的移动底盘原地打转、反复识别错垃圾桶时&#xff0c;就意识到&#xff1a;单纯跑通darknet_ros demo和真正让YOLOv3在ROS里“干活”&#xff0c…

2026/10/21 0:00:11 阅读更多 →

周新闻

基于GMM的语音识别系统原理与MATLAB实现详解

基于GMM的语音识别系统原理与MATLAB实现详解

说到基于高斯混合模型&#xff08;GMM&#xff09;的语音识别系统&#xff0c;很多人第一反应就是一堆数学公式&#xff0c;觉得门槛很高。但如果你真的在MATLAB里把它落地跑通&#xff0c;会发现核心其实就是三件事&#xff1a;把声音变成特征向量&#xff0c;用GMM给每个类别…

2026/10/20 10:02:13 阅读更多 →
数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

数字图像处理这四个字听起来挺唬人&#xff0c;但落到具体操作上&#xff0c;无非就是让计算机按你的想法“摆弄”像素。我在一个模拟项目X里用了一套特别经典的基础处理流程&#xff1a;对图像做反白、改调色板、彩色转灰度&#xff0c;最后把像素数据导出成txt文件。单看每一…

2026/10/20 20:43:59 阅读更多 →
机器人大脑技术盘点:具身智能的感知、决策与数据闭环

机器人大脑技术盘点:具身智能的感知、决策与数据闭环

如果你的信息流最近也天天刷到“机器人大脑”这个词&#xff0c;你会发现一个很有意思的现象&#xff1a;每个人说的“大脑”根本不是同一个东西。有人指的是大语言模型&#xff0c;有人指的是运动控制系统&#xff0c;还有人指的是能理解物理世界的端到端模型。在2026年这个时…

2026/10/20 2:50:50 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/20 10:02:08 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/20 9:50:17 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/20 9:50:45 阅读更多 →