AT32 GPIO — LED 翻转闪烁(入门第一个实验)

AT32F403A GPIO 输出控制 LED 灯,嵌入式开发最基础的入门实验

GPIO — LED 翻转闪烁

难度: ⭐(零基础入门)
固件库: AT32F403A_407_Firmware_Library V2.2.2
源文件: project/at_start_f403a/examples/gpio/led_toggle/src/main.c


这个实验是干嘛的?

如果你是第一次接触 MCU 开发,这个实验就是你的"Hello World"。

目标很简单:让开发板上的 3 个 LED 灯像跑马灯一样依次闪烁。

通过这个实验你将学会:

  • MCU 程序的基本结构(初始化 → 主循环)
  • GPIO 输出模式的概念
  • 如何用软件控制一个引脚的高低电平

硬件准备

  • AT32F403A 开发板(AT-START-F403A)
  • USB 数据线(供电 + 下载)
  • 不需要任何额外接线,LED 焊在板子上了

开发板上一般有 3 个 LED,分别连接在:

  • LED2 → PB5
  • LED3 → PB6
  • LED4 → PB4

(具体引脚请看你的开发板原理图)


完整代码

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#include "at32f403a_407_board.h"
#include "at32f403a_407_clock.h"

int main(void)
{
  /* 第一步:配置系统时钟(让 MCU 跑起来) */
  system_clock_config();

  /* 第二步:初始化开发板上的外设(LED、按键等) */
  at32_board_init();

  /* 第三步:主循环,反复执行 */
  while(1)
  {
    at32_led_toggle(LED2);   // 翻转 LED2 的状态(亮→灭 或 灭→亮)
    delay_ms(200);           // 等 200 毫秒

    at32_led_toggle(LED3);   // 翻转 LED3
    delay_ms(200);

    at32_led_toggle(LED4);   // 翻转 LED4
    delay_ms(200);
  }
}

代码逐行讲解

1. 头文件

1
2
#include "at32f403a_407_board.h"   // 板级支持包(LED、按键、串口等封装好的函数)
#include "at32f403a_407_clock.h"   // 时钟配置

这两个头文件是雅特力官方提供的"工具箱"。board.h 里面封装了 at32_led_toggle()delay_ms() 这些方便的函数,你不用自己去操作寄存器。

2. 系统时钟初始化

1
system_clock_config();

MCU 上电后默认用内部低速时钟(8MHz),这行代码把它切换到高速时钟(比如 240MHz)。这行必须放在最前面,否则后面所有依赖时钟的功能都不正常。

3. 板级初始化

1
at32_board_init();

这行代码帮你把开发板上的 LED、按键等外设都初始化好了。具体做了什么?它内部会:

  • 使能 GPIO 端口的时钟
  • 把 LED 对应的引脚配置为推挽输出模式

4. 主循环

1
2
3
4
5
6
while(1)
{
    at32_led_toggle(LED2);
    delay_ms(200);
    ...
}

while(1) 是死循环,MCU 会一直在这里面转。

at32_led_toggle(LED2) 做的事情很简单:如果 LED2 当前是亮的,就灭掉;如果是灭的,就点亮。本质就是把引脚电平取反

delay_ms(200) 等待 200 毫秒。不加延时的话,翻转太快人眼看不到闪烁(可能只看到 LED 常亮或常暗)。


如果不用封装函数,怎么自己操作 GPIO?

at32_led_toggle() 是官方帮你封装好的。如果你想知道底层怎么实现的,看 io_toggle 那个示例:

1
2
3
4
5
// 直接操作寄存器,把 PA1 拉高(输出 3.3V)
GPIOA->scr = GPIO_PINS_1;

// 直接操作寄存器,把 PA1 拉低(输出 0V)
GPIOA->clr = GPIO_PINS_1;
  • scr(Set Control Register):写 1 拉高,写 0 无效
  • clr(Clear Register):写 1 拉低,写 0 无效

