尧图网络 高端网站定制 · 原创设计
免费咨询热线
400-888-6620
免费获取方案
PS2手柄HAL库驱动:CubeMX工程与GPIO模拟时序源码详解
简介面向STM32开发者与嵌入式初学者的PS2手柄通信实战源码包依托HAL库和CubeMX工具解决从PS2协议解析到外设驱动编写的完整流程。资源包内共970个文件以c/h源码、s汇编及icf链接配置为主同时包含ioc配置文件、uvprojx工程文件整体约22.2MB目录按User、Inc、MDK-ARM、Src等划分便于定位初始化代码、头文件与驱动实现。包内重点提供基于STM32的PS2手柄控制器实现围绕时钟线、数据线的串行通信机制给出ps2_init、ps2_read_data及中断处理等驱动函数并配合CubeMX生成的时钟与GPIO配置可以直观理解STM32的GPIO操作、定时器用法及HAL库的封装逻辑。已有5422人学习下载适合希望掌握CubeMX项目生成、STM32外设驱动编写和游戏手柄通信协议的开发者作为参考模板。1. 定位为什么这是最快跑通PS2手柄的方案之前做一个遥控小车的小项目卡在手柄通信上整整三天读回来的按键全是 0xFF当时差点以为买到了坏手柄。后来放弃标准库手写寄存器那套换成了 HAL 库加 CubeMX 生成的工程框架一个下午就把 PS2 手柄的按键、摇杆、震动全部调通了。这份 PS2 手柄 HAL 库 CubeMX 源码就是这样的存在一个可以直接打开、编译、烧录的工程里面把 PS2 手柄的时钟时序、数据帧读取、按键解析、摇杆映射和震动控制都封装成了独立模块。你不用再对着参考手册逐位配置 GPIO也不用手动初始化时钟树CubeMX 把所有外设配置提前生成了。适合正在做小车、机械臂、云台、遥控摄像头这类项目的开发者尤其是那些想把手柄快速接入主控、而不是花一周时间研究协议文档的人。你要是只想拿一个能跑的手柄驱动这套源码会非常顺手。2. 工程骨架CubeMX 配置与源码目录的对应关系2.1 打开 CubeMX 后最该关注的四个配置项这个工程的核心是让主控芯片通过 GPIO 模拟 PS2 手柄的通信时序所以 CubeMX 里的关键不是某一个复杂外设而是四根信号线的引脚分配和模式。PS2 手柄接口有六根有效线VCC、GND、DATA、CMD、CS也叫 ATT、CLK。其中 DATA 是手柄向主机返回数据CMD 是主机向手柄发送指令CS 是片选使能CLK 是主机产生的时钟。在 CubeMX 里CMD、CS、CLK 都要配成推挽输出DATA 配成输入模式建议下拉或者浮空都可以看手柄上拉情况再调。引脚分配不是固定的你完全可以在 CubeMX 的 Pinout 视图里手动改。下面是我常用的一组映射源码里也基本是这个布局手柄引脚CubeMX 标签GPIO 模式说明DATAPS2_DAT输入下拉/浮空手柄返回数据CMDPS2_CMD推挽输出主机发送指令CS / ATTPS2_CS推挽输出片选使能低电平有效CLKPS2_CLK推挽输出时钟线由主机控制VCC3.3V / 5V电源按手柄型号匹配电平GNDGND电源与主控共地注意 VCC 这一项最容易翻车。原装手柄和大部分副厂手柄工作在 3.3V 到 5V 之间如果你的主控板是 3.3V 逻辑建议先接 3.3V 试如果读不到数据再换 5V。我见过不少案例是 5V 供电加上电平不匹配直接把 GPIO 烧了。另外 CubeMX 里记得把 GPIO 的初始电平设置一下CLK 和 CS 默认拉高CMD 默认拉高这样手柄上电后不会收到一段乱时序。除了 GPIO这个工程还开了两个外设一个串口用于打印调试信息一个定时器输出 PWM 用于摇杆映射或者震动强度控制。串口不是必须的但强烈建议保留调试手柄通信时打印原始帧比用眼睛看灯快得多。PWM 的配置也很简单选一个定时器通道频率设成 1kHz 到 10kHz 之间占空比初始设 0后面在代码里动态改。2.2 目录结构改动集中在哪几个文件CubeMX 生成的工程目录结构比较固定核心源码放在 Core 目录下驱动文件在 Drivers 目录下。这套源码额外加了一个 ps2 目录或者一对 ps2.c / ps2.h 文件一般放在 Core/Src 和 Core/Inc 里方便一起编译进工程。拿一个典型的 CubeMX 工程来说打开后你会看到这些目录目录 / 文件职责要不要改Core/Src/main.c主循环调用手柄读取和解析要改业务逻辑在这Core/Src/gpio.cCubeMX 生成的 GPIO 初始化基本不用动Core/Src/tim.cPWM 定时器初始化按 PWM 通道确认Core/Src/usart.c串口初始化不用动Core/Src/ps2.c手柄时序读取、帧解析、震动指令重点看这个Core/Inc/ps2.h手柄相关宏、结构体、函数声明映射关系在这改ps2.c 和 ps2.h 是整个工程的灵魂。ps2.h 里定义了引脚宏比如 PS2_CLK_Pin、PS2_DAT_Pin 这些CubeMX 生成的引脚宏其实已经放在 main.h 里了但为了模块独立一般会在 ps2.h 里重新映射一次。这样做的好处是以后你换一块板子只需要改 ps2.h 里的引脚宏不用动驱动逻辑。main.c 里的改动也很集中。初始化阶段调用 PS2_Init主循环里调用 PS2_ReadFrame 拿到原始数据再调用 PS2_Parse 解析成结构体。剩下的就是你想用这些数据做什么了控制电机、驱动舵机、调节云台角度都跟手柄驱动本身解耦了。这一点算是工程结构上最值得学习的部分手柄驱动不依赖具体业务业务层也不关心时序细节。2.3 从生成代码到点亮第一个键值三步跑起来这套源码跑起来的路径很短前提是你电脑上装了对应芯片的 CubeMX 和编译环境。第一步用 CubeMX 打开工程里的 .ioc 文件确认芯片型号和你的开发板一致。如果不一致需要在 CubeMX 里重新选芯片然后保持引脚配置不变重新生成代码。这里有个小技巧生成前先看一眼 .ioc 里的引脚分配如果和你手头的板子对不上直接在 Pinout 视图里改完再生成。第二步把 ps2.c 和 ps2.h 放进工程。如果你用 CubeIDE直接右键 Core/Src 目录导入现有文件即可。如果用的是 Keil 或者 IAR需要在工程管理里把 ps2.c 加进源文件组同时把 ps2.h 所在的路径加到头文件搜索路径里。这一步漏了会报一堆未定义的函数不是什么玄学就是文件没加进编译列表。第三步在 main.c 里接上调用编译烧录打开串口助手看数据。主循环代码大概是这样的uint8_t frame[9]; PS2_Report report; while (1) { PS2_ReadFrame(frame, 9); // 读取一帧手柄数据 PS2_Parse(frame, report); // 解析成按键与摇杆结构体 printf(start%d select%d lx%d ly%d rx%d ry%d\r\n, report.key_start, report.key_select, report.lx, report.ly, report.rx, report.ry); HAL_Delay(5); // 控制帧率太快没必要 }编译和烧录可以直接在 IDE 里点按钮完成也可以用命令行工具比如用 st-flash 配合 make 构建出来的 bin 文件烧录。串口波特率看 usart.c 里的初始化配置一般 115200 比较多。如果你发现串口打出来全是 0xFF先别急着怀疑代码大概率是手柄没有进入正常数据模式或者是 CS 和 CLK 的极性反了。具体怎么排查后面避坑章节会细讲。跑通之后你就有了一台可以实时输出手柄数据的最小系统。接下来不管是接电机驱动板还是接舵机控制板逻辑都是在 PS2_Parse 之后加一段业务代码而已。这套工程的价值就在这里通信链路已经通了一半剩下的是你的应用场景。3. 核心模块拆解从 GPIO 模拟时序到按键事件3.1 为什么这套驱动不用硬件 SPIPS2 手柄的通信时序长得非常像 SPI也有 CLK、CMD、DATA、CS 四根线也是主机产生时钟、按位收发数据。但如果你直接拿 MCU 的硬件 SPI 外设去接大概率读回来的数据是乱的。原因是 PS2 的协议在细节上和标准 SPI 有差异它没有像 SPI 那样严格的极性极相配置时钟的占空比要求也比较宽松而且 CS 拉低后手柄需要一小段稳定时间硬件 SPI 在片选管理上不够灵活。更实际的问题是很多 MCU 的 SPI 外设引脚是固定的你可能正好把 PS2 的引脚分配到了非 SPI 复用引脚上。用 GPIO 模拟时序就没有这个限制随便哪四个引脚都能做CubeMX 里配一下就好了。对 PS2 这种低速设备来说GPIO 模拟完全够用时钟频率控制在 250kHz 以内一帧数据 9 字节算下来一帧耗时不到一毫秒远快于人手的操作频率。我一般会用一个微秒级延时函数来控制时钟频率。CubeMX 生成的 HAL 库只提供了豪秒级HAL_Delay微秒延时需要自己封装用 DWT 计数器或者定时器都行。如果你不想折腾直接在循环里放几个空操作也可以就是频率不太可控极端情况下会偶发错位。驱动里我封装了一个PS2_DelayUs逻辑很简单就是对 DWT-CYCCNT 做循环等待移植到别的芯片时把这个函数替换成对应的微秒延时实现即可。这套驱动另一个设计重点是帧的结构。PS2 手柄的通信以字节为单位主机发起一次片选后连续收发 9 个字节。前两个字节通常是握手固定值和模式码中间是按键状态最后是摇杆数据。协议本身不复杂复杂的是时序要对、字节顺序要对、位序要对。这三点任何一个不对解析出来的数据就是乱的。3.2 PS2_ReadFrame逐位读写代码逐行讲核心读取函数并不长逻辑很直白先拉低 CS 告诉手柄“我要开始通信了”然后逐字节、逐位地产生时钟每产生一个时钟下降沿主机送出一位 CMD 数据同时从 DATA 线上读回一位手柄数据最后拉高 CS 结束一帧。下面是去掉无关代码后的核心实现uint8_t PS2_ReadFrame(uint8_t *frame, uint8_t len) { // CS拉低启动一帧通信len一般为9字节 HAL_GPIO_WritePin(PS2_CS_GPIO_Port, PS2_CS_Pin, GPIO_PIN_RESET); for (int byte_idx 0; byte_idx len; byte_idx) { uint8_t rx 0; for (int bit_idx 0; bit_idx 8; bit_idx) { // CLK拉低主机准备输出一位CMD HAL_GPIO_WritePin(PS2_CLK_GPIO_Port, PS2_CLK_Pin, GPIO_PIN_RESET); // 按位送出CMD数据PS2协议低位在前 GPIO_PinState cmd_bit (tx_data (0x01 bit_idx)) ? GPIO_PIN_SET : GPIO_PIN_RESET; HAL_GPIO_WritePin(PS2_CMD_GPIO_Port, PS2_CMD_Pin, cmd_bit); PS2_DelayUs(2); // 等待信号稳定2us对应约250kHz时钟 // 在时钟低电平期间读取DATA线上的返回位 if (HAL_GPIO_ReadPin(PS2_DAT_GPIO_Port, PS2_DAT_Pin) GPIO_PIN_SET) { rx | (0x01 bit_idx); } // CLK拉高完成一个时钟周期 HAL_GPIO_WritePin(PS2_CLK_GPIO_Port, PS2_CLK_Pin, GPIO_PIN_SET); PS2_DelayUs(2); } frame[byte_idx] rx; // 保存当前字节 } // CS拉高结束一帧通信 HAL_GPIO_WritePin(PS2_CS_GPIO_Port, PS2_CS_Pin, GPIO_PIN_SET); return frame[0]; }这段代码里几个参数值得单独说明。PS2_CS_GPIO_Port和PS2_CS_Pin是 CubeMX 生成的引脚宏它们定义在 main.h 里ps2.h 会把这个宏重新映射成 PS2_CS_GPIO_Port这样驱动层写的引脚名称和业务代码隔离。tx_data是主机发送的字节在完整的驱动里它来自一个长度为 9 的发送缓冲区前三字节固定发0x01 0x42 0x00这是让手柄切换到数据模式的指令序列。PS2_DelayUs(2)控制时钟频率2 微秒对应时钟周期 4 微秒也就是 250kHz这正好是 PS2 协议的上限附近。移位方向也是一个关键参数。我用的是0x01 bit_idx也就是每个字节的最低位先发先收。PS2 协议本身是低位在前如果你的手柄读出来按键位置整体错位比如按 Start 却触发了 Select那大概率是把位序写反了。把移位改成0x80 bit_idx再试一次即可这是拿到陌生手柄时最常遇到的调整项。读完一帧后frame[0]如果返回0xFF说明握手基本成功。正常情况下frame[1]会返回0x41这是手柄在数据模式下的标志。如果返回0x73说明手柄还在配置模式需要再发一次完整配置指令才能切过来。这个判断逻辑放在 PS2_Parse 里业务代码不需要关心。3.3 返回数据解析15 个字节里藏着什么PS2 手柄的返回帧在不同文档里写法不太一样常见的是 9 字节但这 9 个字节的具体含义存在版本差异。我这个工程里用的解析方式经过多款手柄验证基本覆盖了市面上主流的副厂手柄。按字节顺序来看含义如下字节含义典型值frame[0]握手固定值0xFFframe[1]模式码0x41 数据模式 / 0x73 配置模式frame[2]固定值0x5Aframe[3]按键状态低字节位为 0 表示按下frame[4]按键状态高字节位为 0 表示按下frame[5]右摇杆 X 轴0x00 - 0xFFframe[6]右摇杆 Y 轴0x00 - 0xFFframe[7]左摇杆 X 轴0x00 - 0xFFframe[8]左摇杆 Y 轴0x00 - 0xFF按键部分要特别注意PS2 的按键状态是低电平有效也就是对应位读到 0 才代表按键按下。这和大部分 MCU 按键扫描默认高电平有效是反的我第一次用的时候就是忘了这层取反导致按键状态全部反了过来。另外 frame[3] 和 frame[4] 里的位定义在不同手柄上可能存在一两个键的差异比如 L3、R3 按下时是否在摇杆数据上同时体现这个要做一下实测。摇杆数据是 8 位无符号数中位值大概在 128 附近。解析函数返回的是原始值具体要不要做中心点校准取决于你的应用。比如做小车你可能希望摇杆在中位时电机完全停止那就需要把 128 当作零点把差值映射成有符号的 PWM 占空比。这个映射属于业务逻辑我没有放进手柄驱动层而是暴露接口让上层自己处理。我习惯把解析结果装进一个结构体方便后续代码引用typedef struct { uint8_t mode; // frame[1]0x41为数据模式 uint8_t key_start; // 1表示按下 uint8_t key_select; uint8_t key_l1; uint8_t key_r1; uint8_t key_l2; uint8_t key_r2; uint8_t lx; // 左摇杆X0~255 uint8_t ly; // 左摇杆Y uint8_t rx; // 右摇杆X uint8_t ry; // 右摇杆Y } PS2_Report;解析函数做的事情就是把 frame 里的位拆进这个结构体。比如report-key_start !(frame[3] 0x10)就是把 frame[3] 的第 4 位取反之后赋值。这种写法比用位域更稳因为位域在数组里的内存布局跟字节序有关换了编译器可能有坑直接位运算反而最可靠。结构体定义放在 ps2.h 里上层业务代码 include 之后可以直接引用。3.4 摇杆映射与震动控制从协议到 PWM 输出拿到摇杆原始值之后下一步通常是把它转成 PWM 占空比。以小车为例左摇杆 X 轴控制左右转向右摇杆 Y 轴控制前进后退。映射公式很简单把 0 到 255 的原始值减去 128得到一个-128 到 127的偏差然后缩放成占空比。要注意的是摇杆存在一个死区问题手柄归中时数值不一定是严格的 128经常是 125 到 131 之间飘。如果不做死区处理小车通电后哪怕你不碰摇杆它也会自己小幅抖动看起来很滑稽。震动的实现比摇杆映射多一步协议配置。PS2 手柄默认是不震动需要主机发送一段专用的配置指令把震动模式打开。常见做法是在初始化阶段发送0x01 0x42 0x00 0x00 0x01这样的指令序列然后再发送震动参数。驱动里我封装了一个PS2_SetVibration(uint8_t motor1, uint8_t motor2)内部会构造一帧指令并通过同一个 GPIO 时序发送出去。motor1 是左侧小电机一般控制高频震动motor2 是右侧大电机控制低频强震。真正驱动震动电机的是外部电路不是 GPIO 直接带动的。手柄内部有驱动电路主机这边只需要在每条返回帧的发送区里更新震动值即可。这也是 PS2 手柄方便的地方不像普通直流电机还要自己搭 H 桥手柄已经把驱动部分做进去了。如果震动没反应先查初始化指令有没有成功发送再查发送频率震动指令必须周期性重复发送只发一次手柄过一会儿会自动退出震动状态。从整体数据流来看这套驱动的链路是GPIO 模拟时序读写一帧原始数据然后按字节解析成 PS2_Report 结构体业务代码再根据结构体里的按键和摇杆值去控制 PWM。每一层只做一件事层与层之间通过结构体解耦。这种分层方式在资源紧张的 MCU 工程里不算复杂但很实用后期要加新按键或者换通信方式都不用改动外层逻辑。4. 避坑记录五个高发问题的现象、原因与解决4.1 读回来的帧全是 0xFF现象是串口打印出来的 frame[0] 一直是 0xFF按键怎么按都没反应。第一次遇到这个问题会怀疑手柄坏了实际上手柄坏的几率很低大概率是手柄从来没有进入正确的数据模式。原因有两类。一是初始化时没有发送完整的配置指令序列PS2 手柄上电默认在配置模式不切到数据模式就不返回按键数据。二是 CS 片选的时序不对比如初始化之前 CS 一直是低电平手柄处于忙状态根本不会响应主机。解决方法是先确认初始化流程上电后延时 100ms 以上再发配置指令发完0x01 0x42 0x00检查返回的 frame[1] 是否变成 0x41。在调试时可以用逻辑分析仪抓 CS、CLK、DATA 三根线看主机发指令时手柄有没有在 DATA 线上返回数据。如果 frame[1] 一直是 0x73说明配置指令没有被正确接收优先排查 CS 拉低的时机和 CMD 数据有没有按要求发送。4.2 摇杆数值跟着供电电压漂现象是摇杆不动时数值不是稳定在 128 附近而是 100 到 160 之间大幅跳动或者随着电机运转明显漂移。这个现象在接了大功率电机驱动板的系统上尤其明显电机一转摇杆值就飘。原因本质上是电源被污染。电机启动瞬间电流很大如果手柄和电机共用一个电源电压跌落会直接反映到 ADC 采样和逻辑电平上。手柄内部的摇杆电位器对电压变化很敏感供电不稳读出来的数值自然不稳。解决方法是把电源分开或者加滤波。最简单的做法是给手柄单独接一个 3.3V 或 5V 的 LDO电路板布局上让电机电源远离手柄电源。如果继续用同一个电源至少在手柄供电引脚旁边并一个 100uF 电解电容和 0.1uF 瓷片电容。调试时可以用示波器看手柄 VCC 引脚如果发现电机启动时电压有超过 100mV 的跌落说明这路供电需要单独处理。4.3 CLK 拉得太快导致偶发错位现象是手柄大部分时间工作正常但偶尔会出现某个按键值突然变成 0x7F 或 0xFE 之类的异常数据而且没有规律。这种偶发问题最难查经常被误判为接触不良。原因是 GPIO 模拟时序时 CLK 频率太快超过了手柄能响应的极限。PS2 规范要求时钟周期不小于一定值如果你在主循环里频繁调用读取函数延时又不够CLK 的有效电平时间过短手柄内部的移位寄存器来不及采样就会产生错位。解决方法是把 PS2_DelayUs 的延时加大。我的驱动默认 2 微秒也就是 250kHz 附近。如果你发现偶发错位先加到 4 微秒甚至 8 微秒试试。PS2 手柄并不会因为时钟慢而丢数据降到 100kHz 依然可以正常通信但稳定性会好很多。这个参数是实测出来的不同副厂手柄对时钟的敏感度不一样遇到不稳定的手柄把频率调低通常能解决。4.4 上电后前几次读取是垃圾数据现象是程序刚烧录完串口打印的前三五帧数据明显异常比如 mode 字段既不是 0x41 也不是 0x73然后过几帧自己恢复正常。这个现象容易让人误以为代码有 bug但实际上是在正常不过的启动时序问题。原因是手柄和主控上电时间不一致。主控启动速度比手柄快很多主控已经在跑 while 循环读数据了手柄还在初始化过程中此时 DATA 线上的电平是随机状态读到什么都正常。解决方法是加一个开机延时和丢帧逻辑。在 PS2_Init 里加 200ms 延时再在主循环开头丢弃前 5 帧数据。可以把丢弃逻辑写成一个简单计数器前几次读取只调用读取函数但不做业务处理。这里要提醒一点不要用 HAL_Delay(200) 直接放在电机初始化之前如果系统里有其他外设也依赖快速启动尽量把手柄初始化放到最后或者先读取但不解析。4.5 键值能读但震动没反应现象是按键和摇杆都很正常但调用震动接口后手柄没有任何反应。很多人会去查驱动电路结果问题根本不在硬件上。原因有两个层面。第一震动模式没有正确开启主机只在初始化时发送了一段震动使能指令之后就没有周期性发送手柄超时自动退出震动状态。第二震动指令发送的时机不对PS2 手柄的震动参数是嵌在数据帧里的需要和按键查询帧一起发送如果你单独发一帧震动指令而不带查询指令手柄会忽略。解决方法是把震动指令和读取帧合并。在每次 PS2_ReadFrame 之前根据当前的震动值构造发送缓冲区把震动电机数值填入对应字节然后再执行片选通信。这样每一帧都在同时更新按键查询和震动参数手柄就不会退出震动状态。我在驱动里把发送缓冲区的构造独立成一个函数业务代码只需要设置PS2_SetVibration的参数剩下的合并逻辑由驱动自动处理。5. 二次开发把手柄驱动改造成自己的模块跑通这套源码之后你大概率不会直接拿它做产品而是要把手柄驱动嵌进自己的工程里。我建议的改造方向是把手柄模块和业务逻辑彻底分离做成一个可以被任意主循环调用的独立组件。先定义一张事件表把按键和摇杆统一成枚举事件。这样业务代码不用关心手柄协议的细节只管响应事件。比如定义一个PS2_Event结构体包含事件类型和数值按键按下产生一次触发事件摇杆变化产生更新事件。然后注册一个回调函数指针驱动在解析完一帧数据后自动调用回调业务层在这个回调里处理自己的逻辑。这个模式在裸机工程里同样适用不算过度设计。如果工程已经在用 FreeRTOS可以把手柄读取放进一个独立的任务用队列把解析结果发给控制任务。手柄读取频率 5ms 一帧队列长度设 8 就行避免读太快丢帧也避免队列溢出。这样做的收益是手柄驱动和主控任务完全隔离控制任务不需要关心手柄读取什么时候完成只要阻塞在队列上等待数据即可。移植到其他芯片时只需要替换 ps2.c 里的引脚宏和延时函数实现。CubeMX 生成的代码会变但 ps2.c 里的逻辑不用动。我一般会把 ps2.h 里的引脚宏改成可以在编译时通过宏开关切换的形式方便一套代码支持多块板子。这样做之后后续玩新板子就是复制两个文件、改几个宏定义的事。我从那以后每次拿到一块新开发板都会先把手柄驱动用逻辑分析仪抓一遍时序确认波形正常再写业务逻辑这个习惯帮我省了很多来回烧录的冤枉时间。希望帮到你。本文还有配套的精品资源点击获取
RELATED

相关推荐

Gompertz各向异性扩散图像去噪Matlab实现与调参技巧

Gompertz各向异性扩散图像去噪Matlab实现与调参技巧

简介:基于Gompertz分布函数的各向异性扩散滤波Matlab代码包,专为图像去噪与边缘保持场景设计,适用于计算机、电子信息工程、数学等专业学生的课程设计、期末大作业和毕业设计。包内共15个文件,含2个m格式主程序、7个tif与6个png格…

📅 2026/10/20 13:16:50
Python疗愈日志分析:情感打分与趋势可视化实践

Python疗愈日志分析:情感打分与趋势可视化实践

要说明白这件事,得先亮个底:我自己有一套用Python写的疗愈日志分析脚本,它不提供诊断、不替代心理咨询,只做一件事——把我记录下来的情绪文本,转换成可以回看的趋势图、关键词和时间线。这套代码我自己断续用了一年多…

📅 2026/10/20 13:11:48
还在本地硬扛大模型?试试 Ollama Cloud,顺便把 OpenCode 也升级了

还在本地硬扛大模型?试试 Ollama Cloud,顺便把 OpenCode 也升级了

/* 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 13:11:48
MORE NEWS

更多资讯

📰

华为交换机GVRP实验:动态VLAN注册、Trunk配置与避坑指南

简介:面向网络工程师、高校学生及备考华为认证的实践者,这份华为GVRP实验配置文档以四台交换机S1至S4互联为拓扑,演示GVRP动态注册与注销VLAN的全过程。文档先厘清Normal、Fixed、Forbidden三种注册模式的含义:Normal允许多VLAN动…

📰

GCC编译流程四阶段深度解析:预处理、编译、汇编、链接

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

📰

登山老手也迷路?四大隐蔽迷路陷阱与保命清单

"登山老手也迷路?四条最隐蔽的迷路陷阱与保命牌"很多人觉得登山迷路是新手才会遇到的事,拿着一张地图、手机充满电、跟着成熟路线走,怎么想都不该出事。但我在山区参与救援协调工作时见过太多反例:有跑了八年越野跑的老…

📰

通达信DLL编程实现一机一码授权:从原理到避坑指南

简介:这份资源面向具备C基础、希望在通达信中实现授权验证的量化开发者与证券软件爱好者,核心是用DLL插件在通达信公式里调用接口,生成与每台机器唯一绑定的标识码,用于激活验证与许可证管理。压缩包共13个文件、约88KB&#xff0…

📰

Hugging Face Inference API 实战:从模型到稳定线上推理服务

直接说结论:pip install transformers只是模型旅程的第一步,真正麻烦的从“把模型跑起来”到“让模型稳定地对外提供服务”才开始。本地起了个 Python 进程、GPU 显存吃满、API 能返回结果,这些在原型阶段看着挺美,可一旦面对真实…

📰

自适应哈夫曼编码:流式数据压缩中的动态树与同步机制

简介:这是一份自适应哈夫曼编码的C完整实现,适合正在学习数据压缩算法、哈夫曼树与动态编码原理的开发者。与静态哈夫曼编码不同,自适应版本在编码过程中根据字符频率变化实时更新哈夫曼树,特别适合流式数据或字符分布动态变化的场…

TODAY

今日更新

THIS WEEK

本周精选

THIS MONTH

本月热门

读完文章,想聊聊您的网站?

告诉我们您的行业与需求,资深顾问一对一梳理方案与报价,全程免费。

📞 💬