一、芯片简介

我使用的是 STM32F103VET6 芯片,板载 USB 转串口芯片(CH340/CP2102 等)和 SWD 调试接口。

学习资料:江协科技 STM32 教程(B站)

开发平台:Keil MDK-ARM v5

库版本:STM32F10x 标准外设库(StdPeriph Library)

开发板选择:复刻开源的STM32电赛开发板

1.1 芯片型号解读

STM32 F 103 V E T 6
      │  │   │ │ │ └── 温度等级:6 = 工业级 -40℃ ~ +85℃
      │  │   │ │ └──── 封装类型:T = LQFP
      │  │   │ └────── Flash容量:E = 512KB
      │  │   └──────── 引脚数:V = LQFP100(100引脚)
      │  └──────────── 系列编号:103 = 中容量增强型
      └─────────────── 产品类型:F = 通用主流闪存 MCU
字段 含义 本芯片参数
F 通用主流闪存 MCU F1 系列(经典M3内核)
103 中容量增强型 外设齐全:ADC、高级定时器TIM1、CAN、USB
V 引脚封装 LQFP100,共100个引脚
E Flash 容量 512KB Flash 程序存储器
T 封装类型 LQFP 薄型四方扁平封装
6 温度等级 工业级,-40℃ ~ +85℃

1.2 核心资源概览

  • 内核:ARM Cortex-M3,最高 72MHz 主频

  • 存储器:512KB Flash + 64KB SRAM

  • GPIO:最多 80 个快速 IO 口,支持 5V 容忍

  • 定时器:8 个定时器(含 1 个高级控制定时器 TIM1)

  • 通信接口:USART×3、SPI×2、I2C×2、USB、CAN、SDIO

  • 模拟外设:ADC×2(12位,共16通道)、DAC×2

  • 电源:2.0V ~ 3.6V 供电,典型工作电压 3.3V

1.3 典型应用场景

  1. 电子竞赛、单片机课程学习、毕业设计

  2. 电机驱动小车、平衡车、舵机控制系统

  3. 数据采集、温湿度/压力传感器采集设备

  4. 工业简易控制器、RS485/CAN 总线节点

  5. 蓝牙/WiFi 串口透传设备、OLED 显示屏控制器

  6. 智能门锁、小型家电控制板、USB 虚拟串口工具


二、GPIO 原理详解

2.1 什么是 GPIO

GPIO(General Purpose Input/Output,通用输入输出端口)是单片机最基本的外设,可以通过软件配置引脚为输入或输出模式,实现与外部电路的数字信号交互。

STM32F103 的 GPIO 按端口分组:GPIOA、GPIOB、GPIOC …… GPIOG,每组最多 16 个引脚(Px0 ~ Px15)。

2.2 GPIO 八种工作模式

模式 分类 特点与应用
GPIO_Mode_AIN 输入-模拟 接 ADC 模拟输入,关闭施密特触发,功耗最低
GPIO_Mode_IN_FLOATING 输入-浮空 复位后默认状态,电平不确定,一般用于按键外部输入
GPIO_Mode_IPD 输入-下拉 内部下拉电阻,默认低电平
GPIO_Mode_IPU 输入-上拉 内部上拉电阻,默认高电平
GPIO_Mode_Out_OD 输出-开漏 只能拉低,高电平由外部上拉决定,可做线与、I2C
GPIO_Mode_Out_PP 输出-推挽 高低电平都由内部 MOS 管驱动,驱动能力强,常用
GPIO_Mode_AF_OD 复用-开漏 片上外设(如I2C)的开漏输出
GPIO_Mode_AF_PP 复用-推挽 片上外设(如SPI、USART TX)的推挽输出

2.3 推挽输出 vs 开漏输出(重点)

推挽输出(Push-Pull)
  • 输出高电平时:P-MOS 导通,N-MOS 截止 → 引脚被强拉到 VDD

  • 输出低电平时:N-MOS 导通,P-MOS 截止 → 引脚被强拉到 GND

  • 优点:高低电平都有驱动能力,速度快

  • 缺点:不能直接线与(两个推挽输出接在一起会短路)

  • 应用:LED 驱动、普通数字输出、SPI 等

