最近在整理 STM32 开发笔记时发现很多新手朋友在拿到一块新的 STM32 开发板后面对第一个“点亮 LED”的实验常常会卡在环境搭建、工程创建、代码编写和下载调试这几个环节。网上的教程虽然多但要么版本老旧要么步骤跳跃对于刚接触 ARM Cortex-M 内核的开发者来说很难形成一个清晰、完整的闭环操作流程。本文将以 STM32C5A3R 这款芯片为例手把手带你完成从零开始点亮 LED 的全过程。无论你是刚入门嵌入式开发的学生还是想快速上手 STM32 的工程师这篇文章都将提供一套可直接复用的实战方案。我们将覆盖开发环境搭建、标准外设库或 HAL 库工程创建、GPIO 原理分析、代码编写、程序下载与调试等核心步骤并重点解释每个操作背后的“为什么”帮你避开初学时的常见陷阱。1. 背景与核心概念在开始动手之前我们先明确几个关键概念这能帮助你更好地理解后续的操作而不仅仅是机械地复制代码。STM32C5A3R 是什么STM32C5A3R 是意法半导体STMicroelectronics推出的基于 ARM Cortex-M 内核的 32 位微控制器MCU。型号中的“C5”通常指代其产品系列“A3”可能代表特定的 Flash/RAM 容量或外设配置“R”则可能指封装类型如 LQFP。对于开发者而言我们更关心它的内核架构、外设资源和开发方式。作为 STM32 家族的一员它继承了 STM32 丰富的生态系统可以使用 ST 官方提供的标准外设库Standard Peripheral Library SPL、硬件抽象层库HAL或直接寄存器操作进行开发。为什么“点亮 LED”是第一个实验“点亮 LED”Blinky是嵌入式世界的“Hello World”。它看似简单却串联了嵌入式开发的几个核心环节开发环境搭建你需要安装编译器、调试器和必要的软件工具链。工程管理学习如何创建一个包含启动文件、库文件、链接脚本的完整工程。外设驱动学习如何配置和使用最基础的外设——通用输入输出GPIO。程序下载与调试掌握将编译好的程序烧录到芯片并验证其运行的方法。 成功点亮 LED意味着你的整个开发链路已经打通为后续学习更复杂的外设如串口、定时器、ADC等打下了坚实基础。GPIO通用输入输出端口GPIO 是 MCU 与外部世界交互的最基本单元。一个 GPIO 引脚可以被软件配置为多种模式输出模式驱动外部器件如点亮 LED、控制继电器。可以配置为推挽输出或开漏输出。输入模式读取外部信号如检测按键状态。可以配置为浮空输入、上拉输入或下拉输入。复用功能引脚作为片上外设如串口、SPI、I2C的通信接口。点亮 LED 主要用到 GPIO 的输出模式。我们需要通过编程配置指定引脚的模式、输出类型和速度然后通过向该引脚的数据寄存器写入“1”高电平或“0”低电平来控制 LED 的亮灭。2. 环境准备与版本说明工欲善其事必先利其器。以下是完成本实验所需的软硬件清单及版本说明。请注意嵌入式开发环境版本较多本文以当前撰写时常见且稳定的版本为例如果你的实际环境不同请根据官方文档进行适配。硬件准备STM32C5A3R 核心板或开发板一块包含 STM32C5A3R 芯片的板子是必须的。确保你知道板载 LED 连接到了哪个 GPIO 引脚例如 PA5。通常原理图或板子丝印上会有标注。ST-LINK/V2 调试下载器这是最常用的 STM32 仿真调试工具。确保你有一个可靠的 ST-LINK。USB 数据线用于连接 ST-LINK 到电脑以及为开发板供电如果板子没有独立供电。杜邦线若干如果使用核心板可能需要连接 LED 或按键。软件准备集成开发环境IDEKeil MDK-ARM (uVision)这是国内非常流行的商业 IDE对 ARM 内核支持好生态完善。本文示例将主要基于 Keil MDK-ARM V5.36 版本。你需要安装对应的设备支持包Device Family Pack for STM32C5 Series。IAR Embedded Workbench另一款强大的商业 IDE。STM32CubeIDEST 官方推出的免费 IDE基于 Eclipse 和 GCC 工具链集成度高推荐新手使用。本文也会简要说明在 CubeIDE 下的操作。STM32 固件库标准外设库SPL较传统的库直接操作寄存器代码效率高但移植性稍差。ST 已停止更新但对于学习底层原理很有帮助。HAL 库硬件抽象层库ST 主推的现代库封装程度高可移植性强但代码体积和效率略有牺牲。它集成在STM32CubeMX工具中。LL 库底层库介于 HAL 和直接寄存器操作之间兼顾效率和易用性。本文将以标准外设库为例进行讲解因为它能让你更清晰地理解 GPIO 的寄存器操作原理。理解了标准库再过渡到 HAL 库会非常容易。STM32CubeMX这是一个图形化配置工具可以初始化芯片时钟、引脚、外设等并生成 HAL/LL 库的初始化代码。即使使用标准库它也能帮助我们快速查看引脚分配。建议安装。串口调试助手如 SecureCRT, Putty, MobaXterm 或 SSCOM用于后续的串口通信实验本篇暂不需要。版本兼容性提示不同版本的 Keil、固件库和芯片支持包之间可能存在兼容性问题。如果遇到编译错误首先检查以下几点Keil 中安装的STM32C5xx_DFP设备家族包版本是否支持你的芯片。工程中引用的固件库头文件路径是否正确。编译器的 ARM Compiler 版本如 V5 或 V6是否与代码语法兼容。标准外设库通常对 AC5 兼容性更好。3. GPIO 原理与寄存器操作拆解在写代码之前我们必须理解如何通过寄存器来控制一个 GPIO 引脚。STM32 的每个 GPIO 端口如 GPIOA, GPIOB...都由一组寄存器管理。对于输出控制我们主要关注以下四个寄存器以 GPIOA 为例GPIOx_MODER (模式寄存器)作用配置引脚的工作模式输入、输出、复用功能、模拟功能。关键位每个引脚占用 2 个位bit。例如PA5 对应 MODER 寄存器的第 10 和 11 位MODER5[1:0]。常用设置00: 输入模式01: 通用输出模式10: 复用功能模式11: 模拟模式要点要点亮 LED必须先将对应引脚配置为通用输出模式(01)。GPIOx_OTYPER (输出类型寄存器)作用配置输出模式为推挽输出Push-Pull或开漏输出Open-Drain。关键位每个引脚占用 1 个位。例如PA5 对应 OTYPER 寄存器的第 5 位OT5。常用设置0: 推挽输出常用能直接输出高/低电平驱动能力强。1: 开漏输出需要外接上拉电阻才能输出高电平常用于电平转换或总线。要点驱动 LED通常使用推挽输出。GPIOx_OSPEEDR (输出速度寄存器)作用配置引脚的输出响应速度低速、中速、高速、超高速。速度越高功耗和噪声可能越大。关键位每个引脚占用 2 个位。例如PA5 对应 OSPEEDR 寄存器的第 10 和 11 位OSPEEDR5[1:0]。常用设置对于简单的 LED 闪烁低速或中速即可。对于高频通信引脚如 SPI则需要高速。要点LED 控制对速度不敏感通常设置为低速以降低功耗。GPIOx_ODR (输出数据寄存器) / GPIOx_BSRR (位设置/清除寄存器)ODR 作用直接读写引脚的输出电平。每个引脚占用 1 个位。写1输出高电平写0输出低电平。BSRR 作用原子操作不会被中断打断地设置或清除某个引脚。高 16 位用于清除写1清零低 16 位用于设置写1置位。这是更推荐的方式因为它能避免“读-改-写”操作在多线程或中断环境下的风险。要点点亮 LED假设 LED 阳极接 GPIO阴极接地需要输出高电平1。熄灭则输出低电平0。标准外设库的封装为了简化编程ST 的标准外设库提供了函数来操作这些寄存器。例如GPIO_Init(): 用于初始化 GPIO 的模式、类型、速度等。GPIO_SetBits(): 设置引脚为高电平对应 BSRR 的设置操作。GPIO_ResetBits(): 设置引脚为低电平对应 BSRR 的清除操作。GPIO_WriteBit(): 向指定引脚写入一个位值。我们的代码将使用这些库函数但你要明白它们底层操作的正是上述寄存器。4. 完整实战基于标准外设库点亮 LED现在我们进入实战环节。假设我们的开发板上一颗 LED 连接在PA5引脚且为高电平点亮即 PA5 输出高电平时 LED 亮。4.1 创建 Keil MDK 工程新建工程打开 Keil uVision点击Project - New uVision Project...。选择一个空文件夹为工程命名例如STM32C5A3R_LED。选择设备在弹出的Select Device for Target对话框中搜索STM32C5A3Rx请根据你的芯片具体型号选择例如 STM32C5A3RBTx然后点击 OK。管理运行时环境在弹出的Manage Run-Time Environment对话框中我们可以添加标准外设库文件。但为了更清晰地理解工程结构我们选择Cancel手动添加文件。这样你能更清楚每个文件的作用。工程结构在 Project 窗口你会看到Target 1。右键点击它选择Manage Project Items...。在Project Items标签页可以创建分组Groups来管理文件。建议创建以下分组User: 存放用户编写的main.c,stm32f10x_conf.h,stm32f10x_it.c(中断文件) 等。CMSIS: 存放 Cortex-M 内核相关的文件如启动文件、系统初始化文件。FWLIB: 存放标准外设库的源文件.c文件。DOC: 存放说明文档可选。点击OK创建这些分组。4.2 添加必要的文件到工程你需要从 ST 官方标准外设库包中拷贝以下文件到你的工程目录并在 Keil 中添加它们。1. 启动文件启动文件Startup File包含了芯片上电后的堆栈初始化、中断向量表以及跳转到main函数等汇编代码。它通常位于固件库包的Libraries\CMSIS\Device\ST\STM32C5xx\Source\Templates\arm目录下。根据你的编译工具链选择对于 Keil MDK选择后缀为startup_stm32c5a3rx.s的文件x可能代表内存大小如startup_stm32c5a3rbtx.s。将其拷贝到你的工程目录下例如CMSIS文件夹并添加到 Keil 工程的CMSIS分组中。2. 系统文件system_stm32c5xx.c位于固件库包的Libraries\CMSIS\Device\ST\STM32C5xx\Source\Templates。它包含了系统时钟初始化函数SystemInit()。将其拷贝并添加到CMSIS分组。core_cm3.h/c或core_cm4.h/c根据你的 Cortex-M 内核版本选择位于Libraries\CMSIS\Include。通常只需要头文件源文件由编译器提供。确保 Keil 的包含路径Include Paths指向了这里。3. 标准外设库文件头文件将固件库包中Libraries\STM32C5xx_StdPeriph_Driver\inc整个文件夹拷贝到你的工程目录例如FWLIB/inc。源文件我们只需要用到的外设驱动。对于点亮 LED至少需要gpio.c和rcc.c因为 GPIO 时钟需要使能。将Libraries\STM32C5xx_StdPeriph_Driver\src下的gpio.c和rcc.c拷贝到你的工程目录例如FWLIB/src并添加到 Keil 工程的FWLIB分组。4. 用户配置文件stm32c5xx_conf.h这是一个重要的配置文件用于启用或禁用你用到的外设库模块。从固件库包的Project\STM32C5xx_StdPeriph_Templates目录下拷贝此文件到你的User目录。在文件中确保#define启用了你将要使用的外设例如#define USE_STDPERIPH_DRIVER #define USE_FULL_ASSERT // 可选用于调试断言 /* 启用 GPIO 和 RCC 模块 */ #include stm32c5xx_gpio.h #include stm32c5xx_rcc.h // 可以注释掉其他不需要的外设头文件stm32c5xx_it.c/h中断服务程序文件。本实验未使用中断但最好从模板拷贝一份空文件到User目录并添加进工程以保持工程完整性。5. 用户主文件在User分组下新建一个main.c文件。6. 设置包含路径和宏定义包含路径点击魔术棒图标Options for Target在C/C选项卡的Include Paths中添加以下路径.\User.\FWLIB\inc.\CMSIS(如果存放了core_cm*.h等文件)标准外设库中CMSIS头文件的实际路径。预处理器宏在同一个C/C选项卡的Preprocessor Symbols的Define框中添加USE_STDPERIPH_DRIVER(必须告诉编译器使用标准外设库)STM32C5A3Rx(根据你的芯片具体型号例如STM32C5A3RBTx)4.3 编写主程序代码现在打开main.c文件编写我们的 LED 闪烁程序。/** ****************************************************************************** * file main.c * author Your Name * version V1.0.0 * date DD-MM-YYYY * brief Main program body - LED Blinky for STM32C5A3R ****************************************************************************** */ /* Includes ------------------------------------------------------------------*/ #include stm32c5xx.h // 这是最重要的头文件它包含了芯片的所有寄存器定义和标准外设库头文件 #include stm32c5xx_conf.h // 用户配置文件 /* Private typedef -----------------------------------------------------------*/ /* Private define ------------------------------------------------------------*/ /* 定义 LED 连接的 GPIO 引脚 */ #define LED_GPIO_PORT GPIOA #define LED_GPIO_PIN GPIO_Pin_5 #define LED_GPIO_CLK RCC_APB2Periph_GPIOA /* 简单的延时函数循环延时不精确仅用于演示 */ void Delay(__IO uint32_t nCount) { for(; nCount ! 0; nCount--); } /* Private function prototypes -----------------------------------------------*/ void GPIO_LED_Init(void); /** * brief 主函数 * param 无 * retval 无 */ int main(void) { /* 系统时钟初始化 - 通常启动文件已调用 SystemInit() */ /* 但为了确保 GPIO 时钟正确使能我们会在 GPIO 初始化中开启 */ /* 初始化 LED 对应的 GPIO */ GPIO_LED_Init(); /* 无限循环 */ while (1) { /* 点亮 LED (PA5 输出高电平) */ GPIO_SetBits(LED_GPIO_PORT, LED_GPIO_PIN); /* 延时 */ Delay(0x8FFFF); /* 熄灭 LED (PA5 输出低电平) */ GPIO_ResetBits(LED_GPIO_PORT, LED_GPIO_PIN); /* 延时 */ Delay(0x8FFFF); } } /** * brief 初始化 LED 所用的 GPIO * param 无 * retval 无 */ void GPIO_LED_Init(void) { GPIO_InitTypeDef GPIO_InitStructure; /* 第一步使能 GPIOA 的时钟 */ /* 在 STM32 中任何外设在使用前都必须先使能其时钟这是为了降低功耗 */ RCC_APB2PeriphClockCmd(LED_GPIO_CLK, ENABLE); /* 第二步配置 GPIO 引脚参数 */ GPIO_InitStructure.GPIO_Pin LED_GPIO_PIN; // 指定要配置的引脚Pin 5 GPIO_InitStructure.GPIO_Mode GPIO_Mode_Out_PP; // 模式推挽输出 GPIO_InitStructure.GPIO_Speed GPIO_Speed_50MHz; // 输出速度50MHz (可根据需要选择 2MHz, 10MHz, 50MHz) /* 第三步初始化 GPIO */ GPIO_Init(LED_GPIO_PORT, GPIO_InitStructure); /* 第四步默认先关闭 LED可选 */ GPIO_ResetBits(LED_GPIO_PORT, LED_GPIO_PIN); }代码逐行解析头文件stm32c5xx.h是核心它根据你在 Keil 选项中定义的芯片型号STM32C5A3Rx包含正确的设备特定头文件。stm32c5xx_conf.h则根据你的设置来包含具体的外设头文件如gpio.h,rcc.h。宏定义将硬件连接信息端口、引脚、时钟定义为宏提高了代码的可读性和可移植性。如果需要更换 LED 引脚只需修改这里。延时函数Delay这是一个非常简单的软件延时函数通过空循环消耗 CPU 时间。注意在实际项目中应使用定时器如 SysTick来实现精确延时这里仅作演示。GPIO_LED_Init函数这是初始化的标准流程。RCC_APB2PeriphClockCmd(LED_GPIO_CLK, ENABLE);至关重要STM32 的外设时钟默认是关闭的低功耗设计使用前必须打开。GPIOA 挂在 APB2 总线上。GPIO_InitStructure这是一个结构体变量用于存储 GPIO 的配置参数。GPIO_Mode_Out_PP推挽输出模式这是驱动 LED 的常用模式。GPIO_Speed_50MHz设置 GPIO 的翻转速度。对于 LED低速即可这里设为 50MHz 也无妨。GPIO_Init调用库函数将配置好的参数应用到实际的 GPIO 寄存器上。main函数调用GPIO_LED_Init完成硬件初始化。进入while(1)死循环不断执行置位 - 延时 - 复位 - 延时从而实现 LED 的闪烁。4.4 编译与下载编译工程点击 Keil 工具栏上的Build(F7) 按钮。如果一切配置正确你将在Build Output窗口看到0 Error(s), 0 Warning(s)的信息并生成.axf或.hex文件。配置调试器点击魔术棒图标进入Debug选项卡。选择你使用的调试器例如ST-Link Debugger。点击Settings在Debug子选项卡中确认 SWD 接口被识别并能看到芯片的 IDCODE。在Flash Download子选项卡中勾选Reset and Run这样程序下载后会自动运行。下载程序点击Load(F8) 按钮或工具栏上的下载图标。程序将被烧录到 STM32 的 Flash 中。复位与运行下载完成后按下开发板的复位键你应该能看到连接在 PA5 上的 LED 开始闪烁。4.5 在 STM32CubeIDE 中快速实现如果你使用 STM32CubeIDE流程会更加图形化新建工程启动 CubeIDE选择Start new STM32 project。选择芯片在芯片选择器中输入STM32C5A3R选择你的具体型号。引脚配置在图形化界面Pinout View中找到 PA5左键点击它选择GPIO_Output。你可以在右侧的GPIO配置中设置用户标签User Label为LED并选择输出模式、上下拉、速度和初始电平。时钟配置在Clock Configuration选项卡通常使用默认的内部时钟HSI或配置外部晶振HSE。对于 LED 闪烁内部时钟足够。项目设置设置项目名称、路径、选择 IDE 为STM32CubeIDE并选择 HAL 库。生成代码点击Generate Code。CubeIDE 会自动生成包含 HAL 初始化代码的完整工程。编写用户代码在main.c文件的/* USER CODE BEGIN 2 */和/* USER CODE END 2 */之间添加你的闪烁逻辑/* USER CODE BEGIN 2 */ /* 初始化已完成进入主循环 */ /* USER CODE END 2 */ while (1) { /* USER CODE END WHILE */ HAL_GPIO_TogglePin(LED_GPIO_Port, LED_Pin); // 翻转 LED 引脚电平 HAL_Delay(500); // 使用 HAL 库的延时函数单位毫秒 /* USER CODE BEGIN 3 */ }编译与下载点击锤子图标编译点击虫子图标进入调试模式或绿色箭头直接运行。5. 常见问题与排查思路即使按照步骤操作你也可能会遇到一些问题。下面是一个常见问题的排查清单问题现象可能原因排查思路与解决方案编译错误stm32c5xx.h找不到1. 包含路径未正确设置。2. 预处理器宏STM32C5A3Rx未定义或定义错误。1. 检查 Keil 的C/C-Include Paths确保路径指向了库文件所在目录。2. 检查C/C-Define中的宏定义必须与芯片型号完全匹配大小写敏感。编译错误大量未定义标识符如GPIO_InitTypeDef1. 未定义USE_STDPERIPH_DRIVER宏。2.stm32c5xx_conf.h中未包含对应的外设头文件如#include stm32c5xx_gpio.h。1. 在 Keil 的Define中添加USE_STDPERIPH_DRIVER。2. 检查stm32c5xx_conf.h文件确保#include了gpio.h和rcc.h。程序下载失败1. ST-LINK 连接不稳定或驱动未安装。2. 芯片型号选择错误。3. 芯片处于写保护状态。4. 复位电路或 Boot 引脚配置问题。1. 重新插拔 ST-LINK检查设备管理器中是否有ST-LINK设备。安装最新版 ST-LINK 驱动。2. 确认 Keil 中选择的 Device 与你的物理芯片一致。3. 使用 ST-LINK Utility 或 CubeProgrammer 尝试解除保护。4. 检查开发板 Boot0/Boot1 引脚是否已正确接地从主Flash启动。LED 不亮但程序下载成功1. GPIO 时钟未使能。2. GPIO 引脚配置错误模式、速度。3. 硬件连接错误LED 极性接反、限流电阻过大、LED损坏。4. 程序未运行可能卡在启动或初始化。1.这是最常见原因确认RCC_APB2PeriphClockCmd函数被正确调用且参数无误。2. 检查GPIO_Init的参数模式必须是GPIO_Mode_Out_PP或GPIO_Mode_Out_OD。3. 用万用表测量 GPIO 引脚在程序运行时的电压看是否在高/低电平间变化。检查 LED 电路。4. 在main函数最开始加一句GPIO_SetBits测试并进入调试模式单步执行看程序流是否正常。LED 常亮或常灭不闪烁1. 延时函数时间太短或太长肉眼无法分辨。2.while(1)循环内的SetBits和ResetBits顺序写反或只执行了一个。3. 延时函数被编译器优化掉了。1. 调整Delay函数的参数或使用示波器/逻辑分析仪观察引脚波形。2. 检查代码逻辑确保亮灭操作都有。3. 将延时函数中的循环变量声明为volatile类型如volatile uint32_t i防止编译器优化。使用 HAL 库时HAL_Delay不工作SysTick 定时器未正确初始化或中断未启用。在 CubeMX 生成代码时确保SYS下的Timebase Source选择了SysTick。HAL 库的延时依赖于 SysTick 中断。基础调试技巧软件仿真在 Keil 中即使没有硬件也可以使用软件仿真来验证代码逻辑。在Debug选项卡选择Use Simulator然后进入调试模式查看Peripherals-GPIO-GPIOA窗口观察 ODR 寄存器的值是否按预期变化。点亮另一个 LED如果你的板子有多个 LED尝试修改代码控制另一个 LED以排除特定 GPIO 引脚或 LED 本身硬件故障的可能。简化测试在main函数开始时直接写GPIO_SetBits(GPIOA, GPIO_Pin_5);然后进入while(1)看 LED 是否常亮。这可以排除延时函数和循环逻辑的问题。6. 最佳实践与工程建议当你成功点亮 LED 后为了构建更健壮、更易维护的工程可以考虑以下实践模块化编程将 LED 相关的初始化、控制函数单独放在led.c和led.h文件中。在头文件中使用#ifndef/#define/#endif防止重复包含。提供清晰的 API如LED_Init(),LED_On(),LED_Off(),LED_Toggle()。这样做的好处是当硬件连接改变例如 LED 换到 PB0时你只需要修改led.c中的宏定义而不必搜索整个main.c。使用精确延时放弃简陋的循环延时。利用 Cortex-M 内核的 SysTick 定时器实现一个毫秒甚至微秒级的延时函数。标准外设库或 HAL 库都提供了基于 SysTick 的延时函数如HAL_Delay。你可以参考其实现编写自己的delay_ms和delay_us函数这样延时更准确且不阻塞其他任务如果结合 RTOS。合理的时钟配置虽然 LED 实验对时钟要求不高但实际项目通常需要精确的时钟。了解你的芯片支持哪些时钟源HSI, HSE, PLL等。使用SystemInit()函数或 HAL 库的SystemClock_Config()函数来配置系统主频这会影响所有外设的工作速度。在GPIO_Init中设置合适的GPIO_Speed。低速外设用低速可以降低功耗和噪声。代码可读性与注释为函数、重要变量、复杂逻辑添加注释。使用有意义的宏定义和枚举而不是魔法数字magic number。例如用LED_STATE_ON和LED_STATE_OFF代替1和0。保持一致的代码缩进和命名风格如驼峰命名法。版本控制从第一个工程开始就使用 Git 进行版本管理。将工程代码不包括编译生成的.o,.axf,.uvprojx等中间文件提交到仓库。这能让你安心地尝试和回滚任何修改。深入理解寄存器在熟练使用库函数后可以尝试直接读写寄存器来控制 GPIO。例如点亮 PA5 可以写成GPIOA-BSRR GPIO_Pin_5;置位GPIOA-BRR GPIO_Pin_5;复位。这能加深你对硬件原理的理解。阅读《STM32C5xx 参考手册》中关于 GPIO 和 RCC 的章节了解每个寄存器位的具体含义。通过这个简单的“点亮 LED”实验你已经成功打通了 STM32 开发的完整链路环境搭建、工程创建、外设配置、代码编写、编译下载和调试。这不仅仅是让一个灯闪烁更是你嵌入式开发之旅坚实的第一步。接下来你可以基于这个工程继续探索按键输入、串口通信、定时器中断、PWM 调光等更丰富的功能。记住遇到问题时善用芯片的参考手册、数据手册以及官方例程它们是你最好的老师。动手去修改代码、观察现象、解决问题是学习嵌入式最快的方式。
