STM32F103移植W5500 ioLibrary:SPI驱动与socket通信实战
简介面向基于STM32F103RCT6等MINISTM32平台的嵌入式开发者这套W5500 ioLibrary移植工程包含完整的驱动适配代码可直接参考使用。W5500是集成SPI接口的硬核以太网控制器自带TCP/IP协议栈配合STM32的SPI外设即可实现网络通信适合需要为已有设备快速增加以太网功能的项目。压缩包共217个文件、约9.17MB其中66个c源码与66个h头文件构成核心驱动框架另有工程配置、编译链接中间产物及chm/htm说明文档可帮助梳理从GPIO配置、SPI初始化到底层读写函数与socket API调用的完整技术脉络附带hex、axf等可烧录文件便于直接验证。借助库内封装好的socket接口完成移植后即可开始编写TCP/UDP网络应用。目前已有1005人浏览学习适合正在做STM32网络化改造的开发者参考。1. STM32F103移植W5500 ioLibrary一个不用协议栈的联网方案很多做嵌入式的人和我一样第一次给板子加网口时都纠结过用 STM32F103 跑 lwIP 吧内存吃紧调起来费劲用 W5500 这种硬协议栈芯片吧又怕驱动不好搞。实际上 W5500 已经把 TCP/IP 打包进了硬件MCU 只通过 SPI 发 socket 命令就行而 ioLibrary 就是官方配套的 C 语言驱动包。这个项目做的就是把它从源码到 demo 完整移植到 MINISTM32 上让 F103 从一块裸机芯片变成能连局域网、能收发数据的小网关。适合正在做工业采集器、智能家居中控、或者单纯想用现成模块规避协议栈坑的开发者。真正的工作量并不在驱动本身而在那几个 SPI 回调和 socket 状态管理上这也是这篇笔记想讲透的部分。2. 硬件底座MINISTM32与W5500的SPI链路设计2.1 引脚分配与硬件连线拿到 ioLibrary 以后第一件事不是打开编译器而是先把 MINISTM32 和 W5500 模块之间的物理连线确定清楚。W5500 是标准的 SPI 从设备但有一点和普通 SPI 外设不同它每个帧的前 8 位是一个控制字节用来指定后面的地址宽度、块选择和读写方向所以 SCS 引脚必须由 MCU 软件控制不能直接用硬件 NSS 自动拉低。我一般把 W5500 挂在 STM32F103 的 SPI1 上理由很简单SPI1 的时钟来自 APB2最高 72MHz分频下来能跑到 18Mbps而 F103 的 SPI1、SPI2 在高速模式下差距不大但 SPI1 引脚复用更顺手。下面是一份我实际用的接线参考表五根信号线加两根控制线就能搞定MCU引脚W5500引脚说明PA4SCS软件片选通讯前拉低PA5SCLKSPI 时钟PA6MISOW5500 输出MCU 读取PA7MOSIW5500 输入MCU 写入PB0RST复位信号低有效PB1INT中断请求可选做轮询时可悬空3.3V / GNDVCC / GND供电必须共地注意W5500 的 INT 引脚是开漏输出如果要用中断方式接收数据必须外部上拉 10k 电阻。我更推荐前期用轮询方式跑通中断留到二次开发阶段再加这样出错时更容易定位是逻辑问题还是电气问题。2.2 SPI模式、速率与电气注意事项W5500 的 SPI 支持模式 0 和模式 3也就是 CPOL0 时 CPHA 可以是 0 或 1。我习惯用 SPI_MODE0也就是 CPOL0、CPHA0这样和大部分 SPI 从设备兼容不容易踩时钟相位翻车的坑。初始化时把 SPI 速率先压到 1Mbps 左右确认通信正常以后再逐步提高分频系数别一上来就追求 18Mbps不然示波器都还没接上数据已经乱了一屏。还有一个容易被忽略的点是电平匹配。MINISTM32 的引脚是 3.3V 逻辑W5500 模块一般也老老实实工作在 3.3V但如果你的模块带了电平转换电路就得确认转换方向有没有接反。另外SCLK 和 MOSI 在布线较长时建议串 33Ω 电阻不是为了滤波而是抑制过冲。很多 SPI 读回数据偶尔错一个字节的玄学问题最后查下来就是信号边沿太陡导致的振铃。电气上还有一条血泪经验W5500 的复位引脚必须保证上电后有一段稳定高电平。我的做法是把 PB0 初始化为高然后延时 100ms 后再拉低 10ms、拉高顺序不能颠倒否则芯片可能进入异常状态后续读寄存器全是 0xFF。3. 源码结构拆解ioLibrary里到底有什么3.1 文件清单与依赖关系ioLibrary 这个源码包的目录结构并不复杂核心是 Ethernet 目录下的 W5500 驱动和 socket 层外加 Internet 目录下的 DNS、DHCP 这类应用层协议模块。第一次打开源码的人最容易犯的错误是全部文件都丢进工程结果发现编译报错无数。实际上基础移植只需要几个文件wizchip_conf.c 和 wizchip_conf.h 负责芯片初始化参数配置w5500.c 和 w5500.h 提供寄存器级的读写函数socket.c 和 socket.h 提供类似 BSD socket 的接口。DNS 和 DHCP 文件在不需要域名解析或自动获取 IP 时完全可以不加入工程。这些文件存在依赖关系应用代码调用 socket 函数socket 层调用 wizchip 层的 read/write 函数wizchip 层最终通过函数指针调用你实现的 SPI 回调。所以在移植前先把这层调用链弄清楚后面出问题时才知道该往哪个文件里断点。3.2 socket层与wizchip层如何分工wizchip 层是距离硬件最近的代码它负责用 SPI 协议去读写 W5500 的寄存器。W5500 内部有多个寄存器块不同块有独立的地址空间wizchip 层的函数会对这些细节做屏蔽。socket 层则是在 wizchip 层之上提供 socket 编程接口包括socket()、connect()、send()、recv()、listen()这些函数。两者的分界非常清晰你只需要在 wizchip 层提供底层 SPI 收发函数上层的 socket 状态机、数据缓冲都在源码里已经实现了。举个例子socket 层维护着每个 socket 的 Sn_SR 状态寄存器它会在 connect 之前检查状态是否正常发送数据时把数据写入 W5500 的 TX buffer再触发发送命令。这些操作最终都会落到 wizchip 层的寄存器读写函数上。3.3 初始化流程与寄存器模型初始化流程的核心函数是wizchip_init()它接收两个参数TX buffer 大小数组和 RX buffer 大小数组。这个设计很有意思因为 W5500 内部有 32KB 的 TX 和 32KB 的 RX 内存但并不是平均分配给每个 socket而是通过这两个数组告诉芯片每个 socket 各分多少。比如 4 个 socket 时可以配置为{2,2,2,2}单位是 KB。下面是初始化代码的关键部分#include wizchip_conf.h #include w5500.h #include socket.h // 每个 socket 的发送/接收缓冲区大小单位 KB uint8_t tx_size[MAX_SOCK_NUM] {2,2,2,2}; uint8_t rx_size[MAX_SOCK_NUM] {2,2,2,2}; void w5500_hw_init(void) { // 复位芯片拉低 RST 10ms再拉高 GPIO_ResetBits(GPIOB, GPIO_Pin_0); delay_ms(10); GPIO_SetBits(GPIOB, GPIO_Pin_0); delay_ms(200); // 注册底层 SPI 读写回调到 wizchip reg_wizchip_cs_cbfunc(spi_cs_select, spi_cs_deselect); reg_wizchip_spi_cbfunc(spi_read_byte, spi_write_byte); // 执行芯片初始化分配各 socket 缓冲区 if (wizchip_init(tx_size, rx_size) 0) { // 初始化成功 } }这段代码中reg_wizchip_cs_cbfunc注册的是片选回调reg_wizchip_spi_cbfunc注册的是 SPI 单字节读写回调。wizchip_init内部会先读取版本寄存器再根据传入的缓冲区配置去写 TMSR 和 RMSR 寄存器。如果版本寄存器读出来不对说明 SPI 链路或者复位时序有问题后面的初始化就不会成功。4. 移植实战把驱动搬到STM32F103上4.1 移植层的三个回调函数ioLibrary 的移植工作集中在这几个回调函数上代码量不大但每个都可能藏坑。第一个是片选函数必须在 SPI 传输前把 SCS 拉低传输结束后拉高而且注意不能过早拉高否则最后一个字节可能没传完。void spi_cs_select(void) { GPIO_ResetBits(GPIOA, GPIO_Pin_4); // PA4 拉低选中 W5500 } void spi_cs_deselect(void) { GPIO_SetBits(GPIOA, GPIO_Pin_4); // PA4 拉高释放片选 }第二个和第三个是 SPI 单字节读写函数。有人会想当然地直接用SPI_I2S_SendData然后不等接收缓冲区空就去读数据这是 SPI 最常见的翻车点。正确的做法是发送和接收同时进行读 MISO 前必须先写一个字节产生时钟。uint8_t spi_read_byte(void) { while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) RESET); SPI_I2S_SendData(SPI1, 0x00); // 写 dummy 字节产生时钟 while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_RXNE) RESET); return SPI_I2S_ReceiveData(SPI1); } void spi_write_byte(uint8_t byte) { while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) RESET); SPI_I2S_SendData(SPI1, byte); while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_RXNE) RESET); SPI_I2S_ReceiveData(SPI1); // 清除 RXNE防止后续传输错位 }这两个函数是 wizchip 层和硬件之间的唯一通道。注意每次写完成后必须读一次 RXNE否则 RXNE 标志一直为 1下一轮写数据前检查 TXE 可能就被绕过导致时序错乱。把这股细节处理好整个 SPI 链路才算稳。4.2 中断与轮询什么时候处理数据W5500 的 INT 引脚会在 socket 事件发生时被拉低典型事件包括连接建立、数据到达、连接关闭。但我建议第一次移植时先用轮询也就是定时调用recv()去查每个 socket 的接收缓冲区大小有数据再读。原因很简单中断需要处理引脚边沿、判断是哪个 socket 的事件还要防止共享中断标志的竞争条件出错时排查链路太长。轮询模式下socket 层提供了一个简单的判断方法调用getSn_RX_RSR(sn)获取接收数据字节数当返回值大于 0 时再调用recv()。这段代码可以放在主循环或 1ms 定时器里。#define SOCK_APP 0 void sock_recv_poll(void) { uint16_t len getSn_RX_RSR(SOCK_APP); if (len 0) { uint8_t buffer[512]; int32_t ret recv(SOCK_APP, buffer, len); if (ret 0) { // 处理收到的数据 } } }getSn_RX_RSR返回的是芯片接收缓冲区中尚未被读取的字节数这个值在读走数据后会自动减少。轮询间隔别太短否则 SPI 频繁访问会占用主循环大量时间也别太长否则芯片接收缓冲区可能溢出丢包。我一般放在 5ms 周期任务里配合 512 字节的 app buffer跑 100M 局域网内的数采场景足够。4.3 一个最小TCP客户端demo跑通 socket 层的最好方式是用一个 TCP 客户端 demo让它主动连到 PC 上的网络调试助手。注意 W5500 的 socket 连接是非阻塞的connect()返回后还需要等待状态变为 SOCK_ESTABLISHED。#include wizchip_conf.h #include socket.h #define SOCK_TCP 0 void tcp_client_demo(void) { // 设置本机 IP使用静态 IP 方式 uint8_t my_ip[4] {192,168,1,200}; wizchip_setipaddr(0, my_ip); // 0 表示网卡编号 // 打开 TCP socket int8_t s socket(SOCK_TCP, Sn_MR_TCP, 8080, 0); if (s ! SOCK_TCP) { // 打开失败检查缓冲区配置 return; } uint8_t server_ip[4] {192,168,1,100}; uint16_t server_port 6000; int8_t ret connect(SOCK_TCP, server_ip, server_port); if (ret ! SOCK_OK) { return; } // 等待连接建立轮询状态寄存器 while (getSn_SR(SOCK_TCP) ! SOCK_ESTABLISHED) { // 如果状态变为 CLOSED说明连接失败需要重新打开 if (getSn_SR(SOCK_TCP) SOCK_CLOSED) { close(SOCK_TCP); return; } delay_ms(10); } // 连接成功发送一条消息 send(SOCK_TCP, (uint8_t*)hello from f103\r\n, 17, 0); }这里Sn_MR_TCP是 socket 类型宏8080是本地端口0是标志位。getSn_SR用来读 socket 状态寄存器。连接超时判断不能只看 connect 函数的返回值因为非阻塞下它会先返回 SOCK_BUSY真正成功与否要看状态是否变成SOCK_ESTABLISHED。PC 端用网络调试助手开一个 TCP Server 监听 6000 端口运行代码后收到 “hello from f103” 就说明整个链路通了。5. 避坑手册SPI通信、复位和socket状态排查5.1 现象SPI读取全0xFFW5500无法应答现象wizchip_init()返回失败或者用 SPI 读取任意寄存器都得到 0xFF。用示波器看 SCLK 波形有脉冲MISO 一直为高。原因最常见的是复位时序不正确芯片还处于复位状态其次是 SPI 模式不对导致控制字节里的地址和块选择被芯片解码失败还有一个很隐蔽的原因是 SCS 在高电平状态下恰好有一个下降沿毛刺把芯片的 SPI 状态机搞乱了。解决先用万用表量 RST 引脚电压正常工作时应该为高。复位时序改成“先拉高 100ms、再拉低 10ms、再拉高 200ms”保证芯片上电稳定。SPI 模式固定为模式 0。片选信号必须确保每次读写帧开始时拉低结束后拉高中间不能有其他代码干扰。另外可以加一段回读测试uint8_t ver getVERSIONR(); if (ver ! 0x04) { // 版本号不等于 0x04说明 SPI 通信有问题 }W5500 的版本寄存器地址是固定值能够正确读回 0x04 说明底层的 SPI 读写函数已经正常不用再拿示波器逐字节分析协议了。5.2 现象socket连接建立后马上断开现象connect()能返回成功getSn_SR()也短暂进入SOCK_ESTABLISHED但不到一秒就变回SOCK_CLOSED抓包软件上能看到 TCP 三次握手完成接着立刻收到 RST 包。原因很多时候不是 W5500 的问题而是对端主动断开。比如 PC 端的 TCP Server 程序把端口关了或者目标 IP 实际上是广播地址。还有一种情况是本地端口和远端端口相同导致 ACK 序号混乱。更隐蔽的坑是 W5500 在 TCP 连接建立后立刻收到数据而你的程序没有及时调用 recv芯片的接收缓冲区溢出会直接发 RST 断开连接。解决先用网络调试助手确认 Server 端口确实在监听。检查 socket 的Sn_RXBUF_SIZE配置如果数据量大就调大该 socket 的缓冲区。连接建立后尽快进入接收循环别在 send 之后一直阻塞等待。还可以用getSn_IR(SOCK_TCP)读取中断标志检查是否出现了接收溢出位。5.3 现象接收缓冲区溢出recv返回异常现象数据量大时recv()返回数据长度比实际发送方发来的少或者直接返回SOCKERR_RECV_TIMEOUT甚至调用getSn_RX_RSR()返回 0但之前已经收到了部分数据。原因W5500 的接收缓冲区是环形结构MCU 读走数据的速度跟不上网络数据到达的速度硬件缓冲区就会溢出。ioLibrary 的recv()依赖getSn_RX_RSR()获取长度如果溢出后没有正确清理就会读到错误的数据长度。解决提高主循环轮询频率把sock_recv_poll周期缩短到 2ms 以内。如果还不行就得加大该 socket 的 RX buffer 分配比如从 2KB 增加到 4KB。另外重要的一点是recv()传入的 buffer 大小要大于getSn_RX_RSR()返回的长度否则函数内部会按 buffer 大小截断剩余的部分不会被清除下次读取时会继续读到旧数据。5.4 现象芯片偶尔无法初始化重新上电又好了现象程序烧录后第一次运行正常断电重启后偶发卡在wizchip_init()再复位一次又能跑通。原因这是一类典型的电源和复位时序耦合问题。MCU 上电速度比 W5500 快导致 W5500 刚上电还没完成内部初始化时MCU 已经通过 SPI 发了命令。另一个原因是复位引脚上的电容放电慢导致 RST 拉低时间不够。解决在调用wizchip_init()之前加 500ms 延时或者把 W5500 的 RST 引脚接到一个独立 GPIO 上由软件控制完整复位时序。我还习惯在初始化前读一次版本寄存器如果失败就再执行一轮复位和重试最多尝试三次这比死等一次成功要可靠得多for (int i 0; i 3; i) { w5500_hw_reset(); if (wizchip_init(tx_size, rx_size) 0) { break; } }6. 二次开发改造从单socket到多路复用与断线重连6.1 修改宏定义扩充socket数量初次跑通单 socket 以后最常见的第一件事是加第二个 socket。ioLibrary 里默认定义的是 4 个 socket但如果你的应用需要挂多种协议比如一个 TCP 做数据上报、一个 UDP 做设备发现就得确认这个宏是否够用。在 socket.h 里有一个_WIZCHIP_相关的宏控制最大 socket 数通常定义在 w5500.h 中默认是 4。要扩展到 8 个需要同时调整 W5500 内部的 socket 寄存器偏移计算和缓冲区分配表。// w5500.h 中调整枚举 #define MAX_SOCK_NUM 8 // wizchip_init 时分配 8 个 socket 的缓冲区 uint8_t tx_size[MAX_SOCK_NUM] {2,2,2,2,2,2,2,2}; uint8_t rx_size[MAX_SOCK_NUM] {2,2,2,2,2,2,2,2};注意 W5500 内部总缓冲区只有 32KB TX 和 32KB RX如果给 8 个 socket 平均分配 2KB总共 16KB还有大量空间闲置。合理做法是把不常用的 socket 设成 1KB热点 socket 设成 8KB这样总容量不超过硬件上限即可。6.2 缓冲区大小调整与内存规划socket 缓冲区调整直接影响 TCP 吞吐量和内存占用。如果一个 socket 需要接收大块 Modbus 报文RX buffer 设为 8KB 会大幅降低溢出概率但代价是其他 socket 可用缓冲区变小。这里有一个常见的误解缓冲区是 W5500 芯片内部的内存不是 STM32 的 RAM所以调大 socket 缓冲区并不会让 MCU 的堆栈多吃 8KB真正占内存的是你取走数据时用作中转的 app buffer。我一般会先算一次需要缓存多少字节数据再把对应 socket 的缓冲区设为这个值的两倍。比如发送 4KB 的批量数据时TX buffer 配到 8KB这样一次 send 调用可以完整放下整个包避免芯片在传输过程中因为缓冲不足而拒绝写入。对应的内存规划表大致是这样Socket用途TX bufferRX buffer说明TCP 数据上报4KB8KB高频上传防止缓冲溢出UDP 设备发现2KB2KB只收短报文TCP 命令监听1KB1KB低频控制指令备用1KB1KB预留6.3 非阻塞socket和重连逻辑移植完成后的运行稳定性往往取决于断线重连的逻辑写得好不好。W5500 的连接是非阻塞的connect()返回后 socket 会经历一系列状态我不能简单地用 if 判断返回值就决定是否重连。我习惯写一个状态机每个 socket 维护一个 app 层的连接状态typedef enum { NET_IDLE, NET_CONNECTING, NET_CONNECTED, NET_RECONNECT } net_state_t; void tcp_state_machine(int sn) { switch (net_status[sn]) { case NET_IDLE: socket(sn, Sn_MR_TCP, local_port, 0); net_status[sn] NET_CONNECTING; break; case NET_CONNECTING: if (getSn_SR(sn) SOCK_ESTABLISHED) { net_status[sn] NET_CONNECTED; } else if (getSn_SR(sn) SOCK_CLOSED) { close(sn); net_status[sn] NET_RECONNECT; } break; case NET_CONNECTED: if (getSn_SR(sn) SOCK_CLOSE_WAIT) { // 对端关闭主动断开 close(sn); net_status[sn] NET_RECONNECT; } break; case NET_RECONNECT: close(sn); delay_ms(2000); // 防止快速重连把端口占满 net_status[sn] NET_IDLE; break; } }这里的SOCK_CLOSE_WAIT状态很关键W5500 在收到对端 FIN 后会进入这个状态如果程序没有及时处理芯片不会自动回到监听状态必须调用close()释放 socket 资源。重连延时放在应用层而不是驱动层避免多个 socket 同时重连时 SPI 周期被拖垮。从那以后我每次做多 socket 移植时都强制走一遍这个状态机先把连接生命周期梳理清楚再接业务逻辑这比事后填坑省事得多。希望这些调试思路能帮你在自己的板子上少走两步弯路。本文还有配套的精品资源点击获取

