ARTICLE DETAIL

资讯详情

深耕网站建设、视觉设计与SEO优化的一线实战洞察。

STM32从选型到实战:时钟树、中断、外设与避坑指南

STM32从选型到实战:时钟树、中断、外设与避坑指南 1. 为什么STM32值得花时间搞明白刚入行那会儿我对STM32的理解就是“一块单片机”跟51没啥本质区别无非引脚多点、跑得快些。直到第一个量产项目卡在ADC采样抖动上折腾了三天才发现是时钟树配置里APB2分频系数没对齐导致采样时间算错了。从那以后我才真正意识到STM32不是“高级51”它是一整套从内核到外设再到工具链的完整生态你不把底层逻辑吃透出了问题连从哪儿下手都不知道。STM32是意法半导体基于ARM Cortex-M内核做的一系列32位MCU。Cortex-M又分M0、M0、M3、M4、M7、M33等好几个档次对应STM32的F0、L0、F1、F4、H7、L5等产品线。选型的时候如果只看主频和Flash大小大概率会在后面踩坑——比如F1没有FPU浮点运算单元你拿它跑电机FOC算法光定点转浮点的开销就能把CPU吃满而F4带单精度FPU同样的算法跑起来轻松很多。这就是为什么搞STM32第一步不是写代码而是搞清楚你手里这颗芯片到底属于哪个系列、内核是什么、有哪些外设资源。这篇文章我打算把STM32从选型、开发环境搭建、核心外设原理到实际项目调试的完整链路捋一遍。不管你是刚学完C语言想入门嵌入式的大学生还是从51转过来想升级技术栈的工程师或者是工作中需要快速上手STM32做产品原型的开发者都能从中找到可以直接用的东西。我不会只讲“怎么点灯”而是把每个环节背后的“为什么”讲清楚——为什么时钟要那样配、为什么中断优先级要那样分、为什么调试器连不上可能不是线的问题。这些才是真正干活时救命的知识。2. STM32的芯片架构与选型逻辑2.1 Cortex-M内核到底分几种怎么选不踩坑ARM公司自己不卖芯片它只设计内核架构然后把授权卖给ST、NXP、GD、华大这些厂商。Cortex-M系列目前主流的有这几个档次内核典型STM32系列主频范围FPUDSP指令典型场景Cortex-M0STM32G0/L032-64MHz无无低成本传感器节点、简单控制Cortex-M3STM32F1/L172-120MHz无无工业控制、家电、通用嵌入式Cortex-M4STM32F3/F4/L480-180MHz单精度有电机控制、音频处理、信号采集Cortex-M7STM32F7/H7216-550MHz双精度有图形界面、复杂算法、高速通信Cortex-M33STM32L5/U5110-160MHz单精度有安全敏感场景、低功耗IoT选型的核心逻辑是先看你的算法需不需要浮点运算再看通信接口够不够用最后看功耗和成本能不能接受。举个例子你要做一个无刷电机的FOC控制需要跑Park变换、Clarke变换、PID调节这些全是浮点运算。如果你选F1就得用定点数模拟浮点代码复杂度翻倍不说控制精度还差。选F4就舒服很多硬件FPU直接算CPU还有余力处理其他任务。还有一个容易忽略的点是Pin-to-Pin兼容性。ST的很多系列在相同封装下引脚是兼容的比如F1和F4的LQFP64封装很多引脚定义一致。这意味着你前期用F103做验证后期性能不够了可以直接换F407PCB不用重新画。这个特性在产品迭代时能省大量时间。2.2 时钟树STM32最容易翻车的地方STM32的时钟系统比51复杂一个数量级。51通常就是一个晶振直接给内核用STM32则有一套完整的时钟树HSI内部高速RC、HSE外部晶振、PLL锁相环、SYSCLK系统时钟、AHB总线、APB1总线、APB2总线每一级都有分频器。我见过太多新手在这里翻车。比如串口波特率算不对查了半天代码最后发现是APB1的时钟频率搞错了——F103的APB1最高36MHzAPB2最高72MHz如果你把串口挂在APB1上算波特率时用了72MHz去算出来的波特率就是错的。配置时钟树的标准流程是这样的假设你用8MHz外部晶振目标系统时钟72MHz。首先HSE8MHz然后经过PLL倍频F103的PLL输入需要先经过一个2分频所以PLL输入是4MHz然后倍频系数设为18得到72MHz。接着SYSCLK72MHzAHB不分频APB1二分频得36MHzAPB2不分频得72MHz。这一套下来每个外设的时钟源就确定了。注意不同系列的PLL配置参数不一样F4的PLL配置比F1复杂得多有PLLM、PLLN、PLLP、PLLQ四个参数。一定要对着参考手册的时钟树图一步步算不要凭感觉填。2.3 存储映射与启动模式STM32的地址空间是4GB从0x00000000到0xFFFFFFFF。其中Flash通常映射在0x08000000开始的位置SRAM在0x20000000开始。为什么Flash不从0x00000000开始因为0x00000000被用作启动别名区根据BOOT引脚的状态它会被映射到Flash、系统存储器或SRAM。BOOT0和BOOT1两个引脚决定了启动模式BOOT00从主Flash启动这是正常运行时的模式BOOT01, BOOT10从系统存储器启动也就是跑出厂固化的Bootloader用于串口下载程序BOOT01, BOOT11从SRAM启动一般用于调试实际项目中我通常会把BOOT0通过一个10K电阻下拉到地需要串口下载时再用跳线帽拉到VCC。这样正常运行时不会因为BOOT0悬空导致意外进入Bootloader模式。3. 开发环境搭建与工具链选择3.1 Keil、IAR还是STM32CubeIDE这是每个新手都会问的问题。我的建议是如果你在学校或者公司已经有人用Keil那就跟着用Keil如果是全新开始直接用STM32CubeIDE。Keil MDK的优势是生态成熟、资料多、编译器优化好但它是收费的而且Keil5要同时兼容C51和STM32的话安装配置比较折腾——需要分别装C51和ARM的芯片包有时候还会遇到fromelf.exe路径报错的问题。IAR同理编译效率高但价格不便宜。STM32CubeIDE是ST官方出的免费IDE基于Eclipse集成了CubeMX配置工具和GCC编译器。它的好处是免费、跨平台、和ST的生态无缝衔接。缺点是Eclipse的界面响应速度确实不如Keil流畅大项目编译时间也偏长。还有一个选择是VS Code PlatformIO或者VS Code STM32CubeCLT。这种方式适合习惯VS Code的开发者代码补全和调试体验很好但初始配置需要花点时间。实操心得不管你用哪个IDE都建议把编译器的优化等级先设为-O0或者-Og来调试等功能稳定了再改成-O2或-Os做发布。我遇到过开了-O2之后某个延时循环被编译器优化掉导致时序完全乱掉的情况。3.2 芯片包安装与工程模板创建以Keil为例安装完MDK之后需要安装对应的Device Family PackDFP。比如你用STM32F103就要装Keil.STM32F1xx_DFP这个包。安装方式有两种一种是在Keil的Pack Installer里在线安装另一种是去Keil官网下载pack文件离线安装。国内网络环境下在线安装经常失败建议直接下载离线包。装好芯片包之后新建工程的流程是Project - New uVision Project - 选择芯片型号 - 勾选需要的软件组件CMSIS的Core和Device Startup是必须的- 确定。然后你需要手动添加main.c和其他的用户代码文件。如果你用STM32CubeIDE流程更简单File - New - STM32 Project - 选择芯片或开发板 - 配置外设 - 生成代码。CubeMX会自动帮你生成时钟配置、外设初始化、中断向量表等代码你只需要在指定的用户代码区域填充业务逻辑。3.3 调试器选型ST-Link、J-Link还是DAPLinkST-Link是ST官方的调试器价格便宜山寨版十几块钱配合STM32CubeProgrammer和IDE都能用。J-Link性能更强支持更多芯片但正版价格高。DAPLink是ARM官方的开源调试器方案很多国产开发板自带。实际使用中ST-Link对STM32的支持是最好的毕竟是自己家的芯片。但有时候会遇到“Could not stop Cortex-M device”的报错这通常是因为芯片进入了低功耗模式调试器无法接管SWD引脚被复用成了GPIO芯片被读保护了复位电路有问题解决办法通常是按住复位键点击下载然后松开复位键。或者在STM32CubeProgrammer里选择“Connect Under Reset”模式。4. 核心外设原理与实操要点4.1 GPIO不只是点灯那么简单GPIO是STM32最基础的外设但它的配置选项比51丰富得多。每个GPIO引脚可以配置为输入浮空输入上拉输入下拉模拟输入开漏输出推挽输出开漏复用功能推挽复用功能为什么要有这么多模式举个例子I2C的SDA和SCL引脚必须配置为开漏复用功能因为I2C总线需要线与逻辑多个设备可以同时拉低总线。如果你配成推挽输出两个设备同时输出不同电平时会短路。推挽输出和开漏输出的区别推挽输出可以主动输出高电平和低电平驱动能力强开漏输出只能主动拉低高电平需要外部上拉电阻。实际项目中驱动LED用推挽输出I2C通信用开漏输出读取按键用输入上拉或下拉。注意STM32的GPIO在复位后默认是模拟输入模式F1系列或浮空输入F4系列不是输出模式。所以你必须显式配置每个用到的引脚不能想当然地以为它默认就是输出。4.2 中断系统与NVIC优先级配置STM32的中断系统由NVIC嵌套向量中断控制器管理。每个中断源都有一个优先级优先级又分为抢占优先级和响应优先级。抢占优先级高的中断可以打断正在执行的抢占优先级低的中断这就是“嵌套”的含义。响应优先级只在同时发生多个中断时决定谁先执行不能打断正在执行的中断。Cortex-M3/M4的NVIC支持最多16个优先级等级4位但STM32通常只用了其中一部分。优先级分组有5种分组抢占优先级位数响应优先级位数说明NVIC_PriorityGroup_004没有抢占全是响应NVIC_PriorityGroup_1132级抢占8级响应NVIC_PriorityGroup_2224级抢占4级响应NVIC_PriorityGroup_3318级抢占2级响应NVIC_PriorityGroup_44016级抢占没有响应实际项目中我通常用Group_2因为4级抢占优先级对大多数应用足够了。配置的时候要注意数值越小优先级越高。比如抢占优先级0比抢占优先级1高。一个常见的坑是在中断服务函数里做了太多事情导致其他中断被延迟响应。比如串口接收中断里直接处理协议解析如果数据量大就会阻塞其他中断。正确的做法是中断里只做数据搬运把数据存到缓冲区然后在主循环里处理协议。4.3 定时器从延时到PWM到输入捕获STM32的定时器分为高级定时器TIM1、TIM8、通用定时器TIM2-TIM5和基本定时器TIM6、TIM7。高级定时器支持互补输出和死区插入专门用于电机控制通用定时器功能最全支持PWM输出、输入捕获、编码器接口等基本定时器只能做定时中断。PWM输出的配置流程选择定时器 - 配置时基预分频器PSC和自动重装载值ARR- 配置PWM模式 - 配置输出通道 - 使能。PWM频率的计算公式是PWM频率 定时器时钟 / ((PSC1) * (ARR1))假设定时器时钟72MHz你要生成1kHz的PWMPSC设为71ARR设为999那么频率 72000000 / (72 * 1000) 1000Hz。占空比通过比较寄存器CCR来设置占空比 CCR / (ARR1)。输入捕获用于测量外部信号的频率和占空比。配置流程是选择定时器 - 配置时基 - 配置输入捕获通道 - 设置触发边沿 - 使能捕获中断。在中断里读取CCR的值两次捕获的差值就是信号周期。实操心得做超声波测距的时候我用TIM的输入捕获模式测量回波高电平时间。这里有个细节超声波模块的Echo引脚输出的是5V电平而STM32的GPIO是3.3V容忍的但最好还是加一个电平转换电路否则长期工作可能损坏引脚。4.4 串口通信USART与UART的区别USART通用同步异步收发器和UART通用异步收发器的区别在于USART支持同步模式可以输出时钟信号而UART只支持异步模式。实际项目中我们绝大多数时候用的是异步模式也就是UART。STM32的串口配置参数包括波特率、数据位、停止位、校验位、流控。最常用的配置是115200-8-N-1即波特率1152008位数据位无校验1位停止位。串口发送数据用HAL_UART_Transmit()接收数据用HAL_UART_Receive()。但这两个函数是阻塞式的实际项目中更常用的是中断接收或DMA接收。中断接收的流程是使能接收中断 - 在中断回调函数里读取数据 - 存到缓冲区。DMA接收适合大数据量场景。配置好DMA通道后串口收到的数据会自动搬到指定内存区域CPU完全不用管。等一帧数据收完了DMA产生中断你再处理数据。注意串口波特率误差要控制在2%以内否则通信会出错。STM32的波特率寄存器USART_BRR的计算公式是BRR 时钟频率 / 波特率。比如72MHz时钟115200波特率BRR 72000000 / 115200 625实际写入BRR的值是625对应波特率 72000000 / 625 115200误差为0。4.5 ADC采样与滤波STM32的ADC是12位逐次逼近型最多有18个通道16个外部2个内部。ADC的时钟不能超过14MHzF1系列所以通常用PCLK2经过分频后作为ADC时钟。ADC采样的关键参数是采样时间。采样时间越长采样精度越高但转换速度越慢。F1系列的采样时间可以设为1.5、7.5、13.5、28.5、41.5、55.5、71.5、239.5个ADC时钟周期。对于大多数传感器信号选41.5或55.5周期就够用了。实际项目中ADC采样值会有抖动需要做滤波。最简单的滤波是多次采样取平均比如连续采16次去掉最大值和最小值剩下的取平均。更好的方式是做滑动平均滤波或者卡尔曼滤波。实操心得ADC的参考电压直接影响采样精度。STM32的VREF通常接VDDA如果VDDA有纹波采样值就会跳。我一般会在VDDA和VSSA之间并一个10uF钽电容和一个100nF陶瓷电容效果很明显。5. 从零搭建一个STM32项目的完整流程5.1 需求分析与硬件选型假设我们要做一个“基于STM32的温湿度监测器”需求是采集温湿度数据通过串口输出同时用OLED显示。这个需求很简单但选型的时候要考虑几个点温湿度传感器用什么DHT11便宜但精度低SHT30精度高但贵。如果只是学习用DHT11够了。OLED用I2C接口还是SPI接口I2C接线少但速度慢SPI速度快但占引脚多。128x64的OLED用I2C就够了。主控选哪个F103C8T6最小系统板便宜且资源够用72MHz主频64KB Flash20KB SRAM完全能胜任。最终选型STM32F103C8T6 DHT11 SSD1306 OLEDI2C接口。5.2 CubeMX配置与外设初始化打开STM32CubeIDE新建工程选择STM32F103C8T6。然后配置RCCHSE选择Crystal/Ceramic ResonatorSYSDebug选择Serial WireClock ConfigurationHSE 8MHzPLL倍频到72MHzAPB1分频到36MHzAPB2不分频USART1异步模式115200波特率8N1I2C1标准模式100kHzGPIO配置一个引脚用于DHT11数据线开漏输出/输入切换配置完成后点击“Generate Code”CubeMX会自动生成初始化代码。5.3 DHT11驱动编写DHT11是单总线协议时序要求比较严格。通信流程是主机拉低数据线至少18ms然后拉高20-40usDHT11响应拉低80us再拉高80usDHT11发送40位数据每位以50us低电平开始高电平持续时间决定数据是0还是126-28us为070us为1代码实现的关键是微秒级延时。可以用SysTick定时器或者DWT数据观察点来实现。我一般用DWT因为精度高且不占用定时器资源。// DWT初始化 void DWT_Init(void) { CoreDebug-DEMCR | CoreDebug_DEMCR_TRCENA_Msk; DWT-CYCCNT 0; DWT-CTRL | DWT_CTRL_CYCCNTENA_Msk; } // 微秒延时 void DWT_DelayUs(uint32_t us) { uint32_t start DWT-CYCCNT; uint32_t ticks us * (SystemCoreClock / 1000000); while ((DWT-CYCCNT - start) ticks); }读取DHT11数据的函数需要切换GPIO方向发送起始信号时配置为输出读取数据时配置为输入。5.4 OLED显示与串口输出SSD1306 OLED的I2C驱动比较简单主要是初始化寄存器和写显存。初始化序列包括设置显示时钟、复用率、显示偏移、起始行、对比度等。写显存就是往GDDRAM里写数据每页8行共8页每页128字节。串口输出用printf重定向int __io_putchar(int ch) { HAL_UART_Transmit(huart1, (uint8_t *)ch, 1, HAL_MAX_DELAY); return ch; }然后在代码里就可以直接用printf了。5.5 主循环逻辑与任务调度主循环的逻辑是每隔2秒读一次DHT11 - 更新OLED显示 - 通过串口输出。但DHT11读取需要至少2秒间隔所以不能用HAL_Delay()阻塞整个循环。更好的方式是使用定时器中断或者状态机。我通常用SysTick做一个简单的任务调度器volatile uint32_t tick 0; void SysTick_Handler(void) { tick; } uint32_t GetTick(void) { return tick; } // 主循环 uint32_t lastRead 0; while (1) { if (GetTick() - lastRead 2000) { lastRead GetTick(); DHT11_Read(temp, humi); OLED_Update(temp, humi); printf(Temp: %d C, Humi: %d %%\r\n, temp, humi); } }这种方式不会阻塞其他任务如果后面要加按键扫描、串口命令解析等功能都可以放在主循环里。6. 常见问题排查与避坑指南6.1 下载与调试问题速查问题现象可能原因解决方法ST-Link连不上芯片SWD引脚被复用/芯片进入低功耗/读保护按住复位键点击下载或Connect Under Reset下载成功但程序不跑BOOT引脚状态不对/时钟配置错误检查BOOT0是否拉低检查HSE是否起振串口无输出波特率不对/TX RX接反/串口时钟未使能用示波器看TX引脚波形确认波特率程序跑飞数组越界/堆栈溢出/中断优先级冲突减小局部数组增大堆栈检查NVIC配置ADC采样值跳动大参考电压不稳/采样时间太短/信号源阻抗高加滤波电容增大采样时间加电压跟随器6.2 那些年我踩过的坑第一个坑Flash等待周期。F103在72MHz运行时Flash需要插入2个等待周期否则取指会出错。CubeMX会自动配置但如果你手动写时钟初始化代码忘了设FLASH_ACR的LATENCY位程序就会莫名其妙地跑飞。第二个坑中断优先级分组。HAL库默认用Group_4也就是4位全是抢占优先级。如果你在代码里又调用了HAL_NVIC_SetPriorityGrouping()改成别的分组之前配置的中断优先级就全乱了。所以要么统一用HAL库的默认分组要么在初始化最开始就设好分组后面不要再改。第三个坑DMA和中断同时用。串口DMA发送的时候如果DMA传输完成中断和串口空闲中断同时触发处理不当会导致数据丢失。正确的做法是在DMA传输完成中断里只置标志位在主循环里处理后续逻辑。第四个坑看门狗。独立看门狗IWDG用的是内部LSI时钟频率约40kHz但不同芯片之间差异很大30-60kHz。如果你用IWDG做精确延时那就不靠谱了。IWDG只适合做“喂狗”监控不适合做定时。6.3 嵌入式面试八股文里的STM32考点面试的时候STM32相关的问题通常集中在几个方面时钟树从HSE到SYSCLK经过哪些环节APB1和APB2的最高频率是多少中断NVIC的优先级分组抢占优先级和响应优先级的区别通信I2C的开漏输出和上拉电阻SPI的四种模式UART的波特率计算存储Flash和SRAM的地址范围启动模式的选择外设定时器的PWM模式ADC的采样时间DMA的传输模式这些问题看起来基础但真正能答清楚的人不多。我的建议是不要死记硬背而是自己动手配置一遍用示波器或者逻辑分析仪看波形理解每个参数的实际效果。7. 进阶方向与项目实战建议7.1 从裸机到RTOS裸机开发适合简单项目但当你的系统需要同时处理多个任务比如按键扫描、串口通信、数据显示、电机控制裸机的前后台架构就会力不从心。这时候就需要引入RTOS比如FreeRTOS。FreeRTOS在STM32上的移植比较简单CubeMX里可以直接勾选FreeRTOS组件它会自动生成移植代码。你只需要创建任务、队列、信号量然后StartScheduler就行了。但RTOS也带来了新的问题任务栈大小怎么定优先级怎么分共享资源怎么保护这些都需要在实际项目中慢慢积累经验。我的建议是先用裸机把功能跑通再考虑要不要上RTOS。不要为了用RTOS而用RTOS。7.2 OTA升级的实现思路OTA空中升级是物联网设备的基本需求。STM32的OTA通常有两种方案第一种是双Bank方案Flash分成两个区域一个跑当前固件一个存新固件。升级时先把新固件写到备用区域然后修改启动地址重启后跑新固件。这种方案安全但需要Flash容量足够大。第二种是BootloaderApp方案Flash开头放Bootloader后面放App。升级时Bootloader接收新固件擦除旧App写入新App。这种方案节省Flash但升级过程中断电会导致设备变砖。实际项目中我倾向于双Bank方案虽然Flash用量大但可靠性高。STM32F4和F7系列支持硬件双BankF1系列需要自己划分区域。7.3 基于STM32的毕业设计选题建议如果你是在校学生需要做基于STM32的毕业设计我建议选一个有实际应用场景的题目而不是简单的“温湿度监测”或者“LED控制”。比如基于STM32的智能药盒定时提醒、药品计数、蓝牙上报基于STM32的电动车充电桩控制器电流检测、继电器控制、刷卡计费基于STM32的便携式心电监测仪AD8232采集、OLED显示、SD卡存储这些题目有足够的复杂度能体现你的综合能力而且面试的时候也有东西可讲。做毕设的时候不要只满足于“能跑”要把代码结构整理好写清楚注释画好流程图这些在答辩和面试时都是加分项。7.4 国产MCU的替代趋势最近几年国产MCU发展很快GD32、华大、中微、航顺等厂商都推出了Pin-to-Pin兼容STM32的产品。GD32的引脚和STM32完全兼容代码也基本兼容但内核频率更高GD32F103可以跑到108MHzFlash访问速度更快。如果你在做产品选型可以考虑国产MCU作为备选方案。但要注意几点国产MCU的外设寄存器可能和STM32有细微差别比如ADC的采样时间配置、定时器的分频系数等。移植的时候要仔细对照数据手册不能直接照搬STM32的代码。实操心得我用GD32替换STM32的时候发现GD32的Flash擦除时间比STM32长导致OTA升级时看门狗超时复位。后来把看门狗超时时间从2秒改成5秒才解决。所以替换芯片时一定要留足余量不要卡着参数上限设计。8. 调试工具与效率提升技巧8.1 逻辑分析仪和示波器的使用调试通信协议的时候逻辑分析仪比示波器好用。比如调试I2C通信逻辑分析仪可以直接解码出地址、数据、ACK/NACK一眼就能看出问题。调试SPI的时候可以同时看CLK、MOSI、MISO、CS四路信号确认时序是否匹配。示波器更适合看模拟信号和电源质量。比如ADC采样不准用示波器看VREF的纹波就能判断是不是电源问题。PWM输出异常用示波器看波形占空比和频率比看代码快得多。8.2 printf调试法的正确姿势printf是最常用的调试手段但在STM32上用printf有几个坑第一半主机模式。Keil默认用半主机模式实现printf需要调试器连接才能工作。如果你脱机运行printf就会卡住。解决办法是重定向fputc到串口或者关闭半主机模式。第二printf的性能。printf函数本身很重如果在一个高频中断里调用printf会严重影响实时性。正确的做法是在中断里只置标志位在主循环里printf。第三printf的缓冲区。标准库的printf有缓冲区如果程序崩溃了缓冲区里的数据可能还没发出去。可以在printf之后调用fflush(stdout)或者用setvbuf把缓冲区设为无缓冲。8.3 版本管理与代码规范STM32项目通常文件比较多建议用Git做版本管理。CubeMX生成的代码里用户代码要写在/* USER CODE BEGIN/和/USER CODE END */之间这样重新生成代码时不会丢失。代码规范方面我建议遵循以下几点变量命名用驼峰或者下划线保持统一每个函数前面写注释说明功能、参数、返回值中断服务函数尽量短复杂逻辑放到主循环宏定义用大写枚举用驼峰头文件加#ifndef保护这些规范看起来琐碎但在团队协作和后期维护时能省大量时间。9. 我个人在实际项目中的几点体会做了这么多年STM32项目最大的体会是不要怕底层。很多人习惯用HAL库觉得调用HAL_Init()、HAL_GPIO_Init()就行了但一旦出问题就抓瞎。我的建议是至少把GPIO、时钟、中断、串口这几个外设的寄存器操作搞明白知道HAL库底层做了什么。这样调试的时候才能有的放矢。另一个体会是数据手册和参考手册要常翻。STM32的参考手册有上千页但真正用到的可能就那几十页。遇到问题的时候先翻手册确认寄存器的定义和时序要求比在网上搜答案靠谱得多。最后分享一个小技巧如果你用ST-Link调试的时候经常遇到连接问题可以在SWDIO和SWCLK上各串一个100欧姆的电阻能有效抑制信号反射提高连接稳定性。这个技巧是我从一个老工程师那里学来的实测下来确实管用。
返回列表