STM32F103开发入门指南:从点灯到RTOS的完整学习路径

发布时间:2026/9/29 1:22:44
STM32F103开发入门指南:从点灯到RTOS的完整学习路径 1. 拿到板子先别急着点灯搞清楚你手里这块F103到底能干什么STM32F103这块板子在嵌入式圈子里基本等同于“51单片机之后的第二堂必修课”。你搜“stm32开发板”能出来一大堆型号但F103系列之所以被无数教程选为入门首选核心原因就三个资料多到溢出、价格低到离谱、外设全到够用。我手上这块是常见的F103ZET6或者C8T6核心板前者引脚多适合折腾大项目后者小巧便宜适合快速验证。不管哪种你拿到手第一件事不是插电脑而是先看清楚板子上印的型号——STM32F103后面跟的字母数字决定了Flash大小、引脚数量和封装形式比如C8T6就是48脚、64KB Flash、20KB RAMZET6则是144脚、512KB Flash、64KB RAM。这个信息直接决定了你后面能跑多大的程序、能接多少外设。很多人买板子的时候顺手加购了ST-Link下载器这个决策是对的。F103支持SWD和JTAG两种调试接口但SWD只需要两根线SWCLK和SWDIO就能下载和调试比JTAG省引脚。你拿到板子后先找找板载的调试接口排针通常标着SWD或者JTAG旁边有3.3V、GND、SWCLK、SWDIO这几个关键引脚。如果板子自带USB转串口芯片比如CH340或者CP2102那串口通信这块就省事了直接一根USB线连电脑就能看到串口输出。供电方面F103的工作电压是2.0V到3.6V典型值3.3V。大部分开发板通过USB的5V供电板上LDO稳压到3.3V给芯片用。你需要注意板子上有没有5V和3.3V的电源指示灯上电后这两个灯亮不亮直接判断供电是否正常。我见过有人拿到板子发现灯不亮折腾半天以为是芯片坏了结果只是USB线是纯充电线没有数据功能换根线就好了。所以第一步确认USB线能传数据确认电源灯亮确认电脑设备管理器里能识别到ST-Link或者串口芯片。提示F103的IO口最大输出电流是25mA单个IO驱动LED没问题但驱动继电器、电机这类大电流负载必须加三极管或者驱动芯片直接接上去轻则IO口烧毁重则整块板子报废。2. 开发环境搭建Keil、CubeMX和VS Code三条路怎么选2.1 Keil MDK最传统但也最稳的路子Keil MDK是STM32开发的老牌工具链国内教程90%以上都是基于Keil写的。你下载安装Keil MDK之后第一件事是装STM32F1的芯片包Device Family Pack这个包包含了启动文件、外设寄存器定义和标准外设库。安装包的时候注意版本匹配Keil 5.38以上对F1系列支持很完善但如果你同时要兼容C51单片机开发那就需要装Keil C51和MDK两个版本它们可以共存但安装顺序有讲究——先装C51再装MDK否则注册表会冲突。新建工程的时候Keil会问你选什么芯片直接搜STM32F103选你板子上对应的具体型号。然后勾选Run-Time Environment里的CMSIS和Device Startup这两个是必须的。如果你用标准库开发还需要手动把STM32F10x_StdPeriph_Driver文件夹复制到工程目录并添加头文件路径。这个过程看起来繁琐但做一遍之后你就理解了STM32工程的目录结构启动文件负责初始化堆栈和中断向量表系统文件负责配置时钟外设驱动文件负责操作具体外设。编译成功但烧录不进去这是新手遇到最多的问题。你搜“vs code里编译成功却怎么也烧录不进开发板”能出来一堆帖子核心原因通常就几个调试器配置选错了选了J-Link但实际用的是ST-Link、SWD引脚被程序禁用了、芯片被读保护了。第一个问题在Keil的Options for Target - Debug里改第二个问题需要按住复位键再点下载然后松开第三个问题需要用ST-Link Utility解除读保护。2.2 STM32CubeMX图形化配置的捷径CubeMX是ST官方出的图形化配置工具你选好芯片型号后它用图形界面让你点选每个引脚的功能比如PA9和PA10点成USART1的TX和RXPB0点成GPIO_Output然后一键生成初始化代码。这个工具最大的价值是把时钟树配置可视化了——F103的时钟源可以选内部HSI8MHz或者外部HSE通常8MHz晶振经过PLL倍频后得到72MHz的系统时钟。你只需要在时钟树界面里把HSE选上PLL倍频因子设成9系统时钟就自动算出来了。如果手动写代码配置时钟RCC寄存器那一堆位操作能把你绕晕。CubeMX生成的代码基于HAL库HAL库的抽象层次比标准库高函数名长但语义清晰比如HAL_GPIO_WritePin(GPIOA, GPIO_PIN_5, GPIO_PIN_SET)一眼就能看懂是让PA5输出高电平。HAL库的缺点是代码体积大、执行效率略低但对于F103这种资源有限的芯片只要你不跑复杂算法HAL库完全够用。我个人的习惯是快速验证用CubeMXHAL对性能有要求的关键部分用标准库或者直接操作寄存器。2.3 VS Code 开源工具链折腾但自由如果你习惯VS Code的编辑体验可以装STM32的VS Code插件配合arm-none-eabi-gcc编译器和OpenOCD调试器。这条路的好处是免费、跨平台、编辑器强大坏处是配置繁琐新手容易在链接脚本和启动文件上卡住。你搜“stm32 vscode配置”能找到很多教程核心步骤是安装Cortex-Debug插件、配置launch.json指定OpenOCD路径和芯片配置文件、配置tasks.json调用make编译。一旦配好开发体验比Keil舒服很多代码补全、跳转、Git集成都是Keil比不了的。提示不管你选哪条路建议先把一条路走通再折腾另一条。我见过有人Keil还没跑通就去搞VS Code结果两边都卡住最后连点灯都没做成。3. 从点灯到串口第一个工程该包含哪些必备模块3.1 GPIO输出点灯背后的寄存器逻辑点灯是嵌入式开发的“Hello World”但很多人点完灯就过去了没搞明白背后发生了什么。F103的GPIO有8种工作模式输入浮空、输入上拉、输入下拉、模拟输入、开漏输出、推挽输出、开漏复用、推挽复用。点灯用的是推挽输出模式推挽的意思是输出高电平时P-MOS管导通输出低电平时N-MOS管导通两个管子轮流工作所以叫推挽。开漏输出则是只有N-MOS管工作输出高电平时需要外部上拉电阻这种模式适合I2C这种需要线与的总线。配置GPIO的步骤在标准库里是使能GPIO时钟RCC_APB2PeriphClockCmd、定义GPIO_InitStructure结构体、设置Pin、Mode、Speed、调用GPIO_Init。在HAL库里更简单HAL_GPIO_Init一个函数搞定。但你要知道不管哪种库最终都是在写GPIOx_CRL和GPIOx_CRH这两个寄存器。CRL控制低8位引脚CRH控制高8位引脚每个引脚占4个bit这4个bit里低2位是MODE输入还是输出、输出速度高2位是CNF具体模式。你手动算一下PA5的配置值就能理解为什么库函数要那么写了。点灯代码写完后编译下载如果灯不亮排查顺序是先量PA5引脚电压有没有变化用万用表或者示波器如果有变化但灯不亮说明LED接法有问题共阳还是共阴如果电压没变化检查时钟使能了没有、GPIO模式对不对、程序有没有卡在启动文件的死循环里。3.2 串口通信调试信息输出的命脉串口是嵌入式开发中最重要的调试手段没有之一。F103通常用USART1引脚是PA9TX和PA10RX。配置串口的步骤使能USART1和GPIOA时钟、配置PA9为复用推挽输出、PA10为浮空输入或上拉输入、设置波特率常用115200、数据位8、停止位1、无校验、使能USART和接收中断。串口发送数据用USART_SendData或者HAL_UART_Transmit接收数据用中断或者DMA。新手建议先用中断接收在中断服务函数里把收到的字节存到缓冲区主循环里处理。注意中断服务函数的名字必须和启动文件里的向量表一致F103的USART1_IRQHandler是固定的写错了就不会进中断。你搜“stm32 usb虚拟串口发送数据”会发现USB虚拟串口是另一个话题F103的USB外设可以模拟成CDC设备电脑上会多出一个虚拟COM口。这个功能在F103C8T6这种没有自带USB转串口芯片的板子上特别有用一根USB线既能供电又能通信。但USB协议栈比较复杂新手建议先把硬件串口玩明白再折腾USB。3.3 定时器从延时到PWMF103有多个定时器TIM1和TIM8是高级定时器TIM2到TIM5是通用定时器TIM6和TIM7是基本定时器。定时器最基础的用法是定时中断比如配置TIM2每1ms进一次中断在中断里对一个变量累加主循环里判断变量达到1000就执行1秒的任务。这种用法比delay函数靠谱因为delay是死等CPU什么都干不了而定时器中断是异步的主循环可以继续处理其他事情。你搜“stm32延时函数delay卡死”通常是因为delay函数里用了while循环等待如果中断优先级配置不当或者看门狗没喂就会卡死。用定时器中断做延时就不会有这个问题。PWM输出是定时器的另一个核心用法配置TIM3的通道1PA6输出PWM需要设置预分频器PSC和自动重装载值ARR。PWM频率 72MHz / ((PSC1) * (ARR1))占空比 CCR / (ARR1)。比如你要输出1kHz、占空比50%的PWM可以设PSC71ARR999CCR500。这个计算过程你手动算一遍就理解了定时器的工作原理。3.4 中断系统NVIC的优先级分组F103的中断优先级用4个bit表示分为抢占优先级和响应优先级。NVIC_PriorityGroupConfig函数用来设置分组比如NVIC_PriorityGroup_2表示2位抢占优先级、2位响应优先级。抢占优先级高的可以打断抢占优先级低的中断响应优先级只在同时发生时决定谁先执行。新手常见错误是把所有中断都设成最高优先级结果中断嵌套混乱程序跑飞。提示串口接收中断和定时器中断同时使用时建议串口接收中断抢占优先级设高一点避免数据丢失。但也不要设成最高留一点余地给系统滴答定时器。4. 进阶外设实战超声波、USB、Modbus和RTOS怎么上手4.1 超声波测距定时器输入捕获的经典应用你搜“stm32超声波测距”能找到大量基于HC-SR04的教程。HC-SR04有四个引脚VCC、GND、Trig、Echo。工作原理是Trig给一个10us的高电平脉冲模块发出8个40kHz的超声波Echo引脚会输出一个高电平高电平持续时间就是超声波往返的时间。距离 (高电平时间 * 340m/s) / 2。测量高电平时间用定时器的输入捕获模式最合适。配置TIM2的通道1为输入捕获上升沿触发在中断里记录第一个捕获值然后改成下降沿触发记录第二个捕获值两个值之差就是高电平时间。注意定时器的计数频率和溢出处理如果距离太远导致定时器溢出需要额外处理溢出次数。实际调试时超声波模块对电源噪声比较敏感建议在VCC和GND之间加一个0.1uF的退耦电容。另外测量周期不要小于60ms否则上一次的回波还没消失下一次的触发就来了会导致测量错误。4.2 USB设备开发从虚拟串口到自定义HIDF103的USB外设是USB 2.0全速设备支持CDC虚拟串口、HID人机接口设备、MSC大容量存储等设备类。你搜“stm32 如何做usb设备”最常看到的就是CDC虚拟串口。实现步骤是用CubeMX使能USB Device选择CDC类生成代码后在main函数里调用CDC_Transmit_FS发送数据在CDC_Receive_FS回调里处理接收数据。USB开发的坑在于时钟配置F103的USB外设要求系统时钟是48MHz或者72MHz但USB模块本身需要48MHz时钟。如果系统时钟是72MHzUSB预分频器要设置成1.5分频这个在CubeMX的时钟树里会自动算好。如果时钟不对电脑会识别不到USB设备或者识别到了但通信不稳定。自定义HID设备比CDC更灵活你可以定义自己的报告描述符实现自定义的通信协议。但HID的报告描述符格式比较晦涩建议先用现成的模板改不要从零写。4.3 Modbus通信工业场景的必修课你搜“agile_modbus stm32”会发现这是一个轻量级的Modbus协议栈适合在F103这种资源有限的芯片上跑。Modbus RTU模式通过串口传输帧格式是地址功能码数据CRC校验。F103作为从站时需要响应主站的读写请求作为主站时需要轮询多个从站。实现Modbus的关键是串口接收要用空闲中断或者定时器超时来判断一帧数据结束因为Modbus RTU没有起始和结束标志靠的是3.5个字符时间的静默间隔。F103的串口支持空闲中断IDLE在中断里判断接收缓冲区是否有数据有就说明一帧结束了。CRC校验的计算可以用查表法或者直接计算法查表法速度快但占Flash空间直接计算法省空间但耗时。F103的Flash够大建议用查表法。4.4 RTOSFreeRTOS在F103上的移植F103的RAM只有20KB到64KB跑FreeRTOS完全够用。移植步骤是把FreeRTOS源码添加到工程、配置FreeRTOSConfig.h、实现SysTick和PendSV中断服务函数、创建任务并启动调度器。注意FreeRTOS的SysTick中断优先级要设成最低因为任务切换是在SysTick中断里触发的如果SysTick优先级太高会打断其他中断导致系统不稳定。任务间通信用队列、信号量或者事件组。队列适合传递数据信号量适合同步事件组适合多条件等待。新手建议先用队列实现串口数据的接收和处理分离一个任务负责收数据另一个任务负责解析数据。提示FreeRTOS的堆空间在FreeRTOSConfig.h里配置F103C8T6只有20KB RAM堆空间建议不要超过8KB否则容易栈溢出。栈溢出是RTOS开发中最隐蔽的bug建议开启configCHECK_FOR_STACK_OVERFLOW。5. 常见问题速查与避坑经验5.1 下载与调试问题问题现象可能原因解决方法Keil编译成功但烧录失败调试器选错Options for Target - Debug里选ST-Link Debugger烧录时提示“No target connected”SWD引脚被禁用按住复位键点下载松开复位键烧录后程序不运行启动文件选错确认启动文件是startup_stm32f10x_hd.s还是md.sST-Link Utility连不上芯片芯片读保护用ST-Link Utility解除读保护串口无输出波特率不对检查代码和串口助手的波特率是否一致5.2 程序运行问题程序跑飞最常见的原因是数组越界和指针错误。F103没有MMU越界写会直接覆盖其他变量或者栈空间导致不可预测的行为。建议在开发阶段开启断言和栈检查Keil的Options for Target - Linker里可以勾选“Enable Stack Usage Analysis”。中断优先级配置错误是另一个高频问题。如果两个中断的抢占优先级相同它们不会互相打断但会按照响应优先级顺序执行。如果响应优先级也相同就按照中断向量表的顺序执行。新手建议先用NVIC_PriorityGroup_2把关键中断的抢占优先级设高其他设低。5.3 硬件设计注意事项F103的BOOT0和BOOT1引脚决定了启动模式。BOOT00时从Flash启动BOOT01时从系统存储器启动用于串口下载。如果你用ST-Link下载BOOT0接地就行。如果用串口下载需要把BOOT0接高电平下载完再接回低电平。晶振电路方面F103的外部高速晶振HSE通常用8MHz负载电容一般选20pF。如果晶振不起振先检查焊接有没有虚焊再检查负载电容是否匹配。有些便宜的开发板为了省成本用内部RC振荡器HSI精度不如外部晶振跑串口通信时容易出误码。提示F103的VDDA和VSSA是模拟部分的电源引脚即使你不用ADC也建议把VDDA接到3.3VVSSA接地否则芯片可能工作不稳定。5.4 代码优化与性能调优F103的主频是72MHz对于大部分控制任务够用但如果你要做FFT或者复杂滤波就需要优化代码。优化手段包括把频繁调用的函数用inline修饰、把常量数组放到Flash里用const修饰、开启编译器的-O2优化等级。但要注意-O2优化可能会导致调试时变量值不对开发阶段建议用-O0发布时再开优化。DMA是提升性能的利器串口收发、ADC采样、SPI通信都可以用DMA。配置DMA的步骤是使能DMA时钟、配置DMA通道、设置外设地址和内存地址、设置传输方向和数据长度、使能DMA。DMA传输完成会触发中断在中断里处理数据即可。6. 从入门到项目学习路径和资源推荐6.1 分阶段学习路线第一阶段1-2周点灯、按键输入、串口打印。目标是熟悉GPIO、中断、串口的基本操作能独立写一个按键控制LED的程序。第二阶段2-4周定时器、PWM、ADC、I2C、SPI。目标是能驱动常见外设比如用I2C读EEPROM、用SPI驱动OLED屏幕、用ADC采集电压。第三阶段1-2个月USB、Modbus、RTOS、文件系统。目标是能做一个完整的项目比如数据采集器、电机控制器、智能家居节点。第四阶段持续看数据手册和参考手册理解寄存器的每一位是什么意思。这个阶段是从“会用”到“精通”的关键。6.2 调试工具推荐ST-Link Utility是ST官方出的下载和调试工具可以查看芯片的Flash和RAM内容也可以解除读保护。逻辑分析仪是调试通信协议的神器几十块钱的USB逻辑分析仪配合开源软件就能抓I2C、SPI、串口的波形。示波器看PWM和超声波波形很直观但价格较贵新手可以先不买。6.3 项目实战建议你搜“基于stm32的毕业设计”能看到很多题目但建议不要一上来就做太复杂的项目。先从“STM32温湿度采集OLED显示”这种小项目开始把传感器驱动、显示驱动、数据处理都跑通再逐步增加功能。每增加一个功能就多一个调试环节项目复杂度是指数级增长的。我个人在实际操作中的体会是STM32的学习曲线在前期比较陡因为要同时理解硬件电路、寄存器、库函数、开发环境四层东西。但一旦你把点灯和串口这两个基础打牢后面的外设都是类似的套路——使能时钟、配置引脚、配置外设参数、使能外设、处理中断。这个套路你重复十遍就形成肌肉记忆了。最后再分享一个小技巧每次新建工程的时候把标准库或者HAL库的文件夹复制一份到工程目录下不要用绝对路径引用。这样工程拷贝到其他电脑上也能直接编译不会出现“找不到头文件”的错误。这个习惯能帮你省下大量排查环境问题的时间。