Bladeren bron

raw: 修复核心位操作速查表管道符未转义导致表格渲染错误

OpenCode 1 dag geleden
bovenliggende
commit
557a6a563d

+ 96 - 89
X-Knowledge-Base/raw/Joplin/嵌入式+Linux/STM32学习笔记/02-GPIO寄存器详解与三步进化法.md

@@ -6,7 +6,6 @@ author: "尚硅谷研究院"
 date: 2026-07-15
 created: 2026-07-15
 ---
-
 # GPIO寄存器详解与三步进化法
 
 > **用生活理解**:GPIO 就像一排开关(每个引脚一个),你可以用程序控制每个开关输出高/低电平(控制 LED),也可以读取每个开关的状态(读取按键)。"三步进化法"就是操作这些开关的方式从"直接掰电线"进化到"用遥控器按按钮"再到"声控"的过程。
@@ -30,13 +29,13 @@ GPIO(General-purpose input/output,通用型输入输出)是 STM32 芯片
 
 ### GPIO的主要特点
 
-| 特性 | 说明 |
-|------|------|
-| 引脚电平 | 0~3.3V(FT 引脚兼容 5V) |
-| 翻转速度 | 最快 50MHz(2 个时钟周期) |
-| 上下拉 | 内置可配置上下拉电阻(约 40KΩ) |
-| 驱动能力 | 最大 ±25mA 拉/灌电流 |
-| 中断能力 | 每个引脚均可作为 EXTI 中断输入 |
+| 特性     | 说明                             |
+| -------- | -------------------------------- |
+| 引脚电平 | 0~3.3V(FT 引脚兼容 5V)         |
+| 翻转速度 | 最快 50MHz(2 个时钟周期)       |
+| 上下拉   | 内置可配置上下拉电阻(约 40KΩ) |
+| 驱动能力 | 最大 ±25mA 拉/灌电流            |
+| 中断能力 | 每个引脚均可作为 EXTI 中断输入   |
 
 ---
 
@@ -47,6 +46,7 @@ GPIO(General-purpose input/output,通用型输入输出)是 STM32 芯片
 ### 保护二极管
 
 GPIO 引脚内部有两个保护二极管,分别连接到 VDD(3.3V)和 VSS(0V):
+
 - 当输入电压高于 VDD+0.3V 时,上方二极管导通,将电压钳位到 VDD
 - 当输入电压低于 VSS-0.3V 时,下方二极管导通,将电压拉高到 VSS
 
@@ -55,6 +55,7 @@ GPIO 引脚内部有两个保护二极管,分别连接到 VDD(3.3V)和 VSS
 ### 上下拉电阻
 
 两个开关控制引脚内部的上下拉电阻(典型值 40KΩ):
+
 - **上拉**:上开关闭合 → 引脚默认高电平
 - **下拉**:下开关闭合 → 引脚默认低电平
 - **浮空**:两个开关都断开 → 引脚电平不确定(高阻态)
@@ -63,6 +64,7 @@ GPIO 引脚内部有两个保护二极管,分别连接到 VDD(3.3V)和 VSS
 ### 施密特触发器(Schmitt Trigger)
 
 施密特触发器是一个带**迟滞特性**的比较器电路:
+
 - 输入信号从低到高:阈值约为 1.8V
 - 输入信号从高到低:阈值约为 1.2V
 - 这种**滞回特性**可以滤除信号上的噪声抖动,实现波形整形
@@ -82,35 +84,36 @@ GPIO 引脚内部有两个保护二极管,分别连接到 VDD(3.3V)和 VSS
 
 ## GPIO的8种工作模式
 
