STM32驱动28BYJ-48步进电机:ULN2003接线、相序表与定时器中断详解

简介:基于STM32F103的28BYJ-48四相五线步进电机驱动源码包,面向嵌入式初学者与电机控制开发者,解决步进电机的精确角度控制、转向控制与脉冲调速问题。项目使用标准外设库编写,代码中涵盖GPIO推挽输出配置、定时器中断产生脉冲、PWM调速思路以及按键切换控制逻辑,能够帮助读者理解整步、半步与细分模式下的电机驱动时序,并掌握从原理图到固件实现的关键链路。压缩包共79个文件,压缩后大小约292KB。文件以.c/.h源文件和.s启动文件为主,同时包含Keil工程配置(uvprojx/uvoptx)、调试配置、清理脚本以及STM32F10x标准库组件;目录按Hardware、Library、Start、User等模块组织,便于查阅、移植和二次开发。目前已有5254人学习下载,适合希望通过完整可编译工程边读边练,快速建立STM32定时器与步进电机驱动项目实战认知的嵌入式学习者。

1. 小电机的大脾气:28BYJ-48 为什么需要一套正经的 STM32 驱动源码

有个正在做小型自动化设备的开发者曾经被一个算不上复杂的问题卡了一周:手里拿到的源码:STM32 驱动步进电机 28BYJ-48,已经是别人跑通过的版本,自己也改了三遍,唯独电机上电后只“嗒”了一声就再没动静。最后查出来的原因特别简单——代码里的相序表按 A、B、C、D 设计,而手上这块 ULN2003 驱动板的丝印顺序是 C、D、B、A,正好错开三拍。这种问题靠看原理图很难看出来,只有一份既讲接线又讲时序的驱动源码才能照着查。这份工程的价值就在这:把 28BYJ-48 电机、ULN2003 驱动板和 STM32 的 GPIO、定时器串成一条完整驱动链,相序表、半步时序、中断调速、转向与位置计数都有完整实现。适合刚把 HAL 库跑熟、准备做门禁、窗帘、转台这类小型步进设备的开发者,也适合“项目就差电机不转”的救火场景。

2. 硬件链路与工程骨架:ULN2003 接线顺序和定时器的初始化设计

要让电机转起来,第一步不是写代码,而是把“电”和“信号”两套关系理顺。很多人一上来就在 CubeMX 里点点点,烧进去发现电机原地抖动,问题十有八九出在接线顺序而不是代码上。

2.1 接线顺序与电平转换:GPIO 引脚选型与 ULN2003 驱动板的对应关系

28BYJ-48 是五根线的小型减速步进电机,五根线里一根是电源正,其余四根是 A、B、C、D 四相绕组。电机额定电压 5V,单相额定电流约 200mA。如果用 STM32 的 GPIO 直接去推线圈,推不动,因为 GPIO 拉电流能力有限,3.3V 电平对电机绕组来说也偏低。所以中间必须夹一块 ULN2003 驱动板。

ULN2003 是达林顿管阵列,输入侧高电平有效,输出侧为集电极开路灌电流,相当于替 GPIO 做了电平转换和功率放大。驱动板和电机之间的接线通常有两排端子:一排是 IN1、IN2、IN3、IN4,另一排是电源和地。这里第一个坑就是线序:不同批次的线颜色并不统一,红、橙、黄、粉、蓝五根线里,红色是 5V,其余四根到底哪根算 A 相哪根算 D 相,只能按实际板子丝印和测试来定,不能只看颜色。

信号28BYJ-48 端ULN2003 板端STM32 引脚
电源红线5V、GND外部 5V 供电
IN1橙线IN1PB0
IN2黄线IN2PB1
IN3粉线IN3PB2
IN4蓝线IN4PB3

上面的接线表是我第一版的样子,它不一定和你手里的板子完全一致。所以后面的相序验证小节会专门讲怎么确认线序。

选 GPIO 时有几个现实约束。第一,别选被开发板占用的引脚,例如某常见开发板的板载 LED 占用了 PB0、PB1,接了电机就冲突,换到 PA0~PA3 或者 PC0~PC3 更省事。第二,GPIO 要配成推挽输出、无上下拉。开漏输出在没有上拉的板子上会让相线处于半浮空,电机表现为低速抖、高速丢步。

