STM32 Study Note

发布于 2025-08-06  366 次阅读


层级方式示例难度适合人群
高级HAL 库(CubeMX 默认)HAL_GPIO_WritePin()新手入门
中级LL 库(Low Layer)LL_GPIO_SetOutputPin()⭐⭐进阶者
底层直接寄存器`GPIOA->ODR= (1 << 5);`⭐⭐⭐
名称含义
GPIOA代表 GPIOA 端口
ODROutput Data Register,输出数据寄存器
1 << 5把第 5 位(PA5)置 1
`=`
HAL_Init();
SystemClock_Config();   // 已由 CubeMX 自动生成 72MHz 配置
MX_GPIO_Init();
while (1)
{
  HAL_GPIO_WritePin(GPIOA, GPIO_PIN_0, GPIO_PIN_SET);   // 设置高电平
  HAL_Delay(500);
  HAL_GPIO_WritePin(GPIOA, GPIO_PIN_0, GPIO_PIN_RESET); // 设置低电平
  HAL_Delay(500);
}

GPIO 初始化MX_GPIO_Init()

系统时钟SystemClock_Config()

CubeMX 中配置外部时钟 + GPIO 步骤

项目当前设置值含义 & 作用
GPIO output levelHigh初始化时的默认输出电平,上电时默认输出高电平(VDD)
GPIO modeOutput Push Pull输出推挽模式(标准输出)✅
GPIO Pull-up/Pull-downPull-up内部上拉电阻使引脚在悬空时为高电平(对输出口其实不起作用)
Maximum output speedMediumGPIO 切换速度为中等(10 MHz 左右)
User LabelLED给这个引脚设置标签(可读性提升)

官方定义说明(STM32 HAL 中):

#define GPIO_PIN_0                 ((uint16_t)0x0001)  // 1 << 0
#define GPIO_PIN_1 ((uint16_t)0x0002) // 1 << 1
...
#define GPIO_PIN_15 ((uint16_t)0x8000) // 1 << 15

注意这些宏是 uint16_t 类型,所以最多只能表达 16 位(即 PIN_0~15)。

GPIOA->ODR |= (1 << pin) 置高,或 GPIOA->ODR &= ~(1 << pin) 置低

| 31 … 16 | 15 … 0 |
| 复位位 Reset Bits | 设置位 Set Bits |
低 16 位(0~15 bit):将对应引脚 置高电平(写 1 有效)

高 16 位(16~31 bit):将对应引脚 置低电平(写 1 有效)

操作写入值说明
设置 PA5 为高电平GPIOA->BSRR = (1<<5)低 16 位 Bit5 写 1
设置 PA5 为低电平GPIOA->BSRR = (1<<21)高 16 位 Bit5 写 1(5+16)
GPIOx->BSRR = GPIO_PIN_0;  // 置 GPIOx 的第 0 引脚为高电平
GPIOx->BSRR = (uint32_t)GPIO_Pin << 16u;

ODR 修改需要 读 → 改 → 写,中断过程中可能打断写入操作。

BSRR 写入是 一次完成、原子操作,不会影响其他引脚,适合高实时场景(如中断、RTOS)

while (1)
{
    GPIOA->BSRR = (1 << 5);           // PA5 = 高
    HAL_Delay(500);                   // 延时 500ms
    GPIOA->BSRR = (1 << (5 + 16));    // PA5 = 低
    HAL_Delay(500);                   // 延时 500ms
}
for i in range(16):
    led_high = 1 << i
    led_low  = 1 << (i + 16)
    print(f"GPIO_PIN_{i:>2}:  SET=0x{led_high:08X}  RESET=0x{led_low:08X}")

Drivers/STM32F1xx_HAL_Driver/Inc/stm32f1xx_hal_gpio.h