相关新闻

Python 操作 Git 仓库:subprocess 与 GitPython 选型与避坑实战

Python 操作 Git 仓库:subprocess 与 GitPython 选型与避坑实战

我自己的日常里,真正让我下决心系统地用 Python 去操作 Git 仓库,是因为一次“人肉同步十几个仓库”的惨痛经历——明明都是机械式的git add、git commit、git push,但一旦仓库数量上来,手动敲命令就容易漏,某次还因为…

2026/10/17 11:31:27 阅读更多 →
AI Agent落地餐饮数字化:从客服到供应链的全链路实战

AI Agent落地餐饮数字化:从客服到供应链的全链路实战

开头不写AI套路话,直接用场景切入。 上个月我帮一个做连锁餐饮的朋友梳理门店数字化方案,聊到一半他忽然问我:“你说的AI,到底和我们现在用的扫码点餐、ERP进销存有什么区别?不就是换个方式记数据吗?”这个…

2026/10/17 11:31:27 阅读更多 →
Python操作Git仓库完整实操:原理、封装与踩坑记录

Python操作Git仓库完整实操:原理、封装与踩坑记录

直接上手 Python 操作 Git 仓库,这是我踩过不少坑之后整理出来的完整实操记录。不管你是想批量拉取几十个仓库、做自动化发布脚本,还是写一个像样的小工具来管理多项目,这套内容都能直接抄作业。文章里我会把底层原理、工具选型、代码封装、常…

