STM32 HTTP远程升级实战:告别串口烧录,实现OTA固件更新

简介:这份资源面向嵌入式开发者与STM32学习者,聚焦通过HTTP协议实现设备固件的远程升级,解决传统现场烧录维护效率低的问题。压缩包共202个文件,约5.23MB,以C源码与头文件为核心,包含36个.c、38个.h,另有编译产物.o、.d、.crf,以及Keil工程文件.uvproj、.uvopt、启动文件.s、链接脚本.sct和可执行.hex、.axf等,构成一套可直接编译调试的完整工程。资源围绕HTTP_GETPkt()函数展开,演示STM32作为客户端发送GET请求、接收服务器分块下发的固件二进制流,并涉及lwIP网络栈适配、请求头设置、MD5或SHA-1完整性校验、闪存写入与安全模式重启等关键环节,同时提示局域网静态配置与公网NAT、动态域名解析的差异。已有5087人学习下载,适合希望掌握TCP/IP协议栈与HTTP远程升级流程的中高级开发者,可据此理解客户端与服务器接口的配合方式,并借鉴其工程组织与排错思路。

1. 串口烧录救不了现场设备,HTTP 远程升级才是正解

做过嵌入式现场维护的都懂那种无力感:设备装在十几米高的塔吊上、埋在农田的监测站里、封在配电柜的角落中,固件一旦有 bug,唯一的办法就是扛着笔记本和 USB-TTL 跑一趟现场。更别提有些设备压根没留调试口,外壳一装就只能拆机。这个基于 STM32 的 HTTP 远程升级项目,解决的正是这个痛点——让设备自己通过 HTTP 协议从服务器拉取固件包,校验后写入 Flash,重启即完成升级。整套逻辑跑在 STM32 上,配合以太网或 WiFi 模块,不需要上位机、不需要串口线,只要设备能联网,升级就是一次 GET 请求的事。适合正在做物联网终端、工业网关、远程监测设备的开发者,尤其是那些被“现场烧录”折磨过的团队。

2. 整体架构拆解:从 HTTP 请求到 Flash 写入的完整链路

2.1 系统分层与数据流向

这个项目的架构可以拆成四层,从上到下依次是:应用层(升级触发逻辑)、协议层(HTTP 客户端 + 固件包解析)、存储层(Flash 驱动 + 分区管理)、硬件层(STM32 + 网络模块)。数据流向很清晰:设备上电后,应用层判断是否需要升级(可以定时轮询、也可以由服务器下发通知),然后协议层发起 HTTP GET 请求,从指定 URL 下载固件二进制文件,边下载边写入 Flash 的备份区,下载完成后校验完整性,最后跳转到 Bootloader 完成搬运和重启。

这里有个关键设计决策:为什么用 HTTP GET 而不是 POST?因为固件包是静态资源,放在服务器上就是一个 .bin 文件,GET 请求天然适合这种场景,而且实现简单,不需要处理表单编码。服务器端只需要一个静态文件服务(Nginx、Apache 甚至 Python 的 http.server 都行),把编译好的 bin 文件放上去就能用。

整个链路里最容易被忽视的是内存管理。STM32 的 RAM 通常只有几十到几百 KB,不可能把整个固件包缓存下来再写入。常见做法是分块下载:每次从 HTTP 响应流里读 1KB 到 4KB 的数据,立刻写入 Flash,然后继续读下一块。这样 RAM 占用极小,但要求 Flash 驱动支持按页写入,并且要做好地址偏移的累加。

2.2 目录结构一览

拿到源码后,先看目录结构,心里有个地图再动手改:

stm32-http-ota/ ├── Core/ │ ├── Inc/ │ │ ├── main.h │ │ ├── http_client.h # HTTP 客户端接口 │ │ ├── ota_manager.h # 升级流程管理 │ │ └── flash_if.h # Flash 操作接口 │ └── Src/ │ ├── main.c # 主循环与升级触发 │ ├── http_client.c # HTTP 请求组装与响应解析 │ ├── ota_manager.c # 升级状态机与校验逻辑 │ └── flash_if.c # Flash 擦写驱动 ├── Drivers/ │ ├── STM32F4xx_HAL_Driver/ # HAL 库 │ └── CMSIS/ # 内核头文件 ├── Middlewares/ │ └── Third_Party/ │ └── LwIP/ # 轻量级 TCP/IP 协议栈 ├── Bootloader/ │ └── Src/ │ └── boot_main.c # Bootloader 主逻辑 └── README.md

