点灯案例实现
#include <stdint.h>
typedef volatile struct
{
uint32_t CRL; // 0x00
uint32_t CRH; // 0x04
uint32_t IDR; // 0x08
uint32_t ODR; // 0x0C
uint32_t BSRR; // 0x10
uint32_t BRR; // 0x14
uint32_t LCKR; // 0x18
} GPIO_TypeDef;
#define GPIOB_BASE 0x40010C00UL
#define GPIOB ((GPIO_TypeDef *)GPIOB_BASE)
int main()
{
uint32_t *pAPB2ENR = (uint32_t *)0x40021018;
*pAPB2ENR |= (1 << 3);
// 清除 PB5 的配置位 [23:20]
uint32_t clear_mask = 0xF; // 00000000 00000000 00000000 00001111
clear_mask = clear_mask << (5 * 4); // 00000000 11110000 00000000 00000000
clear_mask = ~clear_mask; // 11111111 00001111 11111111 11111111
GPIOB->CRL = GPIOB->CRL & clear_mask;
// 设置 PB5 为推挽输出模式,最大速度为 50MHz
uint32_t config_value = 0x3; // 00000000 00000000 00000000 00000011
config_value = config_value << (5 * 4); // 00000000 00110000 00000000 00000000
GPIOB->CRL = GPIOB->CRL | config_value;
// 点亮 PB5
uint32_t pin_mask = 1; // 00000000 00000000 00000000 00000001
pin_mask = pin_mask << 5; // 00000000 00000000 00000000 00010000
pin_mask = ~pin_mask; // 11111111 11111111 11111111 11101111
GPIOB->ODR = GPIOB->ODR & pin_mask;
while (1)
{
}
}
点灯案例解读
1、时钟使能
- 参考【硬件手册】,找到灯 LED0 的 GPIO 为 PB5,PB5 表示它在 GPIO 端口 B 的第 5 号引脚

- 参考【STM32 参考手册】,找到 GPIOB 对应的总线,这里是 APB2

- 参考【STM32 参考手册】,找到复位和时钟控制 RCC 的起始地址,这里是
0x4002 1000 - 0x4002 13FF

- 参考【STM32 参考手册】,找到 APB2 对应的时钟寄存器
RCC_APB2ENR
,偏移量为018h
- 注:
018h
是一种表示十六进制数的写法,主要用于某些汇编语言和旧式编程环境中
h 后缀:表示这是一个十六进制数(Hexadecimal)
前导 0:是可选的,用于对齐或格式美观,例如,018h 和 18h 相同
实际值:18h = 0x18 = 24(十进制)

寄存器名 | 偏移量 | 地址 | 说明 |
---|---|---|---|
RCC_CR | 0x00 | 0x40021000 | 时钟控制寄存器 |
RCC_CFGR | 0x04 | 0x40021004 | 时钟配置寄存器 |
RCC_CIR | 0x08 | 0x40021008 | 时钟中断寄存器 |
RCC_APB2RSTR | 0x0C | 0x4002100C | APB2 外设复位寄存器 |
RCC_APB1RSTR | 0x10 | 0x40021010 | APB1 外设复位寄存器 |
RCC_AHBENR | 0x14 | 0x40021014 | AHB 外设时钟使能 |
RCC_APB2ENR | 0x18 | 0x40021018 | APB2 外设时钟使能 |
RCC_APB1ENR | 0x1C | 0x4002101C | APB1 外设时钟使能 |
RCC_BDCR | 0x20 | 0x40021020 | 备份域控制寄存器 |
RCC_CSR | 0x24 | 0x40021024 | 控制 / 状态寄存器 |
- 参考【STM32 参考手册】,GPIOB 时钟使能位是第 3 位(从 0 开始),使能 GPIOB 时钟

位号 | 名称 | 说明 |
---|---|---|
0 | AFIOEN | 复用功能 IO 时钟使能 |
2 | IOPAEN | GPIOA 时钟使能 |
3 | IOPBEN | GPIOB 时钟使能 |
4 | IOPCEN | GPIOC 时钟使能 |
5 | IOPDEN | GPIOD 时钟使能 |
6 | IOPEEN | GPIOE 时钟使能 |
… | … | … |
uint32_t *pAPB2ENR = (uint32_t *)0x40021018;
*pAPB2ENR |= (1 << 3);
2、点亮灯
- 参考【STM32 参考手册】,找到 GPIOB 的起始地址,这里是
0X4001 0C00 - 0x4001 0FFF