/* gpio_init.c —— 四路相线的 GPIO 初始化 */ static void MX_GPIO_Init(void) { GPIO_InitTypeDef gpio = {0}; __HAL_RCC_GPIOB_CLK_ENABLE(); gpio.Pin = GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_2 | GPIO_PIN_3; gpio.Mode = GPIO_MODE_OUTPUT_PP; /* 推挽输出,别用开漏 */ gpio.Pull = GPIO_NOPULL; /* 外部驱动板自带逻辑电平 */ gpio.Speed = GPIO_SPEED_FREQ_LOW; /* 2MHz 摆率,对步进够用 */ HAL_GPIO_Init(GPIOB, &gpio); }

这段代码把四个引脚全部设为推挽输出。Speed 用 LOW,对 F103 来说对应 2MHz 输出摆率,低速长线场景能减少波形振铃;如果觉得换向沿太软、影响高速段,改成 MEDIUM 也行。这个参数不会影响最终转速,只会影响边沿陡峭程度,不必过于纠结。

需要特别说明,GPIO 侧不需要额外做光耦隔离或电平转换。ULN2003 输入端兼容 3.3V 逻辑,5V 侧由驱动板供电。所以板子给 STM32 供 3.3V,电机 5V 从外部适配器取,两边地线连一起,但电源端不要共用一个 LDO,否则电机启动电流会把 MCU 电压拉垮。

2.2 工程搭建顺序:时钟树、定时器和中断使能的先后关系

代码基于 STM32CubeMX 生成的 HAL 工程,芯片选 F103C8T6 这类常见款。搭建顺序建议是先配时钟,再配 GPIO,最后配定时器。先配时钟是因为 TIM3 的分频系数依赖 72MHz 系统时钟,如果顺序反过来,预分频值就要重算。

时钟树部分:HSE 外部晶振 8MHz 起振,PLL 倍频到 72MHz 系统时钟。APB1 最大 36MHz,所以挂在 APB1 上的 TIM3 会得到倍频后的 72MHz 时钟。这个 72MHz 是后面计算所有定时器参数的基础,先记住它。

CubeMX 里对 TIM3 的配置是:预分频器 PSC = 71,计数器周期 ARR = 999,向上计数模式。这样 TIM3 的计数时钟等于 72MHz / (71 + 1) = 1MHz,即计时分辨率 1us;更新周期是 (999 + 1) / 1MHz = 1ms。定时器每 1ms 溢出一次,溢出一次推进一步,正好对应 1000 步/秒。把 ARR 改成 499,就是 2000 步/秒;改成 1999,则是 500 步/秒。速度就是这样换来的。

我一般把 PSC 固定、ARR 留给运行时改。原因是 PSC 决定计数分辨率和速度换算基准,PSC 一变,计数频率就不再是整数的 1MHz,速度换算会变得别扭;而只改 ARR,是在同样的 1us 分辨率下改变溢出时刻,换算只需一步。

还有两处配置容易漏。第一处是“AutoReload Preload”设置为 Enable,这样运行中改 ARR 时,当前计数周期结束后才生效,不会出现半周期被截断。第二处是 NVIC 里把 TIM3 全局中断打开,并且优先级不要低于 SysTick。SysTick 优先级默认最低,TIM3 优先级如果设得比它高,HAL_Delay 就会卡死,具体坑在第 4 章展开。

/* timer_init.c —— TIM3 初始化,定时器每 1ms 触发一次更新中断 */ static void MX_TIM3_Init(void) { htim3.Instance = TIM3; htim3.Init.Prescaler = 72 - 1; /* 计数时钟 = 1MHz */ htim3.Init.CounterMode = TIM_COUNTERMODE_UP; htim3.Init.Period = 1000 - 1; /* 更新周期 = 1ms */ htim3.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1; htim3.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_ENABLE; HAL_TIM_Base_Init(&htim3); HAL_TIM_Base_Start_IT(&htim3); }

第一处注释需要解释一下:TIM3 挂在 APB1 上,在 72MHz 系统时钟下,APB1 分频后 TIM 时钟会被强制乘 2,所以定时器输入仍是 72MHz。PSC 设 71 后计数器频率变成 1MHz,后面所有速度换算都以这个 1MHz 为基准。