这个结构是典型的 STM32 工程布局,Core 放业务代码,Drivers 放芯片支持包,Middlewares 放第三方协议栈。Bootloader 单独一个目录,因为它编译后要烧到 Flash 起始地址,和应用程序分开。实际项目中,Bootloader 和 App 是两个独立的工程,通过链接脚本控制各自的 Flash 起始地址和大小。

2.3 Flash 分区规划

Flash 分区是整个升级方案的基石,分错了后面全是坑。以 STM32F407(1MB Flash)为例,常见做法是:

区域起始地址大小用途
Bootloader0x0800000064KB启动引导,负责搬运固件
App 运行区0x08010000448KB当前运行的应用程序
备份区0x08080000448KB下载的新固件暂存
参数区0x080F000064KB存储升级标志、版本号、CRC

Bootloader 永远不动,升级时新固件先写到备份区,校验通过后设置升级标志,重启后 Bootloader 把备份区的内容搬运到 App 运行区,搬运完成清除标志,跳转到 App。这样即使升级过程中断电,App 运行区的旧固件依然完整,设备不会变砖。

注意:分区大小要根据实际固件体积调整,App 运行区和备份区必须一样大,且不能有重叠。链接脚本里的 FLASH 长度要对应修改,否则编译出来的 bin 文件可能超出分区范围。

3. 核心模块实现:HTTP 客户端与 Flash 写入的代码细节

3.1 HTTP GET 请求的组装与发送

先看 HTTP 客户端的核心代码。这里假设底层已经有一个可用的 TCP socket(通过 LwIP 或 AT 指令模组实现),我们只需要组装 HTTP 请求报文并解析响应。

// http_client.c #include "http_client.h" #include <string.h> #include <stdio.h> #define HTTP_BUF_SIZE 1024 /** * @brief 发起 HTTP GET 请求,下载固件到 Flash * @param host: 服务器域名或 IP * @param port: 端口号,HTTP 默认 80 * @param path: 固件文件路径,如 "/firmware/app_v2.bin" * @param flash_addr: 固件写入 Flash 的起始地址 * @return 0 成功,-1 失败 */ int http_download_firmware(const char *host, int port, const char *path, uint32_t flash_addr) { char request[256]; char resp_buf[HTTP_BUF_SIZE]; int sockfd, ret; uint32_t write_addr = flash_addr; uint32_t total_len = 0; int header_parsed = 0; // 1. 建立 TCP 连接 sockfd = tcp_connect(host, port); if (sockfd < 0) { printf("[OTA] TCP connect failed\r\n"); return -1; } // 2. 组装 HTTP GET 请求 snprintf(request, sizeof(request), "GET %s HTTP/1.1\r\n" "Host: %s\r\n" "Connection: close\r\n" "User-Agent: STM32-OTA/1.0\r\n" "\r\n", path, host); ret = tcp_send(sockfd, request, strlen(request)); if (ret < 0) { printf("[OTA] Send request failed\r\n"); tcp_close(sockfd); return -1; } // 3. 擦除备份区 Flash(按扇区擦除) flash_erase_sectors(flash_addr, APP_PARTITION_SIZE); // 4. 循环接收响应数据 while (1) { int len = tcp_recv(sockfd, resp_buf, HTTP_BUF_SIZE); if (len <= 0) break; // 连接关闭或出错 if (!header_parsed) { // 跳过 HTTP 响应头,找到 \r\n\r\n char *body = strstr(resp_buf, "\r\n\r\n"); if (body) { body += 4; // 跳过空行 int body_len = len - (body - resp_buf); if (body_len > 0) { flash_write(write_addr, (uint8_t *)body, body_len); write_addr += body_len; total_len += body_len; } header_parsed = 1; } continue; } // 已解析头部,后续数据直接写入 Flash flash_write(write_addr, (uint8_t *)resp_buf, len); write_addr += len; total_len += len; } tcp_close(sockfd); printf("[OTA] Download done, total %lu bytes\r\n", total_len); return (total_len > 0) ? 0 : -1; }