开漏输出(Open-Drain)
  • 输出高电平时:P-MOS、N-MOS 都截止 → 引脚呈高阻态,电平由外部上拉决定

  • 输出低电平时:N-MOS 导通 → 引脚被拉到 GND

  • 优点:可实现线与逻辑、电平转换(外部上拉到不同电压)

  • 缺点:高电平驱动能力弱,需要外部上拉电阻

  • 应用:I2C 总线、电平转换、多路共线

2.4 GPIO 输出速度

速度配置 翻转速率 适用场景
GPIO_Speed_2MHz 2 MHz 低速、低功耗、抗干扰要求高
GPIO_Speed_10MHz 10 MHz 一般应用
GPIO_Speed_50MHz 50 MHz 高速信号、SPI 等

三、RCC 时钟系统(为什么要先开时钟)

3.1 为什么必须使能时钟

STM32 为了降低功耗,所有外设默认都是关闭时钟的。未开启时钟的外设,其寄存器无法读写,配置无效。这是新手最容易踩的坑之一。

GPIO 挂载在 APB2 总线上,所以要用 RCC_APB2PeriphClockCmd() 开启对应端口的时钟。

3.2 STM32 时钟树概览

          ┌─────────┐
 HSE(8M)──┤ PLL 倍频 ├──→ 72MHz SYSCLK ──→ AHB总线 ──→ APB1(最大36M)
          └─────────┘                              └──→ APB2(最大72M)
 HSI(8M)──┘
 LSE(32.768K) → RTC
 LSI(40K) → IWDG
  • SYSCLK:系统时钟,最高 72MHz

  • AHB:高速总线,主频 72MHz,DMA、SDIO 等挂在这里

  • APB2:高速外设总线,最高 72MHz,GPIO、ADC、USART1、TIM1 等

  • APB1:低速外设总线,最高 36MHz,USART2/3、SPI2、TIM2~7 等

3.3 常用时钟使能函数

// 开启 GPIOA 时钟(APB2 总线)
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
​
// 同时开启多个外设时钟(用 | 位或)
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB, ENABLE);

四、点亮 LED —— 完整详解

4.1 硬件接线

共阳接法(本笔记采用)

  • LED 阳极(长脚)→ 限流电阻 → 3.3V

  • LED 阴极(短脚)→ PA0 引脚

  • 当 PA0 输出低电平时,LED 点亮

  • 当 PA0 输出高电平时,LED 熄灭

3.3V ──[ 1kΩ ]───►|─── PA0
         限流电阻   LED

为什么需要限流电阻?

LED 是电流型器件,正向压降约 1.8~2.2V(红色)。不加电阻会导致电流过大烧坏 LED 甚至单片机引脚。

计算公式:R = (Vcc - Vf) / If = (3.3V - 2V) / 10mA ≈ 130Ω实际常用 330Ω ~ 1kΩ,电流越小亮度越低但更安全。

4.2 初始化四步法

GPIO 初始化遵循标准的「结构体配置法」,这是 STM32 标准库的通用套路:

  1. 定义配置结构体 → 准备参数容器

  2. 开启外设时钟 → 给外设供电(最容易忘!)

  3. 填充结构体参数 → 设置引脚号、模式、速度

  4. 调用初始化函数 → 写入寄存器,生效

4.3 完整代码(逐行注释)

#include "stm32f10x.h"  // STM32F10x 标准库头文件
​
/**
 * @brief  PA0 引脚初始化(推挽输出,驱动LED)
 * @param  无
 * @retval 无
 */
void LED_Init(void)
{
    // 第一步:定义一个 GPIO 初始化结构体变量(空白模板)
    // GPIO_InitTypeDef 是标准库定义的结构体类型
    GPIO_InitTypeDef GPIO_InitStructure;
    
    // 第二步:开启 GPIOA 端口时钟
    // 注意:所有外设使用前必须先开时钟,否则配置无效!
    // GPIOA 挂载在 APB2 总线上
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
    
    // 第三步:配置结构体参数
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;        // 选择引脚:PA0
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; // 模式:推挽输出
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;// 速度:50MHz
    
    // 第四步:调用初始化函数,将配置写入寄存器
    // 参数1:哪个端口(GPIOA/GPIOB...)
    // 参数2:结构体指针(取地址 &)
    GPIO_Init(GPIOA, &GPIO_InitStructure);
    
    // 初始化后默认输出高电平,LED熄灭(共阳接法)
    GPIO_SetBits(GPIOA, GPIO_Pin_0);
}
​
int main(void)
{
    // 调用 LED 初始化函数
    LED_Init();
    
    // PA0 输出低电平 → LED 点亮
    GPIO_ResetBits(GPIOA, GPIO_Pin_0);
    
    // 主循环死循环,防止程序跑飞
    while(1)
    {
        // 空循环,程序停在这里
    }
}
​

