STM32F103唯一ID读取实战:原理、代码实现与高级应用
1. 项目概述为什么需要读取STM32的“身份证”在嵌入式开发中尤其是涉及产品量产、软件授权、设备身份识别或防抄板等场景时我们常常需要一个独一无二、无法篡改的硬件标识。这个标识就像是芯片的“身份证”。对于STM32系列单片机而言这个“身份证”就是它的唯一设备标识符。今天我们就来深入聊聊如何在STM32F103这款经典且应用广泛的芯片上准确、可靠地读取这个ID。你可能会有疑问我直接用个EEPROM存个序列号不就行了为什么非要读芯片内部的ID这里面的区别和意义可大了。首先芯片内部的唯一ID是在生产过程中由ST公司激光刻录或固化在芯片内部的对于每一颗STM32都是全球唯一的无法被用户修改或擦除。这保证了标识的绝对唯一性和不可伪造性。其次它不占用任何用户存储空间Flash或RAM是芯片的“原生属性”。基于这个ID我们可以实现许多高级功能比如生成绑定此硬件的软件激活码防止程序被复制到其他板子上运行在物联网应用中作为设备的唯一MAC地址或设备标识符在量产测试中自动记录每块板子对应的芯片信息实现精准溯源。STM32F103的ID存储在一个特定的内存地址区域读取它本质上就是去访问这个只读的内存区域。听起来简单但实际操作中从地址的理解、数据的读取到格式的转换每一步都有需要注意的细节。接下来我将带你从原理到实践完整走一遍这个过程并分享我在实际项目中积累的实操经验和避坑指南。2. 核心原理与存储结构深度解析要正确读取ID首先得知道它放在哪里、长什么样。STM32F103的唯一ID是一个96位即12字节的数据。根据ST官方参考手册这个ID的存储地址是0x1FFFF7E8到0x1FFFF7F4不同STM32系列地址可能不同F103是这个。这96位数据并不是随意排列的它包含了芯片的多种信息。2.1 ID地址映射与数据含义我们通过指针直接访问这个地址区域。具体来说0x1FFFF7E8开始的4个字节32位通常与芯片的晶圆批次相关。0x1FFFF7EC开始的4个字节是芯片在晶圆上的X坐标。0x1FFFF7F0开始的4个字节是芯片在晶圆上的Y坐标。这X、Y坐标的组合保证了在同一个晶圆批次内每颗芯片的ID也是唯一的。当我们读取时通常将这12个字节作为一个整体即一个96位的唯一标识符。在程序中我们常将其转换为一个16字节的十六进制字符串因为每个字节需要两个十六进制字符表示或者一个24字节的ASCII字符串如果你用%02X格式输出。注意虽然手册给出了地址但强烈建议使用ST标准外设库或HAL库中定义的宏来访问而不是直接写死0x1FFFF7E8。例如在标准外设库中这个地址通常被定义为(uint32_t*)0x1FFFF7E8或通过UID_BASE这样的宏。这样做的好处是如果你的项目未来需要更换到另一款STM32如F4系列其ID地址不同只需更新库文件你的代码无需修改可移植性大大增强。2.2 读取操作的硬件与软件本质从硬件层面看这个ID存储在一块特殊的OTP一次性可编程存储器或类似的只读存储单元中。CPU通过内部总线通常是AHB或APB总线访问这个物理地址。这个过程是只读的任何写操作都是无效的这从硬件上保证了ID的安全性。从软件层面看我们的代码需要做以下几件事声明指针定义一个指向uint32_t或uint8_t类型的指针并将其指向ID的起始地址。由于内存访问最好以32位对齐通常使用uint32_t*指针一次读取4字节效率更高。解引用读取通过指针解引用获取该地址存储的数据。数据重组将读取到的多个32位数据按照我们需要的顺序通常是大端或小端组合成最终的96位ID。格式化输出将二进制数据转换为便于显示、存储或传输的格式如十六进制字符串。这里有一个关键点STM32的内存系统是小端模式。也就是说一个32位数据例如0x12345678存储在内存中低字节0x78在低地址。当我们用uint32_t*指针从0x1FFFF7E8读取时读到的就是0x?? ?? ?? ??这个完整的32位值顺序是符合我们直觉的。但如果我们用uint8_t*指针逐个字节读取就需要关注字节序问题。不过在将ID转换为字符串时我们通常按照地址递增的顺序依次处理每个字节这样得到的字符串顺序是固定的、可预期的。3. 三种实战代码实现与对比理解了原理我们来看代码。我将展示三种不同开发环境下的实现方法标准外设库、HAL库以及纯寄存器操作。你可以根据你的项目情况选择。3.1 基于标准外设库的实现如果你的项目使用的是经典的STM32标准外设库StdPeriph Lib实现如下。首先确保你的工程包含了stm32f10x.h和相关头文件。#include stm32f10x.h #include stdio.h // 用于sprintf /** * brief 读取STM32F103的唯一ID96位 * param uidArray: 用于存储ID的数组至少12字节 * retval None */ void Get_STM32F103_UID(uint8_t *uidArray) { uint32_t *uid_addr (uint32_t*)0x1FFFF7E8; // 使用宏更好如 (uint32_t*)UID_BASE // 读取3个32位数据共96位 uint32_t uid_part0 uid_addr[0]; // 地址: 0x1FFFF7E8 uint32_t uid_part1 uid_addr[1]; // 地址: 0x1FFFF7EC uint32_t uid_part2 uid_addr[2]; // 地址: 0x1FFFF7F0 // 将32位数据分解为字节存入数组 // 注意内存布局这里按小端顺序将低地址字节放在数组前端是常见做法 uidArray[0] (uid_part0 0) 0xFF; uidArray[1] (uid_part0 8) 0xFF; uidArray[2] (uid_part0 16) 0xFF; uidArray[3] (uid_part0 24) 0xFF; uidArray[4] (uid_part1 0) 0xFF; uidArray[5] (uid_part1 8) 0xFF; uidArray[6] (uid_part1 16) 0xFF; uidArray[7] (uid_part1 24) 0xFF; uidArray[8] (uid_part2 0) 0xFF; uidArray[9] (uid_part2 8) 0xFF; uidArray[10] (uid_part2 16) 0xFF; uidArray[11] (uid_part2 24) 0xFF; } /** * brief 将UID数组转换为十六进制字符串 * param uidArray: UID数组 * param strBuffer: 输出字符串缓冲区至少需要25字节12字节*2 结束符 * retval None */ void UID_To_HexString(uint8_t *uidArray, char *strBuffer) { for(int i 0; i 12; i) { sprintf(strBuffer[i*2], %02X, uidArray[i]); // 格式化为大写十六进制 } strBuffer[24] \0; // 添加字符串结束符 } // 使用示例 int main(void) { uint8_t uid[12]; char uidStr[25]; Get_STM32F103_UID(uid); UID_To_HexString(uid, uidStr); // 现在可以通过串口打印 uidStr或者用于其他逻辑 // printf(Chip UID: %s\r\n, uidStr); while(1) { // 主循环 } }实操心得在标准库中直接使用地址指针是最快的方式。但务必注意0x1FFFF7E8这个地址位于系统内存区域不是Flash也不是RAM你的调试器在正常运行时可能无法直接查看这个地址的内容。我建议将读取到的UID通过串口打印出来这是最可靠的验证方式。另外数组uid的字节顺序即哪个字节算作UID的最高位取决于你的应用协议上述代码将uid_part0的最低字节放到了uid[0]这是按内存地址递增的常见顺序与用uint8_t*指针逐个读取的结果一致。3.2 基于HAL库的实现对于使用STM32CubeMX和HAL库的新项目过程类似但我们可以利用HAL库可能已经定义好的宏尽管HAL库本身没有专门读取UID的函数。通常我们需要自己定义地址或者查看stm32f1xx_hal.h中是否有相关定义。#include main.h #include stm32f1xx_hal.h // 如果HAL库未定义我们自己定义UID基地址对于F103 #define UID_BASE_ADDRESS 0x1FFFF7E8U void Get_Chip_UID_HAL(uint8_t *buffer) { uint32_t *pUID (uint32_t *)UID_BASE_ADDRESS; // 一次性读取三个32位字 uint32_t word0 pUID[0]; uint32_t word1 pUID[1]; uint32_t word2 pUID[2]; // 使用联合体(union)或内存拷贝进行转换这里使用更直观的移位操作 buffer[0] (uint8_t)(word0 0); buffer[1] (uint8_t)(word0 8); buffer[2] (uint8_t)(word0 16); buffer[3] (uint8_t)(word0 24); buffer[4] (uint8_t)(word1 0); buffer[5] (uint8_t)(word1 8); buffer[6] (uint8_t)(word1 16); buffer[7] (uint8_t)(word1 24); buffer[8] (uint8_t)(word2 0); buffer[9] (uint8_t)(word2 8); buffer[10] (uint8_t)(word2 16); buffer[11] (uint8_t)(word2 24); } // 或者一个更简洁的版本直接按字节指针访问 void Get_Chip_UID_HAL_Simple(uint8_t *buffer) { uint8_t *pUID (uint8_t *)UID_BASE_ADDRESS; for(int i 0; i 12; i) { buffer[i] pUID[i]; } }注意事项Get_Chip_UID_HAL_Simple函数更加简洁它直接以字节为单位遍历内存。这两种方法在结果上是等效的。在HAL库项目中我更喜欢第二种方法因为它意图更清晰——我们就是要12个连续的字节。同时建议将UID_BASE_ADDRESS的定义放在一个独立的头文件如chip_id.h中方便不同源文件引用和管理。3.3 纯寄存器操作实现如果你在写裸机程序或者追求极致的效率和可控性可以直接操作寄存器。对于读取固定地址内存来说这和上面的指针操作没有本质区别但可以让你更清楚地看到发生了什么。// 假设在一个没有标准库的环境下 #define UID_START_ADDR 0x1FFFF7E8 typedef volatile uint32_t vu32; typedef volatile uint8_t vu8; void Read_Chip_ID_Register(uint8_t uid_out[12]) { // 方法1使用32位访问 vu32* uid_reg (vu32*)UID_START_ADDR; vu32 w0 uid_reg[0]; vu32 w1 uid_reg[1]; vu32 w2 uid_reg[2]; // 将字数据分解到字节数组 *((vu32*)(uid_out[0])) w0; // 注意这依赖于编译器的字节序不推荐。 // 更安全的方法仍是逐字节赋值 uid_out[0] (w0 0) 0xFF; // ... 省略后续赋值同前例 // 方法2直接使用8位指针访问推荐清晰无歧义 // vu8* uid_byte (vu8*)UID_START_ADDR; // for(int i0; i12; i) { // uid_out[i] uid_byte[i]; // } }踩坑记录在早期的一次项目中我曾试图用*((uint32_t*)(uid_out)) w0;这样的内存拷贝来快速赋值结果在不同优化等级的编译下出现了字节序错乱的问题。这是因为这种操作直接操作了内存而编译器的行为可能不一致。血的教训是在处理这种需要精确字节顺序的数据时显式地使用移位和掩码操作或者逐字节拷贝是最安全、可移植性最好的方法不要为了所谓的“优化”而引入不确定性。4. 高级应用与功能扩展仅仅读出ID还不够关键在于怎么用。下面分享几个我在实际产品中用到的扩展应用。4.1 生成设备唯一序列号96位的ID很长直接使用不方便。我们可以通过一个哈希函数如CRC32、MD5或简单的自定义算法将其压缩成一个固定长度的短序列号例如4字节或8字节。#include stdint.h // 一个简单的哈希函数示例FNV-1a变种用于从UID生成一个32位序列号 uint32_t Generate_Serial_From_UID(uint8_t *uid, uint8_t len) { uint32_t hash 2166136261u; // FNV偏移基础值 for(int i0; ilen; i) { hash ^ uid[i]; hash * 16777619u; } return hash; } // 使用示例 uint8_t my_uid[12]; Get_STM32F103_UID(my_uid); uint32_t device_sn Generate_Serial_From_UID(my_uid, 12); // device_sn 可以作为设备的短序列号这个device_sn可以烧录到Flash的某个固定位置作为设备出厂信息的一部分比直接存储96位ID更节省空间。4.2 实现简易软件授权与防复制利用UID可以实现简单的软件绑定。思路是在程序初始化时读取UID然后与一个预先设定的“密钥”或算法进行计算得到一个结果。将这个结果与存储在Flash中的另一个值激活码进行比较只有匹配时软件才进入正常工作模式。#define ACTIVATION_CODE_ADDR 0x0800FC00 // Flash中存储激活码的地址示例 uint8_t Check_Software_License(void) { uint8_t uid[12]; uint32_t calculated_key; uint32_t stored_key; // 1. 读取芯片UID Get_Chip_UID_HAL_Simple(uid); // 2. 使用一个算法和主密钥计算本机的“激活码” calculated_key Your_License_Algorithm(uid, MASTER_SECRET_KEY); // 3. 从Flash指定地址读取之前存储的激活码 stored_key *(uint32_t*)ACTIVATION_CODE_ADDR; // 4. 比较 if(calculated_key stored_key) { return 1; // 授权成功 } else { return 0; // 授权失败可进入演示模式或限制功能 } }这里的Your_License_Algorithm是你自己设计的算法可以结合UID和一个只有你知道的MASTER_SECRET_KEY这个密钥不能出现在客户端代码中否则会被反编译找到进行计算。在量产时你通过一个离线工具根据每颗芯片的UID计算出对应的激活码然后通过烧录器写入到Flash的ACTIVATION_CODE_ADDR地址。这样程序就被绑定到了这块具体的硬件上。重要安全提示这种方法只能防君子不防小人对于有经验的破解者通过反汇编找到算法和比较点仍然可以绕过。但它能有效防止普通的程序复制粘贴显著提高了抄袭的门槛。对于高安全需求建议使用带有硬件加密功能的STM32系列如STM32L5。4.3 在物联网中作为设备标识在MQTT、CoAP等物联网协议中设备需要一个Client ID或Endpoint Name。直接使用UID的十六进制字符串就是一个绝佳的选择保证了全球唯一性。void Get_Device_ClientID(char *clientIdBuffer) { uint8_t uid[12]; char uidStr[25]; Get_STM32F103_UID(uid); UID_To_HexString(uid, uidStr); // 可以添加前缀如 DEV_ sprintf(clientIdBuffer, DEV_%s, uidStr); } // 得到的clientIdBuffer类似DEV_1234567890ABCDEF12345678将这个Client ID用于连接阿里云、AWS IoT、腾讯云等物联网平台可以免去你手动分配和管理设备标识的麻烦。平台后台可以直接用这个ID来区分设备。5. 调试技巧与常见问题排查实录即使原理和代码都清楚了第一次实操时还是可能遇到各种问题。下面是我总结的常见“坑点”和解决方法。5.1 问题一读出来的ID全是0xFF或0x00现象通过调试器查看内存地址0x1FFFF7E8或者串口打印出来的UID全部是0xFFFFFFFF或0x00000000。排查思路地址错误首先确认芯片型号是STM32F103并且你使用的地址是正确的。不同STM32系列的UID地址不同F1是0x1FFFF7E8F4是0x1FFF7A10一定要核对《参考手册》。调试器访问限制在调试模式下某些调试器特别是通过SWD接口可能无法直接访问系统内存区域。最可靠的验证方法不是看调试器的Memory窗口而是通过你的代码将数据打印到串口。在代码中读取UID后通过printf发送到串口用串口助手查看。代码优化检查编译器优化等级。如果读取UID的代码被编译器认为是“无副作用”的无效代码可能会被优化掉。确保存储UID的变量是volatile的或者将读取UID的函数返回值用于实际操作如打印、计算避免被优化。芯片问题极少数情况下可能是芯片本身的问题。换一颗同型号芯片测试一下。5.2 问题二每次上电读出的ID不一致现象程序运行中多次读取UID或者复位后重新读取得到的值不一样。排查思路指针或数组越界这是最常见的原因。检查你的数组是否足够大至少12字节检查指针操作是否越界破坏了相邻内存的数据。栈或堆溢出如果读取UID的函数使用了局部数组并且栈空间不足或者程序其他部分有内存溢出可能会覆盖这块内存。确保栈空间设置合理。缓存问题STM32F103没有数据缓存所以不是缓存一致性问题。但如果你是在有Cache的高端芯片如F7、H7上遇到此问题则需要考虑Cache的影响在访问这类特定内存地址前清空或禁用Cache。软件逻辑错误仔细检查你的读取和转换代码特别是字节序处理部分。用一个已知的模拟UID例如在内存中定义一个常量数组测试你的转换和打印函数确保逻辑正确。5.3 问题三UID转换的字符串格式不对现象读出的字节数据看起来是随机的但转换成字符串后与别人读出的格式不同比如字节顺序反了。解决方案明确你的需求。你需要的是大端序还是小端序的字符串通常按照内存地址从低到高依次排列字节得到的字符串是一种最自然、最常用的格式。编写一个测试函数用一组固定的字节数组如{0x12, 0x34, 0x56, 0x78, ...}输入给你的UID_To_HexString函数看输出是否符合你的预期。记录下你确定的转换规则并在整个项目包括上位机软件中保持一致。5.4 调试与验证最佳实践串口打印是王道无论你用什么调试器将UID以十六进制字符串形式通过串口打印出来是最直观、最不容易出错的方法。用串口助手或逻辑分析仪捕获这个字符串。编写单元测试为你的UID读取和转换函数编写简单的测试代码在开发初期就验证其正确性。对比官方工具如果条件允许使用ST官方的编程软件如ST-LINK Utility连接芯片它通常有一个“芯片信息”或“Unique ID”的查看界面将你读出的ID与工具显示的进行对比这是终极验证。注意供电稳定性在极端不稳定的电源环境下读取系统内存区域可能会出错。确保你的板子在读取ID时供电充足、稳定。读取STM32的芯片ID是一个小而精的必备技能它连接着硬件身份与软件逻辑。掌握它不仅能让你轻松完成设备标识、软件授权等任务更能加深你对单片机内存布局和底层访问的理解。希望这篇详尽的拆解和实战记录能让你在下次需要用到这个功能时信手拈来游刃有余。在实际项目中我习惯将UID读取函数封装成一个独立的模块并提供获取字符串、哈希值等不同格式的接口这样在任何需要的地方都能方便地调用让代码更加整洁和模块化。