这段代码有几个关键点。第一,HTTP 请求头里Connection: close告诉服务器响应完就关闭连接,这样我们不需要实现 chunked 编码解析,简化了逻辑。第二,响应头和数据可能在同一包或不同包里到达,所以用header_parsed标志位处理跨包的情况。第三,Flash 擦除在下载前完成,因为 STM32 的 Flash 只能按扇区擦除,不能按字节擦,必须先擦后写。

参数说明:host可以是 IP 也可以是域名,如果域名需要底层支持 DNS 解析;flash_addr是备份区的起始地址,要和分区表一致;APP_PARTITION_SIZE是备份区大小,擦除时按扇区对齐。

3.2 Flash 写入与校验逻辑

Flash 写入不是简单的 memcpy,STM32 的 Flash 控制器有严格的时序要求。下面是基于 HAL 库的实现:

// flash_if.c #include "flash_if.h" #include "stm32f4xx_hal.h" /** * @brief 向指定地址写入数据(自动处理扇区边界) * @param addr: 目标地址,必须是 4 字节对齐 * @param data: 数据指针 * @param len: 数据长度 * @return 0 成功,-1 失败 */ int flash_write(uint32_t addr, uint8_t *data, uint32_t len) { HAL_FLASH_Unlock(); for (uint32_t i = 0; i < len; i += 4) { uint32_t word = 0; // 处理末尾不足 4 字节的情况 uint32_t remain = len - i; if (remain >= 4) { memcpy(&word, data + i, 4); } else { memcpy(&word, data + i, remain); } if (HAL_FLASH_Program(FLASH_TYPEPROGRAM_WORD, addr + i, word) != HAL_OK) { HAL_FLASH_Lock(); return -1; } } HAL_FLASH_Lock(); return 0; } /** * @brief 计算固件的 CRC32 校验值 * @param addr: 固件起始地址 * @param len: 固件长度 * @return CRC32 值 */ uint32_t flash_crc32(uint32_t addr, uint32_t len) { uint32_t crc = 0xFFFFFFFF; for (uint32_t i = 0; i < len; i += 4) { uint32_t word = *(volatile uint32_t *)(addr + i); crc ^= word; for (int j = 0; j < 32; j++) { if (crc & 0x80000000) crc = (crc << 1) ^ 0x04C11DB7; else crc <<= 1; } } return crc; }

flash_write按 4 字节对齐写入,因为 STM32F4 的 Flash 编程单位是字(32 位)。如果数据长度不是 4 的倍数,末尾会补零写入,这在固件场景下没问题,因为 bin 文件本身通常会对齐。flash_crc32用于下载完成后校验固件完整性,服务器端在生成 bin 文件时也要计算同样的 CRC 值,通过 HTTP 响应头或单独的接口传给设备。

注意:Flash 写入前必须解锁,写完立即上锁,否则可能误擦除其他区域。另外,写入地址必须在擦除过的扇区内,否则写入会失败。

3.3 升级状态机与 Bootloader 跳转

升级流程用一个状态机管理,状态包括:空闲、下载中、校验中、待搬运、搬运完成。状态值存在参数区 Flash 里,掉电不丢失。

// ota_manager.c typedef enum { OTA_IDLE = 0, OTA_DOWNLOADING, OTA_VERIFYING, OTA_PENDING, // 下载校验完成,等待重启搬运 OTA_DONE } ota_state_t; // 参数区地址(最后 64KB 的第一个扇区) #define PARAM_ADDR 0x080F0000 typedef struct { uint32_t magic; // 魔数,标识参数有效 ota_state_t state; uint32_t fw_size; // 固件大小 uint32_t fw_crc; // 固件 CRC uint32_t version; // 版本号 } ota_param_t; void ota_set_state(ota_state_t state, uint32_t size, uint32_t crc) { ota_param_t param; param.magic = 0x4F544131; // "OTA1" param.state = state; param.fw_size = size; param.fw_crc = crc; param.version = get_current_version() + 1; flash_erase_sectors(PARAM_ADDR, 0x10000); flash_write(PARAM_ADDR, (uint8_t *)&param, sizeof(param)); } // Bootloader 中的搬运逻辑 void boot_copy_firmware(void) { ota_param_t *param = (ota_param_t *)PARAM_ADDR; if (param->magic != 0x4F544131 || param->state != OTA_PENDING) return; // 从备份区搬运到 App 运行区 flash_erase_sectors(APP_ADDR, APP_PARTITION_SIZE); for (uint32_t i = 0; i < param->fw_size; i += 4) { uint32_t word = *(volatile uint32_t *)(BACKUP_ADDR + i); HAL_FLASH_Program(FLASH_TYPEPROGRAM_WORD, APP_ADDR + i, word); } // 校验搬运后的数据 uint32_t crc = flash_crc32(APP_ADDR, param->fw_size); if (crc == param->fw_crc) { param->state = OTA_DONE; flash_erase_sectors(PARAM_ADDR, 0x10000); flash_write(PARAM_ADDR, (uint8_t *)param, sizeof(ota_param_t)); } }