4.4 常用 GPIO 输出库函数

函数 功能 示例
GPIO_SetBits(GPIOx, GPIO_Pin_x) 置位(输出高电平) GPIO_SetBits(GPIOA, GPIO_Pin_0);
GPIO_ResetBits(GPIOx, GPIO_Pin_x) 复位(输出低电平) GPIO_ResetBits(GPIOA, GPIO_Pin_0);
GPIO_WriteBit(GPIOx, GPIO_Pin_x, BitVal) 写指定引脚电平 GPIO_WriteBit(GPIOA, GPIO_Pin_0, Bit_RESET);
GPIO_Write(GPIOx, PortVal) 写整个端口16位 GPIO_Write(GPIOA, 0x00FF);
GPIO_ReadOutputDataBit(GPIOx, GPIO_Pin_x) 读输出寄存器某一位 回读自己输出的电平
GPIO_ReadInputDataBit(GPIOx, GPIO_Pin_x) 读输入引脚电平 按键检测时用

五、扩展练习:LED 闪烁

在点亮的基础上,加入延时函数实现闪烁效果:

#include "stm32f10x.h"
​
/**
 * @brief  简单延时函数(软件延时,不准,仅入门用)
 * @param  time: 延时参数,数值越大延时越长
 */
void Delay(uint32_t time)
{
    while(time--);
}
​
void LED_Init(void)
{
    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_50MHz;
    GPIO_Init(GPIOA, &GPIO_InitStructure);
}
​
int main(void)
{
    LED_Init();
    
    while(1)
    {
        GPIO_ResetBits(GPIOA, GPIO_Pin_0);  // 亮
        Delay(5000000);                      // 延时
        GPIO_SetBits(GPIOA, GPIO_Pin_0);    // 灭
        Delay(5000000);                      // 延时
    }
}

六、常见问题与排错

6.1 LED 不亮怎么办?按顺序排查

  1. 时钟开了吗? → 检查 RCC_APB2PeriphClockCmd 是否正确调用

  2. 引脚号对吗? → 代码里的引脚和实际接线的引脚一致吗?

  3. 模式对吗? → 必须是 GPIO_Mode_Out_PP 推挽输出

  4. LED 正负极接反了吗? → 长脚阳极、短脚阴极,共阳接法阴极接单IO

  5. 限流电阻接了吗? → 没接可能烧坏 LED

  6. 编译下载成功了吗? → 检查 Keil 是否提示 "Program Done"

  7. 板子上电了吗? → 最基础但最容易忘

6.2 Keil 编译报错:#1 error: "..."

如果复制代码后重建工程报错,检查:

  • 文件最后一行是否为空行 → C 标准要求源文件末尾必须有换行

  • 头文件路径是否添加 → Options → C/C++ → Include Paths

  • 标准库文件是否全部添加 → stm32f10x_gpio.c、stm32f10x_rcc.c 等

6.3 下载失败

  • 检查 SWD 接线(SWDIO、SWCLK、GND 三根必接)

  • 检查芯片是否被锁死(可通过串口 ISP 擦除解除)

  • 检查调试器驱动是否安装(ST-Link / J-Link)

  • 检查启动模式选择是否正确


七、知识总结

7.1 GPIO 输出初始化口诀

一时钟,二结构,三模式,四速度,五调用初始化

  1. 开时钟(RCC)

  2. 定义结构体

  3. 选引脚(Pin)

  4. 设模式(Mode)

  5. 设速度(Speed)

  6. 调 Init 函数

7.2 核心知识点

  • STM32 外设默认关闭时钟,使用前必须使能

  • GPIO 有 8 种工作模式,推挽输出最常用

  • 推挽输出高低都能驱动,开漏输出只能拉低

  • BSRR 寄存器实现原子位操作,比改 ODR 更安全

  • LED 一定要串联限流电阻

Logo

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

更多推荐