1+1=10

记记笔记,放松一下...

STM32CubeMX小记

接前面ARM开发环境小记Keil MDK 社区版小记。不求深入,简单了解一下CubeMX生成的代码的基本结构...

STM32 CubeMX 是什么?

CubeMX 是 STM32 Cube 家族一员,全家福这样:

  • STM32CubeMX: 用于生成初始化代码和配置项目,然后在
  • STM32CubeIDE: 中编辑、编译和调试这些代码
  • STM32CubeProgrammer: 用于将编译好的程序烧写到微控制器上
  • STM32CubeMonitor: 可用于进一步的运行时分析和性能调优。

类比Qt的话,CubeMX 相当于qdesigner,CubeIDE相当于Qt Creator。CubeIDE中集成了CubeMX的大部分功能,但是使用其他IDE(比如Keil MDK)时,使用CubeMX生成的代码更容易。

CubeMX可以为如下工具和IDE生成项目代码:

  • EWARM
  • MDK-ARM
  • STM32CubeIDE
  • Makefile
  • CMake

生成代码结构?

本文所用 STM32CubeMX 版本为6.11.1,盲选择MCU型号STM32F051C8Tx。

尝试一(MDK-ARM)

生成代码结构如下:

  • 顶层 .mxproject 和 MyTest.ioc: 都是 CubeMX 的工程文件。需要保留以便于后续使用Cube重新生成或更新代码【.ioc 文件代表“Initialization and Configuration”】。
  • MDK-ARM:为Keil MDK生成的项目文件(以便于在Keil下直接打开工程),以及启动文件 startup_stm32f051x8.s【这个文件被放在这儿,是因为它能只用于Keil MDK,不通用】
  • Core:用户需要修改的代码!!(在指定位置修改,以免后续用CubeMX更新时被覆盖)
  • Drivers:CMSIS 和 HAL库文件
│  .mxproject
│  MyTest.ioc
│
├─Core
│  ├─Inc
│  │      main.h
│  │      stm32f0xx_hal_conf.h
│  │      stm32f0xx_it.h
│  │
│  └─Src
│          main.c
│          stm32f0xx_hal_msp.c
│          stm32f0xx_it.c
│          system_stm32f0xx.c
│
├─Drivers
│  ├─CMSIS
│  │  │  LICENSE.txt
│  │  │
│  │  ├─Device
│  │  │  └─ST
│  │  │      └─STM32F0xx
│  │  │          │  LICENSE.txt
│  │  │          │
│  │  │          └─Include
│  │  │                 stm32f051x8.h
│  │  │                 stm32f0xx.h
│  │  │                 system_stm32f0xx.h
│  │  └─Include
│  │          cmsis_armcc.h
│  │          cmsis_armclang.h
│  │          ...
│  │
│  └─STM32F0xx_HAL_Driver
│      │  LICENSE.txt
│      │
│      ├─Inc
│      │  │  stm32f0xx_hal.h
│      │  │  stm32f0xx_hal_cortex.h
|      |  |  ...
│      │  │
│      │  └─Legacy
│      │          stm32_hal_legacy.h
│      │
│      └─Src
│              stm32f0xx_hal.c
│              stm32f0xx_hal_cortex.c
|              .....
│
└─MDK-ARM
        MyTest.uvoptx
        MyTest.uvprojx
        startup_stm32f051x8.s

重点关注下Core下的几个文件:

  • main.c
  • stm32f0xx_hal_msp.c
  • stm32f0xx_it.c

这几个文件内部都有大量的如下风格的注释段,用于让用户加入自定义的代码:

  /* USER CODE BEGIN xxxxx */

  /* USER CODE END xxxx */

main.c

  • 系统初始化:初始化硬件抽象层(HAL)、配置系统时钟。
  • 外设初始化:初始化各个外设模块,例如 GPIO、USART、I2C 等。
  • 主循环:包含应用程序的主逻辑,通常是一个无限循环。
  • 功能实现:执行主要的应用功能,例如数据处理、通信协议等。