Bootloader 的搬运逻辑必须在跳转到 App 之前执行,而且搬运过程中不能被打断。实际项目中,Bootloader 会先检查参数区的状态,如果是OTA_PENDING就执行搬运,搬运完成后清除标志,最后跳转到 App 的复位向量。跳转代码用汇编或直接操作 MSP 和 PC 指针实现。

4. 避坑与排查:远程升级最容易翻车的五个地方

4.1 下载到一半断电,设备变砖

现象:升级过程中断电,重新上电后设备无法启动,串口无输出。

原因:新固件直接覆盖了 App 运行区,断电导致 App 区数据不完整,Bootloader 又跳转到了损坏的 App。

解决:采用双区设计,新固件先写备份区,校验通过后再由 Bootloader 搬运。搬运过程如果断电,下次上电重新搬运即可,App 区始终是完整的旧固件。

4.2 HTTP 响应头解析错误,固件写入偏移

现象:下载完成后 CRC 校验失败,对比发现固件头部多了几十个字节。

原因:HTTP 响应头没有正确跳过,把HTTP/1.1 200 OK\r\n...这些文本也写进了 Flash。

解决:用strstr查找\r\n\r\n分隔符,确保只写入分隔符之后的数据。如果响应头跨多个 TCP 包,需要缓存头部直到找到分隔符。

4.3 Flash 擦除不完整,写入数据错乱

现象:固件写入后读取校验,部分扇区数据是 0xFF 或旧数据。

原因:STM32 的 Flash 擦除是按扇区的,如果只擦了部分扇区,未擦除的区域写入会失败。

解决:擦除时按扇区对齐,从起始地址到结束地址覆盖所有涉及的扇区。可以用flash_erase_sectors封装,内部循环调用 HAL 的扇区擦除函数。

4.4 网络不稳定导致下载中断

现象:下载到 80% 时 TCP 连接断开,升级失败。

解决:实现断点续传。在 HTTP 请求头里加Range: bytes=xxx-,服务器返回 206 Partial Content,设备从上次中断的地址继续写入。同时记录已下载的字节数到参数区,重启后可以恢复。

4.5 跳转到 App 后外设异常

现象:Bootloader 跳转到 App 后,串口、定时器工作不正常。

原因:Bootloader 初始化了外设,跳转前没有反初始化,App 再次初始化时冲突。

解决:跳转前调用HAL_DeInit()关闭所有外设,关闭全局中断,设置 MSP 为 App 的栈顶地址,然后跳转到 App 的复位向量。

5. 二次开发改造:从能跑到好用

5.1 加入 HTTPS 支持

HTTP 是明文传输,固件包容易被篡改。改造方向是加入 TLS,可以用 mbedTLS 库,在 TCP 之上加一层 SSL。核心改动在tcp_connect之后加ssl_handshake,发送和接收都走 SSL 接口。服务器端需要配置证书,设备端内置 CA 证书或使用预共享密钥。这个改造工作量不小,但安全性提升明显。

5.2 差分升级减小流量

完整固件包动辄几百 KB,对于 NB-IoT 这类低带宽场景,流量成本很高。差分升级的思路是只下载新旧固件的差异部分,设备端用差分算法(如 bsdiff)合并生成新固件。服务器端需要保存旧版本固件,生成差分包。这个方案能把升级包缩小到原来的 10% 到 20%,但实现复杂度较高,需要额外的差分合并代码。

5.3 升级策略优化

当前是设备主动轮询,可以改成服务器推送。设备保持一个长连接(MQTT 或 WebSocket),服务器有新固件时下发通知,设备再发起 HTTP 下载。这样升级更及时,也减少了无效轮询。另外可以加入灰度发布逻辑,根据设备 ID 或版本号决定是否升级,避免一次性全量推送导致服务器带宽打满。