第二处 AutoReloadPreload 和运行时改 ARR 是配套关系。初始化不启用这个位,中途调用__HAL_TIM_SET_AUTORELOAD改周期,计数器会在写入瞬间清零,当前这一拍到下一拍的时间就会缩短,步进节拍出现毛刺。

到这里,硬件与工程骨架已经就位,可以进入驱动模块核心代码的拆解了。

3. 核心模块拆解:相序表、定时器中断与转向控制的完整驱动链

驱动 28BYJ-48 其实只干三件事:决定哪几个线圈通电、按什么节奏切换、切换后怎么知道自己在正转还是反转。这三个问题对应代码里的相序表、定时器中断和位置计数。

3.1 相序表驱动的 GPIO 刷新:8 拍半步时序的编码方式

步进电机靠轮换线圈通电产生旋转磁场,把转子一步步吸过去。28BYJ-48 最常用的驱动方式是 8 拍半步,即八个通电状态循环切换。八个状态分别是:A 单独通、A 与 B 同时通、B 单独通、B 与 C 同时通、C 单独通、C 与 D 同时通、D 单独通、D 与 A 同时通。

这样做的效果是让转子每次挪动约 5.625 度的一半,按 1:64 减速比折算到输出轴,每一步转角约 0.0879 度,转一整圈需要 4096 步。如果只用 4 拍全步,即 A、B、C、D 四种状态循环,步距角翻倍,整圈约 2048 步,力矩台阶也更明显。所以工程惯例直接用 8 拍,本文代码也按 8 拍写。

/* motor_step_table.h —— 8 拍半步相序表,下标即步序号 */ static const uint8_t motor_seq[8][4] = { {1, 0, 0, 0}, /* 状态 0:A 相导通 */ {1, 1, 0, 0}, /* 状态 1:A + B 导通 */ {0, 1, 0, 0}, /* 状态 2:B 相导通 */ {0, 1, 1, 0}, /* 状态 3:B + C 导通 */ {0, 0, 1, 0}, /* 状态 4:C 相导通 */ {0, 0, 1, 1}, /* 状态 5:C + D 导通 */ {0, 0, 0, 1}, /* 状态 6:D 相导通 */ {1, 0, 0, 1}, /* 状态 7:D + A 导通 */ };

这个表的每一行代表一个通电状态,四列依次对应 IN1、IN2、IN3、IN4。1 表示该相 GPIO 输出高电平,0 表示低电平。切换表下标,就是在选择下一步的通电组合。表头不一定非要从 A 开始,从状态 4 开始也一样能转,只要相邻两行之间的切换符合单方向变化即可。比如从{1,1,0,0}切到{0,1,1,0},只有第一列从 1 变 0、第三列从 0 变 1,这是一次正确换相;如果直接跳到{0,0,1,1},跳过了中间状态,电机就会有明显的齿槽感和异响。

/* motor_core.c —— 按相序表刷新四个 GPIO,phase 指向表的一行 */ static void Motor_WritePhase(const uint8_t *phase) { HAL_GPIO_WritePin(MOTOR_A_PORT, MOTOR_A_PIN, phase[0] ? GPIO_PIN_SET : GPIO_PIN_RESET); HAL_GPIO_WritePin(MOTOR_B_PORT, MOTOR_B_PIN, phase[1] ? GPIO_PIN_SET : GPIO_PIN_RESET); HAL_GPIO_WritePin(MOTOR_C_PORT, MOTOR_C_PIN, phase[2] ? GPIO_PIN_SET : GPIO_PIN_RESET); HAL_GPIO_WritePin(MOTOR_D_PORT, MOTOR_D_PIN, phase[3] ? GPIO_PIN_SET : GPIO_PIN_RESET); }

Motor_WritePhase是个纯函数式操作:给它一行表内容,它就把四个 GPIO 各输出一次。四个写入之间有微秒级的时间差,而电机线圈是毫秒级的感性负载,这点时间差不会产生实际影响。

3.2 定时器中断:把步进速度换算成硬件节拍

电机要匀速转,关键在每次换相的时间间隔要稳定。如果直接在主循环里调用 HAL_Delay,主循环一旦被其他任务阻塞,步序就会乱。更可靠的做法是让定时器每次溢出自动触发回调,在回调里走一步。