2026/10/17 11:31:27 阅读更多 →

最新新闻

金融服务的底层逻辑:从支付链路到账务对账与合规风控

金融服务的底层逻辑:从支付链路到账务对账与合规风控

我在金融服务行业摸爬滚打了快十年,从银行核心系统的外围项目做到支付通道的底层对接,再到现在负责一块面向企业的资金管理产品。这些年下来,我最深的一个感受是:很多人把“金融服务”当成一个漂亮的大词来谈,一聊就是…

2026/10/17 12:23:48 阅读更多 →
用 OpenGem + Claude Code + Obsidian 构建函数调用关系:把 endpoint 改到 TaoToken 的实操大纲

用 OpenGem + Claude Code + Obsidian 构建函数调用关系:把 endpoint 改到 TaoToken 的实操大纲

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

2026/10/17 12:23:48 阅读更多 →
3个月从AI小白到独立搭建智能体:大模型Agent开发实践指南

3个月从AI小白到独立搭建智能体:大模型Agent开发实践指南

我先说明一点:文章里不会涉及任何工具的具体推广话术,只把火山引擎豆包、扣子智能体当作一个可落地的大模型应用案例来讲。毕竟标题里那句“AI Agent 摸鱼大师”也只是个半开玩笑的说法,真正有价值的是“3个月从AI小白到能独立搭建智能体”这…