| 宏定义名                          | 说明                |
| ----------------------------- | ----------------- |
| `GPIO_MODE_INPUT`             | 输入模式(默认悬浮)        |
| `GPIO_MODE_OUTPUT_PP`         | 推挽输出(能主动拉高+拉低)    |
| `GPIO_MODE_OUTPUT_OD`         | 开漏输出(只能拉低)        |
| `GPIO_MODE_AF_PP`             | 推挽复用功能(如 UART TX) |
| `GPIO_MODE_AF_OD`             | 开漏复用功能(如 I2C)     |
| `GPIO_MODE_ANALOG`            | 模拟模式(ADC)         |
| `GPIO_MODE_IT_RISING`         | 上升沿中断输入           |
| `GPIO_MODE_IT_FALLING`        | 下降沿中断输入           |
| `GPIO_MODE_IT_RISING_FALLING` | 双边沿中断输入           |

MX_GPIO_Init() 函数

GPIO_InitTypeDef GPIO_InitStruct = {0};

__HAL_RCC_GPIOA_CLK_ENABLE();  // 1️⃣ 使能 GPIOA 时钟

GPIO_InitStruct.Pin = GPIO_PIN_5;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;  // 2️⃣ 推挽输出模式
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);      // 3️⃣ 初始化 PA5

开漏模式:LED 长脚(正极)连 GPIO 短脚(负极)连电阻 → GND

GPIO_InitStruct.Pin = GPIO_PIN_0;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_OD;   // 开漏输出模式
GPIO_InitStruct.Pull = GPIO_PULLUP;           // 内部上拉电阻启用
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
选项含义用于哪些功能是否必须
HSE (High Speed Clock)高速外部时钟,通常为外接 8MHz 晶振主系统时钟(SYSCLK)、串口、USB、定时器等依赖准确时钟✅ 推荐开启(你的板子通常带 8MHz 晶振)
LSE (Low Speed Clock)低速外部时钟,常为 32.768KHz 晶体用于 RTC 实时时钟、低功耗定时、日历功能等❌ 通常不需要(除非你用到 RTC)

进阶:stm32 + 光敏电阻模块 + 有源蜂鸣器模块

光敏电阻模块Pin

引脚名功能
A0模拟输出(可选)
GND地线
D0数字输出(高/低电平)
VCC电源(一般 3.3V 或 5V)

有源蜂鸣器模块

蜂鸣器引脚说明连接到 STM32 小板
VCC电源(3.3V或5V)3.3V 或 5V(建议先用 5V)
GNDGND
I/O控制引脚(低电平触发)比如 PA0(GPIO输出)

有源蜂鸣器模块接线(低电平触发型)

蜂鸣器模块引脚说明接 STM32 小板
VCC电源5V(或 3.3V)
GNDGND
I/O控制输入PA0(输出)

光敏电阻模块接线(数字输出 D0)

光敏模块引脚说明接 STM32 小板
VCC电源(建议 5V)5V
GNDGND
D0数字信号输出(高/低)PA1(输入)
A0模拟输出(可忽略)不接或接 ADC
#include "main.h"

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

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

  while (1)
  {
    // 如果检测到低电平,说明环境变暗
    if (HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_1) == GPIO_PIN_RESET)
    {
      HAL_GPIO_WritePin(GPIOA, GPIO_PIN_0, GPIO_PIN_RESET); // 蜂鸣器响
    }
    else
    {
      HAL_GPIO_WritePin(GPIOA, GPIO_PIN_0, GPIO_PIN_SET); // 蜂鸣器关闭
    }

    HAL_Delay(100); // 稍作延时
  }
}

继电器吸合:

#define RELAY_ON()  HAL_GPIO_WritePin(GPIOA, GPIO_PIN_0, GPIO_PIN_RESET) // 低电平吸合
#define RELAY_OFF() HAL_GPIO_WritePin(GPIOA, GPIO_PIN_0, GPIO_PIN_SET)   // 高电平断开

RELAY_ON();   // 吸合
HAL_Delay(1000);
RELAY_OFF();  // 断开
HAL_Delay(1000);


一沙一世界,一花一天堂。君掌盛无边,刹那成永恒。