/* motor_core.c —— 定时器溢出回调:每溢出一次,推进一个步态 */ void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) { int32_t idx; if (htim->Instance != TIM3) { return; } if (motor_dir == MOTOR_DIR_FWD) { motor_position++; } else { motor_position--; } /* 位置可能是负数,先 %8 再 +8 再 %8,避免负数取模的坑 */ idx = (int32_t)(motor_position % 8); idx = (idx + 8) % 8; Motor_WritePhase(motor_seq[idx]); }

这里最值得解释的是最后两行取模处理。C 语言对负数取模,结果正负号与被除数相同,所以motor_position为负时,motor_position % 8的结果是负数,直接当数组下标会越界。先加 8 再取模,保证下标落在 0 到 7 之间。这个细节我第一版没处理,反向走到几十步后数组越界,现象是电机走一步、停一下、又走一步,相当迷惑。

速度控制靠改 ARR 实现。因为计数时钟固定为 1MHz,所以 ARR 的数值就等于“多少微秒走一步”。ARR 为 1999 时,2ms 一步,即 500 步/秒,按 4096 步/圈换算约合 7.3 RPM。这个转速不算高,但和 28BYJ-48 的定位匹配,它本来就不是跑高速的电机。

/* motor_speed.c —— 运行时改速度,ARR 的单位是微秒间隔 */ void Motor_SetSpeedHz(uint32_t steps_per_sec) { uint32_t arr; if (steps_per_sec == 0 || steps_per_sec > 5000) { return; /* 超出合理范围,拒绝设置 */ } arr = 1000000 / steps_per_sec - 1; __HAL_TIM_SET_AUTORELOAD(&htim3, arr); __HAL_TIM_SET_COUNTER(&htim3, 0); /* 清计数器,让新周期从零起算 */ }

Motor_SetSpeedHz在运行中被调用,HAL 通过写入 TIM3 的 ARR 寄存器改周期。因为初始化时打开了 AutoReloadPreload,新 ARR 在当前计数周期结束后才生效,不会破坏正在走的这一步。最后一行清零计数器,是防止出现“新周期配旧计数”导致首次换相同隔异常。这里把 steps_per_sec 限制到 5000 是保守值。28BYJ-48 在 5V 下机械极限约为 30 RPM,5000 步/秒约合 73 RPM,已经超出额定范围。二次开发时想往上调,要看实际负载来定,不能照搬。

3.3 方向与行程:位置计数和“走指定步数”的半开环实现

有了相序表和节拍,方向控制其实只是在回调整体上加一减一。正转位置递增,反转递减。这里要明确一点:这套实现没有编码器回读真实位置,位置准确性完全建立在“每一拍都可靠换相”的前提上,所以它是半开环。定时器节奏别设太高,电源也不能抖,否则丢一步就丢一步,位置不会自己恢复。

/* motor_position.c —— 指定行程示例:走 100 步后自动停 */ void Motor_StartSteps(int32_t target_steps) { motor_target = target_steps; if (motor_target > 0) { motor_dir = MOTOR_DIR_FWD; } else if (motor_target < 0) { motor_dir = MOTOR_DIR_BWD; } Motor_SetSpeedHz(1000); HAL_TIM_Base_Start_IT(&htim3); }

在定时器回调里加一段行程判断:

/* motor_core.c —— 到达目标步数后停表,避免无脑空转 */ if (motor_target != 0 && motor_position == motor_target) { HAL_TIM_Base_Stop_IT(&htim3); motor_target = 0; return; }

这段逻辑里,motor_target为正表示正转行程目标,为负表示反转行程目标,初始化时置 0 表示不限行程。回调每次先判断是否到达,到了就停表。这个“先判断再走一步”的顺序会带来最多一步的结束误差,对多数结构件来说无关紧要;但如果你要精确到步,改成“先判断下一步是否越界,不越界才走”即可。

实际调试中要注意一点:在回调里直接调用Motor_SetSpeedHz调速是安全的,因为它只改 ARR;但如果随手改了 PSC,计数基准变了,速度换算全部作废。所以我把调速和停止拆成两个函数,避免在中断里写太复杂的状态逻辑。