#include "main.h"
#include "stm32f0xx_hal.h"

void SystemClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_USART2_UART_Init(void);

UART_HandleTypeDef huart2;

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

    while (1) {
        // 主应用逻辑
    }
}

void SystemClock_Config(void) {
    // 配置系统时钟
}

static void MX_GPIO_Init(void) {
    // 初始化 GPIO
}

static void MX_USART2_UART_Init(void) {
    // 初始化 UART
}

如果生成代码时,勾选了Generate peripheral initialization as a pair of .c/.h files per peripheral,各个外设的代码会生成在独立的外设文件中,比如gpio.c,uart.c 等,对应的初始化代码,比如MX_GPIO_Init(),将不再直接位于main.c中,而是通过include被包含进来。

stm32f0xx_hal_msp.c

msp 表示“Microcontroller Support Package”(微控制器支持包)。这个支持包包含了一些用于初始化和配置硬件外设的底层代码。

  • 外设支持包 (MSP) 配置:提供 HAL 库初始化和去初始化过程中的底层硬件配置。
  • GPIO 配置:配置用于特定外设功能的 GPIO 引脚。
  • 中断配置:配置外设中断优先级和中断处理函数。
#include "stm32f0xx_hal.h"

void HAL_MspInit(void) {
    // 初始化全局 MSP
}

void HAL_UART_MspInit(UART_HandleTypeDef* huart) {
    if (huart->Instance == USART2) {
        // 配置 USART2 的 MSP
    }
}

void HAL_UART_MspDeInit(UART_HandleTypeDef* huart) {
    if (huart->Instance == USART2) {
        // 去初始化 USART2 的 MSP
    }
}

stm32f0xx_it.c

it 表示“Interrupt”(中断)。

  • 中断服务程序 (ISR):实现各种中断处理函数,例如定时器中断、外部中断、通信中断等。
  • 系统中断处理:处理系统级中断,如 SysTick 中断。
#include "main.h"
#include "stm32f0xx_it.h"

void NMI_Handler(void)
{
   while (1){ }
}

void HardFault_Handler(void)
{
  while (1){ }
}

void SVC_Handler(void)
{
}

void PendSV_Handler(void)
{
}

void SysTick_Handler(void)
{
  HAL_IncTick();
}

尝试二(CubeIDE)

和上面很像:

  • 都有 .mxproject 和 MyText.ioc:作为CubeMX的工程文件

  • Drivers 文件夹和前面完全一样

  • 都有对应的工程文件,CubeIDE的工程文件是 .project和 .cproject【这两个文件是Eclipse IDE 及其衍生版本的配置文件】。

  • 都有启动文件,CubeIDE的启动文件在Core文件夹内【文件内容和keil下的不一样,难怪keil下的放置到 MDK-ARM文件夹下】。

不同之外

  • Core下多了两个文件syscalls.csysmem.c。用于实现依赖于底层硬件的C标准库功能,比如内存分配和输入输出等。另外,Keil 有自己的运行时和系统调用,所以不需要它们。

  • 多了一个STM32F051C8TX_FLASH.ld文件。这是一个链接脚本文件(linker script),用于GNU 工具链,链接脚本文件定义了 MCU 内存布局,并告诉链接器如何将编译生成的代码和数据段放置到目标设备的内存中。

由于其他都一样,两套IDE并存,感觉上应该没问题。

│  .cproject
│  .mxproject
│  .project
│  MyTest.ioc
│  STM32F051C8TX_FLASH.ld
│
├─Core
│  ├─Inc
│  │      main.h
│  │      stm32f0xx_hal_conf.h
│  │      stm32f0xx_it.h
│  │
│  ├─Src
│  │      main.c
│  │      stm32f0xx_hal_msp.c
│  │      stm32f0xx_it.c
│  │      syscalls.c
│  │      sysmem.c
│  │      system_stm32f0xx.c
│  │
│  └─Startup
│          startup_stm32f051c8tx.s
│
└─Drivers

尝试三(CMake)

生成适用于arm-none-eabi-gcc的cmake工程文件。

