STM32 FOC调试记录 STM32 FOC调试记录程序卡死在set_pwm_dutyweak符号踩坑现象ADC中断正常后把电流模式代码加进 while(1)cmotor_control_context.torque_norm_d 0;motor_control_context.torque_norm_q 0.4;motor_control_context.type control_type_torque;HAL_Delay(1000);程序卡在这段代码后面后面的printf不打印了。更严重的是电机开始发烫——PWM还在输出但FOC中断不再更新占空比某一相持续通电。排查过程第一步用printf逐段定位在关键位置加printf看程序执行到哪一步cprintf(A\r\n);motor_control_context.type control_type_torque;printf(B\r\n);HAL_Delay(1000);printf(C\r\n);打印到B就停了说明卡在 HAL_Delay(1000) 里或者它后面。第二步在lib_torque_control里加printfcvoid lib_torque_control(float torque_norm_d, float torque_norm_q){printf(T1\r\n);float d torque_d_loop(torque_norm_d);printf(T2\r\n);float q torque_q_loop(torque_norm_q);printf(T3\r\n);foc_forward(d, q, rotor_logic_angle);printf(T4\r\n);}打印到T3就停了卡在 foc_forward。第三步在foc_forward里加printfcvoid foc_forward(float d, float q, float rotor_rad){printf(F1\r\n);float d_u 0, d_v 0, d_w 0;svpwm(rotor_rad, d, q, d_u, d_v, d_w);printf(F2\r\n);set_pwm_duty(d_u, d_v, d_w);printf(F3\r\n);}打印了4个F1进入函数、三个变量初始化、svpwm完成第5个F1set_pwm_duty之后没打印。卡在set_pwm_duty函数里。根因weak符号被链接器选中打开 foc.c发现里面有一个weak版本的 set_pwm_dutycvoid set_pwm_duty(float d_u, float d_v, float d_w) __attribute__((weak));void set_pwm_duty(float d_u, float d_v, float d_w){while (1);}我的 main.c 里明明有强符号版本cvoid set_pwm_duty(float d_u, float d_v, float d_w){d_u min(d_u, 0.9);d_v min(d_v, 0.9);d_w min(d_w, 0.9);__disable_irq();__HAL_TIM_SET_COMPARE(htim1, TIM_CHANNEL_1, d_u * htim1.Instance-ARR);// ...__enable_irq();}但链接器选了 foc.c 里的weak版本运行时卡在 while(1)。关于weak符号__attribute__((weak)) 是GCC/ARM编译器的弱符号机制。规则如果别处有同名的强符号链接器就用强符号如果没有才用弱符号。原作者的意图foc.c 是算法层不应该关心底层硬件所以放一个weak版本的 set_pwm_duty 作为占位如果你的工程里实现了硬件驱动就用你的如果忘了实现就执行 while(1) 死循环让你一运行就发现这个设计思路是对的但在我这翻车了。为什么链接器选错了可能的原因链接顺序问题foc.o 在 main.o 之前被链接链接器先看到weak版本就定了编译器对weak的处理有差异不同工具链行为可能不一致main.c里的强符号因为某种原因没被识别结果就是本该用“主胎”的用了“备胎”卡死在while(1)。修复方法删掉 foc.c 里的weak函数定义只保留一行声明cvoid set_pwm_duty(float d_u, float d_v, float d_w);这样链接器只能去 main.c 里找实现没有选择余地。改完后编译烧录程序不再卡死电机正常响应。声明和定义的区别写法 类型 作用void set_pwm_duty(float d_u, float d_v, float d_w); 声明 告诉编译器有这个函数具体实现去别处找void set_pwm_duty(float d_u, float d_v, float d_w) { ... } 定义 给出函数的完整实现唯一区别在末尾有分号 声明有花括号 定义。总结项目 内容现象 程序卡死电机发烫根因 链接器选了foc.c里的weak版本卡在while(1)解决 删掉weak定义只保留声明教训 weak符号调试时要小心编译期报错比运行期死循环好