news 2026/10/1 15:04:13

STM32F103开发板入门实战:从环境搭建到点灯串口全攻略

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
STM32F103开发板入门实战:从环境搭建到点灯串口全攻略

开发板刚到手那一刻,很多人都是既兴奋又迷茫的。STM32F103这块板子,可以说是无数嵌入式工程师的启蒙老师,从大学实验室到电子爱好者的工作台,到处都能看到它的身影。拆开包装,看着这块蓝色或绿色的板子,上面的芯片、晶振、排针、按键密密麻麻,第一反应往往是:这要从哪下手?

我当年第一次拿到STM32F103开发板也是这样,快递拆开之后摆在桌上看了半天,连芯片第一脚在哪都没搞明白。但说句实在话,STM32入门真的没有想象中那么难。只要把开发环境配好、把第一个程序烧进去点亮一颗LED,后面的事就是一通百通。这篇文章就是给刚拿到板子的你准备的,从环境搭建到工程模板,从点灯到串口,再到烧录失败、Delay卡死这些高频坑,一次性讲清楚。点不点关注随缘,但看完这篇文章能帮你少走至少两个月的弯路,这我是敢保证的。

1. 拿到STM32F103开发板,先搞清楚这几件事

1.1 STM32F103到底是个什么芯片

STM32F103是意法半导体(ST)推出的基于ARM Cortex-M3内核的32位微控制器,主频最高72MHz,片上集成Flash(从16KB到512KB不等)和SRAM(从4KB到64KB不等),外设资源极其丰富:ADC、定时器、串口(USART)、I2C、SPI、CAN、USB、DMA,几乎覆盖了入门到中阶项目能用到的所有接口。

理解这颗芯片有个很形象的生活类比:你可以把它当成一个微型电脑主机,Cortex-M3内核就是CPU,Flash就是硬盘(存放程序),SRAM就是内存(存放运行时的变量),外设引脚就是主板上的各种接口。跑程序的过程,归根结底就是CPU从Flash取指令、在SRAM里读写数据、再通过GPIO和外设驱动外部电路。

对应到STM32F103型号,后缀还有讲究。常见的有STM32F103C8T6(中容量,64KB Flash,20KB SRAM,48引脚,也就是大家说的"蓝丸")、STM32F103ZET6(大容量,512KB Flash,64KB SRAM,144引脚)。你的板子上用的哪一颗,直接看芯片表面的丝印就行。不同型号引脚数差异很大,但编程模型和寄存器结构几乎完全一致,所以学会一颗,换别的型号上手也很快。

1.2 开发板上的东西都认识吗

拿到板子别急着连线,先把板载资源摸清楚。绝大多数STM32F103开发板都包含以下几样东西:

  • 主芯片:就是刚才说的STM32F103,板子正中央那颗最大的LQFP封装芯片。
  • 晶振:通常有一颗8MHz主晶振(HSE)和一颗32.768kHz的RTC晶振(如果有)。8MHz那颗负责给系统提供时钟源,最终经PLL倍频到72MHz。
  • 电源电路:USB口或DC座供电,经AMS1117之类的LDO稳压到3.3V给芯片。
  • 按键:一般有复位键(NRST)和至少一个用户按键(通常接PA0或PC13)。
  • LED:板载LED通常接在PC13(很多核心板上是PC13)或者PB0/PB1等引脚,用来做点灯实验。
  • 下载调试接口:ST-Link/V2的4针SWD接口(SWDIO、SWCLK、GND、3.3V),或者20针JTAG座。
  • USB转串口芯片:比如CH340,用于通过USB口和电脑串口通信,配合串口调试助手打印日志。

搞清楚这些,后续接线的时候就有底了。很多新手一上来就纠结"这个排针是干嘛的",其实不用急,按实验需求一张引脚图一张引脚图去查,用得多了自然就熟了。

1.3 学习路线怎么规划

