3. STM32生态系统:选型、CubeMX与HAL库、定时器与PWM输出

做FOC控制,说白了就是跟STM32的定时器、ADC、PWM这些外设打交道。我见过不少新手,一上来就对着数据手册硬啃,结果越看越懵。其实不用这样,咱们先把生态摸清楚,后面写代码就顺了。

3.1 STM32系列选型:FOC控制该用哪颗芯片?

STM32家族很大,但不是所有型号都适合做FOC。我个人习惯从三个维度来筛选:算力、定时器资源、ADC性能。

需求维度 最低要求 推荐型号举例 说明
算力 72MHz Cortex-M3以上 STM32F103, F302, F4系列 FOC电流环需要10-20kHz,算力不够会卡顿
定时器 至少1个高级定时器 STM32F302, F4, G4系列 高级定时器才有互补PWM和刹车功能
ADC 双通道同步采样 STM32F302, G431 同时采集两相电流,减少相位误差
成本敏感 够用就好 STM32G0, G4系列 G4自带Cordic硬件加速,算FOC很香

我的建议:如果刚入门,直接选STM32F302C8T6或STM32G431CBT6。这两颗芯片在FOC圈子里是“标配”,网上资料多,踩坑了也好找人问。

为什么会这样推荐?F302有双ADC,可以同时采样两相电流;G431更狠,内置了Cordic协处理器,算三角函数比纯软件快好几倍。我在项目里用G431做过一个无人机电调,电流环跑到20kHz,CPU负载才30%出头。

3.2 CubeMX与HAL库:从图形化配置到代码生成

以前做STM32开发,得手动翻寄存器手册,一行一行写初始化代码。现在有了CubeMX,这事儿就简单多了。你想想看,点几下鼠标,时钟树、引脚分配、外设参数就全配好了。

3.2.1 CubeMX的核心操作流程

  1. 选芯片:输入型号,比如STM32F302C8,双击打开。
  2. 配时钟:在Clock Configuration页面,把HCLK拉到72MHz(或芯片最高主频)。
  3. 使能外设:在Pinout页面,勾选TIM1、TIM2、ADC1、ADC2等。
  4. 设参数:比如TIM1的PWM频率设为20kHz,死区时间设500ns。
  5. 生成代码:选好IDE(MDK或IAR),点Generate Code。

小技巧:生成代码后,不要手动修改CubeMX生成的.ioc文件以外的初始化代码。如果你改了,下次重新生成时会被覆盖。我习惯把用户代码写在/* USER CODE BEGIN */和/* USER CODE END */之间,这样CubeMX会保留它们。

3.2.2 HAL库的层次结构

HAL库把寄存器操作封装成了函数。比如你想让定时器开始计数,直接调HAL_TIM_PWM_Start()就行。底层怎么配寄存器,你不用管。

但这里有个坑——HAL库的实时性不够好。为什么?因为它里面有很多错误检查和超时等待。在FOC电流环里,你需要在几微秒内完成ADC读取和PWM更新,HAL库的延迟可能会让你错过控制周期。

我曾经踩过的坑:第一次做FOC时,我用HAL库的HAL_ADC_Start_DMA()来触发ADC转换。结果发现电流环频率一超过10kHz,DMA回调就丢数据。后来查了手册才知道,HAL库在中断里做了太多状态检查。解决方案是:在电流环中断里直接操作寄存器,比如用TIM1->CCR1 = duty;来更新占空比,而不是调HAL函数。

3.3 定时器与PWM输出:FOC的“执行器”

FOC控制最终要输出6路PWM信号给逆变器。这6路PWM必须成对互补,还要带死区时间。STM32的高级定时器(TIM1、TIM8)就是干这个的。

3.3.1 高级定时器的核心功能

  • 互补PWM输出:CH1和CH1N自动互补,你只需设一个占空比。
  • 死区插入:防止上下桥臂直通,死区时间可编程(通常100ns-1μs)。
  • 刹车功能:一旦检测到过流信号,硬件自动封锁PWM输出。
  • 重复计数:可以设置每N次溢出才触发一次中断,减少CPU负担。

3.3.2 PWM频率与死区时间的计算

PWM频率一般设在10kHz-20kHz。频率太低,电机噪音大;频率太高,开关损耗大。我一般取16kHz,人耳听不到,效率也还行。