这就是 GPIO 输出的最底层操作。at32_led_toggle() 内部也是类似逻辑,只是多了一步判断当前状态。


GPIO 初始化的完整写法

at32_board_init() 帮你做了 GPIO 初始化。如果你想自己配置一个新引脚,完整流程是:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
void gpio_config(void)
{
  gpio_init_type gpio_init_struct;

  /* 第一步:使能 GPIO 端口时钟 */
  // 不开时钟,GPIO 寄存器无法访问!这是最常见的坑
  crm_periph_clock_enable(CRM_GPIOA_PERIPH_CLOCK, TRUE);

  /* 第二步:填充默认参数 */
  gpio_default_para_init(&gpio_init_struct);

  /* 第三步:配置参数 */
  gpio_init_struct.gpio_pins = GPIO_PINS_1;              // 选择引脚 1
  gpio_init_struct.gpio_mode = GPIO_MODE_OUTPUT;          // 输出模式
  gpio_init_struct.gpio_out_type = GPIO_OUTPUT_PUSH_PULL; // 推挽输出
  gpio_init_struct.gpio_pull = GPIO_PULL_NONE;            // 不需要上下拉
  gpio_init_struct.gpio_drive_strength = GPIO_DRIVE_STRENGTH_STRONGER; // 强驱动

  /* 第四步:应用配置 */
  gpio_init(GPIOA, &gpio_init_struct);
}

关键参数解释

参数 含义 常用值
gpio_mode 输入/输出/复用/模拟 输出用 GPIO_MODE_OUTPUT
gpio_out_type 推挽/开漏 一般用推挽 PUSH_PULL
gpio_pull 上拉/下拉/无 输出一般不需要 PULL_NONE
gpio_drive_strength 驱动能力 驱动 LED 用 STRONGER

实验现象

  1. 编译、下载程序到开发板
  2. 板子上 3 个 LED 灯依次交替闪烁
  3. 每个灯亮 200ms 后切换到下一个,形成流水灯效果

如果 LED 不亮:

  • 检查程序是否下载成功
  • 确认 LED 引脚与代码一致(看原理图)
  • 确认 system_clock_config() 在最前面

小结

概念 说明
GPIO 通用输入输出,MCU 最基础的外设
推挽输出 可以主动输出高电平和低电平
寄存器操作 scr 拉高、clr 拉低
封装函数 at32_led_toggle() 比直接操作寄存器更方便

学了 GPIO 输出能做什么?

GPIO 输出是最基础的能力,但它是一切控制的起点:

初级项目

项目 原理 难度
LED 呼吸灯 用 PWM 控制亮度渐变(配合定时器) ⭐⭐
按键控制 LED GPIO 输入 + GPIO 输出联动
继电器控制 GPIO 驱动继电器模块,控制 220V 电器开关 ⭐⭐
蜂鸣器播放音乐 不同频率的方波 = 不同音调 ⭐⭐
交通灯模拟 红黄绿三色 LED 按时序切换

进阶项目

项目 原理 难度
WS2812 彩灯驱动 用 GPIO 精确时序控制可编程 LED 灯带 ⭐⭐⭐
步进电机控制 GPIO 按顺序驱动电机的 4 个相位 ⭐⭐⭐
LCD 并口驱动 用 GPIO 模拟 8080/6800 并行总线 ⭐⭐⭐
模拟 I2C/SPI 用 GPIO 软件模拟通信时序(Bit-banging) ⭐⭐⭐

核心思路:GPIO 输出的本质就是"控制一个引脚的高低电平"。理解了这一点,你就能控制任何数字设备——LED、继电器、电机、显示屏……只要它接受高低电平信号。


下一步:学会了 GPIO 输出,接下来可以学 USART printf 重定向,用串口打印调试信息。

世界是你们
使用 Hugo 构建
主题 StackJimmy 设计