第三章 开发环境配置:Keil/IAR环境搭建、STM32CubeMX配置、工程模板建立与调试

好,咱们进入实战环节的第一步。说实话,很多初学者在FOC上栽跟头,不是因为算法多难,而是开发环境没搭好。我见过有人花了一周时间,就为了把工程跑起来。嗯,这章咱们就把这事彻底搞定。

3.1 开发工具选型:Keil还是IAR?

先聊个老生常谈的问题:Keil和IAR,到底选哪个?

我个人习惯用Keil,因为它的界面更直观,调试起来顺手。但IAR的编译优化确实更强,代码体积能小10%-15%。

怎么选?给你个参考:

对比项 Keil MDK IAR EWARM
上手难度 低,界面友好 中,需要适应
编译优化 一般 优秀,代码更紧凑
调试体验 流畅,寄存器查看方便 功能强大,但操作略复杂
生态支持 国内资料多,教程丰富 相对少一些
价格 授权费较高 同样不便宜
我的建议:如果你刚入门,先用Keil。等项目做熟了,再试试IAR。我在一个量产项目中用过IAR,代码优化后,Flash占用从64KB降到了52KB,省出来的空间刚好塞进了一个Bootloader。

3.2 Keil环境搭建与工程模板建立

咱们以Keil为例,一步步来。我假设你已经装好了MDK-ARM V5.38或更新版本。

3.2.1 安装与破解

这一步不细说了,网上教程一堆。但有一点要注意:安装路径不要有中文。我曾经有个同事,装在了"D:\开发工具\Keil_v5",结果编译总是报路径错误。折腾了半天,改成英文路径就好了。

3.2.2 新建工程模板

我习惯建一个干净的模板工程,以后每个项目都从它复制。这样能省不少事。

步骤很简单:

  1. 打开Keil,点击Project → New μVision Project
  2. 选择芯片型号,比如STM32F103C8T6
  3. 在弹出的Manage Run-Time Environment中,只勾选CMSIS核心和Device下的Startup
  4. 添加你的main.c文件

等等,这里有个坑。很多人喜欢把CubeMX生成的代码直接塞进Keil工程。但CubeMX每次重新生成,都会覆盖你手动修改的部分。所以我的做法是:

工程结构建议:

Project/
├── User/          # 你自己写的代码
│   ├── main.c
│   ├── foc.c
│   └── foc.h
├── Drivers/       # 外设驱动
│   ├── stm32f1xx_hal_gpio.c
│   └── ...
├── Middlewares/   # 中间件(比如电机库)
├── Output/       # 编译输出
└── .uvprojx      # Keil工程文件

这样,CubeMX只负责生成Drivers和Middlewares,你的业务代码放在User里,互不干扰。

3.2.3 配置编译选项

打开工程选项(Alt+F7),这几个地方要改:

  • Target → ARM Compiler:选V6版本,编译更快
  • C/C++ → Optimize:调试阶段选Level 0,发布时选Level 2
  • Debug → Use Simulator:勾上,方便没板子时调试
注意:如果你用V6编译器,有些HAL库的语法可能不兼容。我遇到过__IO关键字报错的情况,需要在C/C++ → Misc Controls里加上--diag_suppress=870,屏蔽掉这个警告。

3.3 STM32CubeMX配置:生成FOC所需的外设

CubeMX是ST官方的配置工具,说白了就是帮你生成初始化代码。咱们做FOC,需要配置的外设不少:

3.3.1 时钟树配置

FOC对时序要求高,时钟必须稳。我一般这样配:

  • HSE:8MHz外部晶振
  • PLL:倍频到72MHz(STM32F1)或168MHz(STM32F4)
  • APB1:36MHz(给定时器、ADC用)
  • APB2:72MHz(给高级定时器用)

为什么APB1要分频?因为FOC的PWM和ADC采样需要同步,APB1时钟太高反而容易出问题。我有个项目,APB1设成了72MHz,结果ADC采样总是抖动。降到36MHz后,稳如老狗。

3.3.2 定时器配置

FOC需要至少两个定时器:

定时器 用途 配置要点
TIM1/TIM8 生成6路互补PWM 中心对齐模式,频率20kHz
TIM2/TIM3 触发ADC采样 与PWM同步,在PWM中间点触发

在CubeMX里,配置TIM1的步骤:

  1. 选择TIM1,勾选Channel 1-3为PWM Generation CHx
  2. 设置Prescaler为0,Counter Period为3600(72MHz/20kHz = 3600)
  3. 开启互补输出和刹车功能
  4. 配置死区时间:一般设为1-2μs
死区时间怎么算? 死区 = (DTS × 2^DTG) / TIM时钟频率。DTS是死区步长,DTG是死区发生器配置。我一般直接设DTG为0x0A,对应约1μs的死区。这个值对大多数MOSFET都够用。

3.3.3 ADC配置

FOC需要采集两相电流(Ia、Ib)和母线电压。ADC配置要点:

  • 使用注入组(Injected Group),优先级高
  • 采样时间:设为最慢档(239.5个周期),保证采样稳定
  • 触发源:选择TIM1的TRGO事件

这里有个细节:ADC采样必须在PWM的中间点进行。为什么?因为PWM在中间点时,电流纹波最小,采样值最准。我刚开始做FOC时没注意这个,电流波形全是毛刺。后来查了三天资料才找到原因。

3.4 工程调试:从点灯到跑FOC

模板建好了,怎么验证它能不能用?我的习惯是分三步走:

3.4.1 第一步:点灯测试

别笑,这一步很重要。它能验证你的工程编译、下载、运行都没问题。

// main.c
#include "main.h"

int main(void)
{
    HAL_Init();
    SystemClock_Config();
    MX_GPIO_Init();
    
    while (1)
    {
        HAL_GPIO_TogglePin(LED_GPIO_Port, LED_Pin);
        HAL_Delay(500);
    }
}

下载到板子上,如果LED以1Hz频率闪烁,恭喜你,环境搭好了。

3.4.2 第二步:PWM波形验证

用示波器看TIM1的CH1输出。正常应该看到20kHz的方波,占空比50%。如果波形不对,检查:

  • 时钟配置是否正确
  • 定时器参数是否溢出
  • GPIO复用功能是否开启

3.4.3 第三步:ADC采样验证

在调试模式下,查看ADC的注入组数据寄存器。给电机相线通一个固定电流,看采样值是否稳定。如果跳动超过5%,说明采样有问题。

常见问题:ADC采样值全是0?大概率是触发源没配好。检查TIM1的TRGO事件是否设置为Update事件。另外,ADC的注入组使能位别忘了设。

3.5 避坑指南:我踩过的那些坑

最后,分享几个我实际项目中遇到的坑,你遇到了可以少走弯路:

  • 坑1:Keil编译报错"Error: L6406E: No space in execution regions"。这是Flash不够了。把优化等级从Level 0调到Level 2,能省不少空间。
  • 坑2:PWM输出频率不对。检查定时器的Prescaler和Counter Period,别忘了加1。比如你要20kHz,Counter Period应该是3600-1,不是3600。
  • 坑3:ADC采样值跳动。加个硬件低通滤波器,在ADC引脚对地接一个100nF电容。软件上也可以做均值滤波,采10次取平均。
  • 坑4:下载程序后芯片不运行。检查Boot0和Boot1引脚的电平。我有个项目,Boot0忘了接地,芯片一直停在系统存储器里。

好了,环境搭建就到这里。下一章咱们开始写FOC的核心算法——Clark变换和Park变换。到时候你会觉得,环境搭建这点事,真不算什么。