STM32的学习路线,我建议按这个顺序推进,每一步都有明确的"验收标准":

  1. 环境搭建:装好Keil MDK、STM32芯片包、驱动,能新建工程并编译通过。
  2. GPIO输出:点亮板载LED、跑马灯,理解推挽输出、复用开漏这些概念。
  3. GPIO输入与按键:读取按键状态,理解上拉/下拉电阻和软件消抖。
  4. 中断系统:外部中断(EXTI)点亮LED,理解中断优先级和NVIC。
  5. 定时器:定时中断翻转LED、定时器捕获测频率、PWM输出驱动舵机或调光。
  6. 串口USART:串口发送接收、重定向printf到串口调试助手,这几乎是所有调试的基础。
  7. 常用外设:I2C读写EEPROM/传感器、SPI驱动显示屏、ADC采集电压。
  8. 进阶:DMA、CAN通信、USB设备、FreeRTOS操作系统。

为什么要按这个顺序?因为每一步都是下一步的"地基"。GPIO不会,串口打印就无从谈起;中断不会,定时器做精准延时就是空话。别一上来就想做"鱼缸自动喂食系统"这种综合项目,先把上面每一步走扎实,综合项目是水到渠成的事。

2. 开发环境搭建:Keil、芯片包、下载器一次配齐

2.1 Keil MDK安装与C51/STM32共存问题

STM32开发最常用的IDE还是Keil MDK(也叫MDK-ARM)。如果你以前学过51单片机,电脑上可能已经装了Keil C51。这里有个高频疑问:能不能两个版本共存?答案是可以,但安装时有讲究。

老版本的Keil(比如Keil 4)装C51和MDK很容易冲突,新版Keil 5在共存方面友好很多。我的建议是这样操作:

  1. 先装Keil C51,再装MDK-ARM,装在不同目录,比如C:\Keil_v5(两者共用同一个安装目录也行,重要的是License分开激活)。
  2. MDK安装包在官网下载,或者用国内镜像。安装过程一路Next,唯一需要注意的是路径不要带中文。
  3. 装完后打开Keil,如果新建工程时能看到"STMicroelectronics"这个选项,说明MDK本体装好了;如果还能看到Atmel、NXP等厂商,说明芯片包管理正常。
  4. 许可证(License)方面,C51和MDK是两个独立的License,分别用各自的注册机或正版授权激活,激活时选对应工具链(C51或ARM)。

我见过不少新手在这步卡住:装了MDK但新建工程找不到STM32选项,十有八九是芯片包没装,而不是Keil坏了。所以下一步就是芯片包的事。

2.2 安装STM32芯片包

Keil MDK 5之后,芯片支持从IDE里剥离成了独立的Pack包。新建工程之前,必须到Pack Installer里下载对应芯片的Device Family Pack。

具体步骤:

  1. 打开Keil,点工具栏上的"Pack Installer"图标。
  2. 左侧找到STMicroelectronics,展开目录。
  3. 找到对应你芯片的Pack,比如STM32F1系列是"Keil.STM32F1xx_DFP",点击Install。
  4. 安装过程中会提示需要依赖的CMSIS核心包,一并装上即可。

如果没有网络或者Pack下载速度慢,可以到Keil官网的Pack页面手动下载.pack文件,然后双击导入。下载时注意匹配Pack版本,我用的是2.x版本的STM32F1xx_DFP,稳定性没问题。

还有一个很容易被忽略的点:芯片包不只包含芯片Flash算法和调试描述文件,还包含标准外设库(SPL)的示例工程模板。装好包之后,你可以在C:\Keil_v5\ARM\Pack\Keil\STM32F1xx_DFP\xxx\Projects\StdPeriph\Examples目录下找到大量官方示例代码,这是学STM32最好的入门参考之一。

2.3 下载器选型与接线:ST-Link还是J-Link

程序写好了得烧进板子,烧录方式有三种主流选择:

ST-Link/V2:最推荐,二三十块钱一个的兼容版就够用。支持SWD和JTAG,接线简单,Keil里选"ST-Link Debugger"就能用,稳定可靠。

J-Link:功能更强,调试体验更好,兼容性也广。如果你手头有J-Link,也可以用。J-Link和ST-Link在Keil里的配置入口不同,连接线序也不同,别混着插。另外要注意,现在有些J-Link是盗版克隆的,固件版本太老会被Keil识别后拒绝使用,遇到这种情况要么换ST-Link,要么刷固件。

串口ISP烧录:不需要仿真器,利用芯片内置的Bootloader,通过串口把程序烧进去。这种方式需要把BOOT0引脚拉高,然后用FlyMcu之类的工具下载,比较麻烦,不推荐日常使用。

