ARTICLE DETAIL

资讯详情

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

STM32开发实战:从工程搭建到常见问题排查

STM32开发实战:从工程搭建到常见问题排查 1. 工程搭建与环境配置第一关就劝退不少人1.1 别在固件库选择上纠结太久很多新手一上来就卡在“库函数”和“标准库”二选一的问题上。网上吵得厉害其实本质很简单标准库和HAL库只是同一颗芯片的不同“操作手套”。标准库更像直接操作寄存器的手套薄、贴手、速度快但每个外设都要你自己初始化每一个位HAL库是厚手套封装了好几个抽象层一个函数搞定一串配置但代价是代码体积大、调用链深、调试时跳进跳出容易头晕。我的建议是如果你用的是F1系列而且想真正搞懂芯片底层机制标准库依然是极好的学习材料尤其是你要做电机控制、编码器采集这类对时序敏感的项目时标准库直接翻寄存器位反而更快。但如果你用的是F4、F7、H7系列或者你只是做毕业设计、物联网终端这类应用层面的事HAL库能让你把更多精力放在业务逻辑上。最关键的一条经验是不要在项目写了两千行之后才决定换库那等于把整个工程推倒重来。我见过的绝大多数“开发进度卡死”的案例一半是配置问题另一半就是库选择反复横跳造成的。工程模板是另一个高频坑。网上模板千奇百怪有的编译通过但烧录后完全跑不起来有的连启动文件都是错的。我的习惯是固定用标准外设库自带的标准工程模板或者从芯片官方例程改起。第一次建立工程时务必逐个确认以下文件是否在正确位置启动文件startup_stm32f10x_hd.s是否匹配芯片型号高密度、中密度、低密度不能乱用系统时钟配置文件system_stm32f10x.c芯片头文件、外设头文件的包含路径宏定义STM32F10X_HD是否与芯片一致USE_STDPERIPH_DRIVER是否定义这些看起来琐碎但任何一个错了轻则编译报错重则芯片死机或者时钟跑到一半就挂了。我见过最离谱的一次是启动文件用了ld的结果芯片上电后连延时都没法正常工作折腾半天才发现是启动文件堆栈大小配置和芯片不匹配。1.2 Keil 5 和 C51、STM32 的兼容问题以及 VSCode 环境搭建Keil 5 默认是支持 ARM 编译器的但很多朋友手上还有 C51 的老项目。这个兼容问题不是安装两个包那么简单而是Keil 5 的它分别通过不同的包管理器管理 C51 和 ARM 工具链如果在同一台机器上装了C51和MDK项目文件后缀虽然都是.uvprojx但打开的时候要小心别用 MDK 去打开 C51 工程反之亦然。再说 VSCode。近几年确实很流行用 VSCode 写 STM32 代码因为代码补全、语法高亮、Git集成都比 Keil 舒服太多。但“在 VSCode 里能写代码”和“在 VSCode 里能编译调试”是两回事。我在配置工程时踩过最深的坑是.vscode目录下的c_cpp_properties.json和tasks.json包含路径如果写的是相对路径换一台电脑换了盘符就全崩。推荐的做法是编译器还是用 Keil 的 AC6 或 ARMCC只是把 VSCode 当编辑器编译任务调用 Keil 的命令行构建工具或者在工程根目录放一个Makefile用arm-none-eabi-gcc工具链编译VSCode 只负责编辑和多任务调用用OpenOCD ST-Link调试在 VSCode 里其实也能做但如果你是新手我建议依然保留 Keil 的调试界面至少到你的 UART 能正常打印日志为止。不要在最开始就追求“全 VSCode 工作流”环境问题的排查量会比代码问题大得多。我试过花一整天配 VSCode 调试环境最后发现只是 ST-Link 固件版本太老导致 GDB 连接不上这属于典型的“工具问题掩盖了技术问题”。1.3 STM32CubeMX 到底该不该用我的答案是可以用但别无脑用。CubeMX 生成代码非常方便但最大的坑是它会重新生成并覆盖你自己的用户代码区域如果你不遵守USER CODE BEGIN和USER CODE END注释之间的约定你的代码就会在下一轮生成时被洗掉。我身边至少有三个同事因为这个丢过代码。另外CubeMX 默认生成的HAL_Init()和时钟配置虽然能跑但有些外设的默认参数不适合你的实际电路。比如你要驱动一个超声波测距模块回波引脚需要高精度输入捕获CubeMX 默认的定时器预分频不一定满足你的测距分辨率。所以我的习惯是用 CubeMX 生成工程骨架然后手动修改关键外设参数并且保留一份自己维护的初始化脚本绝不在 CubeMX 里反复改配置。这样既保留了图形化的效率又避免了生成器的“黑盒效应”。2. 下载调试硬骨头连接不上、烧录失败、程序跑飞2.1 ST-Link 连接失败八成不是芯片坏了很多人第一次拿到 STM32 最小系统板插上 ST-Link 点击下载就报错No ST-Link detected或者Target connection failed。其实芯片大概率没事问题基本集中在几处供电问题ST-Link 的 3.3V 输出能力很弱如果你板子上还有其他模块比如 OLED、超声波模块USB 口供电的电压会被拉低到 3.3V 以下芯片虽然还在跑但调试接口已经工作不稳定了。解决办法是单独用 USB 给板子供电而不是全指望 ST-Link 的 3V3 引脚。接线错误SWD 接口只有四条线SWDIO、SWCLK、GND、VCC。但很多人会把 SWDIO 和 SWCLK 接反或者把板子上的 TX/RX 当成调试口。每次接线后先确认引脚丝印再上电。芯片内部的 debug 功能被关闭比如你在代码里执行了GPIO_Init()把 SWD 引脚复用成普通 GPIO或者直接调用了JTAG_DISABLE其实GPIO_Remap_SWJ_Disable()才是真正关闭SWJ这时重新上电也无法通过 ST-Link 连接。解决办法是按住复位引脚不放点击下载在芯片复位瞬间快速插入调试握手。Keil 里有个技巧在下载选项里设置“Connect under Reset”模式这样就能绕过程序里禁用调试口的代码段。ST-Link Utility也是一个救急工具。当你的板子完全无法通过 Keil 连接时先用ST-Link Utility做一次“全擦除”把芯片恢复到出厂状态再回 Keil 重新下载。我遇到过的“flash timeout”错误十有七八是 Options 里的 Flash Download 配置里没有勾选Reset and Run或者编程算法选错了。用 ST-Link Utility 还可以直接查看芯片读保护等级RDP如果芯片被读保护了Keil 会报RDDI-DAP Error这时需要先解除读保护再下载。2.2 烧录不进去时报的FLASH Download failed到底在说什么这个报错看起来像 Flash 物理损坏实际上绝大多数情况是地址配置问题。Project.axf加载失败最常见的原因是Keil 里的目标芯片型号与工程配置不一致导致 flash 算法不匹配。比如你用的是STM32F407ZGT6但工程里选了STM32F405虽然同属 F4 系列Flash 大小和扇区结构有差异下载算法就会出错。另一个被忽视的点是AXF 文件路径包含中文或空格。Keil 对路径中的非 ASCII 字符支持很差我见过一个工程放在D:\新建文件夹\STM32项目\下面编译能通过但下载时一直提示加载Project.axf失败。把整个目录改成纯英文路径后一次通过。所以现在我的所有工程目录都遵守一条规则全英文、无空格、不超过三级目录。这条规则能帮你挡住至少三分之一的诡异问题。2.3 程序“跑飞”的几种典型表现程序烧进去之后最怕的不是不运行而是乱运行。比如LED 该亮的没亮串口打印出乱码或者系统每隔几秒就重启一次。排查经验如下先看电源和地线。用示波器量 3.3V 和 GND 之间有没有高频毛刺。如果毛刺超过 200mV芯片偶尔会因为供电复位表现就是“程序跑着跑着从头开始”。再看复位引脚。如果复位引脚悬空或者被外部干扰拉低也会造成随机复位。建议复位引脚接一个 100nF 电容到地。然后看堆栈溢出。如果你用标准库默认堆栈大小在启动文件里设置如果任务嵌套太深、局部变量太大比如一个 2KB 的数组栈指针就会越过边界跑到其他数据区程序表现得毫无规律。我用MDK的View - Watch Window观察SP指针一旦发现它接近 RAM 末尾就要警觉。跑飞还有一个隐蔽原因是中断优先级配置不当。STM32 的 NVIC 优先级分组有多个模式如果两个中断的抢占优先级和子优先级设置不当会导致中断嵌套时出现异常返回程序卡死在 HardFault 里。遇到 HardFault我的套路是在启动文件里给 HardFault 中断写一个死循环并在死循环里读取SCB-HFSR和SCB-CFSR寄存器这些寄存器能精确指出来是总线错误、用法错误还是状态错误配合map文件功能可以定位到出错的函数。这一步是排查跑飞问题的核心思路比瞎猜原因高效得多。3. 时钟系统与延时一切异常的根源3.1 时钟树配置为什么外部晶振就是不起振STM32 的时钟树比 51 单片机复杂得多很多人上来直接复制别人的时钟初始化代码结果板子上的晶振频率不一样串口波特率全是错的。最典型的案例板子上焊的是 8MHz 晶振但代码里配置是 25MHz导致系统时钟按错的倍频系数跑实际主频和预期差了 3 倍以上延时、串口、定时器全乱。我的建议是拿到开发板后第一件事就是看丝印上的晶振频率然后检查工程里的HSE_VALUE宏定义标准库或者 RCC 配置工具参数HAL 库。如果你用的是内部时钟 HSI那就简单些但 HSI 精度只有 ±1%跑串口容易产生误码对时钟要求高的场合还是得用外部晶振。外部晶振不起振我踩过的坑有晶振的两个负载电容要匹配。8MHz 晶振一般配 10pF~22pF但很多人随便插两个 30pF 电容导致起振困难。示波器量不到振荡波形时优先检查负载电容。晶振引脚和芯片引脚之间走线过长寄生电容太大。尤其是手工打磨的转接板飞线一长就起振困难。芯片内部的 OSC 引脚配置错误比如忘记使能外部晶振对应的 GPIO 时钟。严格来说 RCC 配置里要一并使能RCC_APB2Periph_AFIO和RCC_APB2Periph_GPIOAPB6、PB7为晶振引脚时使能对应端口。3.2 延时函数 delay 卡死别再用简单减法网上的延时函数千奇百怪但很多都有致命缺陷。最常见的就是“软件延时”void delay_ms(uint32_t ms) { uint32_t i, j; for (i 0; i ms; i) for (j 0; j 8000; j); }这个函数在-O0编译优化下可能勉强能用但换个编译器版本、不同芯片主频下就完全失效。更危险的是如果在 delay 过程中来了中断比如串口接收中断你的延时会明显变长甚至卡死。因为中断会打断两个循环之间的操作导致循环次数不可控。我的经验是如果只是简单测试可以用 DWT 实现微秒级延时它不占用定时器而且精度很高void delay_us(uint32_t us) { CoreDebug-DEMCR | CoreDebug_DEMCR_TRCENA_Msk; DWT-CYCCNT 0; DWT-CTRL | DWT_CTRL_CYCCNTENA_Msk; uint32_t start DWT-CYCCNT; uint32_t ticks us * (SystemCoreClock / 1000000); while (DWT-CYCCNT - start ticks); }但如果你想做真正可靠的多任务时序别说软件延时连 DWT 延时都不够因为你在延时期间MCU无法执行其他任务。更好的方案是用硬件定时器做延时把延时函数改成状态标志位这样不仅能精准计时还能让主循环去处理其它事务。我在写按键消抖的时候就是用一个 1ms 的定时器中断每毫秒置一个标志然后在主循环里通过标志计数彻底告别了 delay 卡死的痛点。这里提一下delay卡死的另一个常见原因没有及时喂看门狗。如果你开了 IWDG 或 WWDG然后在主循环里写了一个较长的延时看门狗超时后直接复位芯片。表面上看就是 delay 之后程序不按预期走。解决办法是延时分片执行或者在看门狗快要溢出前塞一个喂狗操作但更建议把延时的粒度控制到 10ms 以内。3.3 串口通信乱码与 USB 虚拟串口串口调试是 STM32 开发最常用的手段但乱码问题困扰我的时间不短。乱码通常不是芯片坏了而是波特率不匹配。这里要注意STM32 的波特率并不是想设多少就设多少它由 APB 总线时钟和波特率寄存器USART_BRR决定。如果你的系统时钟配置错了比如实际只有 8MHz 但你以为 72MHz那程序里设置115200实际上产生的是约 12800自然乱码。排查乱码的顺序先用示波器看 TX 引脚输出有没有波形再看波形周期是不是对应波特率的反比。比如 115200 的位时间是约 8.68us如果你在示波器上看到的是 50us 级别的位时间那说明波特率寄存器配置和实际时钟严重不匹配直接查系统时钟与分频系数。另一个坑是用 USB 虚拟串口时忘记先安装驱动。STM32 的 USB 虚拟串口依赖于VCP驱动如果你用的是 ST-Link 的虚拟串口那需要 ST 官方的 VCP 驱动如果板子上直接接了一个 USB-TTL 芯片那需要对应厂商驱动。Windows 10 之后大部分免驱但 Win7 上经常出现设备管理器里显示“未知设备”这种情况怎么调代码都没用。还有很多人用 USB 虚拟串口发送大量数据时发现丢包这是因为 USB CDC 的缓冲区有限如果你的下位机发送频率超过上位机读取速度数据会被冲掉。正确做法是在上层加协议比如用帧头、帧尾、CRC 校验开启流控并不现实所以应用层控制发送节奏才是根本。4. 外设模块实战从定时器到通信协议4.1 定时器那些坑输入捕获、PWM 和编码器模式定时器是 STM32 的灵魂外设但也是坑最多的外设。先说输入捕获测频率。很多人想测一个外部信号的频率用定时器的捕获通道结果捕获到的频率值总是不对。最常见的原因是没有配置正确的滤波器和重映射。比如 TIM 的通道要检测一个上升沿如果你的输入引脚上有毛刺毛刺会被当成正常沿导致捕获值偏小。此时需要在定时器的 IC 滤波寄存器里配置一个采样频率比如TIM_ICFilter_PSC_4让边沿检测先经过一个数字低通滤波器。再来说 PWM 输出。有个低级但影响很大的错误定时器重载值ARR和预分频系数PSC的关系搞反。ARR 决定 PWM 周期CCR 决定占空比PSC 是对计数器时钟的预分频。当你要产生一个 20kHz、占空比 50% 的信号正确路径是// 假设 APB1 定时器时钟为 72MHz TIM_TimeBaseInitStructure.TIM_Prescaler 71; // 预分频后计数时钟为 1MHz TIM_TimeBaseInitStructure.TIM_Period 49; // 50个计数周期 - 20kHz TIM_OCInitStructure.TIM_Pulse 25; // 占空比 50%很多人的错误是先定 ARR999然后调 PSC 想凑频率最后占空比怎么调都不对因为算术关系乱了。建议在纸上先把公式写清楚计数频率 定时器输入时钟 / (PSC 1)PWM 频率 计数频率 / (ARR 1)占空比 CCR / ARR边沿对齐时调试 PWM 最好的工具是示波器没有示波器那就用逻辑分析仪。我每次看到网上有人用 LED 亮度来判断 PWM 频率是否正确就觉得好笑LED 亮度对占空比的感知很不线性频率只要超过 100Hz 你根本看不出来差别只有示波器才是判断依据。编码器模式也是 STM32 定时器特有的功能。很多人在做电机小车时直接用外部中断去读 A、B 相结果到了高速时中断响应不过来丢步严重。正确的做法是将定时器配置为编码器接口模式硬件自动根据 A、B 相位差计数。我调试时的经验是不要只在初始化时读取TIMx-CNT因为编码器计数是带方向性的溢出后会重新计数你要在溢出中断里记录方向再通过编码器值 计数溢出方向累计值 * 每转脉冲数计算出实际角度这块逻辑写不对你得到的速度曲线会飘到无法解释。4.2 超声波测距模块的常见坑超声波测距几乎人人写过但真正能稳定运行的版本不多。HC-SR04 这种模块本质是发一个 10us 的 TRIG 脉冲然后在 ECHO 引脚上等待高电平时间高电平持续时间乘以声速再除以 2 就是距离。坑在哪里第一TRIG 脉冲必须大于 10us否则模块不触发。很多人用 HAL 的延时函数如果配置不准10us 变成了 5us那模块永远不响应。我之前是用定时器的输出比较来产生 TRIG 脉冲严格保证 20us稳定得多。第二ECHO 高电平持续时间的测量方法。网上写“用循环等待引脚变低然后读取定时器计数”确实能测但如果你在主循环里做这件事测距期间 MCU 基本干不了别的如果你这时候来了一个串口中断ECHO 的高电平窗口可能就错过了测出个完全不合理的距离。我的做法是用定时器输入捕获通道开启上升沿和下降沿中断记录两个时刻的时间戳主循环只负责读结果。这样测距和业务逻辑完全解耦稳定性大大提升。第三声速受温度影响。常温下声速约 340m/s如果温差大测出的距离会偏差几个厘米。要求高的项目可以在代码里加入温度补偿公式是v 331.4 0.607 * T其中 T 是摄氏度。这不是必须但如果你的超声波模块旁边有发热元件还是要考虑一下。4.3 通信协议串口、RS485 和以太网串口通信有另一个隐蔽问题中断与 DMA 的配合。当你用串口接收不定长数据时如果只开接收中断每个字节进一次中断CPU 占用高且容易丢字节。解决方案是用 DMA 空闲中断IDLE在接收空闲时把一整包数据搬到内存。很多人在 STM32F1 上用了 HAL 库的HAL_UART_Receive_DMA后会碰到回调不执行的问题因为 HAL 库的 DMA 中断回调需要自己注册。我踩过这个坑后写了个小框架// 使能 IDLE 中断和 DMA 接收 UART_DMA_Config(huart1, (uint8_t*)rx_buf, RX_BUF_SIZE); __HAL_UART_ENABLE_IT(huart1, UART_IT_IDLE);然后在中断处理函数里判断UART_IT_IDLE标志并读取当前 DMA 剩余数据量算出实际收到多少字节。这样能稳定接收任意长度的数据包而且 CPU 开销极小。这个方法我在多个项目里实测比逐字节中断稳定很多。RS485 则多了一个方向控制的问题。很多人忘了 RS485 是半双工发送时必须将 DE/RE 引脚拉高接收时必须拉低。如果代码里只拉了 DE忘了 RE就会出现“能发不能收”。还有 RS485 总线的终端电阻短距离可以不加但超过几十米或者多个设备并联时不加终端电阻会导致信号反射通信偶发错误。我的经验是RS485 发完最后一个字节后要延时 100us 左右再把方向拉回接收模式这个延时可以用定时器做不然用软件延时可能会被打断。至于 EtherCAT 这种工业以太网那是更高阶的玩法了。STM32 本身不带 EtherCAT 从站控制器但通过外部从站控制器芯片比如 LAN9252连接可以实现基于 STM32 的 EtherCAT 从站。这种方案更多是了解原理实际项目还得上专门的接口芯片。我建议如果只是学习范围内先用普通以太网TCP/UDP练手等理解了 MAC、PHY、中断与 DMA 协同后再考虑 EtherCAT 这种实时协议。4.4 按键模块电路设计消抖和防倒灌按键看似简单但电路设计不好就会出现误触发甚至烧引脚。一个稳妥的按键输入电路是按键一端接地另一端接 GPIO同时 GPIO 外部下拉到地或者开启内部下拉GPIO 配置为输入模式时如果内部无上下拉外部必须加上下拉电阻否则按键悬空时引脚电平不确定读到的值随机。消抖有两种方案硬件 RC 滤波或者软件消抖延时 连续采样确认。我推荐软件消抖因为更灵活。常见误区是把按键扫描放在延时函数里导致整个系统阻塞。正确做法是在一个 10ms 定时器中断里扫描按键每 10ms 更新一次按键状态再用状态机方式判断短按、长按、双击。这样按键响应快且不干扰其他任务。还有一个容易被忽略的是GPIO 引脚的电平兼容性。如果你的按键电路用了 5V 上拉而 STM32 是 3.3V 供电那么按键按下时 GPIO 引脚接收到 5V这会通过引脚内部的 ESD 保护二极管倒灌到 VDD长期运行会损伤芯片。解决办法是上拉电源用 3.3V或者用串联电阻限流或者加电平转换电路。5. 常见问题排查与工具链技巧5.1 一张“问题速查表”照着查能省一天根据我的长期调试记录把最高频的问题整理成了表格你在排查时可以直接对着看现象大概率原因排查方法ST-Link 无法连接SWD 引脚被复用或读保护开启按住复位点击下载用 ST-Link Utility 解除读保护下载时Flash Download failed芯片型号选错 / 路径含中文核对器件型号工程路径改纯英文串口乱码系统时钟和波特率不匹配或地线没共地示波器量 TX 位时间程序跑飞 / 随机复位供电毛刺、复位引脚干扰、堆栈溢出示波器看电源检查 SP 指针延时不准确编译器优化等级或时钟源不对改用定时器延时或 DWT 延时输入捕获值跳变引脚毛刺干扰未配置滤波配置 IC filter超声波测距乱跳ECHO 测量方式阻塞未用捕获改用输入捕获中断RS485 能发不能收DE/RE 方向控制错误检查收发切换时序按键误触发没有上下拉或消抖不彻底加下拉电阻 10ms 状态机消抖这张表的本质是先把硬件和底层配置排除掉再去怀疑你的业务逻辑。我见过太多人拿着逻辑分析仪查一天应用层的 bug最后发现是晶振虚焊导致时钟偏移。所以时钟永远优先排查。5.2 调试工具组合拳示波器、逻辑分析仪、串口助手我调试 STM32 时桌面上常备三样一个两台口的示波器、一个 8 通道的逻辑分析仪、一个支持自定义协议的串口助手。它们的角色分工是示波器看模拟信号质量比如电源纹波、晶振波形、PWM 波形、RS485 信号的差分波形逻辑分析仪看数字时序比如 SPI 的片选和时钟对齐、UART 波形、按键抖动、编码器 A/B 相时序串口助手上位机交互打印日志、解析协议其中逻辑分析仪的价格很便宜几十到一百多块就能买个靠谱的 8 通道 24MHz 采样率的已经能覆盖绝大多数 STM32 调试场景。强烈建议每个做嵌入式的人手一个。当你的程序出现“时而正常时而不正常”的问题时逻辑分析仪直接挂在目标引脚上采一段波形原因往往一眼就能看出比如片选信号抖动、I2C 时钟线被拉低等。5.3 STM32 OTA 升级的实战经验OTA 是一个很常见的进阶需求但里面的坑也不少。我在设计 OTA 时基本会拆成三个部分Bootloader、App、固件接收模块。Bootloader 常驻在 Flash 起始地址负责检测是否有新固件如果有就把新固件写入 App 区然后跳转。跳转本身有个大坑跳转前必须关闭所有中断、复位外设时钟、重新设置中断向量表。如果你在 Bootloader 里开了串口中断跳转到 App 后没有关闭这些中断App 一旦触发对应的中断程序就会跳回 Bootloader 的中断服务函数而不是 App 的行为会极其诡异。我的经验是// 跳转前操作 __disable_irq(); HAL_RCC_DeInit(); SysTick-CTRL 0; // 设置新的中断向量表在 App 启动代码里也要做 SCB-VTOR APP_ADDRESS; __enable_irq();另外固件传输过程必须带上 CRC 校验。我之前用 YModem 协议传输但很多简化协议不校验一旦下载了一条错误固件设备就变砖。现在我无论用什么协议固件包尾部都要加一个 CRC32Bootloader 校验通过后才允许写入。这里要强调OTA 升级最容易出问题的不是传输而是写入 Flash 时的擦写逻辑。STM32 Flash 必须先擦除扇区再写入擦除期间不能有中断嵌套去访问 Flash否则会触发 HardFault。所以升级过程要保证关键中断比如喂狗中断在擦写期间关闭或者安排到 RAM 中执行。6. 写在最后的实际体会做了这么多年 STM32 开发最大的体会就是嵌入式调试的本质是“分层排除”。硬件问题、时钟问题、外设配置问题、应用逻辑问题这四个层次你必须按顺序查不能一上来就怀疑别人写的库有问题。我遇到过很多次让人抓狂的 bug最后都会发现是我自己的配置某个位没填对或者一个分号打错导致宏定义失效。另一个体会是调试效率的提升来自工具的熟练。如果你现在还只用串口打印来调试强烈建议学会用调试器的断点、变量观察窗口、寄存器窗口。虽然刚开始会觉得麻烦但一旦用熟了定位问题的速度会提升好几倍。Keil 的调试模式里可以实时查看外设寄存器比如 TIM 的 CNT、ARR、CCR 值直接能看到定时器是否在工作比盲猜代码强太多。最后想说的是不要害怕踩坑。STM32 的坑基本都是公开的你今天踩过一次明天写下来以后你再遇到同类问题就能十分钟解决。我整理这篇总结就是想把这些年花在查手册、翻论坛、盯示波器上的时间替大家省下来。如果你正卡在某个 STM32 的开发问题上不妨对照上面这些章节找找线索。很多时候你以为芯片坏了其实只是时钟配置错了一个数你以为代码逻辑有问题其实只是硬件上少了一个上拉电阻。把基础打稳调通外设剩下的事情就会顺很多。
返回列表