5.4 验证方法

改造完成后,验证要覆盖几个场景:正常升级、下载中断后恢复、固件 CRC 错误、断电重启后继续搬运、跳转后外设正常。我一般会写一个 Python 脚本模拟服务器,控制响应速度和数据包大小,测试设备在各种网络条件下的表现。脚本核心逻辑:

# ota_server_sim.py from http.server import HTTPServer, BaseHTTPRequestHandler import time class OTAServer(BaseHTTPRequestHandler): def do_GET(self): if self.path == "/firmware/app.bin": with open("app.bin", "rb") as f: data = f.read() self.send_response(200) self.send_header("Content-Type", "application/octet-stream") self.send_header("Content-Length", str(len(data))) self.end_headers() # 模拟慢速网络,每 1KB 延迟 10ms for i in range(0, len(data), 1024): self.wfile.write(data[i:i+1024]) time.sleep(0.01) HTTPServer(("0.0.0.0", 8080), OTAServer).serve_forever()

这个脚本可以控制发送速率,模拟弱网环境。改time.sleep的参数就能调整延迟,改分块大小就能模拟不同的 MTU。

从那以后我每次做远程升级,都强制走一遍「断电测试」:下载到一半直接拔电,看设备能不能恢复。这个习惯帮我拦住了至少三次可能批量返工的 bug。希望帮到你。

本文还有配套的精品资源,点击获取

相关新闻

rsamatlab提取HCP-MMP1.0脑区mask:从区域名到二值掩码

rsamatlab提取HCP-MMP1.0脑区mask:从区域名到二值掩码

简介&#xff1a;针对脑影像分析中需要从HCP-MMP1.0图谱提取特定脑区掩膜的需求&#xff0c;这份MATLAB脚本工具可直接读取MNI空间下的体积图谱&#xff0c;依据mmp.csv中的ROI编号快速生成二值掩膜文件。脚本支持左右半球选择、单个/多个ROI分别保存或合并保存&#xff0c;并可…

2026/10/19 16:56:58 阅读更多 →
Open-Code-Review:基于 Git Diff 的可审计代码审查范式

Open-Code-Review:基于 Git Diff 的可审计代码审查范式

1. “open-code-review”不是工具名&#xff0c;而是正在发生的开发范式迁移你最近在 GitHub 提交 PR 后&#xff0c;是不是发现评论区里多了一条带 &#x1f916; 图标的自动评论&#xff1f;它没用“LGTM”&#xff0c;也没写“建议加个空行”&#xff0c;而是说&#xff1a;…

2026/10/19 16:56:58 阅读更多 →
生产环境 WebSocket 必须用 wss 的底层原理与全链路配置

生产环境 WebSocket 必须用 wss 的底层原理与全链路配置

1. 为什么非得用 wss 而不是 ws&#xff1f;一个被多数人忽略的生产环境铁律“Stomp 以 wss 方式连接 websocket”——这行看似简单的配置语句&#xff0c;背后藏着现代 Web 应用上线前最常被跳过的安全红线。我见过太多团队&#xff1a;本地开发一切顺利&#xff0c;ws://loca…

2026/10/19 16:56:58 阅读更多 →

最新新闻

JSP+Servlet+JDBC图书管理系统实战:源码拆解与避坑指南

JSP+Servlet+JDBC图书管理系统实战:源码拆解与避坑指南

简介&#xff1a;针对Java课程设计与大作业中的常见选题&#xff0c;这套下载资源提供了一套完整可运行的图书管理系统源码与配套数据库。项目内包含前端页面、后端业务逻辑、数据库脚本以及相关配置文件&#xff0c;实现了图书信息的录入、删除、修改、查询和借阅归还等主要功…

2026/10/19 17:40:46 阅读更多 →
DVWA靶场实战:XSS攻击原理、绕过技巧与修复方略

DVWA靶场实战:XSS攻击原理、绕过技巧与修复方略

1. 项目与靶场选择&#xff1a;为什么DVWA是练XSS的好教材 1.1 DVWA是什么&#xff0c;练XSS为什么绕不开它 DVWA&#xff08;Damn Vulnerable Web Application&#xff09;是一套开源的Web漏洞靶场&#xff0c;专门用来模拟真实业务里最常见的脆弱点。它把SQL注入、XSS、文件…