相关新闻

Llama-3与vLLM部署优化:消费级显卡高效运行指南

Llama-3与vLLM部署优化:消费级显卡高效运行指南

1. 项目概述:当Llama-3遇上vLLM的化学反应去年在部署Llama-2时还在为OOM(内存不足)错误焦头烂额,如今Meta最新开源的Llama-3-8B-Instruct模型配合vLLM推理框架,在我的RTX 3090上竟然能跑出每秒50 token的生成速度。这个…

2026/7/30 7:18:53阅读更多 →
【面试题-多线程】什么是 ABA 问题,怎么产生的,怎么解决?

【面试题-多线程】什么是 ABA 问题,怎么产生的,怎么解决?

一篇吃透CAS的ABA问题:成因、风险与全套解决方案前言💡 并发编程中我们经常使用 CAS(Compare And Swap)实现无锁并发,相比重量级 synchronized拥有更高吞吐量。很多开发者熟练使用 CAS,却忽略它经典的ABA漏洞。 本文循序渐进讲清楚…

2026/7/30 7:18:53阅读更多 →
基于Django与人脸识别的智能考勤系统开发实践

基于Django与人脸识别的智能考勤系统开发实践

1. 项目背景与核心价值考勤管理是企业日常运营中最基础却至关重要的环节。传统刷卡、指纹等方式存在代打卡、设备磨损等痛点,而基于人脸识别的智能考勤系统正成为行业新趋势。我们团队最近用Django框架开发了一套融合人脸识别技术的企业级考勤系统,实测识…