接线原则很简单:SWD接口只需要四根线,SWDIO、SWCLK、GND、3.3V(供电)。注意SWDIO和SWCLK不要接反,GND一定要共地。很多烧录失败的问题就出在杜邦线接触不良上,这四根线务必插牢。

2.4 芯片第一脚怎么确认

这是个很基础但坑过无数新手的问题。LQFP封装的芯片上会有一个圆形或三角形的凹点标记,这个点旁边的那一脚就是第一脚(Pin 1)。确定第一脚之后,逆时针数,依次是2、3、4……一直到最后一脚。

对应到开发板上,如果看不清芯片上的丝印,就找板子上的"1"标注。很多开发板在排针旁边会印引脚编号,比如"PA0"、"PB1"这种,结合芯片数据手册里的引脚定义表,就能准确找到任意一个引脚。

在线调试的时候有个更省力的办法:用Keil的寄存器窗口或者引脚状态窗口,把某个引脚配置成输入模式,用手触碰引脚的杜邦线,观察IDR寄存器对应位的变化,反向验证引脚对不对。但这属于进阶技巧,新手阶段老老实实对照数据手册和原理图,慢一点但不容易错。

3. 新建工程:标准库模板从零开始

3.1 标准库 vs HAL库怎么选

这是STM32新手绕不开的岔路口。先说结论:STM32F103学习阶段,我更推荐用标准外设库(SPL),理由后面详细讲;等基础打好之后再过渡到HAL库或直接寄存器操作,各有所长。

标准库就是ST官方封装好的外设驱动函数库,把寄存器操作封装成结构体和函数,比如GPIO_Init()、TIM_Cmd(),代码可读性好、执行效率高。F1系列官方虽然已经停止更新标准库,但社区资料极其丰富,网上教程、例程、毕业设计代码几乎全是标准库写的,你遇到问题搜索时,90%的答案都是标准库风格。

HAL库则是新一代的抽象层库,配合STM32CubeMX图形化配置工具使用,开发速度快,跨芯片移植方便,但代码量大、间接层多,新手常常"配置一时爽,调试火葬场",因为CubeMX生成的初始化和回调机制不容易一眼看透。

我的建议非常明确:F103入门用标准库,理由是你需要"看见"寄存器层面的行为;等工作之后需要快速开发或者上STM32F4/H7时再切HAL,那时你对底层已经有感觉,任何库都只是工具而已。

3.2 完整新建工程步骤

这里我给出一个可以照抄的标准库工程创建流程,每一步都经过验证:

  1. 在Keil里选择"Project -> New uVision Project",工程名自定,存在全英文路径下,千万不能有中文。
  2. 选择芯片型号,比如STM32F103C8,此时Keil自动加载启动文件和寄存器定义。
  3. 弹出"Manage Run-Time Environment"时,新手直接点OK跳过,因为我们要手动添加外设库文件。
  4. 手动创建工程目录结构:
    • USER:存放main.c、stm32f10x_it.c、system_stm32f10x.c
    • CORE:存放core_cm3.c、startup_stm32f10x_md.s
    • FWLib:存放标准库的src和inc(stm32f10x_gpio.c、stm32f10x_rcc.c等)
    • 或者更简单的方式:直接复制一份网上成熟的工程模板改名,这是我最推荐的入门方式。
  5. 在Keil里添加分组(Groups),分别命名为USER、CORE、FWLib,把对应文件加进去。
  6. 配置魔术棒(Options for Target):
    • Output页勾选Create HEX File
    • C/C++页的Define填STM32F10X_MD(中容量芯片)或STM32F10X_HD(大容量),Include Paths添加所有头文件路径
    • Debug页选择ST-Link Debugger或J-LINK
  7. 编译。如果看到"0 Error(s), 0 Warning(s)",恭喜,工程模板就成了。

新手最容易在Include Paths上栽跟头,明明头文件都在,编译器就是找不到。记住一个原则:Include Paths要把所有含有.h的目录全部加进去,一个都不能漏。

3.3 时钟配置和SystemInit

模板建好之后,第一个要理解的核心函数是SystemInit()。在startup文件里,Reset_Handler调用SystemInit之后才跳转到main函数。SystemInit的作用是把系统时钟从默认的HSI(8MHz内部RC)切换到HSE外部晶振,再经过PLL倍频到72MHz,也就是我们常说的"系统主频72MHz"。

