前言

STM32开发有主要几种方式分别为:

  • 标准库(StdPeriph)
  • 寄存器直接开发
  • HAL库(STM32Cube HAL)
    以上三种开发方式,有着不同的抽象层次、 控制能力、学习曲线。

一、寄存器直接开发

概述:

直接操作 MCU 的寄存器地址和位,不依赖任何库,仅使用 CMSIS 提供的头文件(如 stm32f10x.hstm32f4xx.h),手动读写寄存器。

优点:

  • 最底层、最轻量,代码最小化。
  • 完全掌控硬件,对于性能要求很极限的情景。

缺点:

  • 代码可读性差,维护困难。
  • 易错,手动位操作,容易忘记开启时钟等前置配置。
  • 兼容性差,迁移到其他芯片要重写大量代码。

示例:用裸寄存器配置 GPIO 输出 PA0

RCC->APB2ENR |= (1 << 2);        // 开启 GPIOA 时钟
GPIOA->CRL &= ~(0xF << (0 * 4)); // 清除 PA0 模式
GPIOA->CRL |= (0x1 << (0 * 4));  // 设置为通用推挽输出 10MHz
GPIOA->ODR |= (1 << 0);          // 设置 PA0 输出高电平

补充:嵌入式开发的各种位操作

  • 位操作的常见用法
用途 示例代码 解释(通俗理解)
设置某一位 reg |= (1 << n); 把第 n 位变成 1,其他位不变。常用于“打开一个功能”或“设置一个状态”。
清除某一位 reg &= ~(1 << n); 把第 n 位清零,其它位保持原样。常用于“关闭一个功能”或“清除标志位”。
读取某一位 reg & (1 << n) 取出第 n 位的值:是 0 还是 1?适合用来判断某功能是否被打开或标志是否被置位。
设置多位 reg |= mask; mask 指定的多位都变成 1。例如 mask = 0b00110100 会设置第 2、4、5 位为 1。
清除多位 reg &= ~mask; mask 指定的多位都清零。其余位不受影响。
读取多位 reg & mask; 取出 mask 指定的位的值。可用于分析多个状态位组合。
修改某几位 reg = (reg & ~mask) | (value << shift); 清掉某些位后,再把 value 写进去,常用于“配置某字段”。
判断某位为 1 if (reg & (1 << n)) 判断第 n 位是否是 1,是的话就执行 if 内的内容。
判断某位为 0 if (!(reg & (1 << n))) 判断第 n 位是否是 0,是的话就执行 if 内的内容。

二、标准库开发(StdPeriphLib)

概述:

ST 官方早期发布的库(多用于 STM32F1/F4),基于结构体封装,使用函数调用替代直接寄存器操作,比裸寄存器更友好,但仍保留底层控制能力

优点:

  • 文档丰富、资料多,初学者容易上手。
  • 易于理解底层行为,但又不用自己设置每个寄存器。
  • 跨平台方便(在 F1/F4 之间迁移简单)。

缺点:

  • ST 已停止更新(F0/F1/F4 支持,F7/H7 不支持)。
  • 抽象度中等,还是偏底层,需要理解时钟树、寄存器含义。

示例:使用标准库配置 GPIO PA0 输出

GPIO_InitTypeDef GPIO_InitStructure;

RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); // 使能时钟
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_10MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);               // 初始化 GPIO

GPIO_SetBits(GPIOA, GPIO_Pin_0);                     // 设置 PA0 高

三、HAL 库开发(STM32Cube HAL)

概述:

ST 官方现在主推的 STM32Cube HAL(Hardware Abstraction Layer)库,包含 CubeMX 配套图形化配置工具。HAL 是高度封装的抽象层,对所有外设都提供一致接口。

优点:

  • 快速上手:通过 STM32CubeMX 生成初始化代码。
  • 跨平台能力强,F0~H7 通用接口。
  • 支持 RTOS / USB / LWIP / FATFS 等中间件集成
  • 易于调试,很多函数内部会检查错误状态。

缺点:

  • 封装较重,性能差一些
  • 代码臃肿,不适合资源非常受限的项目。
  • 很多细节隐藏了,不利于底层理解。

示例:使用 HAL 初始化 GPIO PA0 输出

void MX_GPIO_Init(void)
{
  GPIO_InitTypeDef GPIO_InitStruct = {0};

  __HAL_RCC_GPIOA_CLK_ENABLE(); // 启用 GPIOA 时钟

  GPIO_InitStruct.Pin = GPIO_PIN_0;
  GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;

  HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

  HAL_GPIO_WritePin(GPIOA, GPIO_PIN_0, GPIO_PIN_SET); // PA0 输出高
}

三者比较总结:

特性 寄存器开发 标准库开发(StdPeriph) HAL 库开发
开发门槛
控制粒度 最强 中等偏弱
学习硬件原理 ★★★★★ ★★★★☆ ★★☆☆☆
可移植性
编码效率 中等
资源占用 最小 最大
支持芯片范围 全部 部分 (F0~F4) 全系列 (CubeMX 支持的都有)
ST 官方支持 停止维护 有历史资料 正在维护中

参考文档

AI

Logo

智能硬件社区聚焦AI智能硬件技术生态,汇聚嵌入式AI、物联网硬件开发者,打造交流分享平台,同步全国赛事资讯、开展 OPC 核心人才招募,助力技术落地与开发者成长。

更多推荐