-| 模式 | 类型 | 用途 | P-MOS | N-MOS | 施密特触发器 | 上下拉 |
-|------|------|------|-------|-------|------------|-------|
-| 输入浮空 | 输入 | 按键、通信引脚 | 关闭 | 关闭 | 开 | 禁止 |
-| 输入上拉 | 输入 | 按键(默认高电平) | 关闭 | 关闭 | 开 | 上拉 |
-| 输入下拉 | 输入 | 按键(默认低电平) | 关闭 | 关闭 | 开 | 下拉 |
-| 模拟输入 | 输入 | ADC 采集 | 关闭 | 关闭 | **关闭** | 禁止 |
-| 通用推挽输出 | 输出 | LED、普通信号 | 交替 | 交替 | 开 | 禁止 |
-| 通用开漏输出 | 输出 | I2C 总线、电平转换 | 关闭 | 交替 | 开 | 禁止 |
-| 复用推挽输出 | 输出 | USART_TX、SPI_SCK | 交替 | 交替 | 开 | 禁止 |
-| 复用开漏输出 | 输出 | I2C_SCL/SDA | 关闭 | 交替 | 开 | 禁止 |
+| 模式         | 类型 | 用途               | P-MOS | N-MOS | 施密特触发器   | 上下拉 |
+| ------------ | ---- | ------------------ | ----- | ----- | -------------- | ------ |
+| 输入浮空     | 输入 | 按键、通信引脚     | 关闭  | 关闭  | 开             | 禁止   |
+| 输入上拉     | 输入 | 按键(默认高电平) | 关闭  | 关闭  | 开             | 上拉   |
+| 输入下拉     | 输入 | 按键(默认低电平) | 关闭  | 关闭  | 开             | 下拉   |
+| 模拟输入     | 输入 | ADC 采集           | 关闭  | 关闭  | **关闭** | 禁止   |
+| 通用推挽输出 | 输出 | LED、普通信号      | 交替  | 交替  | 开             | 禁止   |
+| 通用开漏输出 | 输出 | I2C 总线、电平转换 | 关闭  | 交替  | 开             | 禁止   |
+| 复用推挽输出 | 输出 | USART_TX、SPI_SCK  | 交替  | 交替  | 开             | 禁止   |
+| 复用开漏输出 | 输出 | I2C_SCL/SDA        | 关闭  | 交替  | 开             | 禁止   |
 
 ### 常见模式选择指导
 
-| 应用场景 | 推荐模式 |
-|----------|---------|
-| 驱动 LED | 推挽输出 |
-| 读取按键 | 上拉输入 或 下拉输入 |
+| 应用场景 | 推荐模式                     |
+| -------- | ---------------------------- |
+| 驱动 LED | 推挽输出                     |
+| 读取按键 | 上拉输入 或 下拉输入         |
 | I2C 通信 | 复用开漏输出(需要外部上拉) |
-| 串口 TX | 复用推挽输出 |
-| 串口 RX | 浮空输入 或 上拉输入 |
-| ADC 采样 | 模拟输入 |
-| SPI 通信 | 复用推挽输出 |
-| PWM 输出 | 复用推挽输出 |
+| 串口 TX  | 复用推挽输出                 |
+| 串口 RX  | 浮空输入 或 上拉输入         |
+| ADC 采样 | 模拟输入                     |
+| SPI 通信 | 复用推挽输出                 |
+| PWM 输出 | 复用推挽输出                 |
 
 ---
 
 ## GPIO的7个关键寄存器
 
 每个 GPIO 端口有 7 个 32 位寄存器,基地址如下:
+
 - GPIOA: `0x4001 0800`
 - GPIOB: `0x4001 0C00`
 - GPIOC: `0x4001 1000`
@@ -125,37 +128,40 @@ GPIO 引脚内部有两个保护二极管,分别连接到 VDD(3.3V)和 VSS
 
 控制 **Pin0~Pin7** 的配置模式。
 
-| 位域 | 名称 | 说明 |
-|------|------|------|
-| 31:30 | CNF7[1:0] | Pin7 配置位 |
+| 位域  | 名称       | 说明        |
+| ----- | ---------- | ----------- |
+| 31:30 | CNF7[1:0]  | Pin7 配置位 |
 | 29:28 | MODE7[1:0] | Pin7 模式位 |
-| ... | ... | ... |
-| 3:2 | CNF0[1:0] | Pin0 配置位 |
-| 1:0 | MODE0[1:0] | Pin0 模式位 |
+| ...   | ...        | ...         |
+| 3:2   | CNF0[1:0]  | Pin0 配置位 |
+| 1:0   | MODE0[1:0] | Pin0 模式位 |
 
 **MODE 位含义**:
-| MODE[1:0] | 模式 |
-|-----------|------|
-| 00 | 输入模式(复位状态) |
-| 01 | 输出,最大速度 10MHz |
-| 10 | 输出,最大速度 2MHz |
-| 11 | 输出,最大速度 50MHz |
+
+| MODE[1:0] | 模式                 |
+| --------- | -------------------- |
+| 00        | 输入模式(复位状态) |
+| 01        | 输出,最大速度 10MHz |
+| 10        | 输出,最大速度 2MHz  |
+| 11        | 输出,最大速度 50MHz |
 
 **CNF 位含义(输入模式下,即 MODE=00)**:
-| CNF[1:0] | 模式 |
-|----------|------|
-| 00 | 模拟输入 |
-| 01 | 浮空输入(复位状态) |
-| 10 | 上拉/下拉输入 |
-| 11 | 保留 |
+
+| CNF[1:0] | 模式                 |
+| -------- | -------------------- |
+| 00       | 模拟输入             |
+| 01       | 浮空输入(复位状态) |
+| 10       | 上拉/下拉输入        |
+| 11       | 保留                 |
 
 **CNF 位含义(输出模式下,即 MODE>00)**:
-| CNF[1:0] | 模式 |
-|----------|------|
-| 00 | 通用推挽输出 |
-| 01 | 通用开漏输出 |
-| 10 | 复用功能推挽输出 |
-| 11 | 复用功能开漏输出 |
+
+| CNF[1:0] | 模式             |
+| -------- | ---------------- |
+| 00       | 通用推挽输出     |
+| 01       | 通用开漏输出     |
+| 10       | 复用功能推挽输出 |
+| 11       | 复用功能开漏输出 |
 
 > **配置示例**:PA0 推挽输出 50MHz → MODE0[1:0]=11, CNF0[1:0]=00 → CRL 低 4 位 = 0011 = 0x3
 
@@ -165,34 +171,34 @@ GPIO 引脚内部有两个保护二极管,分别连接到 VDD(3.3V)和 VSS
 
 ### 3. GPIOx_IDR — 端口输入数据寄存器(Address: 0x08)
 
-| 位 | 说明 |
-|----|------|
-| 31:16 | 保留 |
-| 15:0 | IDRy:读取 Pin y 的输入电平(0=低,1=高) |
+| 位    | 说明                                      |
+| ----- | ----------------------------------------- |
+| 31:16 | 保留                                      |
+| 15:0  | IDRy:读取 Pin y 的输入电平(0=低,1=高) |
 
 ### 4. GPIOx_ODR — 端口输出数据寄存器(Address: 0x0C)
 
-| 位 | 说明 |
-|----|------|
-| 31:16 | 保留 |
-| 15:0 | ODRy:写入 Pin y 的输出电平(0=低,1=高) |
+| 位    | 说明                                      |
+| ----- | ----------------------------------------- |
+| 31:16 | 保留                                      |
+| 15:0  | ODRy:写入 Pin y 的输出电平(0=低,1=高) |
 
 ### 5. GPIOx_BSRR — 端口位设置/清除寄存器(Address: 0x10)
 
-| 位 | 名称 | 功能 |
-|----|------|------|
-| 31:16 | BRy | 清除 ODR 的对应位(写 1 清 0) |
-| 15:0 | BSy | 设置 ODR 的对应位(写 1 置 1) |
+| 位    | 名称 | 功能                           |
+| ----- | ---- | ------------------------------ |
+| 31:16 | BRy  | 清除 ODR 的对应位(写 1 清 0) |
+| 15:0  | BSy  | 设置 ODR 的对应位(写 1 置 1) |
 
 > **特点**:BSRR 是**原子操作**,同时写低 16 位和高 16 位不会冲突。
 > **对比**:`GPIOA->BSRR = (1<<0)` 相当于 `GPIOA->ODR |= (1<<0)`,但 BSRR 不需要"读-改-写"三步,不会被打断。
 
 ### 6. GPIOx_BRR — 端口位清除寄存器(Address: 0x14)
 
-| 位 | 说明 |
-|----|------|
-| 31:16 | 保留 |
-| 15:0 | BRy:清除 ODR 的对应位(写 1 清 0) |
+| 位    | 说明                                |
+| ----- | ----------------------------------- |
+| 31:16 | 保留                                |
+| 15:0  | BRy:清除 ODR 的对应位(写 1 清 0) |
 
 相当于 BSRR 高 16 位的简化版。
 
@@ -215,6 +221,7 @@ LED1 连接 PA0,低电平点亮。
 ![LED 电路原理图](assets/led_电路原理图.png)
 
 **原理**:
+
 ```
 PA0=1(3.3V) → LED 灭(两端电压差接近 0)
 PA0=0(0V)   → LED 亮(电流经 VCC→限流电阻→LED→PA0→GND)
@@ -398,27 +405,27 @@ int main(void)
 
 ### 三步进化法总结
 
-| 阶段 | 写法 | 优点 | 缺点 |
-|------|------|------|------|
-| 进化0 | 裸地址 | 理解硬件本质 | 烦琐、不安全 |
-| 进化1 | 结构体宏 | 可读性好 | 仍可能覆盖其他位 |
-| 进化2 | 位运算 | 只改需要的位 | 需查手册知移位次数 |
-| **进化3** | **位宏** | **最安全、最可读** | 需要了解宏名含义 |
+| 阶段            | 写法           | 优点                     | 缺点               |
+| --------------- | -------------- | ------------------------ | ------------------ |
+| 进化0           | 裸地址         | 理解硬件本质             | 烦琐、不安全       |
+| 进化1           | 结构体宏       | 可读性好                 | 仍可能覆盖其他位   |
+| 进化2           | 位运算         | 只改需要的位             | 需查手册知移位次数 |
+| **进化3** | **位宏** | **最安全、最可读** | 需要了解宏名含义   |
 
 ---
 
 ## 核心位操作速查表
 
-| 操作 | 语法 | 解释 |
-|------|------|------|
-| 位置1 | `REG |= BITMASK;` | 按位或:其他位不变,指定位置1 |
-| 位清0 | `REG &= ~BITMASK;` | 按位与+取反:其他位不变,指定位清0 |
-| 位翻转 | `REG ^= BITMASK;` | 按位异或:指定位置1变0,0变1 |
-| 位移位 | `x << N` | 左移N位(相当于乘 2^N) |
-| 位移位 | `x >> N` | 右移N位(相当于除 2^N) |
-| 测试位 | `if (REG & BITMASK)` | 按位与:测试指定位是否为1 |
-| 连续位置1 | `REG |= (MASK << N)` | 将 N 位开始的 MASK 位写入1 |
-| 连续位清0 | `REG &= ~(MASK << N)` | 将 N 位开始的 MASK 位清0 |
+| 操作      | 语法                    | 解释                               |
+| --------- | ----------------------- | ---------------------------------- |
+| 位置1     | `REG \|= BITMASK;`     | 按位或:指定位设为1,其他位不变    |
+| 位清0     | `REG &= ~BITMASK;`     | 按位与+取反:其他位不变,指定位清0 |
+| 位翻转    | `REG ^= BITMASK;`      | 按位异或:指定位置1变0,0变1       |
+| 位移位    | `x << N`               | 左移N位(相当于乘 2^N)            |
+| 位移位    | `x >> N`               | 右移N位(相当于除 2^N)            |
+| 测试位    | `if (REG & BITMASK)`   | 按位与:测试指定位是否为1          |
+| 连续位置1 | `REG \|= (MASK << N)`  | 将 N 位开始的 MASK 位置1           |
+| 连续位清0 | `REG &= ~(MASK << N)`  | 将 N 位开始的 MASK 位清0           |
 
 > **典型技巧**:`先清除后设置` 是嵌入式位操作的黄金法则。对连续位域(如 MODE[1:0])总是先 `&= ~MASK` 清空,再 `|= VALUE` 设置。
 
@@ -428,12 +435,12 @@ int main(void)
 
 (本笔记以寄存器操作为主,无标准库/HAL 库函数)
 
-| 操作 | 寄存器方式 | 说明 |
-|------|----------|------|
-| 设置输出高 | `GPIOx->BSRR = (1<<n)` | 原子操作,推荐 |
-| 设置输出低 | `GPIOx->BRR = (1<<n)` | 原子操作,推荐 |
-| 读取输入 | `uint8_t val = (GPIOx->IDR >> n) & 1` | 提取第n位值 |
-| 翻转输出 | `GPIOx->ODR ^= (1<<n)` | 异或翻转 |
+| 操作       | 寄存器方式                              | 说明           |
+| ---------- | --------------------------------------- | -------------- |
+| 设置输出高 | `GPIOx->BSRR = (1<<n)`                | 原子操作,推荐 |
+| 设置输出低 | `GPIOx->BRR = (1<<n)`                 | 原子操作,推荐 |
+| 读取输入   | `uint8_t val = (GPIOx->IDR >> n) & 1` | 提取第n位值    |
+| 翻转输出   | `GPIOx->ODR ^= (1<<n)`                | 异或翻转       |
 
 ## 常见问题与避坑