2026/7/30 7:18:53阅读更多 →
CardView高级特性:交互状态管理与手势识别

CardView高级特性:交互状态管理与手势识别

CardView高级特性:交互状态管理与手势识别 【免费下载链接】CardView CardsView | CarouselView | CoverflowView | CubeView for Xamarin.Forms 项目地址: https://gitcode.com/gh_mirrors/ca/CardView CardView是Xamarin.Forms中一款功能强大的卡片视图组…

2026/7/30 18:32:19阅读更多 →
uniapp app端 和webview页面前后端沟通

uniapp app端 和webview页面前后端沟通

app里嵌入一个webview 前后端通信 在我的环境里面 不清楚原因是什么&#xff0c;似乎和通用的不一致 uniapp 里有个web-view用于嵌入h5页面 <web-viewref"webview":key"subUrl":src"subUrl":update-title"false"message"handl…

2026/7/30 18:32:19阅读更多 →
OpCore-Simplify终极指南:5分钟完成OpenCore EFI配置的智能解决方案

OpCore-Simplify终极指南:5分钟完成OpenCore EFI配置的智能解决方案

OpCore-Simplify终极指南&#xff1a;5分钟完成OpenCore EFI配置的智能解决方案 【免费下载链接】OpCore-Simplify A tool designed to simplify the creation of OpenCore EFI 项目地址: https://gitcode.com/GitHub_Trending/op/OpCore-Simplify 想在PC上安装macOS却被…