寄存器名 | 偏移量 | 地址 | 说明 |
---|---|---|---|
GPIOB_CRL | 0x00 | 0x4001 0C00 | 配置 PB0 ~ PB7 的模式(输入 / 输出等) |
GPIOB_CRH | 0x04 | 0x4001 0C04 | 配置 PB8 ~ PB15 的模式(输入 / 输出等) |
GPIOB_IDR | 0x08 | 0x4001 0C08 | 读取引脚输入电平 |
GPIOB_ODR | 0x0C | 0x4001 0C0C | 控制引脚输出电平 |
GPIOB_BSRR | 0x10 | 0x4001 0C10 | 原子操作(置位 / 复位引脚) |
GPIOB_BRR | 0x14 | 0x4001 0C14 | 快速复位引脚(仅写) |
GPIOB_LCKR | 0x18 | 0x4001 0C18 | 锁定引脚配置 |
保留 | 0x1C~0x3FF | - | 未使用,为未来扩展预留 |
- 参考【STM32 参考手册】,操作
GPIOx_CRL
,清除 PB5 的配置位

// 清除 PB5 的配置位 [23:20]
uint32_t clear_mask = 0xF; // 00000000 00000000 00000000 00001111
clear_mask = clear_mask << (5 * 4); // 00000000 11110000 00000000 00000000
clear_mask = ~clear_mask; // 11111111 00001111 11111111 11111111
GPIOB->CRL = GPIOB->CRL & clear_mask;
- 参考【STM32 参考手册】,操作
GPIOx_CRL
,设置 PB5 为推挽输出模式,最大速度为 50MHz

// 设置 PB5 为推挽输出模式,最大速度为 50MHz
uint32_t config_value = 0x3; // 00000000 00000000 00000000 00000011
config_value = config_value << (5 * 4); // 00000000 00110000 00000000 00000000
GPIOB->CRL = GPIOB->CRL | config_value;
- 参考【STM32 参考手册】,操作
GPIOB_ODR
,点亮 PB5

uint32_t pin_mask = 1; // 00000000 00000000 00000000 00000001
pin_mask = pin_mask << 5; // 00000000 00000000 00000000 00010000
pin_mask = ~pin_mask; // 11111111 11111111 11111111 11101111
GPIOB->ODR = GPIOB->ODR & pin_mask;
补充学习
1、GPIOx_CRL
与 GPIOx_CRH
-
GPIOx_CRL
(Port Configuration Register Low)用于配置 GPIO 端口低 8 位引脚(Pin0 - Pin7)的工作模式,每个引脚占用 4 个位,共 32 位 -
GPIOx_CRH
(Port Configuration Register High)用于配置 GPIO 端口高 8 位引脚(Pin8 - Pin15)的工作模式,每个引脚占用 4 个位,共 32 位
- 每个引脚的配置由
CNFy[1:0]
与MODEy[1:0]
组成
位域 | 说明 |
---|---|
CNFy[1:0] | 配置位,控制引脚的工作模式 |
MODEy[1:0] | 模式位,控制输出模式的速率或输入模式 |
CNFy 值 | 输入模式(MODEy = 00 ) | 输出模式(MODEy > 00 ) |
---|---|---|
00 | 模拟输入 | 通用推挽输出 |
01 | 浮空输入(复位默认) | 通用开漏输出 |
10 | 上拉 / 下拉输入 | 复用功能推挽输出 |
11 | 保留 | 复用功能开漏输出 |
2、清除配置位
- 清除 PB0 的配置位
// 清除 PB0 的配置位 [3:0]
uint32_t clear_mask = 0xF; // 00000000 00000000 00000000 00001111
clear_mask = clear_mask << (0 * 4); // 00000000 00000000 00000000 00001111
clear_mask = ~clear_mask; // 11111111 11111111 11111111 11110000
GPIOB->CRL = GPIOB->CRL & clear_mask;
- 清除 PB1 的配置位
// 清除 PB1 的配置位 [7:4]
uint32_t clear_mask = 0xF; // 00000000 00000000 00000000 00001111
clear_mask = clear_mask << (1 * 4); // 00000000 00000000 00000000 11110000
clear_mask = ~clear_mask; // 11111111 11111111 11111111 00001111
GPIOB->CRL = GPIOB->CRL & clear_mask;
- 清除 PB2 的配置位
// 清除 PB2 的配置位 [11:8]
uint32_t clear_mask = 0xF; // 00000000 00000000 00000000 00001111
clear_mask = clear_mask << (1 * 4); // 00000000 00000000 00001111 00000000
clear_mask = ~clear_mask; // 11111111 11111111 11110000 11111111
GPIOB->CRL = GPIOB->CRL & clear_mask;
- 依次类推,清除 PB5 的配置位
// 清除 PB5 的配置位 [23:20]
uint32_t clear_mask = 0xF; // 00000000 00000000 00000000 00001111
clear_mask = clear_mask << (5 * 4); // 00000000 11110000 00000000 00000000
clear_mask = ~clear_mask; // 11111111 00001111 11111111 11111111
GPIOB->CRL = GPIOB->CRL & clear_mask;
2、GPIOB_ODR
位域 | 说明 |
---|---|
ODRy[15:0] | 每个 ODRy 位对应一个 GPIO 引脚 0:输出低电平 1:输出高电平 |
保留[31:16 ] | 保留 |