#include "stm32f4xx.h"
#define MY_PERIPH_BASE ((uint32_t)(0x40000000UL)) // 外设基地址
#define MY_AHB1PERIPH_BASE ((uint32_t)(MY_PERIPH_BASE + 0x20000UL)) // AHB1总线基地址
#define MY_RCC_BASE ((uint32_t)(MY_AHB1PERIPH_BASE + 0x3800UL)) // RCC基地址
#define MY_RCC_AHB1ENR ((uint32_t *)(MY_RCC_BASE + 0x30UL)) // AHB1外设时钟使能寄存器
#define MY_GPIOF_BASE ((uint32_t)(MY_AHB1PERIPH_BASE + 0x1400UL)) // GPIOF基地址
#define MY_GPIOF_MODER ((uint32_t *)(MY_GPIOF_BASE + 0x00UL)) // GPIOF端口模式寄存器
#define MY_GPIOF_ODR ((uint32_t *)(MY_GPIOF_BASE + 0x14UL)) // GPIOF输出数据寄存器
int main(void)
{ // AHB1外设时钟使能寄存器
*MY_RCC_AHB1ENR |= (1 << 5); // 让第5位置1,其它位不变
//配置pd9为输出模式
*MY_GPIOF_MODER &=~(1<<19);
*MY_GPIOF_MODER |= (1 << 18); // 让第18位置1,其它位不变
*MY_GPIOF_ODR &=~(1<<9);
return 0;
}
这段代码是基于 STM32F4 系列单片机的寄存器级底层初始化代码,核心功能是:配置 GPIOF 端口的第 9 号引脚(PF9)为推挽输出模式,并将其电平拉低(输出低电平)9号引脚接了个灯泡其实就是点灯。
一、宏定义:地址映射
这部分代码的作用是给STM32F4的特定寄存器地址起一个易记的名字,是寄存器操作的基础。
STM32 的所有外设(如 GPIO、RCC)都被映射到内存的特定地址上,我们可以通过指针直接访问这些地址来控制硬件。
-
外设基地址
#define MY_PERIPH_BASE ((uint32_t)(0x40000000UL))0x40000000UL是 STM32F4 系列单片机所有外设的起始地址。可以把它想象成一个巨大的仓库,里面存放着所有的硬件设备(GPIO、定时器、串口等)。uint32_t和UL都是为了明确这是一个32位的无符号长整型地址,避免编译时出现类型或溢出问题。
-
AHB1 总线基地址
#define MY_AHB1PERIPH_BASE ((uint32_t)(MY_PERIPH_BASE + 0x20000UL))- STM32 的外设被挂在不同的总线上,其中 AHB1 总线主要挂载高速外设,如 GPIO 端口、RCC 等。
- 这个宏定义了 AHB1 总线外设的起始地址,它是在外设基地址的基础上偏移了
0x20000。
-
RCC 基地址
#define MY_RCC_BASE ((uint32_t)(MY_AHB1PERIPH_BASE + 0x3800UL))RCC是 Reset and Clock Control(复位和时钟控制)的缩写。它是整个单片机的“心脏”,负责配置和分发系统时钟。任何外设要想工作,都必须先通过 RCC 为其使能时钟。- 这个宏定义了 RCC 外设的基地址。

-
RCC AHB1 外设时钟使能寄存器
#define MY_RCC_AHB1ENR ((uint32_t *)(MY_RCC_BASE + 0x30UL))- 这是一个非常关键的寄存器。它的全称是 RCC AHB1 peripheral clock enable register。
- 这个寄存器的每一个 bit 都对应一个挂在 AHB1 总线上的外设。当我们将某个 bit 置为
1时,就意味着给对应的外设“通电”(使能时钟)。 (uint32_t *)将计算出的地址强制转换为一个指向 32 位整数的指针,这样我们才能通过*来读写这个寄存器的值。