如果SystemInit没跑通,最直接的后果就是所有延时和外设时序全部错乱:delay(500)原本应该闪0.5秒,结果闪得飞快。所以遇到"程序行为完全不对"的诡异问题,第一个检查项就是时钟树。

时钟配置的核心寄存器是RCC_CFGR,相关代码在system_stm32f10x.c里。有个常用的偷懒办法:直接调用库函数SystemInit(),然后把SystemCoreClock变量拿去给SysTick做延时基准。SysTick是一个24位的系统节拍定时器,专门用来做时间基准,后面写Delay函数全靠它。

再说一个新手常见的误区:以为GPIO配置好就能工作了,其实GPIO的时钟默认是关闭的,必须在配置GPIO之前打开对应端口的时钟。比如用GPIOA,就要先调用RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE)。漏了这一步,端口引脚就是死的,怎么配置都没反应。这也是"点了灯不亮"最常见的原因。

4. 核心实验实操:点灯、按键、串口、定时器

4.1 跑马灯:GPIO的推挽输出

跑马灯实验是STM32的"Hello World"。它的本质是配置GPIO为推挽输出模式,然后轮流控制多个引脚的高低电平。

以PB0和PB1两个引脚接LED为例,完整流程分三步:

void LED_GPIO_Config(void) { GPIO_InitTypeDef GPIO_InitStructure; RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE); GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOB, &GPIO_InitStructure); }

main函数里就是循环翻转电平:

while (1) { GPIO_SetBits(GPIOB, GPIO_Pin_0); GPIO_ResetBits(GPIOB, GPIO_Pin_1); Delay(500); GPIO_ResetBits(GPIOB, GPIO_Pin_0); GPIO_SetBits(GPIOB, GPIO_Pin_1); Delay(500); }

这里有几个关键点要说明:

为什么用推挽输出?推挽输出模式下,引脚能主动输出高电平和低电平,驱动能力最强。而开漏输出只能主动拉低,要高电平必须外接上拉电阻,用在I2C等需要"线与"的场景。点LED用推挽是标准做法。

GPIO_Speed为什么选50MHz?这个参数表示引脚的翻转速率上限。点LED这种低速场合,2MHz都够用。但为了后续兼容,一般都配置50MHz,输出模式下的翻转速度越快,边沿越陡,功耗和噪声也略高。如果你用GPIO模拟I2C或SPI,速率可能还要细分,这里先记结论:普通实验一律50MHz。

关于延时:F103没有统一的sleep函数,最常用的延时方式是通过SysTick定时器实现毫秒级阻塞延时。这也是热词里"stm32延时函数delay卡死"的高发点,后面专门讲。

如果想在Keil里查看GPIO输出的实际波形,不一定要接示波器。用调试器的逻辑分析仪窗口(Keil的Analysis窗口)监视ODR寄存器或者引脚变量,就能看到翻转波形。如果想看真实波形,一个几十块钱的逻辑分析仪也完全够用。

4.2 按键输入:上拉下拉与消抖

按键实验的关键不在于"读到引脚电平",而在于可靠地读到电平变化。

按键的典型接法有两种:按键一端接GND,另一端接GPIO,GPIO内部配置上拉输入;或者按键一端接3.3V,另一端接GPIO,GPIO配置下拉输入。这样按键按下时引脚电平发生明确变化,不会悬空。

STM32的GPIO配置里,上拉和下拉通过GPIO_InitStructure.Pull参数控制:

GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; // 上拉输入 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0; GPIO_Init(GPIOA, &GPIO_InitStructure);

读到按键之后,不能直接拿电平变化作为触发事件。因为机械按键在按下和释放的过程中会有抖动,一个按键动作可能在几毫秒内产生几十次电平跳变。解决办法就是软件消抖:检测到电平变化后,延时20ms左右再次读取,如果电平仍然一致,才确认按键状态变化。