2026/7/30 18:32:19阅读更多 →
终极跨平台ffmpeg静态二进制文件解决方案:一键部署多媒体处理引擎

终极跨平台ffmpeg静态二进制文件解决方案:一键部署多媒体处理引擎

终极跨平台ffmpeg静态二进制文件解决方案&#xff1a;一键部署多媒体处理引擎 【免费下载链接】ffmpeg-static ffmpeg static binaries for Mac OSX and Linux and Windows 项目地址: https://gitcode.com/gh_mirrors/ff/ffmpeg-static ffmpeg-static 项目为开发者提供了…

2026/7/30 18:32:19阅读更多 →
如何5分钟搭建AI视频创作流水线:Pixelle-Video完全指南

如何5分钟搭建AI视频创作流水线:Pixelle-Video完全指南

如何5分钟搭建AI视频创作流水线&#xff1a;Pixelle-Video完全指南 【免费下载链接】Pixelle-Video &#x1f680; AI 全自动短视频引擎 | AI Fully Automated Short Video Engine 项目地址: https://gitcode.com/GitHub_Trending/pi/Pixelle-Video 在内容创作领域&…

2026/7/30 18:32:19阅读更多 →
统信UOS+沐曦C500 基于Ray集群多节点vLLM部署方案

统信UOS+沐曦C500 基于Ray集群多节点vLLM部署方案