-
GPIOF 基地址
#define MY_GPIOF_BASE ((uint32_t)(MY_AHB1PERIPH_BASE + 0x1400UL))GPIOF是指 Port F,即 F 组 GPIO 端口。STM32F4 有多个 GPIO 端口(A, B, C, …, K 等),每个端口都有 16 个引脚(Pin 0 ~ Pin 15)。- 这个宏定义了 GPIOF 端口控制器的基地址。
-
GPIOF 模式寄存器
#define MY_GPIOF_MODER ((uint32_t *)(MY_GPIOF_BASE + 0x00UL))MODER是 Mode Register 的缩写,用于配置每个 GPIO 引脚的工作模式(输入、输出、复用功能等)。- 它是一个 32 位寄存器,每两位(bit)控制一个引脚。例如:
- Pin 0 由 bit 0 和 bit 1 控制。
- Pin 1 由 bit 2 和 bit 3 控制。
- …
- Pin 9 由 bit 18 和 bit 19 控制。 (这与我们后面的代码密切相关)
-
GPIOF 输出数据寄存器
#define MY_GPIOF_ODR ((uint32_t *)(MY_GPIOF_BASE + 0x14UL))ODR是 Output Data Register 的缩写,用于控制 GPIO 引脚的输出电平。- 它是一个 32 位寄存器,每一位(bit)对应一个引脚。
- 当引脚被配置为输出模式时,将
ODR的某一位置1,对应的引脚就输出高电平(VCC);置0则输出低电平(GND)。 - Pin 9 对应
ODR的 bit 9。
二、main 函数:核心逻辑
main 函数是程序的入口,所有代码从这里开始执行。
-
使能 GPIOF 时钟
*MY_RCC_AHB1ENR |= (1 << 5);- 这是操作寄存器的标准写法。
MY_RCC_AHB1ENR是一个指向时钟使能寄存器的指针,*是解引用操作,代表访问该地址上的值。 (1 << 5)的意思是将数字1向左移动 5 位,得到一个只有第 5 位为1的二进制数0b100000。|=是按位或赋值操作。它会将(1 << 5)的值与MY_RCC_AHB1ENR寄存器的当前值进行“或”运算,然后将结果写回寄存器。- 为什么是第 5 位? 根据 STM32F4 的芯片手册,
RCC_AHB1ENR寄存器的第 5 位(Bit 5)是GPIOFEN,专门用于使能 GPIOF 端口的时钟。 - 这一步是所有 GPIO 操作的前提! 如果不使能时钟,后续对 GPIOF 寄存器的所有操作都将无效。
- 这是操作寄存器的标准写法。
-
配置 PF9 为输出模式
*MY_GPIOF_MODER &= ~(1 << 19); *MY_GPIOF_MODER |= (1 << 18);- 这两行代码共同配置了 GPIOF 的第 9 号引脚(PF9)。
- 回顾一下,
MODER寄存器中,Pin 9 由 bit 18 和 bit 19 控制。 - 第一行
*MY_GPIOF_MODER &= ~(1 << 19);:(1 << 19)创建一个只有 bit 19 为1的掩码。~是按位取反操作,将这个掩码变成只有 bit 19 为0,其余都为1。&=是按位与赋值操作。这个操作可以保证 bit 19 被清零,而不影响其他位的值。这是一种安全的清位方法。
- 第二行
*MY_GPIOF_MODER |= (1 << 18);:(1 << 18)创建一个只有 bit 18 为1的掩码。|=操作可以保证 bit 18 被置为 1,同样不影响其他位。
- 最终结果:经过这两步,控制 PF9 的两位(bit 18 和 bit 19)被设置为
01。根据MODER寄存器的定义,01就代表该引脚被配置为 推挽输出模式(General purpose output push-pull)。
-
设置 PF9 输出低电平
*MY_GPIOF_ODR &= ~(1 << 9);- 现在 PF9 已经是输出模式了,这行代码用来控制它的输出电平。
(1 << 9)对应ODR寄存器的 bit 9。&= ~操作将 bit 9 清零。- 因此,GPIOF 的第 9 号引脚(PF9)会输出低电平(0V)。
-
程序结束
return 0;- 在嵌入式系统中,
main函数通常不会返回。返回0在这里只是一个形式,表示程序“正常”执行完毕。在实际的工程项目中,这里通常会是一个无限循环while(1),让单片机持续运行。
- 在嵌入式系统中,
核心功能是:初始化并将 GPIOF 端口的第 9 号引脚(PF9)设置为推挽输出低电平。
这样就完成点亮一个灯泡
3090

被折叠的 条评论
为什么被折叠?