2026/10/17 12:23:48 阅读更多 →
Trillium 创始人给行业泼了盆冷水:RSI 是幌子,服务器没上锁是真,蒸馏你更是拦不住

Trillium 创始人给行业泼了盆冷水:RSI 是幌子,服务器没上锁是真,蒸馏你更是拦不住

前沿实验室没有想象中那么封闭,保密几个月可以,长期不能。 Natha n Lam ber t 对 RSI 叙事的批评一向尖锐:不接受 AI 即将突然起飞、迅速失控。 而他真正担心的是更土的事情:AI 实验室自己那些没加固好的基础设施。他创立 Tr…

2026/10/17 12:23:48 阅读更多 →
体检正常却浑身不舒服?读懂身体求救信号与功能失衡

体检正常却浑身不舒服?读懂身体求救信号与功能失衡

你有没有过这种经历:体检报告拿在手里,血糖、血脂、肝肾功能、甲状腺全套……所有指标后面都跟着一个向上的小箭头“正常”,医生看完甚至头都没抬,说了一句“没事”。可你自己清楚,日子一点都不好过——早上睡醒比睡前…

2026/10/17 12:23:48 阅读更多 →
遥感导论ENVI上机实验教程一:遥感影像几何校正的TaoToken统一Key配置与验证

遥感导论ENVI上机实验教程一:遥感影像几何校正的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/17 12:22:48 阅读更多 →

