3. STM32CubeMX项目创建:从零搭建你的AI推理工程

说实话,很多初学者拿到一块开发板,第一件事就是急着写代码。我当年也是这样,结果往往是灯不亮、串口没输出,折腾半天发现是时钟没配对。做嵌入式AI项目,底子打不好,后面模型推理再牛也跑不起来。

这一章,我们就手把手把STM32项目搭起来。时钟树、GPIO、UART,一个都不能少。

3.1 新建STM32项目——选对芯片是第一步

打开STM32CubeMX,界面很清爽。点击“New Project”,进入芯片选择界面。

我个人习惯用Part Number搜索,直接输入芯片型号。比如我们课程用的STM32F746ZG,输入后下方列表会过滤出来。双击选中,项目就创建了。

小技巧: 如果你不确定具体型号,可以用“Series”筛选。比如选“STM32F7”,再根据引脚数、Flash大小慢慢挑。我在项目中经常用这个功能帮客户选型。

创建项目后,你会看到芯片的引脚图。别慌,咱们一步步来配置。

3.2 时钟树配置——芯片的心脏起搏器

时钟树,说白了就是给芯片各个模块分配时钟信号。配错了,外设可能不工作,或者工作频率不对。

点击“Clock Configuration”标签页,进入时钟树配置界面。这里我重点讲三个时钟源:

时钟源 典型频率 用途
HSE(高速外部晶振) 8 MHz / 25 MHz 系统主时钟、PLL输入
LSE(低速外部晶振) 32.768 kHz RTC实时时钟、低功耗模式
PLL(锁相环) 可倍频至216 MHz(F7) 将低频时钟倍频到高频

配置步骤:

  1. 选择HSE作为时钟源:在“HSE”下拉框选择“Crystal/Ceramic Resonator”。
  2. 配置PLL:我一般把PLL Source选为HSE,然后设置倍频系数。比如HSE=8MHz,PLLM=8,PLLN=216,PLLP=2,最终得到216MHz。
  3. 设置系统时钟:在“System Clock Mux”选择“PLLCLK”。
  4. 检查APB1/APB2分频:确保总线时钟不超过各自的最大频率。APB1通常最大54MHz,APB2最大108MHz。
注意: 我曾经在项目里把PLL倍频设得太高,芯片直接不启动。后来用示波器量晶振才发现,HSE根本没起振。原因是负载电容没配好。所以,如果你发现时钟配置后芯片不工作,先检查晶振电路。

配置完成后,CubeMX会自动计算各总线时钟频率。你可以在右上角看到HCLK、APB1、APB2的值。确认无误后,进入下一步。

3.3 GPIO与UART外设配置——让芯片开口说话

时钟配好了,接下来配置外设。我们先配一个LED灯(GPIO输出),再配一个串口(UART),用来打印调试信息和AI推理结果。

3.3.1 GPIO配置——点亮第一盏灯

在Pinout视图里,找到你板子上的LED引脚。以STM32F746G-DISCO为例,LED通常接在PI1(红色)、PI2(绿色)、PI3(蓝色)。

点击PI1,选择“GPIO_Output”。然后右键点击该引脚,选择“Enter User Label”,输入“LED_RED”。这样代码里就能直接用LED_RED这个宏了。

配置GPIO参数:

  • Output Level:Low(默认低电平,LED灭)
  • Mode:Push-Pull(推挽输出)
  • Pull-up/Pull-down:No pull(不拉)
  • Maximum output speed:Low(LED不需要高速)
关键点: 推挽输出能同时输出高电平和低电平,驱动LED足够了。开漏输出需要外部上拉电阻,一般用于I2C等总线。

3.3.2 UART配置——串口打印Hello World

回到Pinout视图,找到USART1。点击“USART1”的TX和RX引脚,系统会自动分配引脚(通常是PA9和PA10)。

在“Configuration”面板里,设置UART参数:

参数 推荐值 说明
Baud Rate 115200 常用波特率,兼顾速度和稳定性
Word Length 8 Bits 标准数据位
Parity None 无校验
Stop Bits 1 1个停止位

配置完成后,记得在“NVIC Settings”里使能USART1全局中断。这样后续做中断接收时就不用再回头配了。

经验之谈: 波特率不是越高越好。115200在大多数场景下够用,而且不容易丢数据。如果你用蓝牙模块,很多模块默认就是115200。

3.4 生成初始化代码——一键生成,省心省力

所有外设配置完成后,点击右上角的“GENERATE CODE”按钮。CubeMX会弹出一个对话框,让你选择IDE和项目路径。

我一般选“MDK-ARM”或“STM32CubeIDE”,然后点“OK”。几秒钟后,代码就生成好了。

生成的代码结构很清晰:

  • Core/Inc:头文件,包含main.h、gpio.h、usart.h等
  • Core/Src:源文件,包含main.c、gpio.c、usart.c等
  • Drivers:HAL库驱动文件

打开main.c,你会看到CubeMX已经帮我们写好了初始化代码:

int main(void)
{
  HAL_Init();
  SystemClock_Config();
  MX_GPIO_Init();
  MX_USART1_UART_Init();

  while (1)
  {
    // 你的AI推理代码将写在这里
  }
}

看到没?时钟、GPIO、UART的初始化函数都自动生成了。你只需要在while(1)里添加业务逻辑就行。

避坑指南: 我曾经直接修改了CubeMX生成的代码,结果重新生成时被覆盖了。后来我学乖了,把用户代码写在“USER CODE BEGIN”和“USER CODE END”注释块之间。这样重新生成时,这部分代码不会被覆盖。

3.5 本章知识结构图

下面这张图总结了从创建项目到生成代码的完整流程:

STM32CubeMX项目创建流程 1. 新建项目 2. 时钟树配置(HSE/PLL) 3. GPIO + UART 配置 4. 生成初始化代码 5. 编译验证 关键检查点 • 晶振负载电容匹配 • PLL倍频不超上限 • 用户代码写在BEGIN/END块内