简介:这份资源面向嵌入式电机控制开发者与学习者,聚焦意法半导体MCU平台下的无刷直流电机磁场定向控制实现,核心解决双电机协同驱动与霍尔位置传感接口的工程落地问题。压缩包共约2000个文件,以1273个C源文件与672个头文件为主体,辅以少量txt说明、cpp及工程配置文件,整体约26.76MB,代码量可观,覆盖底层驱动到上层算法的完整链路。内容涉及ST MCSDK V5.4.4相关组件、霍尔传感器位置读取与相位计算、FOC电流电压调制与状态估计,以及基于实时操作系统的双电机任务调度与同步策略,可帮助读者理解多任务环境下两个电机协调控制的实现思路。目前已有307人学习下载,适合希望深入掌握霍尔FOC双电机控制架构、对照源码梳理驱动与算法分层设计的中高级开发者参考。
1. 双电机霍尔FOC控制:从一份工程包看ST MCSDK的落地路径
如果你手头正好有一块STM32板子、两个带霍尔传感器的无刷电机,却卡在“单电机跑通了,双电机怎么搞”这一步,那这份工程包大概率能省你不少时间。它基于ST MCSDK(Motor Control SDK)搭建,核心是用霍尔传感器做位置反馈,同时驱动两路BLDC/PMSM电机跑FOC(磁场定向控制)。不是那种只点亮一个LED的Demo,而是把双电机的PWM资源分配、ADC采样时序、霍尔换相中断都揉在一起的完整工程。适合谁?适合已经用CubeMX+MCSDK生成过单电机代码、想进一步做双电机协同(比如差速小车、云台、双轴机构)的嵌入式开发者。下面我按“能干什么→怎么跑→怎么改”的顺序,把这份包拆开讲。
2. 工程架构拆解:双电机FOC在MCSDK里怎么摆
2.1 从单电机到双电机:MCSDK的配置差异
ST MCSDK默认工作流是“一个电机一套控制环”。当你用Motor Control Workbench配置时,它生成的代码里MCI_Handle_t、PWMC_Handle_t、SpeednTorqCtrl_Handle_t这些结构体都是单实例的。双电机意味着你要把这些句柄复制成两份,并且保证它们不抢同一个定时器资源。
常见做法是:电机1用TIM1的CH1/CH2/CH3做三相PWM,电机2用TIM8的CH1/CH2/CH3。霍尔接口方面,电机1的H1/H2/H3接TIM2的CH1/CH2/CH3(或外部中断),电机2接TIM3或TIM4。ADC注入通道要分别对应两路电流采样,通常用双ADC规则同步或注入组交替触发。
工程包里能看到MCSDK_v5.x.x的目录痕迹,MotorControl文件夹下有两个独立的MCI任务文件,分别叫mci_motor1.c和mci_motor2.c(或类似命名)。这就是双电机最朴素的拆分方式:控制逻辑各管各的,只在系统层做电流环频率和PWM死区时间的统一。
2.2 霍尔驱动在FOC里的角色
霍尔传感器在FOC里干两件事:一是提供转子扇区(每60度一个状态,共6个),二是算速度。MCSDK里对应HALL_Handle_t,里面有HALL_GetState()和HALL_GetSpeed()。双电机时,两个霍尔定时器的中断优先级要错开,否则同时进中断会互相延迟。
代码里通常这样初始化:
// 电机1霍尔接口初始化(基于TIM2) HALL_Handle_t hall1; hall1.Timer = TIM2; hall1.Hall_GetState = HALL_GetState; // 读三路霍尔电平 hall1.Hall_GetSpeed = HALL_GetSpeed; // 用捕获值算速度 HALL_Init(&hall1); // 电机2霍尔接口初始化(基于TIM3) HALL_Handle_t hall2; hall2.Timer = TIM3; hall2.Hall_GetState = HALL_GetState; hall2.Hall_GetSpeed = HALL_GetSpeed; HALL_Init(&hall2);逻辑说明:HALL_Init里会配置定时器的从模式为“复位模式”,让霍尔跳变自动复位计数器,从而测出两个跳变之间的时间。参数上,HALL_GetSpeed返回的是电角度速度,需要乘以极对数才得到机械转速。双电机时两个霍尔定时器的预分频值要一致,否则速度环的PID参数没法复用。
2.3 电流采样与PWM的同步
FOC的命根子是电流采样时刻。单电机时,MCSDK用TIM1的更新事件触发ADC注入组,在PWM中心对齐模式下采样。双电机后,TIM1和TIM8的更新事件要分别触发各自的ADC。如果两个电机PWM频率相同,可以让它们同步启动;如果不同,就得各用各的触发源。
工程里常见配置是:ADC1注入组采电机1的Ia/Ib,ADC2注入组采电机2的Ia/Ib。触发源分别选TIM1_TRGO和TIM8_TRGO。注意ADC的采样窗口要避开PWM开关瞬间,通常设在计数器过零点附近。
提示:双电机同时采样时,如果两个ADC共用一个DMA,数据会错位。要么用两个DMA通道,要么用ADC1/ADC2的交替模式。
3. 跑起来:从工程包到电机转动的实操步骤
3.1 环境准备与工程导入
这份包是.rar格式,解压后应该能看到STM32CubeIDE或Keil的工程文件。我一般先用STM32CubeMX打开.ioc文件(如果有),检查时钟树和引脚分配。没有.ioc的话,直接看main.c里的SystemClock_Config和MX_GPIO_Init。
需要装的软件:
- STM32CubeIDE(或Keil MDK,看工程是哪个版本)
- STM32CubeMX(用于改配置)
- ST MCSDK(如果工程里引用了MCSDK的库文件,需要装对应版本)
- 串口调试助手(看速度/电流波形)
导入步骤:
- 解压到无中文路径的文件夹。
- 用CubeIDE打开工程,如果提示缺失MCSDK组件,去
Help→Manage Embedded Software Packages里装X-CUBE-MCSDK。 - 编译前检查
Include Paths里有没有指向MCSDK的MotorControl库目录。
3.2 关键参数检查:极对数、霍尔相位、电流极性
编译通过不代表能转。上电前必须核对三个参数:
| 参数 | 在哪改 | 典型值 | 错了会怎样 |
|---|---|---|---|
| 极对数 | pmsm_motor_parameters.h | 7(云台电机)或2(大功率) | 速度显示差倍数,电流环震荡 |
| 霍尔相位 | hall_parameters.h | 根据实际接线 | 电机抖动、堵转、反转 |
| 电流极性 | pmsm_motor_parameters.h | 正或负 | 电流环正反馈,直接过流 |
霍尔相位尤其玄学。如果电机上电后原地抖动不转,先把HALL_PHASE_SHIFT改±60度试试。我一般会先用示波器看三路霍尔波形,确认它们互差120度且与反电动势对齐。
3.3 上电顺序与调试观察
第一次上电别直接给速度指令。按这个顺序来:
// 1. 先只开电流环,速度环开环 MC_ProgramTorqueRamp(&Motor1, 0, 0); // 转矩给定0 MC_ProgramSpeedRamp(&Motor1, 0, 0); // 速度给定0 MC_StartMotor1(); // 启动状态机 // 2. 给一个小转矩(比如0.05标幺值),看电机是否平稳 MC_ProgramTorqueRamp(&Motor1, 50, 100); // 50是目标值,100是斜率 // 3. 正常后再切速度模式 MC_ProgramSpeedRamp(&Motor1, 1000, 500); // 1000rpm,500rpm/s加速观察点:串口打印的MCI_GetCurrents和MCI_GetSpeed。如果电流波形是正弦且速度稳定,说明霍尔相位对了。如果电流是尖峰,检查ADC采样时刻是否在PWM中心。
注意:双电机同时启动时,电源功率要够。两个电机同时加速可能拉低母线电压,导致欠压保护。建议先分别启动,再同时给指令。
4. 避坑与排查:双电机霍尔FOC的五个血泪经验
4.1 电机1转、电机2不转,或两个都抖
现象:编译下载后,电机1正常,电机2没反应;或者两个电机都原地抖动,电流很大。
原因:最常见的是霍尔定时器中断优先级冲突。如果两个霍尔中断都是同一优先级,CPU会先响应一个,另一个被延迟,导致换相时刻错乱。另一个原因是MCSDK的MCI_Handle_t数组越界,两个电机共用了同一个句柄。
解决:在NVIC设置里,把电机1霍尔中断设为优先级1,电机2设为优先级2。检查mci_motor1.c和mci_motor2.c里传入的MCI_Handle_t是不是两个独立变量。用调试器看MCI_GetState返回值,如果一直是IDLE,说明状态机没启动。
4.2 霍尔速度反馈跳变,速度环震荡
现象:速度显示在目标值附近大幅波动,电机声音忽大忽小。
原因:霍尔测速的分辨率低,每个扇区只有一次跳变。如果速度环PID的积分时间太短,就会把霍尔跳变的量化误差放大。双电机时,两个霍尔定时器的预分频不一致也会导致速度标幺值不同。
解决:把速度环的Kp调小,Ki调大,或者加一个低通滤波器。MCSDK里可以改SPEED_LOOP_FREQUENCY_HZ,从1kHz降到500Hz。另外确认两个霍尔定时器的Prescaler值相同,且HALL_GetSpeed里用的SpeedSampling周期一致。
4.3 电流采样值偏置,电机发热
现象:电机能转,但发热严重,效率低。串口看Ia、Ib的直流偏置不为零。
原因:双电机时,两个ADC的参考电压或地线不一致。或者采样电阻的运放电路有温漂。MCSDK默认会在启动时校准电流偏置,但如果两个电机同时校准,可能互相干扰。
解决:在MC_StartMotor1之前,分别对两个电机做偏置校准。代码里找ADC_Calibrate或MCI_CalibrateCurrents,确保校准期间电机不转。如果偏置还是大,检查硬件上两个采样运放的地是不是单点接地。
4.4 霍尔换相时电流尖峰,触发过流保护
现象:电机加速到一定转速就报OVER_CURRENT,示波器看相电流有尖刺。
原因:霍尔跳变到实际换相之间有时间差。如果换相延迟太大,电流在错误的扇区里续流,产生尖峰。双电机时,如果两个霍尔中断同时来,延迟更大。
解决:在霍尔中断里直接做换相,不要等主循环。MCSDK的HALL_TIMx_IRQHandler里会调用HALL_GetState和MC_SetPhase。把这两个函数的执行时间压到最短,比如用查表法代替计算。另外把过流阈值适当调大,但别超过MOS管额定值。
4.5 双电机同时跑,串口打印乱码或丢数据
现象:单独跑一个电机时串口正常,两个一起跑就乱码。
原因:串口中断被电机控制中断打断,或者DMA发送被高优先级中断抢占。双电机时,霍尔中断和ADC中断频率翻倍,CPU负载高。
解决:把串口发送改成DMA+空闲中断,或者降低串口波特率。更彻底的办法是减少串口打印频率,只在调试时开。MCSDK的MC_GetControlState可以放在低速任务里,比如1ms一次。
5. 二次开发:改双电机协同与参数整定
5.1 从独立控制到协同控制
这份工程默认是两个电机各跑各的速度环。如果你想做差速控制(比如一个电机加速、另一个减速),需要在上层加一个协调器。常见做法是:
// 差速控制示例:根据转向指令分配两个电机的速度 void DifferentialDrive(float linear, float angular) { float speed_left = linear - angular * WHEEL_BASE / 2; float speed_right = linear + angular * WHEEL_BASE / 2; // 限制最大速度 speed_left = CLAMP(speed_left, -MAX_SPEED, MAX_SPEED); speed_right = CLAMP(speed_right, -MAX_SPEED, MAX_SPEED); // 分别给两个电机 MC_ProgramSpeedRamp(&Motor1, speed_left, ACCEL); MC_ProgramSpeedRamp(&Motor2, speed_right, ACCEL); }参数说明:WHEEL_BASE是两轮间距,ACCEL是加速度斜率。这个函数放在1ms任务里调用。注意两个电机的速度环PID参数要一致,否则差速时一个响应快一个慢,车会跑偏。
5.2 霍尔相位自校准技巧
霍尔安装误差是双电机最头疼的事。我一般会写一个自校准流程:让电机开环旋转,记录每个霍尔跳变对应的电角度,然后算偏移量。代码框架:
// 开环旋转,记录霍尔跳变时的电角度 float hall_offset[6] = {0}; for (int i = 0; i < 6; i++) { // 等霍尔状态变化 while (HALL_GetState(&hall1) == last_state); hall_offset[i] = MCI_GetElAngle(&Motor1); // 记录当前电角度 last_state = HALL_GetState(&hall1); } // 计算平均偏移 float avg_offset = 0; for (int i = 0; i < 6; i++) { avg_offset += hall_offset[i]; } avg_offset /= 6; // 写入参数 HALL_SetPhaseShift(&hall1, avg_offset);这个流程跑一次就能把霍尔安装误差补掉。注意开环旋转时电流要给小一点,别让电机飞车。
5.3 验证改造效果的方法
改完代码后,别急着上车。先做三个验证:
- 堵转测试:用手按住电机轴,看电流是否稳定在限幅值,不震荡。
- 阶跃响应:给速度指令从0到1000rpm,看超调量和调节时间。
- 双电机同步:给两个电机相同的速度指令,用编码器(如果有)对比实际转速差。
我习惯在main.c里加一个调试变量debug_speed_diff,实时算两个电机的速度差,超过阈值就报警。从那以后我每次改完双电机参数,都强制走一遍堵转和阶跃,不然心里没底。希望这份拆解能帮你把双电机霍尔FOC跑起来,少烧两个MOS管。
本文还有配套的精品资源,点击获取