if (GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_0) == 0) { Delay(20); // 消抖 if (GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_0) == 0) { // 确认按键按下,执行操作 } }

这个20ms不是瞎拍的,机械按键的抖动时间一般在5~10ms,20ms的延时可以稳定覆盖抖动窗口。如果你用示波器看按键波形,会发现不消抖直接读引脚,一次按下能跳变十几次,这就是为什么有时候感觉"按一下灯亮了好几次"。

4.3 串口打印:调试的命脉

串口(USART)是嵌入式开发最实用的调试手段。我可以说,学会串口打印printf,你的STM32调试效率立刻翻倍。

串口初始化需要配置三块:GPIO引脚复用(通常TX是PA9、RX是PA10)、USART外设模式(波特率、数据位、停止位、校验位)、中断(收发用轮询就行,接收中断必开)。

波特率的选择要注意:115200是默认最常用的,但前提是你的系统时钟准确为72MHz。如果时钟配置错乱导致USART波特率偏差,就会出现"串口收到乱码"的经典问题。所以碰见乱码第一反应:查SystemCoreClock是不是72MHz,第二反应:查波特率是不是两边一致。

把printf重定向到串口的经典代码如下:

int fputc(int ch, FILE *f) { USART_SendData(USART1, (uint8_t)ch); while (USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET); return ch; }

重定向之后,在main里就可以直接用printf打印变量、状态、调试信息。要注意的是,这个重定向依赖Keil的微库(MicroLIB),需要在魔术棒Target页勾选"Use MicroLIB"。不勾的话,链接时fputc会冲突或者不生效,printf打印不出东西。

串口接收则是另一个常见难点。轮询接收简单但会占用CPU,中断接收效率高但要注意缓冲区管理。我推荐用串口空闲中断(IDLE)+ DMA的方式做不定长数据接收,这在做报文项目时是标准方案。F103的USART1支持DMA,配置一次DMA接收环形缓冲区,之后串口收数据完全不占CPU资源。

4.4 定时器与PWM扩展

定时器是STM32外设里最"值钱"的一个,因为它太常用了。F103系列有TIM1(高级定时器)、TIM2/3/4(通用定时器)、TIM6/7(基本定时器),还有独立的SysTick。

定时器最基础的功能就是定时中断。配置流程:

  1. RCC开启定时器时钟。
  2. 设置预分频器PSC和自动重装载值ARR。
  3. 选择计数模式(向上计数、向下计数、中央对齐)。
  4. 使能更新中断,配置NVIC。
  5. 启动定时器。

延时时间的计算公式是:定时周期 = (PSC + 1) × (ARR + 1) / 72MHz。比如要1ms进一次中断,PSC设为71(72分频),ARR设为999,那么定时周期 = 72 × 1000 / 72000000 = 0.001秒 = 1ms。这个公式要牢记,后面所有定时相关的配置都围绕它展开。

定时器的PWM输出模式也很实用,驱动LED调光、舵机、直流电机都能用。PWM输出时,GPIO要配置为复用推挽输出(GPIO_Mode_AF_PP),然后用TIM_SetCompareX()调整占空比。占空比 = 比较寄存器CCR的值 / (ARR + 1)。舵机控制就是在20ms周期里,把1ms~2ms的高电平映射到0°~180°,思路很简单,配置对了就行。

还有一个热词是"stm32定时器捕获测频率",这是定时器的输入捕获功能。测量外部信号的频率时,用定时器捕获上升沿,记录两次捕获之间的计数值差,结合定时器时钟频率反推信号频率。这是数字频率计的核心原理,做超声波测距、红外遥控解码、转速测量都会用到。

5. 踩坑实录:烧录不进、Delay卡死、CAN连不上

5.1 编译成功却烧录不进去

"VSCode里编译成功,却怎么也烧录不进开发板"这类的求助帖子我见得太多了,这个问题百分之八十出在下面几个地方。

第一,下载器与目标板连接不正确。SWD接口四根线SWDIO、SWCLK、GND、3.3V,任何一根没接牢都会导致烧录失败。用杜邦线时,捏一下插头确保插到底,再用万用表通断档确认连线是否导通。很多"时好时坏"的烧录问题就是接触不良。

第二,Keil里没有正确选择下载器。魔术棒 -> Debug -> 右侧下拉框选择ST-Link Debugger或J-LINK,点Settings后能看到SW Device框里出现芯片ID,比如0xBB11477。如果SW Device是空的,说明仿真器和芯片没有建立连接,先解决连线问题。

第三,芯片被读保护(Read Protection)锁住。这个情况常见于二手板子或者之前烧录过程异常断电。现象是Keil报"Internal Flash Error"或"RDDI-DAP Error"。解决办法是在ST-Link Utility或Keil的Flash Download里选择"Erase Full Chip"或取消读保护。用J-Link的Unlock命令也可以。F103一旦开了读保护,SWD口会被禁用,必须先全片擦除才能重新烧录。

第四,烧录算法(Flash Algorithm)没选对。在Flash Download页面必须有对应芯片的烧录算法,比如STM32F10x Med-density Flash。如果缺失或选错,会报"Flash Timeout"。这时重新添加正确的Flash算法即可。

第五,芯片的BOOT引脚状态异常。如果你的板子BOOT0被拉高,芯片复位后会进入Bootloader模式而不是用户程序模式,烧录偶尔能成功但程序不运行。请确认BOOT0接低电平(启动Flash)。

还有个容易被忽略的:VSCode环境下用PlatformIO或EIDE开发STM32时,烧录命令与Keil不同,要确认配置里烧录器的类型和接口参数与硬件一致。VSCode编译成功只代表代码通过编译,烧录环节是独立配置的,经常出现"工具链没问题、烧录参数没配对"的情况。

5.2 Delay卡死的原因分析

"stm32延时函数delay卡死"也是一个高频问题。我见过的最常见原因是:Delay函数依赖SysTick,而SysTick没有被正确初始化,或者中断优先级配置让它无法执行。

经典的SysTick延迟实现是这样:

void Delay_us(uint32_t us) { uint32_t temp; SysTick->LOAD = us * 72; // 72MHz下1us计数72次 SysTick->VAL = 0x00; SysTick->CTRL = 0x01; // 使能,选择HCLK do { temp = SysTick->CTRL; } while ((temp & 0x01) && !(temp & (1 << 16))); SysTick->CTRL = 0x00; SysTick->VAL = 0x00; }

如果系统时钟不是72MHz,LOAD的值就不对,DELAY时间错乱但不至于卡死。真正的卡死往往是这样:

  • 在中断服务函数里调用Delay,而SysTick的中断优先级高于当前中断,导致嵌套异常或死循环;
  • SysTick中断没有清标志位,反复进入中断;
  • 用了HAL库的HAL_Delay,但HAL库的超时机制依赖SysTick中断,中断没开启就直接死等。

还有一类卡死是软件仿真(Simulation)下延时不对。Keil软件仿真时默认时钟周期和真实芯片不一致,延时函数在仿真环境里表现怪异,这是正常的,别慌,以实际硬件为准。

排查思路是这样的:先用最简化的循环延时(for循环空转)替代SysTick延时,如果程序能跑起来,说明问题出在SysTick配置上;如果还是卡死,那就是程序逻辑问题,比如指针越界、数组访问越界把栈搞崩了。F103的栈默认1KB,我不止一次看到新手在中断里定义大数组导致栈溢出,程序跑着跑着突然死机,就是这个原因。

5.3 JTAG/SWD被禁用怎么办

这个坑很经典。GPIO初始化的时候,如果一不小心把PB3、PB4、PA13、PA14、PA15这些引脚配置成了普通GPIO,就会禁用掉JTAG/SWD功能。PA13是SWDIO,PA14是SWCLK,PB3是JTDO,PB4是JNTRST。一旦禁用,下次烧录就找不到芯片了。

处理办法有几个,按优先级排序:

  1. 串口ISP全片擦除:最通用。把BOOT0拉高,复位上电,用FlyMcu连接USART1,执行"清除芯片"或者"擦除"。全片擦除后选项字节复位,SWD口就恢复了。
  2. 下载器强行连接:ST-Link在连接失败的情况下尝试多次,有时在复位瞬间能连上。在Keil里把Connect选项设置为"under Reset",可以增加连接成功率。
  3. 用J-Link Commander的unlock命令:J-Link支持在未连接状态下执行解锁操作,恢复被禁用的调试口。

预防措施更关键:只要你的程序没用到JTAG引脚的复用功能,GPIO初始化代码里就别碰引脚重映射和AFIO_MAPR_SWJ_CFG寄存器。如果确实要用,增加一个"调试口保持使能"的配置,并且至少留一个软件开关来恢复。

5.4 CAN通信突然连不上

再讲一个热词里出现的高频问题:STM32 CAN通信突然连不上。CAN总线在工业场景用得极多,F103的bxCAN外设也经常出现在项目里。连不上的原因通常有几类:

第一,波特率配置不一致。CAN是非归零编码总线,通信双方波特率必须一致,本质上还是PSC和BS1/BS2分频的计算问题。F103的CAN时钟来自APB1(最大36MHz),配置时必须算准时序参数。我的经验是:先用CAN分析仪或者两块板子对发测试,排除波特率问题之后再去查硬件。

第二,总线没有正确的终端电阻。CAN总线两端需要各接一个120Ω终端电阻,如果总线上只有一块开发板,没有终端电阻的波形会很差,通信时好时坏。开发板上一般默认带120Ω电阻,但如果是自己搭的收发器电路,务必确认是否需要外接线缆电阻。

第三,发送缓冲区和错误寄存器异常。当CAN控制器检测到大量错误时,会进入Bus Off状态。这时候库函数的CAN_TransmitStatus会返回发送失败,但程序没有及时处理,看起来就是"连不上"。排查时先读CAN_GetFlagStatus(CAN_FLAG_EWG/EPV/BOF),看看是不是进入了Bus Off,如果是,软件里必须做总线恢复处理。

第四,收发器芯片供电和引脚接线问题。CAN_H和CAN_L接反是很常见的事故,尤其是自己焊线的时候。TJA1050这类收发器的CANH和CANL标识看仔细,混接后设备无法通信,严重时可能损坏收发器。

我个人排查CAN问题的顺序永远是:硬件接线 -> 终端电阻 -> 波特率 -> 错误状态 -> 软件逻辑。不要一上来就怀疑库函数,CAN的坑大多在物理层。

6. 学完基础之后往哪走

6.1 超声波测距、传感器与经典小项目

当你把GPIO、定时器、串口、中断、I2C这些基础都跑通之后,就可以开始做综合项目了。我列几个非常适合F103练手、也是毕业设计和DIY圈子里出现频率最高的方向:

  • 超声波测距:HC-SR04超声波模块,Trig引脚发10us以上高电平触发,Echo引脚回高电平,高电平持续时间乘以声速再除以2就是距离。用定时器输入捕获测Echo高电平时间,这是把定时器捕获能力用起来的经典场景。
  • OLED显示:I2C接口的0.96寸OLED屏,SSD1306驱动芯片,用软件模拟I2C或者硬件I2C驱动,显示温湿度、距离、时间等信息。I2C时序的"起始条件、停止条件、应答"三要素在这个项目里体会最深。
  • DS3231/DS1302时钟模块:做时钟显示时分秒,DS1302是SPI类接口,DS3231是I2C接口且带温度补偿。配合数码管或者OLED,做一个桌面电子钟是很完整的入门项目。
  • 步进电机控制:五线四相步进电机配合ULN2003驱动板,用GPIO输出脉冲序列控制电机转动,涉及时序控制、速度曲线,对理解"脉冲-方向"控制很有帮助。
  • 伺服电机485通信:通过RS485总线控制伺服电机,涉及USART的数据帧协议设计、CRC校验、地址管理,这是工业控制场景的缩影。

做完两到三个这样的小项目,你会发现自己已经能独立读数据手册、查寄存器、改库函数了。这个能力才是STM32学习最核心的收获。

6.2 USB设备、RTOS与系统架构进阶

如果还想往深走,F103上还有几个方向非常值得投入:

USB设备开发。F103的USB外设是USB 2.0 Full Speed,可以做成HID键盘鼠标、虚拟串口(CDC)、U盘(MSC)。STM32官方有USB库,标准库版本里也有USB例程。做虚拟串口是入门USB开发比较好的起点——无需额外驱动,Windows/Mac/Linux都能识别,而且和串口调试的习惯无缝衔接。

FreeRTOS移植。F103跑FreeRTOS完全没有压力,资源占用小,内存足够。移植之后再回头看之前的裸机程序,你会理解"任务调度"和"裸机循环"的本质区别:裸机while(1)是一次只能做一件事,RTOS可以让多个任务按优先级和时间片"同时"运行。

嵌入式系统架构。学了这么久,回头再去看STM32系统架构,理解就有质的飞跃:AHB总线负责高速外设(Flash、SRAM、DMA),APB2负责高速外设(ADC、USART1、定时器),APB1负责低速外设(I2C、USART2/3、CAN)。为什么I2C的最高频率是36MHz而不是72MHz?因为APB1总线就是36MHz。这种架构认知,才是从"会调库"到"懂芯片"的分水岭。

我还想说一句:STM32只是工具,解决实际问题的能力才是核心。你做的每一个项目、踩过的每一个坑,都是在积累这种能力。鱼缸自动控制、智慧农业、宿舍门禁、贴片机控制系统,这些看起来复杂的项目,本质都是传感器采集、数据处理、执行器驱动的组合,框架你已经在基础阶段全部见过了。

写在最后

从开发板到手到独立完成一个综合项目,这个过程急不得。我见过太多人一上来就下载几十个G的视频教程,收藏了上百个帖子,结果板子落灰。真正有效的方式就是:装好环境,新建工程,点亮一颗LED,然后一个模块一个模块地学。每完成一个小目标,那种"我能控制这块板子了"的成就感,是支撑你坚持学下去最强的动力。

开发板这个东西,不怕你不会,就怕你不动手。我当初学的时候踩过的坑,比你们现在遇到的只会多不会少。烧录失败就查线,Delay不准就查时钟,I2C不通就查上拉电阻。问题的答案通常不难,难的是你有没有耐心一步步排查。把上面这些常见问题的排查思路吃透,你已经比大多数"收藏了等于会了"的新手走得远多了。

最后送一个实用小技巧:在你的工程里多写注释,尤其是每个外设配置函数前面,写上这个函数是干嘛的、参数怎么选、动了哪个寄存器。三个月之后再回头看你自己的代码,这些注释就是你最宝贵的复习资料。加油,你的STM32之路从这块开发板上电的那一刻,已经正式开始了。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/1 15:03:35

Paperclip 实战:Node.js + React 多 AI Agent 编排与 SSE 流式可视化

1. 从“paperclip”这个名字说起&#xff1a;它到底想解决什么问题第一次看到“paperclip”这个项目名&#xff0c;我脑子里蹦出来的画面特别朴素——一枚回形针。它不炫技&#xff0c;不张扬&#xff0c;就是把几页散落的纸夹在一起&#xff0c;让它们别乱飞。后来我把这个项目…

作者头像 李华
网站建设 2026/10/1 15:02:27

大数据场景下的缓存技术选型与实战解析

1. 大数据场景下的缓存需求画像 1.1 大数据链路里缓存到底解决什么问题 先聊个很多人容易忽略的事实&#xff1a;在大数据项目里&#xff0c;缓存往往不是最先被设计的模块&#xff0c;却是最后被性能问题逼出来的必需品。我见过不少团队&#xff0c;数据管道跑通了、报表能出…

作者头像 李华
网站建设 2026/10/1 15:02:15

STM32开发必懂:CubeMX、Keil、烧录与串口工具链分工详解

开篇先说实话&#xff1a;我写这篇的契机&#xff0c;是群里有个刚入坑 STM32 的朋友发了一段话&#xff0c;大意是“照着教程装完了 Keil、CubeMX、烧录软件和串口助手&#xff0c;四个软件整整齐齐躺在桌面上&#xff0c;但你要问我它们各自是干嘛的&#xff0c;我只会打开和…

作者头像 李华
网站建设 2026/10/1 15:02:00

STM32开发参考方案怎么找?国内优质资源平台与实战方法论

前些天群里又有人问“STM32做什么项目练手比较合适”&#xff0c;底下回答五花八门&#xff1a;有人直接扔出一堆网盘链接&#xff0c;有人甩了个收费专栏&#xff0c;还有人贴了国外论坛的英文原帖。说实话&#xff0c;这种“资源看着很多&#xff0c;真要用的时候一个都对不上…

作者头像 李华
网站建设 2026/10/1 15:02:00

解决大促咨询爆量难题,适合电商的智能客服系统推荐

大促期间&#xff0c;电商客服团队面临的不是“有没有系统”的问题&#xff0c;而是“系统能不能扛住”的问题。双11峰值时&#xff0c;单一平台的智能客服系统并发请求量可达3万QPS以上&#xff0c;一条消息如果超过200ms未回复&#xff0c;用户就会转向人工&#xff0c;而人工…

作者头像 李华