尧图精选

STM32CubeMX+HAL库实战:硬件SPI读取W25Q64 Flash

🕒 发布时间:2026/10/2 20:32:25 📁 来源:尧图网络
1. 下载前的准备选择版本与账号注册这些琐事如果你这段时间在查STM32相关的学习路线肯定会被反复安利一个名字STM32CubeMX。我身边不少同事是从寄存器开发一路走过来的最开始对这类图形化配置工具都不太当回事觉得不就是生成一下初始化代码嘛。但等你真正在一个项目里要同时兼顾时钟树、引脚复用、外设初始化、RTOS任务的时候就会发现手工维护初始化代码有多痛苦而CubeMX生成的工程结构有多省心。这篇教程我会从最基础的下载安装开始讲一直带你走到用HAL库的硬件SPI接口操作W25Q64 Flash芯片这种实际项目场景顺带把FreeRTOS和STM32CubeIDE的配合也说清楚。1.1 官方下载路径与账号注册STM32CubeMX的官方下载地址是ST官网的www.st.com/cubemx页面。这里有一点要提前说明这个工具是ST提供的免费工具但下载之前你得注册一个ST账号而且是必须登录之后才能看到下载按钮。注册流程很简单一个常用邮箱就够了验证邮件点一下就完成。我遇到过不少读者卡在这一步究其原因不是注册环节难而是很多人习惯性以为那种Development Tool的下载都藏在产品页下面绕了半天没找到。实际路径是进入www.st.com后搜索STM32CubeMX进入产品详情页选择Get Software登录账号后就能看到下载链接。下载文件通常是一个名为类似STM32CubeMX-Win-x.x.x.zip的压缩包注意它是zip格式不是exe。很多小白看到压缩包就愣住了以为下错了其实需要先解压解压后再运行里面的安装程序。别笑这个点我至少被问过十次。1.2 Java环境老话题新答案关于Java环境网上很多老教程都会说你必须先装JRE这在STM32CubeMX的早期版本比如4.x、5.x确实是真的因为当时软件依赖外部Java运行时。但从6.x版本开始CubeMX已经自带了JRE安装包解压后直接就能跑不需要再单独配置JAVA_HOME这些环境变量。如果遇到双击没反应的情况先确认解压是否完整再看看路径里有没有中文。把整个CubeMX目录放到一个纯英文路径下比如C:\ST\STM32CubeMX\基本就稳了。另外系统时间不对也会引发启动异常这是我碰到过的一次玄学问题把系统时间校准后一切正常。提示如果你电脑上恰好还留着老版本CubeMX想升级到6.x不建议直接覆盖安装。先把老版本卸载再清理干净安装目录否则有可能出现界面里固件包列表混乱的情况。1.3 版本选择建议CubeMX的版本更新非常频繁官网同时维护多个release。我的建议是优先选LTS长期支持版本稳定性远比新功能重要。举例来说当年我在一个量产项目里用过一款刚发布的版本结果固件包下载仓库的路径变了团队里一部分机器能正常下载另一部分一直报网络错误排查了半天最后回退到LTS版才消停。具体操作上打开https://www.st.com/en/development-tools/stm32cubemx.html后页面上通常有一个Get latest的按钮旁边还会列出历史版本列表。除非你明确需要某个新特性比如新发布的MCU型号支持否则直接下载最新LTS即可。2. 安装过程里最容易翻车的细节与汉化真相下载解压后安装过程本身可以说是全自动的。双击安装程序一路Next到Finish没必要改任何默认选项。真正的问题通常出在安装之后的首次启动阶段。2.1 安装路径与权限的坑安装过程中唯一的建议是安装目录不要选到C:\Program Files (x86)这种带空格且有写保护的位置也不要选任何包含中文的路径。原因有两个一是CubeMX的配置文件和固件包仓库需要读写安装目录附近的资源二是后续命令行工具链比如部分第三方编译、烧写脚本对空格路径的处理并不完美。如果安装后点击图标一直转圈打不开先检查Windows Defender是否拦截了。CubeMX首次运行时会在后台初始化一堆配置文件杀毒软件很容易误报慢速操作把它加入白名单就行。另外Windows早前版本下最好以管理员身份运行一次安装程序后续正常双击使用反倒没那么多问题。2.2 固件包Firmware Package下载慢的解决方法首次启动CubeMX它会提示你安装目标芯片的固件包。这一步是很多人第一次崩溃的地方打开界面选好F103系列点击下载结果进度条爬得比蜗牛还慢。固件包的体积通常是数百MB级别从ST的服务器拉取在国内网络环境下确实不太乐观。最稳妥的办法是手动下载并导入。流程如下从官网的STM32CubeF1页面、STM32CubeF4页面等对应产品页下载对应的固件包zip文件例如 STM32Cube_FW_F1_V1.8.5.zip。解压后的文件夹放入CubeMX的仓库目录。默认位置在C:\Users\你的用户名\STM32Cube\Repository或新版C:\Users\你的用户名\STMicroelectronics\STM32Cube\Repository。重启CubeMX它会在仓库里识别到已存在的固件包不再重复下载。这个办法我用了很久实际体验非常稳定。下载zip包的速度往往比CubeMX内部下载快很多因为走的是浏览器通道还可以断点续传。2.3 中文汉化官方其实没有中文界面在网上搜STM32CubeMX中文汉化会看到不少教程教你怎么下载汉化包、覆盖语言文件。这里我需要说几句实在话这个软件官方是没有中文版的所谓的汉化包基本是第三方爱好者自己翻译后做成了语言文件。使用第三方汉化包最大的风险是版本号严格匹配问题——CubeMX几乎每个月都有小版本更新汉化包跟不上时界面上会出现大量英文英文混杂甚至乱码的情况而且连菜单项都错位。我的建议是英文界面真不是核心门槛。CubeMX的界面结构非常固定核心操作路径就那几个选MCU、配引脚、配时钟、Project Manager生成代码菜单项翻来覆去就是十几个。与其找汉化包去适配版本不如把这十几个英文菜单项记住配合中文教程一起看反而更清晰。记住这一句话省你后面一堆折腾。2.4 安装常见问题自查表现象大概率原因处理方法双击没反应解压不完整/路径带中文重新完整解压到纯英文路径启动后提示Java相关错误老版本依赖外部JRE改用6.x以上版本或安装JRE固件包下载慢/失败网络问题官网下载zip后手动放仓库目录界面菜单错乱第三方汉化包版本不匹配删除汉化文件还原英文界面无法切换芯片型号列表固件包未安装Help-Manage Embedded Software Packages3. 第一个工程全流程从选芯片到生成代码安装搞定之后我们来看这个工具的核心流程。我会用一个最常见的点亮LED例子带你完整走一遍从新建工程到生成代码的路径。3.1 选择MCU型号的两种方式双击打开CubeMX首页有两个主要入口Access to MCU Selector按MCU型号选和Access to Board Selector按开发板型号选。如果手头是某宝常见的STM32F103C8T6最小系统板用MCU Selector更快。在MCU Selector界面左上角的搜索框输入STM32F103C8右侧列表中会实时过滤出对应型号。看到列表里出现绿色芯片图标双击进去就进入了主配置界面。3.2 主界面三个Tab怎么分工进入主界面后你会看到三个固定标签页Pinout Configuration、Clock Configuration、Project Manager。理解三个页面各干什么比背任何快捷键都有用。Pinout Configuration中间是芯片引脚图左边是外设列表你要的功能GPIO、USART、SPI等都在左边选中后再到中间的引脚图上去配置。Clock Configuration时钟树配置决定芯片跑多快、外设挂在哪个时钟源上。Project Manager工程名称、存放路径、以及代码由哪个IDE打开这就是热词里STM32CubeIDE的入口。这里有个新手特别容易忽略的点CubeMX的引脚图上很多引脚左侧有一个模式选项比如PA9可以选USART1_TX、TIM1_CH2等。同一个引脚复用了多种功能你选了一种其他引脚就自动不可选。理解复用这个词是看懂这个界面的钥匙。引脚就像一栋楼里的多功能厅既能开会也能办婚礼但一个时间只能干一件事。3.3 点灯操作的完整配置步骤以STM32F103C8T6最小系统板为例板载LED一般接在PC13上。配置流程如下在左侧列表找到System Core展开后选GPIO然后在中间引脚图上左键点击PC13选择GPIO_Output。左侧下方会出现GPIO配置面板把PC13的Maximum output speed设为LowUser Label改名为LED。给引脚起名字是CubeMX的一大好处生成代码后直接用LED_Pin、LED_GPIO_Port操作不用记一堆 GPIOA、GPIOB 的编号。切换到Project Manager页签Project Name填LED_DemoProject Location选自己的工程目录Toolchain / IDE选择STM32CubeIDE如果你习惯用Keil选MDK-ARM也可。点击右侧GENERATE CODE按钮等生成完成选择打开工程。打开工程后在main.c的while(1)循环里加一句HAL_GPIO_TogglePin(LED_GPIO_Port, LED_Pin); HAL_Delay(500);编译下载如果看到LED以一秒周期闪烁恭喜你的第一条CubeMX流水线已经跑通了。3.4 为什么推荐CubeMX生成代码而不是手写我经常被问一个问题教程里都在讲怎么手写寄存器或者用标准库学CubeMX会不会让我变笨我的看法是初始化代码本来就是高度模式化的劳动今天写SPI初始化明天写USART初始化后天写定时器初始化CtrlC、CtrlV的东西占据了你大量时间。CubeMX生成的代码不一定比你手写的更优雅但它胜在三点可复现、可阅读、可维护。团队协作时.ioc文件CubeMX工程文件放到Git里任何人拉下来都能看到引脚分配和时钟配置的全貌。新人接手一个陌生板子第一件事就是打开.ioc文件看看哪些引脚被用了哪些外设没使能比看一百页电路图直观得多。这套图形化配置自动生成的工作流本身就是现代MCU开发的标准做法之一。4. 时钟树与调试器配置跳过的迟早要补课有些初学者生成工程之后直接就开始写代码了完全不看时钟配置那个页面。一开始可能没啥问题等你用到串口波特率、SPI速度、PWM频率的时候会发现怎么调都不对。这时候你才回过头来研究时钟树等于把前面省下来的时间又加倍赔回去了。4.1 为什么时钟树决定一切STM32F103的内部结构是外部晶振HSE输入后经过PLL锁相环倍频产生系统时钟SYSCLK然后经过AHB预分频、APB预分频分别给不同总线上的外设供电。这里最关键的结论是SPI挂在APB上USART也挂在APB上定时器也是。你要想让外设的时钟跑得准必须把时钟树配清楚。CubeMX的Clock Configuration页面里所有参数都以图形化的方块呈现调整方式是直接输入想要的频率然后回车CubeMX自动帮你计算各分频系数。以典型的8MHz外部晶振配置为例时钟源/总线目标频率说明HSE8 MHz外部晶振PLLx9倍频到72MHzSYSCLK72 MHz系统时钟最大值AHB72 MHz分频数1APB136 MHz分频数2SPI2、USART2等挂在这条总线APB272 MHz分频数1SPI1、USART1等挂在这条总线如果你用的是外部晶振记得把时钟配置里的HSE选成Crystal/Ceramic Resonator默认是Bypass Clock外部直接给时钟信号。这个选项选错芯片也能跑但精度差很多。选HSE为Crystal这一步经常被遗忘在教程的角落里。4.2 Debug接口的经典坑不配SWD就再也下载不了这是我在新手阶段踩得最深的一个坑。新建工程后如果不去管SYS标签下的Debug配置CubeMX默认把它设为No Debug。生成的代码烧进芯片后SWD引脚PA13/PA14会被当作普通GPIO或者被释放掉下一次你想用ST-Link或J-Link去下载程序会发现芯片完全不响应。解决方式很简单在SYS→Debug中选择Serial Wire。这样CubeMX就会自动预留下SWDIO和SWCLK两个引脚调试器永远可用。注意如果一个芯片已经被No Debug的程序锁住重新下载的方法是按住复位键在IDE里点下载然后瞬间松开复位键。这种强行握手方式能救回大部分芯片但最省事的还是从源头配置好。4.3 时钟配置与Debug接口的联动关系其实时钟配置和Debug接口选择在CubeMX里不是完全独立的两件事。F103单片机在72MHz系统时钟下flash等待周期需要设置为2。你在时钟配置页把SYSCLK改成72MHz后CubeMX会自动将Flash Latency调到2同时AHB/APB的分频也一并帮你算好。这就是CubeMX这类工具的意义它把原本需要翻Reference Manual去算的分频系数变成了自动推导。但自动推导不代表你可以不检查。我处理过好几个同事的工程时钟树页面显示SYSCLK 72MHz可实际主频跑的不是72MHz——原因是他们用了外部8MHz晶振却把HSE的Bypass Clock这个选项开着等于把8MHz晶振当成无源直通信号部分环境下晶振无法起振系统自动降级到HSI内部8MHz时钟主频实际只有64MHz8MHz x8。这类问题排查起来非常隐蔽最好的防御方式就是始终检查时钟配置页的HSE选项是否是Crystal/Ceramic Resonator。5. 实战用HAL库硬件SPI接口读写W25Q64 Flash本章是整篇教程的重头戏。很多人在网上搜stm32cubemx hal库 硬件spi接口实现w25q64 spi flash芯片的读写操作说明这已经是一个真实项目的标准组合了CubeMX生成SPI初始化代码HAL库操作SPI外设W25Q64作为外部存储来保存参数、字库或者日志数据。这里我完整拆解一遍。5.1 硬件连接与引脚分配W25Q64是一颗8MB64Mbit的SPI NOR Flash芯片市面上最常见的封装是SOIC-8白色小方块标着W25Q64字样。它和STM32之间只挂四根线SCK、MOSI、MISO、CS。注意CS片选虽然逻辑上属于SPI协议的一部分但在绝大多数电路里它由普通的GPIO控制而不是SPI外设硬件自动管理。这也是很多人刚接触硬件SPI时最大的认知落差以为CS像I2C那样自动拉低拉高实际上需要你手动控制GPIO。我推荐一组很标准的接线方案W25Q64引脚STM32F103引脚CubeMX配置CS片选PA4GPIO_Output默认高电平SCK时钟PA5SPI1_SCKMISO数据输出PA6SPI1_MISOMOSI数据输入PA7SPI1_MOSIVCC3.3V电源GNDGND地在CubeMX里左侧找到Connectivity展开SPI1选择模式为Full-Duplex Master再进入Parameter Settings配置参数。此时CubeMX会自动将SPI1的引脚指定到PA5/PA6/PA7我们只需把PA4单独配置成GPIO输出默认电平设为高即可。这样连接之后SPI1挂载在APB2总线上72MHz配合下面的时钟分频设置能够获得稳定的通信时钟。5.2 SPI参数配置模式选对通信就成功了一半硬件SPI最折磨人的参数是CPOL时钟极性和CPHA时钟相位。这两个东西决定SCK在空闲时是高还是低、数据在时钟的哪个沿采样。如果不匹配表现的结果就是数据发送不报错但接收方读出来全是0xFF或乱码。不少人的第一反应是怀疑接线松了实际上往往是模式没配对。W25Q64支持SPI Mode 0和Mode 3实际项目里用Mode 0最省心。对应的CubeMX配置是参数值说明ModeFull-Duplex Master全双工主机模式Data Size8 Bit一字节一字节传Prescaler472MHz / 4 18MHz低于W25Q64最高时钟没问题CPOLLow空闲时SCK为低电平Mode 0CPHA1 Edge第一个时钟沿采样数据NSSSoftware片选由GPIO软件控制First BitMSB First最高位先传SPI惯例这里特别想强调的是NSS必须选Software。如果你选了Hardware NSSCubeMX会把片选信号绑定到SPI外设的NSS引脚上由硬件自动控制但与大多数板卡的接线方式对不上而且它会在通信开始前自动拉低结束后自动拉高这种自动管理在实际调试里很容易跟手动时序打架。分频系数这里为什么选4而不是2SPI2的最高频率跑到36MHz以上对W25Q64来说依然在允许范围内但分频越低的SPI时序对布局布线越敏感。18MHz对于8MB容量的Flash读写已经非常快我实测整片擦除时间也不差那几秒没必要冒险。5.3 W25Q64核心命令与时序拆解W25Q64的数据手册里有一张指令表但实际日常开发也就用到那么几条。下面这几条是核心中的核心指令命令码功能Read JEDEC ID0x9F读出厂ID用于验证连接Write Enable0x06写使能擦除/写之前必须发Read Data0x03从任意地址读数据Page Program0x02页编程一次最多写256字节Sector Erase0x20扇区擦除一次擦除4KBRead Status Register0x05读状态寄存器bit0为忙标志时序上有一个铁律写Flash之前必须先擦除。NOR Flash的物理特性是写只能把1变0而擦除是把整块恢复成10xFF。所以如果你往一个扇区里第二次写入数据必须先把整个4KB扇区擦掉再执行页编程。这个特性跟普通EEPROM完全不同是配合Flash时最容易出bug的地方。我建议把操作封装成四个基础函数后面所有业务逻辑都基于它们来组合。5.4 完整代码实现首先是片选和基础读写原语#define W25Q64_CS_LOW() HAL_GPIO_WritePin(FLASH_CS_GPIO_Port, FLASH_CS_Pin, GPIO_PIN_RESET) #define W25Q64_CS_HIGH() HAL_GPIO_WritePin(FLASH_CS_GPIO_Port, FLASH_CS_Pin, GPIO_PIN_SET) static void SPI_WriteByte(uint8_t data) { HAL_SPI_Transmit(hspi1, data, 1, 100); } static void SPI_ExchangeBytes(uint8_t *txData, uint8_t *rxData, uint16_t len) { for (uint16_t i 0; i len; i) { uint8_t tx txData ? txData[i] : 0xFF; uint8_t rx 0; HAL_SPI_TransmitReceive(hspi1, tx, rx, 1, 100); if (rxData) { rxData[i] rx; } } }为什么接收数据时要用HAL_SPI_TransmitReceive而不是HAL_SPI_Receive原因在于SPI总线是同步全双工的主机要收到数据必须同时持续发送时钟。直接调用HAL_SPI_Receive在HAL内部虽然也会产生时钟但不同HAL库版本、不同芯片系列在行为上有时会让人困惑用TransmitReceive发送全10xFF来产出时钟是更稳妥更直观的做法。然后是核心的读写封装uint8_t W25Q64_ReadID(void) { uint8_t cmd 0x9F; uint8_t id[3] {0}; W25Q64_CS_LOW(); SPI_ExchangeBytes(cmd, NULL, 1); SPI_ExchangeBytes(NULL, id, 3); W25Q64_CS_HIGH(); return id[0]; // 通常为0xEF }void W25Q64_WriteEnable(void) { uint8_t cmd 0x06; W25Q64_CS_LOW(); SPI_WriteByte(cmd); W25Q64_CS_HIGH(); }void W25Q64_WaitBusy(void) { uint8_t cmd 0x05; uint8_t status 0; do { W25Q64_CS_LOW(); SPI_WriteByte(cmd); SPI_ExchangeBytes(NULL, status, 1); W25Q64_CS_HIGH(); } while (status 0x01); // bit0 WIP写忙标志 }重点说一下W25Q64_WaitBusy这个函数。擦除4KB扇区的时间大约在几十毫秒到上百毫秒不等不同批次芯片差异明显。可靠做法是轮询状态寄存器的WIP位直到硬件自己说我不忙了而不是傻等固定延时。延时方案不仅浪费时间还可能在芯片负载高时读出未完成的数据。uint8_t W25Q64_ReadData(uint32_t addr, uint8_t *buf, uint32_t len) { uint8_t cmd[4] {0x03, (addr 16) 0xFF, (addr 8) 0xFF, addr 0xFF}; W25Q64_CS_LOW(); SPI_ExchangeBytes(cmd, NULL, 4); SPI_ExchangeBytes(NULL, buf, len); W25Q64_CS_HIGH(); return 0; }uint8_t W25Q64_PageProgram(uint32_t addr, uint8_t *data, uint16_t len) { uint8_t cmd[4] {0x02, (addr 16) 0xFF, (addr 8) 0xFF, addr 0xFF}; if (len 0 || len 256) return 1; W25Q64_WriteEnable(); W25Q64_CS_LOW(); SPI_ExchangeBytes(cmd, NULL, 4); SPI_ExchangeBytes(data, NULL, len); W25Q64_CS_HIGH(); W25Q64_WaitBusy(); return 0; }页编程函数有几个细节值得注意页编程最多只能写256字节如果目标地址跨越了页边界即上一个256字节页的末尾需要拆分成多次来写。另外写数据之前必须先擦除对应扇区否则你写进去的数据会和旧数据做位与结果就是全乱。5.5 验证连接读JEDEC ID是第一步拿到一块W25Q64最好先执行一次读ID操作验证连接。读ID成功说明四根线接对了、SPI模式配对了。W25Q64的JEDEC ID通常是 0xEF 0x40 0x17。如果读出来是0xFF大概率是MISO没接好或者片选始终拉高导致芯片没被选中如果读出来是0x00则要怀疑MOSI和MISO是否接反了。实测中我还遇到过一种情况SCK引脚上串了太大的电阻导致波形边沿过缓读ID偶尔成功偶尔失败。这类问题在低速SPI下不明显频率上去之后才会暴露。所以我的习惯是先用低速比如1MHz验证ID跑通之后再提时钟到18MHz。这不丢人这叫工程稳妥。6. 从CubeMX到FreeRTOS再到CubeIDE一套完整开发工作流很多项目用到最后都会走到这一步用CubeMX生成外设初始化和FreeRTOS任务骨架再让CubeIDE承接工程编译、下载和调试。这两款工具的配合是ST官方目前主推的工作流热度一直居高不下我把整条链路的用法和卡点都梳理一下。6.1 CubeMX里集成FreeRTOS的配置方法在Pinout Configuration中左侧找到Middleware and Software Components展开后选FREERTOS。关键是Interface这款配置项新版CubeMX默认为CMSIS_V2这是ARM官方提供的较新的RTOS API标准功能比旧的CMSIS_V1更完善我建议直接用V2没必要为了兼容老代码而降级。接下来在Tasks选项卡里会看到默认生成的一个任务通常是defaultTask。点Add按钮新增任务可以给它起名叫FlashTestTask优先级设Normal。CubeMX生成的FreeRTOS任务代码分两个文件app_freertos.c存放任务函数本体不同版本叫法可能不同和FreeRTOS的初始化逻辑通常内含MX_FREERTOS_Init。应用逻辑写在任务函数里即可void FlashTestTask(void *argument) { uint8_t id[3] {0}; uint8_t txBuf[256] {0}; uint8_t rxBuf[256] {0}; for (;;) { W25Q64_ReadID(id[0]); // 业务逻辑... osDelay(1000); } }这里有个新手容易踩的坑HAL_Delay和osDelay混用。在FreeRTOS环境下任务里尽量不要用HAL_Delay因为它会让当前任务把CPU占死阻塞其他任务的调度。所有需要延时的场景统一用osDelay它把控制权交还给FreeRTOS调度器。另一个免费送上门的提示CubeMX生成的FreeRTOS默认堆大小是128字节起步但CMSIS_V2接口下任务控制块TCB通常要占几十字节如果你创建了多个任务或者任务栈设得偏大很容易堆溢出导致任务创建失败。遇到任务不跑的情况第一反应去检查FreeRTOS Kernel配置里的Total heap size把它调大例如512或1024问题通常就消失了。6.2 CubeIDE如何打开CubeMX生成的工程在CubeMX的Project Manager里Toolchain / IDE选择STM32CubeIDE点GENERATE CODE之后会生成一个包含.project和.cproject格式的完整Eclipse工程。然后打开STM32CubeIDE用File - Import - Existing Projects into Workspace选择CubeMX生成的目录导入后就能直接编译。你可能会有疑问CubeIDE自己也内置了CubeMX的集成入口有区别吗区别在于你导入的是已经生成好的工程IDE只负责编译调试不会回写CubeMX的.ioc文件而CubeIDE内置的方式打开.ioc文件时还会自动启动内嵌的CubeMX视图。两种方式都能用我个人常用前一种先生成再导入逻辑清晰。建议工具链选型时保持统一。团队里如果有人习惯用Keil那CubeMX里的Toolchain / IDE就统一选MDK-ARM一次性把Keil工程生成出来。切换工具链不是不行但同一份.ioc文件生成多种IDE工程时部分外设配置可能会有微妙的差异没必要给自己找麻烦。6.3 实测下来的完整工作流脚本我自己做带Flash存储、跑FreeRTOS的板子时通常的操作顺序是先在CubeMX里把引脚、时钟、SPI、FreeRTOS全部配好。生成CubeIDE工程直接编译一次确保基础工程干净。在生成的用户代码区/* USER CODE BEGIN */和/* USER CODE END */之间添加W25Q64驱动。在任务函数里调用Flash驱动进行读写测试。用CubeIDE的调试器连接ST-Link设好断点观察JEDEC ID是否读回0xEF。这条链路我已经跑了十几个项目了最大的感受是CubeMX负责的是不出错而你负责的是业务正确。初始化代码交给工具业务逻辑自己写两者边界清晰沟通成本也低。6.4 我踩过的最后一个坑中文路径导致的IDE编译失败看似不起眼的一点差点让我怀疑人生。明明CubeMX工程生成得很好代码也正确但CubeIDE一编译就报找不到头文件或者IDE直接弹出无法解析的路径错误。最后发现是工程路径里有中文目录名。Eclipse底层对Unicode路径的支持一向一言难尽CubeIDE继承了这个毛病。所以从开始建立工程目录那一刻起所有路径都保持英文字母数字下划线能少很多莫名其妙的幺蛾子。这个习惯我从那之后就记住了每次新建工程第一件事就是把路径敲成D:\work\proj\led_demo这种形式。很多人觉得这种问题属于小事但在一线写代码真正浪费时间的往往就是这种防不胜防的小事。
上一篇/下一篇内容由系统自动关联 返回资讯列表 →