所有源码文件都和为CubeIDE生成的一样,局部差异

  • 启动文件startup_stm32f051x8.s从Core文件夹移到根目录下(内容完全一样)。Why?

  • STM32F051C8TX_FLASH.ld文件,大致一样,但是内容又不完全一样!!(是否通用?)

│  .mxproject
│  CMakeLists.txt
│  CMakePresets.json
│  MyTest.ioc
│  startup_stm32f051x8.s
│  STM32F051C8Tx_FLASH.ld
│
├─cmake
│  │  gcc-arm-none-eabi.cmake
│  │
│  └─stm32cubemx
│          CMakeLists.txt
│
├─Core
│  ├─Inc
│  │      main.h
│  │      stm32f0xx_hal_conf.h
│  │      stm32f0xx_it.h
│  │
│  └─Src
│          main.c
│          stm32f0xx_hal_msp.c
│          stm32f0xx_it.c
│          syscalls.c
│          sysmem.c
│          system_stm32f0xx.c
│
└─Drivers

如何生成代码?

  • 选择MCU
  • 指定引脚
  • 配置时钟

似乎很简单,但是由于不了解硬件,看起来很发懵...

指定引脚

  • 直接在左侧启用相应的功能,有自动分配的引脚
  • 在引脚上点击右键,可以选择引脚

stm32cubemx-pinout

图中,系统Core部分配置了:

  • GPIO(General-Purpose Input/Output):通用输入输出端口。STM32 微控制器的每个引脚都可以配置为不同的功能,包括输入、输出、模拟功能或特定外设的功能。
  • NVIC(Nested Vectored Interrupt Controller):管理和处理中断。无论是使用中断方式还是 DMA 方式进行 UART 通信,都需要正确配置 NVIC 以确保中断能够正确触发和处理。
  • RCC(Reset and Clock Control):配置微控制器的时钟系统,包括内部和外部时钟源的选择、时钟分频、总线时钟的配置等。此处启用外部高速时钟HSE(其他 外部低速时钟LSE,内部高速时钟HSI,内部低速时钟LSI)
  • SYS(System Configuration):配置系统级别的设置,包括中断优先级、调试接口、复位源等。图中配置了SYS_SWDIOSYS_SWCLK引脚,用于调试接口。

外设部分配置了:

  • SPI1
  • SPI2
  • USART1

设置时钟

出来这个图,完全不知道是什么了...

stm32cubemx-clock

概念

时钟源(Clock Sources):

  • High Speed External (HSE) Clock:配置外部高速时钟(如晶振或外部时钟源)。
  • High Speed Internal (HSI) Clock:配置内部高速时钟。
  • Low Speed External (LSE) Clock:配置外部低速时钟(如 RTC 时钟源)。
  • Low Speed Internal (LSI) Clock:配置内部低速时钟。

系统时钟(System Clock):

  • SYSCLK:系统时钟,是所有时钟的核心,可以由 HSE、HSI 或 PLL 产生。
  • HCLK:AHB 总线时钟,用于 CPU、存储器和 DMA。
  • PCLK1:APB1 总线时钟,用于低速外设。
  • PCLK2:APB2 总线时钟,用于高速外设。

PLL配置(Phase-Locked Loop Configuration):

  • PLL Source:PLL 的输入时钟源(通常为 HSE 或 HSI)。
  • PLL Multipliers and Dividers:配置 PLL 的倍频和分频因子,以生成所需的时钟频率。

缩写:

  • AHB(Advanced High-performance Bus):高级高性能总线,链接高带宽和高性能外设,如DMA和存储控制器等。
  • APB(Advanced Peripheral Bus):低带宽的外设。不同的MCU上细分不同,比如F1系列又分APB1和APB2,其中APB1通常比APB2频率低。

配置

  • 选择时钟源(HSE或HSI)
  • 配置PLL(如果需要更高的时钟频率,使用PLL,并设置其倍频和分频因子)
  • 设置总线时钟分频器(AHB、APB1、APB2等)

EE STM32