4. 避坑与排查:不转、抖动、卡死和丢步的现场记录

这一章把几类出现率最高的故障集中说明。每一条都是真实板子上反复出现过的,排查顺序也按现场操作习惯排好了。

4.1 现象:电机通电后嗡嗡响、发热,但轴不转

这是 28BYJ-48 驱动里最典型的现场。症状通常是:上电后电机发出连续“嗡嗡”声,壳体温度上升,但输出轴完全不动或轻微颤动。

原因主要分三类,按顺序排查。第一,相序表与线圈实际接线不一致。比如相序表按 A、B、C、D 编码,但板子丝印把 C、D、B、A 换了个顺序,两个通电状态之间无法形成连续的旋转磁场,电机就原地抱死。第二,GPIO 模式配错,比如用了开漏输出,但板子没有上拉,输入电平在临界区浮动。第三,5V 电源带载能力不足。这个电机每相约 200mA,堵转时接近 300mA,如果 USB 口的 5V 同时供电机和主控,电压会被拉到 4V 以下。

解决套路也是三步。第一步,给驱动板单独供 5V,电流至少 1A,先排除电源问题。第二步,用万用表的通断档量电机红线和四根相线之间的电阻,确认哪两个引脚属于同一绕组;或者用 GPIO 逐拍输出,拿示波器看 IN1~IN4 的波形是否按序列出现。第三步,如果波形在但轴不动,那就是相序表排列和板子丝印不一致。此时直接交换 IN1~IN4 中任意两路物理接线,比改代码快得多,改完看转向变化再决定是否调整代码。

提示:28BYJ-48 带减速齿轮,输出轴本身比较紧,上电后能听到电机内部齿轮在“咔咔”响但输出轴不动,先用手轻轻转动输出轴判断减速箱是否卡涩,再怀疑驱动问题。

4.2 现象:能转,但方向反了,或者步数和预期差很多

方向反是最容易修正的一类。代码里正转对应motor_position++,也就是沿相序表下标递增走。想换方向,只需要把回调里的增减逻辑反过来:

/* motor_core.c —— 反转时位置递减,同样用负数取模修正下标 */ if (motor_dir == MOTOR_DIR_FWD) { motor_position++; } else { motor_position--; }

有个常见误用:有人为了改方向,把相序表整体倒序重排,代码变长还容易错。其实方向反转只需要改这一处判断,表本身不用动。

另一个现象是“步数对不上”。如果你按 4096 步一圈去数,结果电机转两圈才停,大概率是被配置成了 4 拍全步而不是 8 拍半步。4 拍全步一圈约 2048 步,正好是 4096 的一半。相序表是四行的那种格式:

static const uint8_t motor_seq_4[4][4] = { {1, 0, 0, 0}, /* A */ {0, 1, 0, 0}, /* B */ {0, 0, 1, 0}, /* C */ {0, 0, 0, 1}, /* D */ };

这本身不是 bug,但如果你拿 4096 做位置换算,行程就会放大一倍。所以当电机走出的距离和预期不符,先检查相序表是几行,再看STEPS_PER_REV是不是 4096。

最后是关于减速比的一个反直觉点:28BYJ-48 标称减速比 1:64,但实际齿轮组的减速比不是整数 64,部分批次在 63.68 左右。也就是说,严格算一圈需要的原步数不是精确的 4096,而是 4076 到 4096 之间。短行程几十圈范围内无所谓,跑几百圈之后位置会累积出明显偏移。工程上的处理办法是在机构上加光电限位开关,每次上电回原点校正一次,而不是去改步距角参数。

4.3 现象:定时器中断里调用 HAL_Delay 导致系统卡死或步数乱跳

这种写法的坑是隐藏的。现象:电机转起来之后,整个系统像是死机,串口无输出,重新下载固件都要先按复位键才能进入下载模式。

原因在于 HAL_Delay 依赖 SysTick 中断递减计数。如果 TIM3 优先级高于 SysTick,TIM3 中断在跑回调时,SysTick 永远没机会打断它,HAL_Delay 里的 while 循环永远等不到计数归零,形成死锁。比这更隐蔽的版本是:不在回调里 delay,而是在中断里调用阻塞式串口打印函数。打印几十个字符耗时百余微秒,定时器节拍只有 1ms,偶发一次还能撑过去,速度一高就会丢步,现象变成“位置计数漂移”。

