ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

STM32F1标准库模板工程搭建指南:从零到一构建开发环境

STM32F1标准库模板工程搭建指南:从零到一构建开发环境 1. 从零到一为什么需要一个“模板工程”如果你刚开始接触STM32或者刚从51单片机、Arduino平台转过来第一个让你感到困惑的可能不是复杂的寄存器而是“怎么新建一个工程”。在Keil5里点“New Project”很简单但接下来呢从哪里复制启动文件哪些库文件是必须的为什么别人的工程编译一下就过我的却报了一堆“undefined symbol”的错误这些问题本质上是因为STM32的开发需要一个完整的“生态”支持——启动代码、外设库、链接脚本、头文件路径缺一不可。“模板工程”就是为了解决这个痛点而生的。它不是一个空壳而是一个预先配置好所有基础依赖、编译选项甚至包含一个闪烁LED例程的“种子项目”。有了它你就不用每次新建项目都去翻手册、找文件、配路径重复那些繁琐且容易出错的步骤。你可以把它理解为你专属的“车间”里面工具库文件齐全、电源启动代码接通、工作台工程结构整洁你进来后直接开始焊接你的核心电路编写应用代码就行了。对于STM32F1系列尤其是使用经典的“标准外设库”Standard Peripheral Library 也就是常说的“库函数”创建一个稳定、可靠的模板工程是后续所有学习与开发的第一步。这个模板将贯穿你的整个学习过程从点灯到驱动OLED从串口通信到使用定时器它都是那个最坚实的底座。今天我就以Keil MDK-ARM也就是大家常说的Keil5为工具手把手带你搭建一个“纯净版”的STM32F1库函数模板工程并解释清楚每一个文件、每一个配置选项背后的“为什么”。这不仅是复制粘贴更是理解STM32开发环境构成的过程。2. 战前准备理清你的“武器库”与“弹药”在开始搭建工程之前我们必须把需要的“原材料”准备好。盲目开始只会导致中途反复浪费时间。你需要的东西主要分为三类开发工具、芯片支持包和官方库文件。2.1 开发工具Keil MDK-ARM的安装与确认首先确保你已经正确安装了Keil MDK-ARM。这里有几个关键点需要注意版本选择建议使用较新的版本如MDK5.3x。新版本对C语言标准的支持更好界面也更友好。但请注意Keil5是一个大版本其下有很多小版本更新。安装路径强烈建议安装路径不要包含中文和空格。例如D:\Keil_v5就是一个好选择。这可以避免后续一系列因路径解析问题导致的编译错误。芯片支持包Device Family Pack这是Keil5引入的新机制。安装完Keil后它只是一个空壳你需要为你的目标芯片比如STM32F103系列单独安装支持包。安装方法有两种在线安装打开Keil点击菜单栏Project - Manage - Pack Installer。在打开的窗口中搜索“STM32F1”找到STMicroelectronics的STM32F1系列DFP点击“Install”即可。这需要网络环境。离线安装从ST官网或Keil官网下载对应的.pack文件双击运行即可安装。注意很多新手遇到的第一个坑就是编译时提示“No Device Selected”。这几乎百分之百是因为没有安装对应的芯片支持包。安装成功后在新建工程选择设备时你才能看到“STMicroelectronics”下的“STM32F103xx”等具体型号。2.2 核心弹药STM32标准外设库的获取与解构这是模板工程的灵魂。标准外设库是ST官方提供的用于操作STM32所有外设GPIO、USART、TIM等的一套C语言函数集合。它封装了对底层寄存器的直接操作让我们可以用GPIO_SetBits(GPIOA, GPIO_Pin_0)这样的函数来点亮一个LED而不是去写GPIOA-BSRR 0x0001。你需要去ST官网或通过搜索引擎下载名为“STM32F10x_StdPeriph_Lib”的库文件包。解压后你会看到一个结构清晰的文件夹。对我们模板工程最重要的部分在Libraries目录下STM32F10x_StdPeriph_Lib_V3.5.0\Libraries\ ├── CMSIS\ # Cortex微控制器软件接口标准包含内核相关文件 │ ├── CM3\CoreSupport\ # 核心文件如 core_cm3.c/.h任何Cortex-M3芯片都需要 │ └── CM3\DeviceSupport\ST\STM32F10x\ # STM32F1专属文件如启动文件、系统初始化文件 │ ├── startup\arm\ # 启动文件.s汇编文件按芯片Flash大小选择 │ ├── stm32f10x.h # 最重要的头文件包含所有寄存器定义 │ ├── system_stm32f10x.c │ └── system_stm32f10x.h └── STM32F10x_StdPeriph_Driver\ # 标准外设驱动库 ├── inc\ # 外设驱动头文件 (.h) └── src\ # 外设驱动源文件 (.c)此外根目录下的Project\Template文件夹里有一个官方提供的简易模板但通常不够完善我们会以其为参考自己构建一个更清晰、更易用的。2.3 明确目标芯片以STM32F103C8T6为例为了讲解具体我们以最常见的“蓝色药丸”核心板主控——STM32F103C8T6为例。这是一款基于Cortex-M3内核拥有64KB Flash和20KB RAM的芯片。知道具体型号非常重要因为它决定了我们该选择哪个启动文件Flash容量为64K属于“中等密度”产品。一些芯片特有的外设或配置。现在工具和材料已备齐我们可以开始“施工”了。3. 工程骨架搭建创建清晰的目录结构一个好的工程结构就像一本书的目录能让你和你的队友甚至一个月后的你自己快速找到所需内容。我建议在电脑的某个位置同样路径无中文空格新建一个文件夹例如STM32_Project然后在其内部为我们的模板工程创建如下子目录STM32F1_Template\ ├── Core\ # 核心文件与芯片强相关通常固定不变 │ ├── Inc\ # 用户应用头文件 │ └── Src\ # 用户应用源文件 ├── Drivers\ │ ├── CMSIS\ # 从官方库复制的CMSIS文件 │ └── STM32F10x_FWLib\ # 从官方库复制的标准外设库文件重命名以清晰 ├── MDK-ARM\ # Keil工程文件 (.uvprojx) 和输出文件 (.axf, .hex) ├── Project\ # 也可将Keil工程文件放在这里与MDK-ARM二选一 ├── User\ # 用户主要编写代码的地方main.c就在这里 └── README.md # 工程说明文档为什么这样分Core/存放与Cortex-M内核、启动相关的文件。这些文件一旦选定在项目生命周期内基本不会改动。Drivers/存放硬件抽象层的驱动。CMSIS是ARM公司定的标准STM32F10x_FWLib是ST的库。将它们与User/代码分离符合软件分层的思想。当ST发布新库时你可以尝试替换这个文件夹而不会影响你的应用代码。User/这是你的“主战场”main.c,stm32f10x_it.c中断服务函数文件stm32f10x_conf.h库配置文件等都应放在这里。MDK-ARM/或Project/专门存放IDE相关的工程文件以及编译生成的中间文件和最终输出文件。将它们独立出来便于进行版本管理如Git时忽略这些频繁变动的文件。接下来我们把官方库里的必要文件“搬运”到对应目录。复制启动文件从Libraries\CMSIS\CM3\DeviceSupport\ST\STM32F10x\startup\arm中根据你的芯片Flash容量选择启动文件。对于STM32F103C8T664K Flash属于“中等密度”复制startup_stm32f10x_md.s到你的Core\Src\目录。小容量ld、大容量hd、互联型xl对应不同文件选错会导致栈堆设置错误程序无法运行。复制CMSIS核心文件将Libraries\CMSIS\CM3\CoreSupport下的core_cm3.c和core_cm3.h复制到Drivers\CMSIS\。将Libraries\CMSIS\CM3\DeviceSupport\ST\STM32F10x下的system_stm32f10x.c,system_stm32f10x.h以及最重要的stm32f10x.h也复制到Drivers\CMSIS\。注意stm32f10x.h是总纲包含了所有寄存器的地址映射。复制外设库文件将整个Libraries\STM32F10x_StdPeriph_Driver下的inc和src文件夹复制到Drivers\STM32F10x_FWLib\下。复制用户模板文件从官方库的Project\Template下复制main.c,stm32f10x_it.c,stm32f10x_it.h,stm32f10x_conf.h到你的User\目录。system_stm32f10x.c我们已经放到CMSIS里了这里不用重复复制。至此物理文件准备就绪。接下来我们要在Keil5中把它们“组装”起来。4. Keil5工程配置详解让编译器认识你的工程打开Keil5点击Project - New uVision Project...定位到你创建的工程根目录STM32F1_Template建议将工程文件保存在MDK-ARM子目录下命名为Template。点击保存。4.1 选择目标设备与添加文件组在弹出的设备选择窗口中找到STMicroelectronics - STM32F103 Series - STM32F103C8。点击OK。之后弹出的“Manage Run-Time Environment”对话框是用于配置软件组件如RTOS、中间件的我们使用标准库所以直接点击“Cancel”关闭即可。现在得到一个空的工程。我们需要在左侧“Project”窗口创建文件组Folder来对应我们的目录结构并将文件添加进去。创建文件组右键点击“Target 1”选择Manage Project Items...。新建组在“Groups”区域点击“New (Insert)”按钮创建以下组Startup用于存放启动文件。CMSIS用于存放内核相关文件。FWLIB用于存放外设库源文件。User用于存放用户应用文件。Doc可选用于存放说明文档。添加文件依次选中每个组点击“Add Files”按钮将之前复制到对应目录的文件添加进来。Startup组添加Core\Src\startup_stm32f10x_md.s。CMSIS组添加Drivers\CMSIS\system_stm32f10x.c。注意core_cm3.c通常不需要手动添加因为它的内容已被包含在其他文件中但添加了也不会错。stm32f10x.h是头文件不需要在这里添加。FWLIB组点击“Add Files”后文件类型选择C Source file然后导航到Drivers\STM32F10x_FWLib\src\可以全选所有.c文件添加。但这里有个重要技巧为了加快编译速度通常只添加你当前工程需要用到的外设库文件。例如如果你只用到GPIO和USART就只添加stm32f10x_gpio.c和stm32f10x_usart.c。对于模板工程我们可以先全选添加以后再做精简。User组添加User\main.c和User\stm32f10x_it.c。完成后点击OK你的工程窗口应该呈现出清晰的分组结构。4.2 配置头文件包含路径编译器需要知道去哪里找#include的头文件。右键点击工程目标“Target 1”选择Options for Target ‘Target 1’...切换到C/C选项卡。在Include Paths一栏点击末尾的“...”按钮添加以下路径根据你的实际目录调整../Drivers/CMSIS// 为了找到 stm32f10x.h, core_cm3.h, system_stm32f10x.h../Drivers/STM32F10x_FWLib/inc// 为了找到所有外设库的头文件如 stm32f10x_gpio.h../User// 为了找到 stm32f10x_conf.h, stm32f10x_it.h../Core/Inc// 为你将来自己创建的头文件预留位置为什么需要这些路径当你在main.c中写#include “stm32f10x_gpio.h”时编译器会按照你这里设置的顺序去这些目录下搜索该文件。路径设置错误会导致“cannot open source file”的致命错误。4.3 定义全局宏与编译器优化仍在C/C选项卡找到Preprocessor Symbols下的Define输入框。这里需要输入一个至关重要的宏USE_STDPERIPH_DRIVER。这个宏的作用是告诉stm32f10x.h头文件“我们要使用标准外设库”。如果你不定义它stm32f10x.h就不会去包含stm32f10x_conf.h从而导致所有库函数相关的声明都不可见。此外根据你的芯片型号可能还需要定义芯片相关的宏例如对于STM32F103C8T6属于“中等密度”需要定义STM32F10X_MD。但请注意在较新的库版本和Keil环境中这个宏有时不是必须的因为芯片支持包可能已经通过其他方式告诉了编译器。为了保险起见可以一并加上。所以在Define框中输入USE_STDPERIPH_DRIVER, STM32F10X_MD多个宏之间用英文逗号隔开。关于优化等级Optimization选项默认是-O0不优化在调试阶段建议保持此设置因为优化可能会改变代码执行顺序导致单步调试时指针跳来跳去难以跟踪。在最终发布版本时可以改为-O1或-O2以减小代码体积、提高运行速度。4.4 配置调试器与Flash下载切换到Debug选项卡。这里配置你使用的调试工具最常见的是ST-LINK和J-Link。在“Use”下拉框中选择你的调试器例如ST-Link Debugger。点击右侧的“Settings”按钮。在Debug子选项卡中确认“Port”是否选择正确ST-LINK通常选SWJ-Link根据硬件连接选择JTAG或SWD。如果连接正常在“SW Device”区域应该能看到识别到的芯片ID。切换到Flash Download子选项卡。这里必须勾选Reset and Run这样程序下载后会自动复位运行否则你需要手动复位。同时确保“Programming Algorithm”里已经添加了对你芯片Flash的编程算法。对于STM32F103C8通常是STM32F10x Medium-density Flash。如果没有点击“Add”手动选择。4.5 生成Hex文件与分散加载切换到Output选项卡勾选Create HEX File这样编译后会生成一个.hex文件方便使用一些烧录工具。Listing选项卡可以控制生成列表文件一般默认即可。Linker选项卡里通常不需要改动。Keil会根据你选择的芯片自动使用一个默认的分散加载文件.sct它定义了代码Code、只读数据RO、读写数据RW、零初始化数据ZI在内存中的布局。对于绝大多数应用默认配置完全足够。只有当你需要将特定函数或变量放到绝对地址或者使用复杂的多区域内存时才需要修改它。完成以上所有配置后点击OK保存。一个工程的基本框架就配置好了。5. 核心文件解读与修改让工程“活”起来现在工程虽然能编译但可能还无法运行。我们需要理解并修改几个关键的用户文件。5.1 配置文件stm32f10x_conf.h这个文件是标准外设库的“总开关”。它通过一系列#define来使能或失能你将要使用的外设库。打开User\stm32f10x_conf.h你会看到很多被注释掉的#include例如// #include “stm32f10x_adc.h” // #include “st32f10x_bkp.h” ... #include “stm32f10x_gpio.h” // #include “stm32f10x_i2c.h”规则很简单你用了哪个外设就把对应头文件的注释取消。例如你的模板工程里如果有一个用GPIO控制LED的例程那么stm32f10x_gpio.h和stm32f10x_rcc.h因为任何外设都需要时钟就必须被包含。对于初始模板建议先保留gpio,rcc 其他注释掉以后用到再打开。这样可以显著减少编译时间并避免因未初始化某些外设而可能产生的潜在问题。5.2 中断服务文件stm32f10x_it.c/.h这个文件集中放置所有中断服务函数ISR。模板里已经预置了一些常见中断的弱定义Weak空函数如SysTick_Handler系统滴答定时器中断、USART1_IRQHandler等。弱定义意味着如果你在其他地方比如main.c重新定义了同名函数编译器会使用你的新函数而不会报重复定义错误。你需要做的是当你开启某个外设的中断比如串口接收中断后就需要在这个文件里找到对应的中断函数如USART1_IRQHandler并编写具体的中断处理逻辑。对于模板工程我们可以先保持原样。5.3 主函数main.c这是程序的入口。官方模板的main.c提供了一个非常基础的框架。我们来剖析一下#include “stm32f10x.h” // 必须包含的总头文件 int main(void) { // 通常在这里进行系统时钟初始化 // SystemInit(); // 这个函数在启动文件中已被调用它设置了系统时钟为默认的HSI 8MHz。 // 用户外设初始化代码写在这里 // 例如初始化GPIO、USART等 while (1) { // 主循环 } }关键点SystemInit()函数在启动文件里被调用它会在main()函数执行前将系统时钟配置为内部高速时钟HSI8MHz。对于STM32F103系列内部HSI精度不高通常我们会使用外部晶振HSE来获得更精确的72MHz系统时钟。因此在真正的项目中我们往往会在main()函数一开始重新调用一个自定义的时钟配置函数例如RCC_Configuration()将系统时钟切换到HSE并倍频至72MHz。但在最简模板中我们可以先使用默认的8MHz HSI以验证工程基础是否正常。6. 第一个测试点亮一颗LED理论说再多不如实际跑一遍。让我们给这个模板工程添加最简单的功能——闪烁一个LED来验证整个开发环境是否工作正常。假设我们使用PC13引脚很多最小板上的用户LED连接于此连接LED低电平点亮。修改 stm32f10x_conf.h确保#include “stm32f10x_gpio.h”和#include “stm32f10x_rcc.h”未被注释。编写LED初始化函数在main.c中while(1)循环之前添加以下代码void LED_Init(void) { GPIO_InitTypeDef GPIO_InitStructure; // 定义一个GPIO初始化结构体 // 第一步开启GPIOC的时钟。任何外设使用前必须先开启其时钟。 RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE); // 第二步配置GPIO初始化结构体成员 GPIO_InitStructure.GPIO_Pin GPIO_Pin_13; // 选择引脚13 GPIO_InitStructure.GPIO_Mode GPIO_Mode_Out_PP; // 推挽输出模式 GPIO_InitStructure.GPIO_Speed GPIO_Speed_50MHz; // 输出速度50MHz // 第三步调用初始化函数将配置写入寄存器 GPIO_Init(GPIOC, GPIO_InitStructure); // 第四步初始状态设置为高电平LED灭 GPIO_SetBits(GPIOC, GPIO_Pin_13); }编写主循环闪烁逻辑在main()函数的while(1)循环中添加int main(void) { LED_Init(); // 初始化LED GPIO while (1) { GPIO_ResetBits(GPIOC, GPIO_Pin_13); // PC13置低LED亮 Delay_ms(500); // 延时500ms GPIO_SetBits(GPIOC, GPIO_Pin_13); // PC13置高LED灭 Delay_ms(500); // 延时500ms } }实现简易延时函数标准库没有提供毫秒级延时函数我们需要自己实现一个基于SysTick的系统滴答定时器延时或者写一个简单的循环延时。这里先用一个不精确的循环延时演示void Delay_ms(uint32_t nms) { uint32_t i, j; for(i0; inms; i) for(j0; j8000; j); // 这个循环次数需要根据你的主频调整 }注意这个Delay_ms函数非常不精确受编译器优化影响很大仅用于临时测试。在实际项目中强烈建议使用SysTick定时器实现精确延时。编译与下载点击Keil工具栏的“Rebuild”按钮或按F7。如果一切配置正确你应该在“Build Output”窗口看到0 Error(s), 0 Warning(s)。连接硬件用ST-LINK通过SWD接口连接你的开发板并给板上电。下载程序点击“Load”按钮或按F8。如果Flash下载配置正确程序会自动下载并运行。你应该能看到板载LED开始闪烁。如果LED成功闪烁恭喜你你的第一个STM32库函数模板工程已经创建并验证成功。这个工程将成为你未来所有STM32F1项目的基础。你可以在这个基础上添加新的外设驱动文件、编写更复杂的应用逻辑而无需再重复搭建环境。7. 进阶配置与深度优化打造更专业的模板基础模板能跑起来但一个“好用”的模板还需要一些打磨。这里分享几个让模板更专业的配置点。7.1 使用HSE时钟并配置系统时钟为72MHz默认的8MHz HSI时钟性能有限。绝大多数STM32F103项目都会使用外部8MHz晶振通过PLL倍频到72MHz系统时钟。我们需要修改main.c在main()函数开头调用一个自定义的时钟配置函数。首先在stm32f10x_conf.h中确保#include “stm32f10x_rcc.h”已开启。然后在main.c中添加如下函数void SystemClock_Config(void) { RCC_DeInit(); // 将RCC寄存器重置为默认值 RCC_HSEConfig(RCC_HSE_ON); // 开启HSE // 等待HSE就绪 if (RCC_WaitForHSEStartUp() SUCCESS) { // 设置AHB时钟HCLK SYSCLK RCC_HCLKConfig(RCC_SYSCLK_Div1); // 设置APB2高速时钟PCLK2 HCLK RCC_PCLK2Config(RCC_HCLK_Div1); // 设置APB1低速时钟PCLK1 HCLK/2 (最大36MHz) RCC_PCLK1Config(RCC_HCLK_Div2); // 配置PLLHSE输入9倍频。HSE8MHz, PLL输出8*972MHz RCC_PLLConfig(RCC_PLLSource_HSE_Div1, RCC_PLLMul_9); RCC_PLLCmd(ENABLE); // 使能PLL while(RCC_GetFlagStatus(RCC_FLAG_PLLRDY) RESET); // 等待PLL就绪 RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK); // 选择PLL输出作为系统时钟源 while(RCC_GetSYSCLKSource() ! 0x08); // 等待系统时钟切换成功 } else { // HSE启动失败可以在这里处理错误比如让LED快闪报警 while(1); } }最后在main()函数最开始调用SystemClock_Config();。这样你的系统就跑在72MHz下了。注意此时之前那个不精确的Delay_ms函数延时时间会变短需要调整循环次数或者改用SysTick。7.2 启用微库MicroLib以减小代码体积对于资源紧张的嵌入式系统Keil提供了一个精简版的C库——MicroLib。它比标准C库小很多但牺牲了一些功能如浮点数格式化输入输出、完整的文件IO等。对于大多数不需要复杂IO和浮点打印的嵌入式应用MicroLib是很好的选择。在Options for Target - Target选项卡中勾选Use MicroLIB。然后必须重新编译整个工程。启用后你可能会发现生成的.hex文件体积明显减小。7.3 配置串口打印调试信息printf重定向调试时通过串口打印信息非常有用。需要做两件事初始化USART外设以及重定向printf函数的底层输出到串口。初始化USART假设使用USART1PA9为TXPA10为RX。编写USART初始化函数需在stm32f10x_conf.h中开启stm32f10x_usart.h。重定向fputc在main.c中添加以下代码#include stdio.h // 需要包含标准IO头文件 // 重写fputc函数将printf的输出导向串口1 int fputc(int ch, FILE *f) { USART_SendData(USART1, (uint8_t) ch); // 发送一个字符 while (USART_GetFlagStatus(USART1, USART_FLAG_TXE) RESET); // 等待发送完成 return ch; }在Options for Target - Target中如果你使用了MicroLib确保勾选了Use MicroLIB。然后在Options for Target - Linker中可以取消勾选Use Memory Layout from Target Dialog并在Scatter File中指定一个包含--library_typemicrolib选项的分散加载文件或者更简单的方法是在Options for Target - C/C的Misc Controls框中添加--library_typemicrolib。现在你就可以在代码中使用printf(“Hello STM32!\r\n”);了信息将通过串口1发送出去。7.4 管理工程文件添加与移除外设库随着项目进行你可能会添加很多外设。为了保持工程整洁和编译快速建议在FWLIB组中只保留你用到的.c文件。右键点击FWLIB组下的某个.c文件选择Remove File可以将其从工程中移除注意这只是从工程管理列表中移除并不会删除硬盘上的物理文件。当你需要时可以再通过Add Files加回来。8. 常见问题排查与避坑指南即使按照步骤操作新手也难免会遇到问题。这里汇总几个高频坑点编译错误stm32f10x.h: error: #35: #error directive: “Please select first the target STM32F10x device used in your application (in stm32f10x.h file)”原因没有正确定义芯片密度宏如STM32F10X_MD。解决在Options for Target - C/C - Define中确保添加了USE_STDPERIPH_DRIVER, STM32F10X_MD。编译错误大量undefined symbol错误提示找不到SystemInit或__main等。原因启动文件没有添加到工程或者添加的启动文件型号不对如给C8T6用了startup_stm32f10x_hd.s。解决检查Startup组是否正确添加了对应的启动文件.s汇编文件。编译错误cannot open source file “stm32f10x_gpio.h”原因头文件包含路径没有设置正确。解决仔细检查Options for Target - C/C - Include Paths中的路径是否正确、完整。程序下载失败No ULINK/ME Device Found或Cannot enter Debug Mode原因调试器连接问题、驱动未安装、芯片型号选择错误、复位电路问题、Boot引脚配置错误。解决检查硬件连接SWDIO, SWCLK, GND, 3.3V是否牢固。检查Keil中Debug - Settings是否能识别到设备。确认芯片供电正常。检查开发板的BOOT0和BOOT1引脚是否都接地从主Flash启动模式。尝试给芯片断电再上电然后立刻点击下载。程序下载成功但LED不闪或行为异常原因GPIO初始化代码错误、时钟未开启、LED硬件连接与代码不符、延时函数不准确导致闪烁过快/过慢肉眼无法分辨。解决用万用表测量LED对应引脚在程序运行时的电压变化确认是否有高低电平切换。检查RCC_APB2PeriphClockCmd是否开启了对应GPIO端口的时钟。确认GPIO_InitStructure.GPIO_Pin和GPIO_Init的第一个参数端口是否正确。大幅度增加延时时间如5秒亮5秒灭来排除延时问题。使用printf无法输出原因串口未初始化、fputc重定向未实现或实现有误、电脑串口助手配置错误波特率、端口号。解决确保USART初始化函数被调用且参数正确特别是波特率检查fputc函数代码确认电脑端串口助手的波特率与代码中设置一致。创建一个稳定可靠的模板工程是STM32开发路上至关重要的一步。它帮你扫清了环境搭建的障碍让你能更专注于代码逻辑和硬件功能本身。这个模板会随着你学习的深入不断被完善和个性化最终成为你最得心应手的开发起点。希望这篇超详细的指南能帮你打下坚实的基础。
返回列表