死区时间怎么算?公式很简单:
死区时间 = 死区寄存器值 × T_clk
其中T_clk是定时器的时钟周期。比如定时器时钟72MHz,T_clk≈13.9ns。如果你想设500ns死区,寄存器值≈500/13.9≈36。

关键参数速查表(定时器时钟72MHz):

PWM频率 自动重装值(ARR) 死区时间 死区寄存器值
10kHz 7200-1 500ns 36
16kHz 4500-1 300ns 22
20kHz 3600-1 200ns 14

3.3.3 代码示例:用HAL库配置TIM1输出6路互补PWM

// 在CubeMX中配置好TIM1后,生成的初始化代码大致如下:
// 注意:这里只展示核心配置,实际代码由CubeMX生成

TIM_HandleTypeDef htim1;

void MX_TIM1_Init(void)
{
    TIM_OC_InitTypeDef sConfigOC = {0};
    TIM_BreakDeadTimeConfigTypeDef sBreakDeadTimeConfig = {0};

    htim1.Instance = TIM1;
    htim1.Init.Prescaler = 0;               // 不分频,72MHz
    htim1.Init.CounterMode = TIM_COUNTERMODE_CENTERALIGNED1; // 中央对齐模式
    htim1.Init.Period = 4500 - 1;           // 16kHz PWM
    htim1.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
    htim1.Init.RepetitionCounter = 0;
    htim1.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_ENABLE;
    HAL_TIM_PWM_Init(&htim1);

    // 配置通道1(U相上桥)
    sConfigOC.OCMode = TIM_OCMODE_PWM1;
    sConfigOC.Pulse = 0;                    // 初始占空比0
    sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH;
    sConfigOC.OCNPolarity = TIM_OCNPOLARITY_HIGH;
    sConfigOC.OCFastMode = TIM_OCFAST_DISABLE;
    sConfigOC.OCIdleState = TIM_OCIDLESTATE_RESET;
    sConfigOC.OCNIdleState = TIM_OCNIDLESTATE_RESET;
    HAL_TIM_PWM_ConfigChannel(&htim1, &sConfigOC, TIM_CHANNEL_1);

    // 配置死区时间
    sBreakDeadTimeConfig.OffStateRunMode = TIM_OSSR_ENABLE;
    sBreakDeadTimeConfig.OffStateIDLEMode = TIM_OSSI_ENABLE;
    sBreakDeadTimeConfig.LockLevel = TIM_LOCKLEVEL_OFF;
    sBreakDeadTimeConfig.DeadTime = 36;     // 500ns死区
    sBreakDeadTimeConfig.BreakState = TIM_BREAK_ENABLE;
    sBreakDeadTimeConfig.BreakPolarity = TIM_BREAKPOLARITY_HIGH;
    sBreakDeadTimeConfig.BreakFilter = 0;
    sBreakDeadTimeConfig.AutomaticOutput = TIM_AUTOMATICOUTPUT_ENABLE;
    HAL_TIMEx_ConfigBreakDeadTime(&htim1, &sBreakDeadTimeConfig);

    // 启动PWM输出
    HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_1);
    HAL_TIMEx_PWMN_Start(&htim1, TIM_CHANNEL_1);  // 启动互补通道
    // 通道2和通道3同理...
}

注意:高级定时器有个“坑”——你必须先调用HAL_TIMEx_ConfigBreakDeadTime()配置刹车和死区,然后再启动PWM。顺序反了,PWM可能不输出。我刚开始就因为这个折腾了半天。

3.4 本章知识结构图

下面这张图把STM32生态、CubeMX配置、定时器PWM这三块串起来了。你可以把它当作一个“路线图”,后面写代码时随时回来对照。

STM32 FOC开发知识结构图 STM32 FOC开发知识结构图 STM32芯片选型 算力 ≥72MHz 高级定时器 双ADC同步采样 CubeMX图形化配置 时钟树配置 外设使能与参数 HAL代码生成 高级定时器PWM输出 互补PWM + 死区 刹车与故障保护 中央对齐模式 说明 箭头表示开发流程方向,从选型→配置→输出

3.5 本章小结

嗯,这一章内容不少,但都是后面实战的基础。总结几个关键点:

  • 选型:F302或G431,别纠结,直接上。
  • CubeMX:用它生成初始代码,但电流环里别依赖HAL库。
  • 定时器:高级定时器的互补PWM、死区、刹车,这三个功能必须吃透。