ARTICLE DETAIL

资讯详情

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

STM32入门:手把手教你用Keil MDK从零建工程点亮LED

STM32入门:手把手教你用Keil MDK从零建工程点亮LED 做嵌入式这些年被问到最多的问题不是某个外设怎么写、某个协议怎么调而是“我怎么从零建一个STM32工程”。听起来像是很简单的事但实际带过十几个新手之后我发现多数人在这一步就卡住了。Keil装了芯片包里没有STM32工程建了编译报错几十条好不容易编译过了下载又连不上板子。这些问题单个拎出来都不大但堆在一起足够劝退一个刚起步的人。这篇是“嵌入式软件AI编程”系列的第八篇。前几篇聊完了工具链、芯片基础和一些辅助编程的思路这一篇落回最朴素的事情用Keil MDK从零到一建一个STM32工程让一颗LED亮起来。我会拿最常见的STM32F103C8T6蓝色板做例子走完环境搭建、标准库工程配置、GPIO点灯、编译下载的完整链路再把新手最常遇到的几个坑单独拉出来讲透。无论是准备用AI辅助开发还是纯手工写代码这一步都是绕不开的地基。1. 为什么第一个工程要先解决环境而不是急着写代码1.1 STM32工程和51、Arduino的差别很多人是从51单片机或者Arduino转过来的。51单片机在Keil里新建工程选个芯片型号直接就能写整个流程十分钟搞定Arduino更简单装好IDE和板卡包插上USB就能点灯。但STM32完全不是这个路子——芯片型号一大堆固件库要自己准备启动文件需要手动添加头文件路径要配宏定义要填连下载器都得单独选。这些步骤缺一个工程就跑不起来。我经常跟新手说STM32的第一个工程本质不是写代码而是建立一条从“芯片”到“库”到“编译”到“下载”的完整通路。这条通路一旦打通后面任何一个外设开发都只是往这个框架里添加文件通不过就只能永远复制别人建好的工程改一改跑一跑一遇到环境问题就抓瞎。这个系列的标题里带“AI编程”不少人可能期待直接用AI生成代码。但AI能帮你写出GPIO初始化的函数却没法替你解决芯片包没装、调试器没识别、路径有中文这类环境问题。所以第一个工程我坚持让你手动走一遍就是要用这个“慢过程”把背后每一块拼图都看清楚。1.2 这一篇选什么组合、为什么在正式开始之前先把选型说清楚。我见过很多初学者在“用标准库还是HAL库”上纠结很久其实这个选择没有绝对对错关键是要匹配你当前的目标。开发方式上手难度代码可读性官方支持状态适合场景寄存器操作最高差满屏位运算永久深度理解芯片、极致优化标准库中等较好已停止更新但资料最全入门学习、看老例程HAL库CubeMX较低较冗长持续更新项目开发、图形化配置这篇我选“Keil MDK 标准库 STM32F103C8T6”的组合。原因很简单标准库的函数封装刚好介于寄存器和HAL库之间你能看到“库函数→寄存器”的对应关系又不用直接跟一堆位运算较劲。网上大量入门视频和老例程用的都是标准库遇到问题搜一下基本都有答案。F103C8T6也是目前最便宜的STM32芯片之一几块钱一片板上引出的GPIO够多蓝色小板几十块就能到手就算烧坏几片也不心疼。HAL库CubeMX的路线我后面会专门写一篇。CubeMX自动生成初始化代码、图形化配置时钟和外设确实方便但前提是你得知道它生成的代码在干什么。先用标准库把GPIO、时钟、中断这些基础概念打通再切HAL库会顺很多。2. 开发环境搭建Keil MDK、芯片支持包、调试器驱动一个都不能少2.1 Keil MDK的安装与版本选择IDE选择上我用的是Keil MDK。STM32开发还有IAR、STM32CubeIDE、VSCodePlatformIO这些工具IAR编译器优化确实好但License费用不低入门阶段没必要STM32CubeIDE免费调试功能也不差但很多老教程都是Keil界面新手照着做容易对不上VSCodePlatformIO更现代但坑更多。Keil MDK在STM32生态里资料最多、用户最多遇到问题解决成本最低。安装本身没有太多玄学但有两点值得注意。第一安装路径和工程路径都不要带中文也不要带空格Keil对这类路径的处理一直不干净后面编译、下载时会出现各种莫名其妙的错误。第二安装包尽量从官网下载MDK 5.x版本即可Community版或者评估版功能足够学习使用不要花冤枉钱去淘宝买所谓的“破解完整版”安全性无法保证。装完之后桌面上会出现uVision5的图标双击打开默认界面是一个纯代码编辑器。这时候如果你直接新建工程会发现在Select Device里根本找不到STMicroelectronics这个厂商——很多人第一次就是卡在这里。2.2 芯片支持包为什么装了Keil还是没有STM32这就是MDK5和旧版本最大的区别。从MDK5开始Keil的IDE只是一个壳芯片支持完全依赖独立的Pack包Device Family PackIDE安装包里不再预置任何厂商的芯片数据。装好Keil不等于就有STM32可用你必须单独下载对应芯片系列的DFP。解决办法有两个。第一种是打开Keil里的Pack Installer工具在Device标签页找STMicroelectronics → STM32F1 Series在线安装DFP包。如果网络不太好更推荐第二种去Keil官网或者一些镜像站直接下载Keil.STM32F1xx_DFP_x.x.x.pack文件下载完双击它就能装进Keil完全离线操作。安装完成后新建工程时在Select Device窗口左侧如果能看到STMicroelectronics的树形列表说明芯片包已经生效。这一步做完相当于告诉Keil我手上的芯片是STM32F103系列它有哪些寄存器、多大Flash、多少引脚你编译的时候按这个芯片来。2.3 调试器驱动ST-Link和它的兼容版问题芯片包解决了“编译给谁看”下载还需要一个调试器把程序烧进芯片。STM32F103入门最常见的调试器是ST-Link V2二十几块钱一个的蓝壳小棒子其次是J-Link兼容版和CMSIS-DAP。ST-Link驱动的正确安装姿势是去ST官网搜STSW-LINK009这是ST-Link的官方USB驱动包。这里必须提一个新手几乎都会踩的坑很多便宜的ST-Link V2不是原装正品Windows对它们的识别不太稳定。插上之后设备管理器里可能显示成“USB大容量存储设备”或者“未知USB设备”而不是“ST-Link Debug”。原因是一些兼容版ST-Link内置了模拟U盘的固件升级功能Windows优先把它识别成U盘了。遇到这种情况不要急着退货。先把设备管理器里那个“大容量存储设备”禁用或卸载再重新插拔一次有些板子会恢复如果还是不行下载STM32 ST-LINK Utility用里面自带的功能尝试重新烧写ST-Link固件。注意烧写固件的操作要选对芯片型号选错了ST-Link可能彻底变砖。另外如果你手头有J-Link或其他调试器这几种在Keil里的配置逻辑是一样的只是选择下载器类型时换一项就行。2.4 顺手把USB转串口驱动也装上可能有人觉得奇怪点灯用不到串口为什么要装这个驱动因为接下来任何一个实际项目都逃不开串口调试UART几乎是嵌入式开发者的“第二个屏幕”。大多数STM32蓝色开发板或者USB转串口小板用的芯片是CH340或者CP2102去官网下载对应驱动装好Win10以下版本需要手动安装Win10以上通常自动识别。驱动装好后把板子的USART1和USB转串口模块连上设备管理器里能看到COM口编号。这个编号后面在调试工具里要用很多新手串口工具收不到数据就是没选对COM口或者驱动没装好导致设备根本没被识别。3. 新建工程的分步操作从选芯片到配置下载器的完整链路3.1 先建好工程目录结构别在Keil里裸奔我要求每个跟我学的人先建一个干净的目录结构再打开Keil。这不只是强迫症而是工程文件一旦多起来乱七八糟堆在一个文件夹里后面添加文件、改路径、找问题都会很难受。我常用的目录结构是这样Project_Name/ ├── USER/ // main.c、stm32f10x_it.c等用户代码 ├── CORE/ // 启动文件、core_cm3.c/core_cm3.h ├── SYSTEM/ // delay、sys、usart等系统级底层 ├── HARDWARE/ // led、key、lcd等外设驱动模块 ├── OBJ/ // 编译输出文件 └── 标准库文件/ // LibrariesCMSIS、固件库的inc/src说明一下USER放用户主逻辑CORE放内核相关的启动文件和CMSIS文件SYSTEM是系统基础服务HARDWARE是以后每个外设自己独立的.c和.h。关键是分层清楚底层的东西归底层用户逻辑归用户每个外设一个模块。后面你加一个传感器就新建一个HARDWARE/sensor.c和sensor.h往工程里拖进去就行。“标准库文件”这个文件夹放的是从ST标准外设库解压出来的Libraries目录里面包含CMSIS和STM32F10x_StdPeriph_Driver两个大目录。STM32F10x_StdPeriph_Driver里有inc和srcinc是所有外设的头文件src是对应的源文件。这部分是整个库的核心建议保持原始目录结构不要动。3.2 准备标准库文件最关键的几个文件标准库可以从ST官网搜索STM32F10x standard peripheral library下载版本一般用V3.5。下载解压之后真正需要的文件并不多我列一下stm32f10x.h芯片寄存器定义和内存映射整个库的地基stm32f10x_conf.h外设头文件汇总配置开启需要使用的模块头文件stm32f10x_gpio.c/.hGPIO驱动这次点灯必用stm32f10x_rcc.c/.h时钟控制使能外设时钟system_stm32f10x.c系统时钟初始化负责把时钟配置到72MHzstartup_stm32f10x_md.s启动文件中容量F103用md版本core_cm3.c/.hCortex-M3内核抽象层NVIC等内核外设的访问接口其中startup_stm32f10x_md.s是汇编写的启动文件它负责上电后的第一段代码设置初始栈指针、调用SystemInit初始化时钟、然后跳转到main函数。很多新手忽略这个文件的作用一旦漏掉编译能过但下载后程序根本无法运行因为CPU不知道从哪里开始执行。把上述文件的副本按目录结构放好后工程的文件准备工作就算完成了。这里有个小技巧标准库的源码文件永远保留一份干净的原版不要直接在里面改以后所有工程都从这份原版复制避免改到一半想还原找不到原始代码。3.3 Keil里新建工程、分组和添加文件打开Keil选Project → New uVision Project在弹窗里选到你的工程目录输入工程名。紧接着会弹出Select Device窗口左侧列表展开STMicroelectronics → STM32F1 Series选STM32F103C8。这里选型要根据你手上的芯片准确定选错了后面Flash大小、外设定义都可能对不上。选完芯片后Keil会问“Copy STM32 Startup Code to Project Folder and Add File?”这时我建议选No不要让它自动拷贝启动文件。不是自动拷贝不好而是为了让你清楚地知道启动文件放在哪个位置、叫什么名字。我们手动把CORE目录下的startup_stm32f10x_md.s添加到工程里路径自己可控后面排查问题也知道去哪里看。接下来在Project窗口右键Target选Manage Project Items。我按目录结构建了四个组USER、CORE、SYSTEM、HARDWARE。然后把对应文件往组里拖USER组放main.c和stm32f10x_it.cCORE组放core_cm3.c和startup_stm32f10x_md.sSYSTEM组放delay.c、sys.c、usart.cHARDWARE组放led.c。如果暂时没有这些文件先建一个main.c放USER组里也可以后面再补。3.4 C/C设置宏定义和头文件路径两个容易翻车的地方文件加完先别急着编译魔术棒Options for Target里的设置才是决定成败的关键。打开C/C选项卡在Define一栏填两个宏USE_STDPERIPH_DRIVER,STM32F10X_MDUSE_STDPERIPH_DRIVER的作用是告诉stm32f10x.h我要使用标准外设库请把stm32f10x_conf.h包含进来从而汇总所有外设驱动头文件。STM32F10X_MD表示芯片属于中容量Medium-density它会影响内部寄存器结构体的定义方式。F103C8T6是64KB Flash属于中容量所以填MD如果是F103ZET6这种512KB大容量芯片就要填HD。然后是Include Paths。点击后面的...按钮把USER、CORE、SYSTEM、HARDWARE目录以及标准库的CMSIS目录、外设库的inc目录全部加进去。说白了就是告诉编译器我写的#include“xxx.h”这些头文件分别从哪些文件夹里找。很多人编译报错“fatal error: stm32f10x.h: No such file or directory”99%是这个路径没加全。还需要在Output选项卡里勾选Create HEX File。虽然用ST-Link直接下载时不一定需要hex文件但生成一个备着没坏处以后如果要用串口ISP方式烧录没有这个文件就干不了活。至于其他选项现阶段保持默认就行。3.5 配置下载器ST-Link、烧录算法和Reset and Run下载配置同样在魔术棒里。Debug选项卡右侧下拉框选ST-Link Debugger然后点Settings按钮进入详细设置。正常情况下左侧显示的调试器应该是ST-Link右侧SW Device一栏能读到STM32F103CB的IDCODE。如果这里读不到芯片ID就说明调试器没有识别到目标芯片后面不用继续了回第2节排查驱动和接线。接下来切到Utilities选项卡。勾选Use Debug Driver然后Settings进入Flash Download界面在Programming Algorithm里添加STM32F10x Med-density 128K Flash。这个算法文件是Keil用来控制调试器写入Flash的程序不同容量的芯片对应不同算法选错了下载会报错。最后在Flash Download界面勾选Reset and Run。这个选项的意思是在下载完成后自动复位并运行程序。如果没有勾选每次下载完都要手动按板子上的复位键程序才会跑很多新手下载成功后看到开发板毫无反应还以为程序错了其实只是没复位。设置完成以后点OK编译一下0 Error 0 Warning环境配置就算闭环了。4. 点亮LED背后的GPIO控制原理与完整代码4.1 先看原理图再写代码“点灯”听起来简单但它其实是一次完整的“芯片外设操作”演练。在写代码之前必须先回答两个问题LED接在哪个引脚是高电平点亮还是低电平点亮这两个问题的答案都在开发板原理图里。以最常见的STM32F103C8T6蓝色板坊间叫Blue Pill为例板载一颗LED接在PC13引脚LED另一端接到3.3V电源也就是所谓的共阳极接法。这意味着要让LED亮PC13必须输出低电平让电流从3.3V经LED再到引脚流进芯片。所以后面代码里GPIO_ResetBits(GPIOC, GPIO_Pin_13)是亮灯GPIO_SetBits是灭灯。有些开发板的LED接在PB0或PB1上还有些是共阴极接法高电平点亮。这些信息一定以原理图或者卖家给的例程为准不要照搬网上的代码。我记得有个学员就是手里板子LED接PB0照着PC13的教程写折腾了两天没亮看原理图才发现引脚根本不对。先看图纸再写代码这个习惯从第一个工程就要养成。4.2 GPIO输出需要配置什么时钟、模式、速度GPIO在STM32里不算单纯的“引脚”它是一个挂在总线上的外设。要让某个引脚输出高低电平必须依次做三件事。第一打开GPIO外设的时钟。STM32为了省电几乎所有外设默认都是断电状态你不主动开启时钟寄存器写什么都没反应。GPIOC挂在APB2总线上所以用RCC_APB2PeriphClockCmd来使能RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE);为什么是APB2而不是APB1看F103的系统架构图就明白GPIO挂在高速APB2总线最高72MHz上而不是低速APB1最高36MHz。这属于F1系列的特殊安排F4系列又不一样。这就是为什么我不建议你跳过原理直接背API不了解总线结构换个芯片型号你可能连“为什么用这个函数打开时钟”都说不清。第二配置引脚的工作模式。作为普通的推挽输出我们用GPIO_InitTypeDef GPIO_InitStructure; GPIO_InitStructure.GPIO_Pin GPIO_Pin_13; GPIO_InitStructure.GPIO_Mode GPIO_Mode_Out_PP; GPIO_InitStructure.GPIO_Speed GPIO_Speed_50MHz; GPIO_Init(GPIOC, GPIO_InitStructure);GPIO_Mode_Out_PP是推挽输出它既能主动输出高电平也能主动输出低电平带负载能力强非常适合驱动LED。另一种常见的GPIO_Mode_Out_OD是开漏输出输出低电平靠引脚自身拉低输出高电平需要外部上拉电阻通常用在I2C这类需要“线与”的协议上。第三GPIO_Speed是输出翻转速率点灯这种低速场景用2MHz都没问题但一般例程习惯写50MHz这里跑满频率没坏处只是功耗略高。4.3 完整main.c代码与逐段说明下面是这次点灯工程的完整main.c我加上了SYSTEM里的延时函数调用#include stm32f10x.h #include delay.h void LED_GPIO_Config(void) { GPIO_InitTypeDef GPIO_InitStructure; RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE); GPIO_InitStructure.GPIO_Pin GPIO_Pin_13; GPIO_InitStructure.GPIO_Mode GPIO_Mode_Out_PP; GPIO_InitStructure.GPIO_Speed GPIO_Speed_50MHz; GPIO_Init(GPIOC, GPIO_InitStructure); } int main(void) { LED_GPIO_Config(); while (1) { GPIO_ResetBits(GPIOC, GPIO_Pin_13); // 低电平LED亮 Delay_Ms(500); GPIO_SetBits(GPIOC, GPIO_Pin_13); // 高电平LED灭 Delay_Ms(500); } }main函数里没有调用SystemInit因为这个函数在启动文件startup_stm32f10x_md.s里已经被调用过了它会负责把系统时钟从内部8MHz切换到外部晶振并倍频到72MHz。你在main里再调一次也不算错属于双保险。GPIO_ResetBits和GPIO_SetBits这对函数背后的实现很值得看一下。GPIO_SetBits是向BSRR寄存器写1将对应引脚置高GPIO_ResetBits是向BRR寄存器写1将对应引脚拉低。标准库把这层寄存器操作封装成了两个直观的函数你要做的就是记住操作的是哪个GPIO口和哪个引脚。这里要特别提一个初学者误区如果LED是低电平点亮你写了GPIO_SetBits给PC13置高灯是灭的很容易让人误以为引脚没配置成功。所以遇到“LED不亮”先确认你用的板子是电平点亮还是低电平点亮别一上来就觉得芯片坏了。4.4 延时函数的选择别用空循环也别被优化坑了这个点值得单独写一节因为它坑过太多人。最直观的延时写法是空循环void Delay(unsigned int t) { while (t--); }但这个方法有个隐患——如果编译优化级别开得高编译器发现循环体什么实际操作都没有可能直接把这个循环优化掉结果就是延时失效看起来像是“程序卡死”或者“延时函数不工作”。就算没被优化掉这种延时的时长也极不准确跟主频、优化等级、编译器类型都有关。正确的做法是用SysTick也就是Cortex-M3内核自带的系统定时器。F103的SysTick默认配置为1ms中断一次中断服务函数里递减一个全局变量Delay函数就靠这个变量判断时间是否到static __IO uint32_t TimingDelay; void Delay_Ms(uint32_t ms) { TimingDelay ms; while (TimingDelay ! 0); } void SysTick_Handler(void) { if (TimingDelay ! 0) { TimingDelay--; } }使用前在main函数里调用一次SysTick_Config(SystemCoreClock / 1000);SystemCoreClock在72MHz主频下是72000000除以1000得到72000意思是SysTick每72000个时钟周期触发一次中断正好1ms。这个基于中断的延时有不少讲究比如SysTick中断优先级设置不当在以后跑RTOS时会引起时间管理问题但对于现在这个点灯工程它是稳定、精准、可用的。我把这个设计放进SYSTEM组里做成delay.c和delay.h以后所有工程直接复用不用再到处写空循环。你在自己做第一个工程时也可以把延时、GPIO配置这种通用代码沉淀成自己的模块文件后面真的会越用越顺手。5. 编译、下载与调试让程序真正跑起来的三个步骤5.1 编译从报错到0 Error 0 Warning的过程按下Build按钮后第一次编译通常会冒出几个错误这很正常。关键是要学会读编译输出窗口的信息。如果报的是“fatal error: stm32f10x.h: No such file or directory”说明Include Paths没加全如果报“Undefined symbol GPIO_Init”说明stm32f10x_gpio.c没有添加进工程或者stm32f10x_conf.h里没有启动GPIO模块的包含。有些错误看似复杂其实根据错误信息里的文件名和行号往上定位几个回合就能找到原因。我的习惯是第一次编译之前先确认三件事文件都加进工程了宏定义两个单词写对了没空格头文件路径包含的目录名和实际文件夹能对上。这三项检查完第一次编译通常能直接通过。如果还有问题记住一个原则编译器报错信息从第一条开始看不要被后面的几十条error吓到往往第一条是根因后面都是连锁反应。5.2 下载Keil里一键下载与常见失败编译通过后点一下Load按钮Keil会调用ST-Link把生成的hex文件烧写进芯片Flash。如果一切正常输出窗口会显示Programming Done和Verify OK。如果这里卡住最常见的两种情况。一种是报“No Target Connected”或者“Cannot access Target”说明调试器没有和芯片建立连接常见原因是接线没接好、调试器驱动有问题、芯片和调试器之间的SWDIO或SWCLK线松动还有可能是板子没供电。另一种是“Flash Download failed - Cortex-M3”多半是Utilities里没有添加烧录算法或者算法选错了型号。处理方式就是把第3.5节的流程重新检查一遍。下载成功不等于程序没问题你可能看到板载LED在一闪一闪地亮那说明程序已经跑起来了。如果板子毫无反应先确认有没有勾选Reset and Run没勾就手动按一下复位键按了复位还没反应就该进入调试模式看了。5.3 调试用Debug模式确认代码真的在跑很多人把调试理解成“打日志、print”。在嵌入式开发里硬件的调试器远比打印函数强大。按下CtrlF5进入Debug模式后代码会在main函数入口处停住你可以单步执行、全速运行、打断点还能实时查看外设寄存器的值。点开Peripherals菜单里的GPIOC窗口就能看到PC13引脚对应的ODR寄存器位。全速运行后点暂停你会看到ODR的第13位在1和0之间来回翻转这个翻转过程就是LED闪烁的本质。如果ODR在翻转但LED没亮问题出在外部电路如果ODR不动问题出在代码逻辑或时钟配置。很多新手对调试器有心理障碍觉得那是高手才用的东西。其实从第一个点灯程序就开始用调试模式是性价比最高的学习方法。它不仅让你“看到”程序在跑而且帮你建立“代码→芯片内部状态”的对应认知这个认知比背一百个API都有用。6. 新手最容易踩的五个坑与我的排查思路6.1 装了Keil却没有STM32芯片包现象新建工程时在Select Device窗口里找不到STMicroelectronics。成因我在第2.2节讲过MDK5的IDE和芯片支持包是分离的。解决办法就是安装STM32F1系列的Device Family PackDFP在线用Pack Installer装或者下载离线.pack双击安装。装完后重启Keil再新建工程就能看到ST厂商列表了。这个坑几乎是所有MDK5新用户必踩的踩过一次之后换用其他芯片型号时思路就通了。6.2 编译报错头文件找不到、函数未定义现象fatal error: xxx.h file not found或者L6218E: Undefined symbol。“头文件找不到”就是Include Paths没配好编译器不知道去哪里找头文件把C/C的Include Paths窗口里的目录路径逐项核对一遍就行。“函数未定义”则分三种情况相关外设源文件没有加进工程、路径正确但源文件没编译、宏定义里缺少USE_STDPERIPH_DRIVER导致驱动头文件没有进来。排查思路是按照编译输出里第一条error信息定位不要被后续的几十条报错带偏。6.3 ST-Link插入后设备管理器显示“大容量存储设备”现象ST-Link插上去后电脑弹出一个U盘盘符设备管理器里也是“USB大容量存储设备”而不是“ST-Link Debug”。这个我提过许多兼容版ST-Link模仿了原装ST-Link的U盘升级机制Windows一插上就把最高优先级的U盘模式识别出来了。处理办法是先卸载该设备然后重新插拔如果还是不行用STM32 ST-LINK Utility重刷一次ST-Link的V2固件。这类兼容版ST-Link掉固件的概率不低养成“插上后先看一眼设备管理器”的习惯能帮你省下很多排查时间。6.4 下载成功但LED怎么都不亮现象Keil提示下载成功板上LED毫无反应。顺序排查第一步确认驱动LED的引脚和你代码里初始化的是否一致PC13还是PB0看原理图。第二步确认电平逻辑你的板子是共阳极还是共阴极代码里的SetBits和ResetBits要不要反过来。第三步确认Reset and Run是否勾选或者手动按复位键。第四步进入Debug模式看ODR寄存器是否翻转。如果ODR翻转了但LED不亮检查你的LED限流电阻和接线极少数情况是把引脚烧了。多数的“LED不亮”不是芯片坏了而是逻辑搞反或者根本没进入调试去确认。我见过有人把共阴极和共阳极搞反折腾两天最后满头大汗地发现代码里一个SetBits和ResetBits的顺序问题。6.5 工程路径里的中文和空格引发的奇怪错误现象编译时可能报一些“cant load file”“access denied”之类的错或者Keil界面里文件名旁边显示一个大大的问号。原因就是工程路径里带了中文、全角字符或者太长的路径。Keil的老架构对非英文字符路径支持一直不好。解决办法也简单所有工程目录统一用英文字母、数字和下划线路径里不要放空格不要放在桌面这种带权限限制的位置最好建一个类似D:\STM32_Projects的目录作为所有工程的根目录。这些坑看起来都很基础但它们是新手期最消耗信心和时间的。我提供这套排查思路是希望你在遇到问题时能按“环境→配置→代码→硬件”的顺序来找而不是一上来就怀疑程序写错了。最后说一个我自己的习惯每完成一个阶段的工程就把整个目录复制一份去掉OBJ里的编译输出文件存成一个干净的“工程模板”。以后不管是写新的传感器驱动还是复刻某个实验都从这个模板开始复制而不必每次都从选型配置走一遍。第一个STM32工程最大的价值不是那颗LED亮起来本身而是你用自己的手把整条链路完整走了一遍。这条链路里的经验和踩过的坑会在后面每一个外设、每一个项目里不断以“幸亏当时搞懂了”的方式回报你。
返回列表