解决思路是让定时器中断“快进快出”,只做改 GPIO 和计步两件事。涉及“走 200 步,停 50ms,再走”这类节奏,用一个运行标志位在主循环里协调:

volatile uint8_t motor_pause_flag = 0; /* 主循环置 1 表示暂停 */ volatile uint32_t motor_pause_count = 0; /* 暂停剩余节拍数 */

中断里只对这个标志做减减操作,等待逻辑放主循环。串口日志更是要放到主循环,甚至用 DMA 发送。这三类坑覆盖了“烧完代码不转”的大多数场景,按现象对照排查,大部分几分钟能定位。

5. 二次开发:把步进模块升级成带加减速的运行器

基础驱动已经能转,但真正要落到项目里,还需要处理加减速、行程回调和堵转检测三个点。这三个方向是二次开发最通用的扩展路径,其中加减速优先级最高。

直接固定频率运转,电机从静止瞬间切到高速频率,会因为惯性丢步。最简单的工程做法是梯形加减速:启动时低速,每进一次定时器中断提升一档,到达巡航速度后保持,停止前再逐级降速。

/* accel.c —— 梯形加速:每次定时器回调提升一档速度 */ #define ACCEL_STEPS 16 /* 加速阶段分 16 档 */ uint16_t speed_table[ACCEL_STEPS]; uint8_t speed_index = 0; static void Motor_AccelInit(void) { uint32_t i; uint32_t start_hz = 500; /* 起步 500 步/秒 */ uint32_t peak_hz = 2000; /* 巡航 2000 步/秒 */ for (i = 0; i < ACCEL_STEPS; i++) { speed_table[i] = (uint16_t)(start_hz + (peak_hz - start_hz) * i / ACCEL_STEPS); } } void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) { /* 这里保留原有位置与相序处理逻辑 */ if (speed_index < ACCEL_STEPS) { Motor_SetSpeedHz(speed_table[speed_index++]); } }

这段代码用查找表预计算 16 档速度,每次中断提升一档。起步 500 步/秒约合 7 RPM,巡航 2000 步/秒约 29 RPM,正好落在电机合理工作区内。真实产品中可以用 S 形曲线拟合更多档位,但先跑通梯形骨架,再改曲线参数表,比直接上复杂算法更容易调试。

行程回调和堵转检测则是工程化必须补的部分。行程回调可以扩展现有Motor_StartSteps,到达目标后在回调函数指针里执行“断电”或“通知上位机”的动作。堵转检测不需要复杂的电流采样,在输出轴上加一个光电遮片,走固定步数后读光电信号,如果没变化就认为堵转,接着做复位流程。这个方案成本低,稳定性也好。

最后讲我自己的验证习惯。在轴上贴一片纸,手动转一圈看起始位置是否回到同一处。然后用逻辑分析仪抓 IN1~IN4 四路波形,确认相邻两个切换点时间间隔均匀。没有逻辑分析仪时,用示波器双通道同时看 A、B 两相,也能发现“半个波形被截断”——那是 ARR 在运行中被写坏的典型特征。

从那以后,我每次拿到新板件的第一件事,都是先用万用表把 IN1~IN4 与相线的对应关系量一遍,再烧 20 步低速试转;调速度必带示波器看波形,再也不敢跳过基础验证直接跑高速。希望帮到你。

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

相关新闻

QLScriptPublic 三步跑通自动签到:从部署到百款应用全打卡,只需 10 分钟

QLScriptPublic 三步跑通自动签到:从部署到百款应用全打卡,只需 10 分钟

QLScriptPublic 三步跑通自动签到&#xff1a;从部署到百款应用全打卡&#xff0c;只需 10 分钟 【免费下载链接】QLScriptPublic 青龙面板脚本公共仓库 企鹅交流1021185005 项目地址: https://gitcode.com/GitHub_Trending/ql/QLScriptPublic 每天早上挨个打开十几个 A…

2026/10/20 1:27:59 阅读更多 →
黑苹果 EFI 自动配置 10 分钟实战:用 OpCore-Simplify 生成可用的 OpenCore EFI