基础环境 组件规格/版本操作系统UOS V25 服务器操作系统服务器型号鲲鹏920AI 加速卡沐曦C500Docker 版本v24.0.9 驱动安装 请参考&#xff1a;UOS V2500 沐曦驱动安装手册 部署步骤 在两个节点分别启动vllm容器 # 拉取容器镜像 # x86架构镜像 docker pull registry.uniont…

2026/7/30 18:30:19阅读更多 →
覆盖国产 + 海外 + 开源模型,OpenClaw 2.7.9 Windows/Mac 双端部署详解

覆盖国产 + 海外 + 开源模型,OpenClaw 2.7.9 Windows/Mac 双端部署详解

&#x1f539; 工具基础介绍 OpenClaw 是开源生态中一款实用性较强的本地智能工具&#xff0c;凭借本地离线运行、可视化图形操作和任务自动化三大核心特性&#xff0c;赢得了众多用户的青睐。与普通在线对话AI工具不同&#xff0c;它属于能够直接操控本机软硬件的智能数字员工…

2026/7/30 15:03:16阅读更多 →
伺服阀焊完微漏毁整机?精密激光焊接三关锁住高压

伺服阀焊完微漏毁整机?精密激光焊接三关锁住高压

所谓液压伺服阀体的精密激光焊接&#xff0c;是用激光束对阀座壳体&#xff08;通常为不锈钢或铝合金&#xff09;进行密封焊接&#xff0c;使阀体在21-35MPa的高压液压油或压缩气体中长期运行而不发生介质泄漏。液压伺服阀是高端液压系统的"大脑"。从航空航天飞行控…