2026/10/19 17:40:46 阅读更多 →
数据库设计核心考点:事务、并发控制与性能优化全解析

数据库设计核心考点:事务、并发控制与性能优化全解析

1. 这一章到底在考什么&#xff1a;先看清下半场的牌面备考系统架构设计师的人都知道&#xff0c;第六章“数据库设计基础知识”是个让人又爱又恨的部分。爱的是它考点相对固定、拿分路径清晰&#xff0c;恨的是内容太碎——尤其是下半部分&#xff0c;事务、并发、恢复、安全、…

2026/10/19 17:40:46 阅读更多 →
AI图像生成五大模型对比:FLUX.2、Seedream、Z-image、Qwen-Image、GLM-Image选型指南

AI图像生成五大模型对比:FLUX.2、Seedream、Z-image、Qwen-Image、GLM-Image选型指南

近几年AI图像生成领域的竞争格局&#xff0c;可以说“月月都在刷新”。前两年大家还在讨论“AI能不能画出手”&#xff0c;现在话题早已升级成“谁的提示词理解更准、谁的风格控制更稳、谁的API更适合作业系统”。这次我想把目前讨论度最高的五个模型——FLUX.2、Seedream&…

2026/10/19 17:40:46 阅读更多 →
Spring Boot+MySQL员工信息管理系统:从数据库设计到部署避坑全指南

Spring Boot+MySQL员工信息管理系统:从数据库设计到部署避坑全指南

由于员工信息管理系统是计算机类毕业设计中出现频率最高的一类选题&#xff0c;很多同学拿到题目之后第一反应是“功能太简单、没啥可写”&#xff0c;但真正动手之后才发现处处是坑&#xff1a;框架版本不兼容、Mapper扫描不到、JSON序列化死循环、部署到服务器之后数据库连不…

2026/10/19 17:40:46 阅读更多 →
YOLO26轻量化优化:DualConv双卷积替换主干,mAP涨1.3且参数降27%

YOLO26轻量化优化:DualConv双卷积替换主干,mAP涨1.3且参数降27%

跑完新一轮YOLO26优化实验&#xff0c;我先把结论扔到前面&#xff1a;用轻量化双卷积DualConv替换掉主干网络里一部分标准卷积之后&#xff0c;模型mAP50-95涨了1.3个点&#xff0c;同时参数量从12.9M掉到9.4M&#xff0c;计算量从18.7G降到12.3G。这不是靠蒸馏&#xff0c;也…

2026/10/19 17:39:45 阅读更多 →

日新闻

频率跟踪型PWM电源设计:臭氧发生器谐振点漂移与软开关实现

频率跟踪型PWM电源设计:臭氧发生器谐振点漂移与软开关实现

简介&#xff1a;本资源为电源技术方向的学术研究文档&#xff0c;聚焦介质阻挡放电型臭氧发生器电源的频率跟踪型PWM控制策略&#xff0c;面向电力电子、高压电源及臭氧应用领域的科研人员与工程技术人员。针对负载呈容性、等效电容随外加电压升高而增大、谐振频率随之漂移的难…

2026/10/19 0:00:47 阅读更多 →
Vibe Coding 遇上 TaoToken:把开发者思维圣殿的灵感流接入统一 Key 通道

Vibe Coding 遇上 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/19 0:00:47 阅读更多 →
HundredCV-Chat话题建模实战教程:利用4,871个内置话题标签构建主题分析系统

HundredCV-Chat话题建模实战教程:利用4,871个内置话题标签构建主题分析系统

【免费下载链接】HundredCV-Chat 项目地址&#xff1a; https://ai.gitcode.com/hf_mirrors/Jax-dan/HundredCV-Chat 点击查看 免费下载 HundredCV-Chat 是一个由 100 位青年简历数据开发而来的中文多轮对话数据集&#xff0c;共包含 24,750 组日常闲聊对话和 4,871 个话题标签…

2026/10/19 0:00:47 阅读更多 →

周新闻

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

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

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

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

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

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

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

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

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

2026/10/19 1:30:52 阅读更多 →

月新闻

我发现了一个新思路:用 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/19 2:54:50 阅读更多 →
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/19 9:10:22 阅读更多 →
黑夜航拍船只数据集训练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/18 12:16:16 阅读更多 →