黑苹果 EFI 自动配置 10 分钟实战:用 OpCore-Simplify 生成可用的 OpenCore EFI

黑苹果 EFI 自动配置 10 分钟实战&#xff1a;用 OpCore-Simplify 生成可用的 OpenCore EFI 【免费下载链接】OpCore-Simplify A tool designed to simplify the creation of OpenCore EFI 项目地址: https://gitcode.com/GitHub_Trending/op/OpCore-Simplify 黑苹果安装…

2026/10/20 1:26:59 阅读更多 →
如何用RDPWrap.ini开家庭版多用户远程桌面

如何用RDPWrap.ini开家庭版多用户远程桌面

如何用RDPWrap.ini开家庭版多用户远程桌面 【免费下载链接】rdpwrap.ini RDPWrap.ini for RDP Wrapper Library by StasM 项目地址: https://gitcode.com/GitHub_Trending/rd/rdpwrap.ini Windows 家庭版远程桌面默认单用户登录&#xff0c;第二个人接入就得先顶掉旧会话…

2026/10/20 1:26:59 阅读更多 →

最新新闻

Day90-Java后端工程师的AI时代竞争力地图

Day90-Java后端工程师的AI时代竞争力地图

这套专栏走到今天&#xff1a;正篇 90 篇打底&#xff0c;续集《AI 工程化深水区》60 篇接着往生产级走&#xff0c;加起来 150 篇、22 个阶段。你现在的位置和要去的地方&#xff0c;都在这张图里&#xff1a;上半部分是正篇——前 8 个阶段&#xff08;Day 1-56&#xff09;把…

2026/10/20 2:12:24 阅读更多 →
基于SpringBoot的智能肥胖个性化管控系统-附源码

基于SpringBoot的智能肥胖个性化管控系统-附源码

温馨提示&#xff1a;本人主页置顶文章(点我)开头有 CSDN 平台官方提供的学长联系方式的名片&#xff01; 温馨提示&#xff1a;本人主页置顶文章(点我)开头有 CSDN 平台官方提供的学长联系方式的名片&#xff01; 温馨提示&#xff1a;本人主页置顶文章(点我)开头有 CSDN 平台…

2026/10/20 2:12:24 阅读更多 →
技术人如何系统化管理技能:从技能矩阵到学习路径的完整指南

技术人如何系统化管理技能:从技能矩阵到学习路径的完整指南

1. 从“skills”这个标题说起&#xff1a;一个被低估的硬核话题“skills”这个词&#xff0c;乍一看平平无奇&#xff0c;甚至有点太宽泛了。但如果你在技术社区或者职场成长圈子里待过一段时间&#xff0c;就会发现一个很有意思的现象&#xff1a;越是看起来简单的词&#xff…

2026/10/20 2:12:24 阅读更多 →
四、类和对象(三)

四、类和对象(三)

&#x1f449; 欢迎阅读这篇文章 &#x1f447; 目录1、构造函数延伸2、类型转换3、static成员4、友元5、内部类6、匿名对象7、对象拷贝时的编译器优化1、构造函数延伸 我们上一篇文章中介绍了构造函数&#xff0c;我们在实现构造函数的时候&#xff0c;初始化成员变量主要使用…

2026/10/20 2:12:24 阅读更多 →
4款芯片获UFCS认证,快充协议碎片化时代迎来破局

4款芯片获UFCS认证,快充协议碎片化时代迎来破局

/* 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 2:12:24 阅读更多 →
十分钟教你如何升级OpenClaw:npm与Docker两种方式配TaoToken

十分钟教你如何升级OpenClaw:npm与Docker两种方式配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/20 2:11:22 阅读更多 →

日新闻

CLRC663芯片Pin-to-Pin替代实战:从评估到量产全记录

CLRC663芯片Pin-to-Pin替代实战:从评估到量产全记录

/* 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 1:01:30 阅读更多 →
ESP32舵机控制指南:原理、多路驱动与避坑实战

ESP32舵机控制指南:原理、多路驱动与避坑实战

/* 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 1:01:30 阅读更多 →
位移法实现一阶低通滤波:单片机ADC采样降噪实战

位移法实现一阶低通滤波:单片机ADC采样降噪实战

/* 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 1:01:30 阅读更多 →

周新闻

基于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 阅读更多 →