2026/7/30 12:22:27阅读更多 →
D2DX:三步实现《暗黑破坏神2》高清宽屏体验的终极指南

D2DX:三步实现《暗黑破坏神2》高清宽屏体验的终极指南

D2DX&#xff1a;三步实现《暗黑破坏神2》高清宽屏体验的终极指南 【免费下载链接】d2dx D2DX is a complete solution to make Diablo II run well on modern PCs, with high fps and better resolutions. 项目地址: https://gitcode.com/gh_mirrors/d2/d2dx 你是否还在…

2026/7/30 15:13:02阅读更多 →
3分钟解锁iOS应用自由:TrollInstallerX让你的iPhone摆脱安装限制 [特殊字符]

3分钟解锁iOS应用自由:TrollInstallerX让你的iPhone摆脱安装限制 [特殊字符]

3分钟解锁iOS应用自由&#xff1a;TrollInstallerX让你的iPhone摆脱安装限制 &#x1f680; 【免费下载链接】TrollInstallerX A TrollStore installer for iOS 14.0 - 16.6.1 项目地址: https://gitcode.com/gh_mirrors/tr/TrollInstallerX 你是否曾经因为iOS系统的严格…

2026/7/30 0:00:58阅读更多 →
[GESP202606 四级] 扫雷

[GESP202606 四级] 扫雷

