资讯动态

STM32核心理论解析:时钟树、定时器、串口与中断实战指南

发布时间:2026/9/26 5:41:30 来源:尧图企业网站定制
不少朋友学STM32上来直接打开Keil照着网上的例程把LED点亮灯一亮就觉得自己入门了。但真到了做毕业设计、做项目、或者去面试的时候往往发现不对劲换了块板子不亮了改了引脚不跑了调个PWM也不知道占空比和频率到底是怎么算出来的。问题出在哪说白了就是只学会了“抄”没搞懂“理论”。STM32这颗芯片说复杂确实复杂但它的核心理论框架是固定的只要把架构、时钟、外设、中断这几块啃透后面写代码、调bug都会顺畅得多。这篇文章我就从工程实践的角度把STM32的理论体系完整梳理一遍全程用大白话尽量不用晦涩的术语堆砌。很多内容是我自己调板子踩坑后总结出来的比如时钟树怎么配、定时器捕获测频为什么比外部中断稳定、标准库和HAL库到底该怎么选、delay卡死是什么原因造成的。适合正在学STM32的初学者也适合已经会点灯但想系统理解原理的人。你不需要把整篇背下来但建议在看原理图、建工程、排查问题的时候回来翻一翻当做一份“理论地图”用。1. 先说清楚STM32到底是一个什么东西1.1 它的系统架构决定了你的代码怎么跑起来STM32是意法半导体STMicroelectronics推出的32位ARM Cortex-M内核微控制器。玩单片机的人都知道8位的51单片机是冯·诺依曼结构取指令和数据共用一条总线而STM32内部实际上是基于ARM的哈佛结构指令总线和数据总线是分开的。这个区别带来的直接好处就是CPU可以同时取指令和读写数据执行效率比同主频的51高不少。但STM32并不是“只靠一个CPU在跑”它的内部有一张“总线互联图”也就是系统架构。以常见的STM32F1/F4为例内部有多条总线ICode总线取指令、DCode总线数据访问、System总线外设访问再加上AHB、APB1、APB2总线外设就挂在APB总线上面。理解这张图的价值在于当你配置外设时钟时要知道它挂在哪个总线上不同总线的最大主频是不一样的。我举一个实际例子STM32F103的APB1总线最高36MHzAPB2总线最高72MHz。如果你把串口或者定时器挂在APB1上又希望它跑到72MHz那就要注意分频器的设置了。很多人用标准库写USART初始化波特率总是算不对十有八九就是没弄清楚外设时钟源实际是多少MHz。这不是玄学是总线架构决定的。1.2 最小系统板和完整系统有什么差别市面上常见的“STM32最小系统板”核心就是芯片、晶振、复位电路、电源电路、BOOT启动配置再加上SWD下载接口。你看原理图的时候重点就看这几样VCAP引脚上的电容、VDD/VSS的滤波电容、NRST复位电路、BOOT0和BOOT1的电平配置、以及8MHz晶振HSE和32.768kHz晶振LSE低功耗场景用。这几个地方设计对了芯片就能稳定跑起来。这里有个新手容易忽视的点BOOT0和BOOT1不是随便接的。BOOT0拉高、BOOT1拉低是从系统存储器启动也就是进入BootloaderBOOT0拉低才是从Flash启动正常跑用户程序。我曾经遇到过一个人焊完板子怎么都下载不进去程序检查了半天发现他把BOOT0用跳线帽短到了3.3V芯片一直在Bootloader模式里程序当然跑不起来。这个属于纯硬件层面的“理论”但它直接影响你能不能正常开发。2. 时钟树STM32的命脉搞懂它省一半调试时间2.1 内部时钟、外部晶振、PLL本质是一个“分水系统”“时钟树”这三个字听起来玄其实把它想成城市的供水管网就行。外部8MHz晶振是“水源”PLL锁相环是“增压泵”分频器是“减压阀”各个外设就是“用户水龙头”。你要让某个外设工作在想要的频率就得顺着管网的路径一级一级算清楚。STM32的时钟源有几个HSI内部高速RC约8MHz、HSE外部高速晶振通常是4-16MHz、LSI内部低速RC约40kHz、LSE外部低速晶振通常是32.768kHz。默认情况下芯片上电先跑HSI所以单片机“没配时钟也能点灯”就是这个原因。但HSI精度不高温漂明显通信场景下不建议作为系统时钟源。系统时钟SYSCLK通常由HSE经PLL倍频得到比如F103最大72MHz、F407最大168MHz、H743可以跑到480MHz。很多人用STM32CubeMX生成代码界面上一拉就完事但你必须能自己在脑子里算出这条链路HSE 8MHz - PLLM分频 - PLLN倍频 - PLLP分频 - 得到SYSCLK。这个公式是通用的。我在《STM32H743系列微控制器中文技术手册》里看到过更夸张的时钟树图密密麻麻但实际上你只需要关心自己用到的那几条路。2.2 照着CubeMX配时钟为什么还要手算一遍有个问题值得想清楚既然有CubeMX自动生成时钟配置为什么还要理解时钟树因为自动生成只保证“能运行”不保证“符合你的场景”。举一个典型的例子做定时器捕获测频率你需要一个尽量精准的时基。如果直接用系统时钟72MHz不分频测量低频信号时计数器溢出很快测量分辨率也受限制如果你把定时器预分频设为71计数频率就变成1MHz这时候每个计数值代表1微秒测方波频率就非常直观读CCR寄存器里的捕获值倒数就是频率。这种配置如果你不懂时钟树根本不知道定时器时钟是从哪来的、为什么预分频要填71而不是72。我在“STM32测频法”这个关键词下看到过很多提问基本分两类一类是用外部中断测频率引脚一变化就进入中断计数这种方法在低频信号下很准但频率高了以后中断太频繁CPU根本忙不过来会丢数另一类就是用定时器输入捕获模式硬件自动记录边沿时刻不占CPU。后者稳定可靠前提是你要把定时器的时钟、预分频、捕获通道配置对。2.3 时钟配置踩坑实录我整理几个自己实际踩过的坑都是时钟相关的非常典型第一外部晶振起振失败。现象是代码里配了HSE作为时钟源但程序一直卡在等待HSE就绪的死循环里。排查方向检查晶振焊接是否虚焊谐振电容通常10pF到22pF是否匹配再不行就用示波器看晶振引脚有没有波形。如果只是做学习板可以先用HSI跑通再说不要死磕硬件。第二改了系统时钟后串口波特率全乱了。这不是玄学是波特率计算公式里USART的时钟源变了但你程序里的分频值没跟着变。用CubeMX改时钟后记得确认一下串口配置页里的“Clock”链路是否同步更新。第三APB1和APB2的定时器时钟频率混淆。F103里APB1的定时器时钟默认是系统时钟的1/2但APB2的定时器时钟默认跟系统时钟一样。很多人直接套网上例程明明主频一样定时器溢出中断却快了一倍其实就是总线分频没搞明白。3. 片上外设的理论从寄存器到功能远不止点灯3.1 GPIO别小看这个最基础的外设GPIOGeneral Purpose Input Output是STM32里最简单也最常用的外设。理论上你要掌握四个要素输入还是输出、上拉还是下拉、输出速度、复用功能。对应到代码里就是标准库的GPIO_InitStructure结构体哪怕你用HAL库也绕不开这几个属性。我特别提醒一点GPIO速度不是越快越好。GPIO_Speed_2MHz、10MHz、50MHz这代表输出驱动电路的翻转速率上限。如果你的信号只是控制LED2MHz绰绰有余如果做SPI时钟线那就要选高速。选了高速模式信号沿更陡EMI会变大而且在你不需要高频翻转的场景里还可能导致功耗增加和信号振铃。GPIO还有一个容易踩的坑是“禁用JTAG”。STM32在默认情况下PA13、PA14、PA15、PB3、PB4这几个引脚被JTAG调试功能占用。你如果想把这几个引脚当普通IO用比如PA15做按键、PB3做PWM输出必须先在代码里调用GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable, ENABLE)把JTAG关掉。否则你会发现引脚电平怎么都拉不起来。我当时第一次用PB4做输出时折腾了小半天最后查手册才知道这是复用引脚必须先禁用JTAG功能。这个知识点很多教程不会细讲。3.2 定时器一个计数器能玩出多少花样定时器Timer绝对是STM32理论里最值得花时间的部分。它本质就是一个递增/递减计数器外接一个时钟源每来一个时钟脉冲计数器加一或减一溢出时产生更新事件。但在这个基础上硬件扩展出了输入捕获、输出比较、PWM生成、编码器接口、霍尔传感器接口等一系列高级功能。输入捕获测频率原理听起来很简单记录两次边沿到来时的计数器值差值就是周期。但实操中有几个细节一是边沿选择你可以捕获上升沿或下降沿测周期通常用同一边沿两次触发二是预分频需要让计数频率和被测信号频率匹配否则要么计数溢出要么分辨率太粗三是DMA或中断方式量程和实时性要平衡。编码器模式也是定时器的一大亮点。STM32的高级定时器TIM1、TIM8和通用定时器TIM2、TIM3、TIM4、TIM5支持编码器接口模式把正交编码器的A、B相直接接到两个通道上硬件自动判断方向和位置增量。这意味着你的电机转速、位置反馈不需要额外芯片也不占CPU计算资源。我之前做两轮差速小车就是直接用TIM2的编码器模式读左右轮转速TIM3和TIM4输出PWM控制电机驱动整个控制闭环代码非常干净。PWM输出则利用输出比较的“比较匹配”机制计数器从0数到自动重载值ARR比较寄存器CCR存一个阈值计数值小于阈值时输出有效电平反之输出无效电平。占空比是CCR/(ARR1)频率是定时器时钟/(预分频1)/(ARR1)。这三个值的关系新手一定要能张口就来。写代码时你会发现标准库的函数名一大堆但核心就是操作TIMx_ARR和TIMx_CCR这两个寄存器。3.3 串口通信从轮询到中断再到DMA串口是STM32项目里最常用的通信方式也是最“能体现理论水平”的一个外设。它的核心理论包含了波特率生成、数据帧格式起始位、数据位、校验位、停止位、发送/接收缓冲、以及中断和DMA机制。标准库下USART的配置流程是固定的开启时钟、GPIO复用配置、设置波特率和数据格式、配置NVIC中断、使能USART。波特率发生器内部有一个USARTDIV的概念如果你用的是库函数填一个波特率值就行但如果你自己操作寄存器就必须算USARTDIV的整数部分和小数部分。我见过一个帖子问“USARTDIV25怎么换算成波特率”下面回答五花八门说到底就是没搞清楚波特率寄存器的位定义。在项目里串口接收最忌讳的就是“在中断里裸等”。很多人一开始写中断服务函数在RXNE中断里用while循环等数据接收完这样看似没什么问题数据多了就会死锁。正确做法是中断只负责把接收到的字节丢进环形队列主循环里再解析。这个做法牵涉到数据结构的设计后面我会专门讲。USB虚拟串口USB Virtual COM Port其实也是串口的一种上层应用它走的是USB CDC类协议区别在于数据链路从UART变成了USB。之前我做过一个基于STM32的USB虚拟串口发送数据的项目上位机那边只需要装一个驱动串口就能直接收发比用CH340还要方便调试环境监测数据的时候很实用。3.4 ADC采样时间精度和速度的平衡ADC模数转换器是另一个绕不开的外设。STM32内部ADC是逐次逼近型SAR理论上它的采样过程分为两个阶段采样阶段和转换阶段。我们常说的“采样时间”Sampling Time就是采样阶段保持电容充电的时间。如果信号源内阻很大采样时间太短会导致电容充不满测量结果偏低。这就是“STM32 AD采样时间”这个关键词背后的物理意义。你可以在CubeMX里选择1.5周期、7.5周期、28.5周期等不同采样时间。经验法则信号源内阻越大所需采样时间越长追求速度的场合比如电流环采样时间短但精度可能受影响慢速传感器如温度、电位器用较长的采样时间更稳定。这里有一个ADC的实用技巧如果你的信号源是高阻抗的比如分压电阻网络直接进ADC强烈建议在ADC引脚对地并联一个0.1uF的电容给采样电容提供一个低阻抗充电源。我在做一个空气质量检测项目时用了两个分压电阻采样MQ系列传感器的模拟输出最初读数跳动很厉害后来在ADC引脚加了一个电容数值一下子就稳定了。这个属于硬件层面的ADC理论效果立竿见影。4. 中断与实时性裸机系统设计的核心逻辑4.1 中断优先级分组怎么理解STM32的NVIC嵌套向量中断控制器支持抢占优先级和子优先级。这里必须讲清楚两个概念抢占优先级可以打断正在执行的低优先级中断实现“嵌套”效果子优先级只在同一组抢占优先级的中断同时来的时候决定响应顺序它不能打断别的高优先级任务。我在项目里常用的分配策略把时间关键的中断设置为最高抢占优先级比如编码器计数、霍尔传感器采样、电流环控制把串口接收、按键扫描设置为较低优先级把耗时操作如Flash擦写尽量避开中断上下文。因为高优先级中断会阻塞其他中断的执行如果高优先级里放了耗时的Flash操作整个系统的实时性都会崩溃。你还要知道一个细节同一个中断服务函数里不同事件标志的响应顺序由你写的代码决定。比如串口同时来了“发送完成”和“接收完成”两个事件你可以在中断里先处理哪个这就是理论转化为代码的地方。4.2 中断服务函数为什么越短越好我不止一次强调过中断服务函数里不要做冗长的处理任务。很多人把数据解析、LCD刷新、LED显示逻辑全塞进中断里结果主循环闲得冒泡中断里忙得焦头烂额。系统一旦多了几个中断源互相抢占之下程序行为变得非常难预测。我个人的做法是中断服务函数里只做引起中断的“最小必要操作”——读寄存器清标志、把数据放进缓冲区然后置一个标志位或者触发一个信号量。主循环检测到标志位后再做真正的处理。这套模式在裸机开发里非常好用也是RTOS任务间通信的雏形。后来我玩了一段时间FreeRTOS发现里面队列和信号量的思路跟我当初在裸机里用环形队列和标志位是一样的只是内核帮你把调度做了。5. 开发环境选型标准库、HAL库、LL库别再傻傻分不清5.1 标准库和HAL库有什么区别这是STM32社区里问得最多的问题之一“STM32库函数和标准库有什么区别”。我直接说结论标准库Standard Peripheral Library是ST早期推出的外设库直接操作寄存器封装不深代码直观适合学习芯片原理HAL库Hardware Abstraction Layer是基于面向对象思想的高度抽象库配合CubeMX图形化配置开发效率高但底层封装较深出了问题会让你找半天。如果你是在校学生时间充裕强烈建议先学标准库。因为标准库代码和寄存器手册基本一一对应你可以通过看代码明白外设的工作原理。等你把时钟树、GPIO、定时器、串口这些外设都搞明白了再切到HAL库。那时候你会发现HAL库不过是一层“马甲”核心配置你还是看得懂的。反过来如果你一上来就用HAL和CubeMX很多东西被封装得看不见了遇到问题就像黑盒调试比较痛苦。LL库Low Layer是ST后来提供的轻量级库比HAL更接近寄存器层又没有标准库那么旧。现在新出的芯片比如H7系列ST官方主推HALLL混合使用CubeMX生成的代码也可以选择LL库。但我的建议依然是先通标准库学原理再用HAL写工程用LL优化关键链路。5.2 Keil MDK 工程模板的搭建步骤无论用哪个库你都需要一个能跑起来的工程模板。以Keil MDK为例搭建步骤大致如下先下载安装Keil MDK并完成注册然后下载对应芯片的器件支持包Device Family PackDFP。注意如果你以前装过Keil C51不要和MDK混在一个目录安装但两者可以分别装在不同目录共存在一台电脑上。启动Keil时它会让你选“Keil C51”还是“Keil MDK”这就是“keil5兼容c51和stm32安装”这个关键词的答案。工程里需要添加的文件有几类启动文件startup_stm32f10x_hd.s这类汇编文件或者F4后的.s文件、内核相关文件core_cm3.h、core_cm4.h等CMSIS文件、外设库文件标准库的stm32f10x_xxx.c/h、以及你自己的main.c和中断处理文件。然后配置宏定义比如STM32F10X_HDUSE_STDPERIPH_DRIVER。不要小看这两个宏第一个告诉编译器芯片是哪个型号决定寄存器定义第二个告诉编译器启用标准外设库。我第一次建工程时就因为忘了配宏定义编译报了一堆“undeclared identifier”的错误排查了半小时。这种经验大家记住省得走弯路。5.3 ST-Link Utility、芯片包安装和下载调试ST-Link Utility是ST官方的一个工具主要用来烧录、擦除、读取芯片Flash、修改选项字节。它的存在感在正常开发中不高因为Keil里就能直接下载调试但在两个场景下它就是救命的一是芯片读保护了。如果你用ST-Link Utility连不上目标板提示有RDPRead Protection级别限制那多半是芯片设置了读保护。点一下“Option Bytes”把Read Protection调到Level 0执行擦除或解除保护芯片就能恢复正常。注意解除高等级读保护会擦除整个Flash程序会丢这是正常现象。二是量产烧录。Keil下载速度慢而且依赖电脑上的工程生产环境下直接用ST-Link Utility或者官方命令行工具烧录Hex/bin文件效率更高。这一点做产品的人应该深有体会。还有一个非常常见的报错在帖子里见过无数次“load d:\stm32 prohect\2-1 stm32工程模板\objects\project.axf error: flash”。这个错误的本质是下载算法Flash Algorithm不对或者芯片选型错误。解决方法是检查Debug设置里Flash Download选项卡是否选对了下载算法比如F103系列要选STM32F10x Med-density/High-density Flash另外确认芯片型号是否匹配。还有一个小坑工程路径里尽量不要有中文和空格否则编译器处理起来可能出幺蛾子路径里的prohect这种拼写错误也要查清楚因为Keil报错不会帮你纠正文件名拼写。6. 从理论到实战的桥状态机与数据结构6.1 状态机让单片机“有条理”地工作写完几个单独的例程后你会发现最难的不是某个外设怎么初始化而是把多个功能组合在一起。这时候我要强烈推荐一个嵌入式开发中的万能理论有限状态机Finite State MachineFSM。拿按键消抖举例。一个按键按下在电平上会有一个大约5-20ms的抖动期如果你只用延时消抖主循环会被卡住几毫秒甚至几十毫秒这在只有一个按键时无所谓但系统同时要处理屏幕刷新、串口接收和大功率驱动时延时消抖就显得很笨。状态机方式是这样的定义按键状态为“空闲态”、“确认按下态”、“确认松开态”。用定时器定时扫描比如每5ms扫描一次检测到稳定低电平且连续两次扫描一致才切换到“按下”状态。这样既不需要阻塞延时又能可靠消抖。按键只是一个例子。我做的智能台灯项目里把“自动亮度调节”、“手动PWM调光”、“定时关灯”三个功能全部设计成状态机主循环每次运行只处理一种状态。测试下来逻辑非常清晰后面增加一个“睡眠模式”也只需要往状态迁移表里加一行。6.2 环形队列串口数据接收的“缓冲仓库”串口中断接收数据时如果每个字节都立即处理处理不过来就会丢数据。这时候环形队列Ring Buffer就是最合理的数据结构一个数组、两个下标读指针和写指针、一个元素计数。串口中断把收到的字节写入队列主循环从队列里取数据解析。用环形队列的好处是生产者中断和消费者主循环解耦生产快、消费慢也不丢数据反过来也不阻塞中断。写环形队列时有一个细节判空和判满要区别开。我用一个size变量记录当前数据量写入时size加1读取时size减1这样就不会出现“读指针追上写指针”的歧义。很多初学STM32的人串口一复杂就收到乱码或者丢数据并不是波特率不对而是没有一个可靠的缓冲机制。USB虚拟串口发送数据也是同理。CDC类驱动把上位机发送的数据放进接收缓冲区底层再按标准串口设备的方式交给用户程序。如果你在端点中断里去解析命令代码写起来很痛苦但如果你先把数据收进环形队列主循环里再按帧格式解析整个上位机协议处理就清晰多了。框架理论在这里的价值体现得非常明显。7. 常见问题与排查技巧实录7.1 延时函数delay卡死是怎么回事“STM32延时函数delay卡死”这个关键词我见过很多次。最常见的原因就是用了SysTick系统滴答定时器做延时但你在中断里没有及时清除SysTick中断标志或者SysTick被配置成了低优先级但中断一直被其他高频中断抢占导致延时函数里的等待变量永远不被更新。另一种常见情况出现在使用HAL库时HAL_Delay依赖于一个全局变量uwTick它在SysTick中断里每1ms加一。如果你在某个时候关掉了全局中断比如执行Flash擦除时HAL_Delay就会永远卡住。解决办法是在关中断之前先计算好延时时间或者用基于实际计数器的非阻塞延时。我自己的习惯是简单项目里写一个基于循环的软延时只用在初始化阶段正式逻辑里的延时尽量用定时器计数或者非阻塞状态机替代。有一次我在做伺服电机485控制的时候因为HAL_Delay卡住整个控制循环电机直接抖动换了非阻塞延时后系统才恢复正常。这个经历给我留下的印象非常深。7.2 芯片包安装失败和下载报错怎么破芯片包DFP安装失败通常有这几点一是Keil版本太老不支持新出的芯片包格式。二是下载包损坏你可以去Keil官网或者芯片厂商官网下载离线安装包手动安装。三是安装路径权限问题建议以管理员身份运行Pack Installer。遇到H743这类新芯片尤其要注意Keil MDK版本太旧的MDK不认识新芯片的Flash算法就算装了包也编译不过。下载报错“Error: Flash Download failed - Cortex-M4”绝大部分情况是Flash下载算法没选对或者芯片型号不匹配。另一个可能是你的目标板供电不足SWD下载时电压跌落也会导致下载失败。这里有个排查顺序先确认芯片型号和下载算法再确认连接线质量最后查供电。我之前遇到过下载失败结果是杜邦线太长太细信号质量太差换成短粗的排针线就好了。还有一个值得提醒的实用经验如果你用SWD下载时把PA13/PA14SWDIO/SWCLK配置成了普通IO程序第一次烧进去之后第二次就下载不进去了。解决方法是按住复位键在Keil里点下载等它开始写入的瞬间松开复位键。这是因为芯片上电后会短暂停留在复位状态趁它还没把错误引脚配置执行完的时候下载器抢先把Flash擦掉了。这个方法不优雅但非常管用。7.3 接口复用和引脚功能的“隐形坑”除了JTAG禁用之外引脚复用是另一个高频踩坑点。STM32的很多引脚都有默认复用功能比如USART1_TX在PA9但PA9同时也可以作为TIM1_CH2输出。你用CubeMX或者标准库配置时必须明确引脚被“复用”成了哪个外设。标准库里对应的就是GPIO_PinAFConfig或GPIO_Remap配置HAL库里就是MX_GPIO_Init和MX_USART1_UART_Init两个函数的顺序。我做一个基于STM32的智能台灯项目时一开始想用PB0做PWM输出结果发现PB0默认复用是TIM1_CH2N而TIM1的互补通道还有特殊的死区插入逻辑输出波形和我预期完全不一样。后来改用TIM3的通道问题半小时就解决。这就是引脚复用知识欠缺造成的典型时间浪费。另外如果你把两个不同外设配到了同一个引脚上在标准库模式下不会报错因为寄存器只会存在一个配置值后配置的覆盖先配置的程序行为就会变得“莫名其妙”。我建议在工程里维护一个“引脚分配表”哪怕就是写在注释里也能帮你省一大半调试时间。7.4 通信接口不工作的排查套路串口、I2C、SPI这些通信接口出问题几乎都有一个通用排查顺序先用逻辑分析仪或示波器看波形再看寄存器状态最后怀疑代码逻辑。举一个我亲身经历的例子我用STM32和K210通讯做视觉识别数据回传。K210那边用UART发数据STM32这边死活收不到。我用逻辑分析仪一看发现TX/RX接反了。这不是低级笑话因为很多扩展板把引脚定义印在背面你按正面丝印接就容易反。所以排查通信问题第一步永远是用工具确认波形在哪一段消失。I2C还有一个常见坑总线死锁。SDA被拉低不放通常是因为某个从设备挂了或者主设备在某个错误状态下释放总线不完整。排查方法很简单给总线多来几个时钟脉冲也就是“bit-banging”方式模拟SCL可能就解开了。这个比换芯片快得多。8. 写在最后的经验沉淀理论这层纸捅破了就那么回事。STM32的核心无非是CPU、存储器、总线、外设、中断这几个模块的组合。你只要愿意花一周甚至几天时间把时钟树、定时器、串口、中断这四个重点吃透整个芯片在你的脑子里的轮廓就会清晰起来。后面不管是做超声波测距、编码器测速、还是OTA升级、EtherCAT伺服控制都是在同一个框架上加功能。我个人在实际开发中还有一个体会不要迷信任何一个“万能例程”。网络上的例程往往是在别人的板子、别人的库版本、别人的系统时钟下调试出来的直接套用经常出问题。最好的方式是拿例程做参考自己动手新建工程一个外设一个外设地搭每搭一个就验证一个。这个方法看起来很慢但积累下来的经验是迁移到任何芯片平台都能用的。最后再分享一个小技巧在工程里把芯片型号、系统时钟频率、关键引脚分配、库版本号写成一个readme文件放在工程根目录。半年后你回头翻代码会感谢当初写下这些信息的自己。这不算什么高深理论却是实战里最有价值的习惯。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