日新闻

DeepSeek选型与部署:V3/R1、Ollama、API全攻略

DeepSeek选型与部署:V3/R1、Ollama、API全攻略

简介:《DeepSeek使用方法.pdf》是一份面向DeepSeek入门及进阶用户的完整使用指南,重点围绕V3与R1两款模型的能力差异与适用场景展开,帮助读者根据任务类型与成本选择合适的模型。资源共1个PDF文件,压缩包大小约311KB,篇…

2026/10/17 0:00:25 阅读更多 →
200+Deepseek润色指令拆解:从底层原理到场景落地的完整指南

200+Deepseek润色指令拆解:从底层原理到场景落地的完整指南

简介:这是一份聚焦DeepSeek提示词优化的《200Deepseek润色指令》PDF文档,共收录两百余条可直接套用的润色指令,涵盖语法修正、风格统一、逻辑梳理、表达精炼等维度,并针对商务写作、学术论文、广告文案等场景给出差异化建议。文档…

2026/10/17 0:00:25 阅读更多 →
OpenCV轮廓法物体计数系统:轻量、可控、可落地的工业级实现

OpenCV轮廓法物体计数系统:轻量、可控、可落地的工业级实现

简介:本资源是一份基于OpenCV的本科课程设计完整报告,面向计算机视觉初学者、图像处理学习者及高校通信/信息类专业学生,解决物体智能计数与检测结果结构化记录的实际问题。项目覆盖图像预处理、轮廓检测、边界框绘制、轨迹栏交互式参数调节、…

2026/10/17 0:00:25 阅读更多 →

周新闻

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

简介:基于 ARIMA、LSTM、Transformer 等模型的流感时间序列预测 Python 源码,面向计算机相关专业课程设计与期末大作业学生,以及项目实战学习者。内容覆盖预处理、平稳性检验、定阶、残差分析、多模型对比预测的完整时序建模流程,…

2026/10/16 21:35:51 阅读更多 →
影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别 做影刀RPA自动化,十个新手有八个栽在"往输入框里填东西"这件事上:要么填不进去,要么填了一半,要么直接把原来内容追加在后面。这背后的根因&…

2026/10/17 1:44:59 阅读更多 →
影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容 1. 认识影刀:什么场景该用RPA采小说数据 起点中文网的页面结构相对稳定——分类榜单、书籍详情、章节内容三块独立页面,跳转链路清晰。这种场景非常适合影刀自动化&#x…

2026/10/16 15:04:24 阅读更多 →

月新闻

我发现了一个新思路:用 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/16 21:54:38 阅读更多 →
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/16 3:49:43 阅读更多 →
黑夜航拍船只数据集训练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/16 14:23:36 阅读更多 →