B4557 [GESP202606 四级] 扫雷 https://www.luogu.com.cn/problem/B4557 中国计算机学会&#xff08;CCF&#xff09;2026年6月C四级讲解——扫雷 https://www.bilibili.com/video/BV1MCMg6AEXR/ B4557 [GESP202606 四级] 扫雷 https://www.bilibili.com/video/BV1ZKTj6ZEVh/ 2…

2026/7/30 0:00:58阅读更多 →
Windows驱动存储终极清理工具:DriverStoreExplorer完全指南

Windows驱动存储终极清理工具:DriverStoreExplorer完全指南

Windows驱动存储终极清理工具&#xff1a;DriverStoreExplorer完全指南 【免费下载链接】DriverStoreExplorer Driver Store Explorer 项目地址: https://gitcode.com/gh_mirrors/dr/DriverStoreExplorer 您是否曾因Windows系统盘空间不足而烦恼&#xff1f;是否遇到过设…

2026/7/30 0:00:58阅读更多 →
YOLOv8推理性能优化:从1.2FPS到35FPS的全链路加速实践

YOLOv8推理性能优化:从1.2FPS到35FPS的全链路加速实践

如果你在部署 YOLOv8 时&#xff0c;发现推理速度只有可怜的 1-2 FPS&#xff0c;而别人的演示视频却能跑到 30 FPS 以上&#xff0c;那么问题很可能不在模型本身&#xff0c;而在于你的整个处理链路。很多开发者拿到一个训练好的 YOLOv8 模型后&#xff0c;会直接使用官方示例…

2026/7/30 0:27:26阅读更多 →
Coze与Dify对比指南:低代码AI应用开发从入门到实战

Coze与Dify对比指南:低代码AI应用开发从入门到实战

1. 从零到一&#xff1a;为什么你需要了解 Coze 和 Dify&#xff1f;如果你对 AI 应用开发感兴趣&#xff0c;但一看到“大模型”、“智能体”、“工作流”这些词就头疼&#xff0c;觉得门槛太高&#xff0c;那这篇文章就是为你准备的。很多开发者&#xff0c;包括我自己&#…

2026/7/30 4:47:18阅读更多 →
AI生图工具怎么选?2026年6月版实测对比

AI生图工具怎么选?2026年6月版实测对比

做自媒体的朋友应该都有体会&#xff1a;配图一直是个让人头疼的问题。2026年&#xff0c;AI生图工具已经非常成熟了&#xff0c;但工具太多反而不知道怎么选。以下是截至2026年6月我对主流AI生图工具的实测对比。Midjourney V8.1&#xff1a;速度之王2026年6月11日&#xff0c…

2026/7/30 15:43:46阅读更多 →