ARTICLE DETAIL

资讯详情

深耕编程入门与网站建设的一线实战洞察。

STM32F103开发板从点灯到物联网网关的完整实战指南

STM32F103开发板从点灯到物联网网关的完整实战指南 1. 拿到STM32-103开发板之后先别急着点灯STM32-103开发板到手的那一刻很多人第一反应是插上USB线打开Keil找个点灯例程烧进去看到LED闪烁就觉得“我会了”。但如果你真想把这块板子用透从点灯到做USB设备、从串口调试到物联网网关中间隔着一条很长的路。我前后用过十几块不同品牌的STM32F103开发板从最小系统板到带以太网、CAN、RS485的工控板都折腾过踩过的坑比点亮的灯还多。这篇文章就把我这些年用STM32-103做项目的完整思路、实操细节和避坑经验一次性讲清楚适合刚拿到板子的新手也适合想从“点灯工程师”进阶到能做完整项目的朋友。STM32F103这颗芯片圈内人叫它“单片机界的AK47”——皮实、便宜、资料多、供货稳。它基于ARM Cortex-M3内核主频72MHz常见型号如STM32F103C8T6有64KB Flash和20KB SRAM足够跑FreeRTOS、LwIP协议栈甚至做一些简单的USB设备。你手上那块开发板不管是最小系统板还是带各种外设的“大板”核心都是这颗芯片。关键是你怎么把它用起来而不是让它躺在抽屉里吃灰。提示拿到开发板后第一件事不是写代码而是确认板子上的供电跳线、BOOT跳线和晶振配置。很多“板子坏了”的问题其实是跳线帽插错了。2. 开发环境搭建别在工具链上浪费三天2.1 Keil、IAR还是VSCode加GCC新手最纠结的就是用什么IDE。我的建议很直接先用Keil MDK把第一个工程跑通再考虑换VSCode。原因很简单Keil的STM32芯片包安装最省事点几下鼠标就能把启动文件、外设库、例程全部配好。你需要的只是去官网下载MDK-ARM然后安装STM32F1系列的Device Family Pack。安装完成后新建工程选择STM32F103C8勾选CMSIS Core和Device Startup再手动添加标准外设库或HAL库的源文件即可。如果你更习惯VSCode那就要做好折腾半天的心理准备。VSCode配置STM32开发环境需要装Cortex-Debug插件、配置J-Link或ST-Link的GDB Server、手写tasks.json和launch.json。好处是代码补全和界面更舒服坏处是第一次配置容易卡在“找不到芯片”“下载失败”这些环节。我实测下来VSCode加GCC加OpenOCD的组合在Linux和Windows下都能跑但新手还是先用Keil把硬件调通更稳妥。工具链上手难度代码补全调试体验适合人群Keil MDK低一般好新手、快速验证IAR EWARM中好好企业用户VSCodeGCC高极好需配置有经验开发者STM32CubeIDE低好好官方生态用户2.2 芯片包安装与第一个工程STM32芯片包安装有个坑Keil的Pack Installer有时候下载速度极慢甚至卡死。我的做法是去官网手动下载.pack文件双击安装。安装完成后在Keil里新建工程选择芯片型号时如果找不到STM32F103说明包没装好。这时候检查Pack Installer里STM32F1系列是否显示已安装。第一个工程不要急着写复杂逻辑就做三件事配置系统时钟为72MHz、初始化一个GPIO输出、在main循环里翻转电平。这三步能验证你的工具链、下载器、板子供电全部正常。系统时钟配置是重点STM32F103默认使用内部8MHz RC振荡器要跑到72MHz必须配置PLL。外部晶振一般是8MHz经过9倍频得到72MHz。如果你板子上的晶振是12MHz那倍频系数要改成6。这个细节很多例程里没写清楚导致串口波特率不对、定时器不准。// 系统时钟配置关键代码外部8MHz晶振目标72MHz RCC-CR | RCC_CR_HSEON; while(!(RCC-CR RCC_CR_HSERDY)); RCC-CFGR | RCC_CFGR_PLLSRC | RCC_CFGR_PLLMULL9; RCC-CR | RCC_CR_PLLON; while(!(RCC-CR RCC_CR_PLLRDY)); RCC-CFGR | RCC_CFGR_SW_PLL; while((RCC-CFGR RCC_CFGR_SWS) ! RCC_CFGR_SWS_PLL);注意如果你用的是STM32F103C8T6最小系统板板载晶振通常是8MHz但有些廉价板子用的是劣质晶振起振困难。如果程序卡在等待HSERDY先换一个晶振试试。2.3 下载器选择ST-Link还是J-Link开发板通常预留了SWD接口四根线VCC、GND、SWDIO、SWCLK。ST-Link便宜几十块钱配合STM32CubeProgrammer很好用。J-Link贵但速度快支持更多芯片。如果你只是玩STM32F103ST-Link完全够用。我遇到过ST-Link固件版本太老导致Keil识别不到的问题解决办法是用STM32CubeProgrammer升级ST-Link固件。还有一点有些开发板把SWD接口和JTAG接口复用如果你之前禁用了JTAG但没启用SWD下次就下载不进去了。这时候需要把BOOT0拉高进入系统存储器启动模式用串口擦除芯片。这个坑我踩过两次后来每次写代码前都确认AFIO_MAPR寄存器里SWJ_CFG位配置正确。3. 核心外设逐个攻破从GPIO到USB设备3.1 GPIO与中断最基础也最容易翻车GPIO操作看起来简单但有几个细节新手必踩。第一复用功能时钟要单独使能。比如你想用PA9和PA10做串口除了使能GPIOA时钟还要使能USART1时钟并且把PA9配置为复用推挽输出PA10配置为浮空输入或上拉输入。第二中断优先级分组。STM32F103有4位优先级可以分成5组。如果你用了FreeRTOS通常设置为NVIC_PriorityGroup_4所有位都做抢占优先级。第三按键消抖。硬件消抖用电容软件消抖用延时或定时器。我一般用10ms定时器中断扫描按键状态机消抖比delay函数靠谱得多。外部中断还有个隐藏坑AFIO时钟。使用EXTI外部中断时必须使能AFIO时钟否则中断不触发。这个在标准库函数里是RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE)HAL库是__HAL_RCC_AFIO_CLK_ENABLE()。很多人只使能了GPIO时钟结果中断死活进不去。3.2 串口通信调试和联网的命脉串口是STM32开发中最常用的外设没有之一。调试信息输出、模块通信、固件升级都靠它。STM32F103通常有3个USART和2个UART。USART1挂在APB2上最高4.5MbpsUSART2和USART3挂在APB1上最高2.25Mbps。配置串口时波特率计算要准确。以72MHz主频、115200波特率为例USARTDIV 72000000 / (16 * 115200) 39.0625整数部分39小数部分0.0625乘以16等于1所以BRR寄存器值为0x271。如果你用HAL库直接填115200就行库函数会自动算。串口接收不定长数据是常见需求。我一般用三种方式一是空闲中断加DMA效率最高二是定时器超时判断三是环形缓冲区加中断。空闲中断加DMA的方式最优雅配置DMA接收开启USART的IDLE中断一帧数据接收完成后触发中断在中断里计算接收长度并处理。这个方案我用来对接巴法云、HTTP库、GPS模块都很稳。// 串口空闲中断DMA接收配置片段 __HAL_UART_ENABLE_IT(huart1, UART_IT_IDLE); HAL_UART_Receive_DMA(huart1, rx_buffer, BUFFER_SIZE); void USART1_IRQHandler(void) { if(__HAL_UART_GET_FLAG(huart1, UART_FLAG_IDLE)) { __HAL_UART_CLEAR_IDLEFLAG(huart1); HAL_UART_DMAStop(huart1); uint16_t len BUFFER_SIZE - __HAL_DMA_GET_COUNTER(huart1.hdmarx); // 处理rx_buffer中长度为len的数据 HAL_UART_Receive_DMA(huart1, rx_buffer, BUFFER_SIZE); } }3.3 定时器PWM、输入捕获和编码器STM32F103有4个通用定时器、2个高级定时器和2个基本定时器。做电机控制、超声波测距、频率测量都离不开它。PWM输出配置时ARR和PSC的计算是关键。假设72MHz主频想要1kHz PWMPSC设为71ARR设为999则PWM频率 72000000 / (72 * 1000) 1kHz。占空比通过CCR寄存器设置CCR 500时占空比50%。输入捕获测频率是另一个高频需求。比如用HC-SR04超声波模块测距就是通过捕获回波高电平时间来计算距离。配置定时器为输入捕获模式上升沿触发记录CCR值然后切换为下降沿触发再次记录CCR值两次差值乘以计数周期就是高电平时间。距离 时间 * 340 / 2。这里要注意定时器溢出的处理如果回波时间超过定时器周期需要记录溢出次数。编码器模式用来读电机编码器脉冲配置定时器为编码器接口模式两路输入分别接编码器的A相和B相定时器自动计数。我做过两轮差速小车用TIM3和TIM4分别读左右轮编码器TIM1输出PWM控制电机配合PID算法实现速度闭环。串口调试PID参数时用VOFA或SerialPlot画波形比看数字直观得多。3.4 ADC多通道采集与切换STM32F103的ADC是12位逐次逼近型有18个通道其中16个外部通道。多通道采集有两种方式规则组扫描加DMA和注入组。规则组扫描适合按顺序采集多个通道DMA自动搬运数据不占CPU。注入组可以打断规则组适合紧急采样。我一般用规则组加DMA配置好通道顺序和采样时间启动DMA循环模式ADC连续转换数据自动更新到数组里。ADC切换通道时有个坑采样时间要匹配信号源内阻。如果信号源内阻大采样时间要加长否则采集值不准。STM32F103的采样时间可选1.5、7.5、13.5、28.5、41.5、55.5、71.5、239.5个ADC时钟周期。我测过采集电位器电压用7.5周期就够了采集NTC热敏电阻分压用55.5周期更稳。另外ADC参考电压要干净最好加LC滤波否则采集值跳动大。3.5 USB设备开发从虚拟串口到自定义HIDSTM32F103C8T6自带USB 2.0全速设备控制器可以做虚拟串口、HID键盘鼠标、自定义USB设备。做USB设备的第一步是确认你的板子USB接口的D上拉电阻。STM32F103的USB模块内部有上拉电阻但需要软件使能。如果你用HAL库在USB初始化后调用HAL_PCD_Start()即可。如果电脑识别不到设备先检查USB时钟配置USB模块需要48MHz时钟而STM32F103的主频是72MHz不能直接分频得到48MHz。解决办法是用PLL输出72MHz然后USB预分频1.5得到48MHz。这个配置在CubeMX里选USB功能后会自动生成但手动配置时容易漏掉。虚拟串口CDC是最实用的USB功能。配置好USB CDC后电脑会识别出一个串口波特率随便设实际通信速度远超物理串口。我用它来传传感器数据、做命令行交互比接USB转串口模块方便。自定义HID设备可以用来做游戏手柄、自定义控制面板免驱即插即用。做USB设备时端点缓冲区的配置要注意STM32F103的USB缓冲区只有512字节要合理分配给不同端点。提示STM32F103的USB和CAN共用SRAM如果同时用USB和CAN需要仔细规划内存。我一般不同时用这两个外设。4. 进阶实战从单模块到完整项目4.1 FreeRTOS移植与任务划分裸机跑复杂项目代码会变成一堆状态机维护困难。FreeRTOS在STM32F103上跑很轻松20KB SRAM够创建十几个任务。移植FreeRTOS需要准备三个东西FreeRTOS源码、FreeRTOSConfig.h配置文件、一个硬件定时器做系统节拍。我一般用SysTick做节拍但注意FreeRTOS会接管SysTick中断HAL库的延时函数会失效需要重写HAL_Delay()或者用vTaskDelay()替代。任务划分有个原则按功能模块划分按实时性要求定优先级。比如串口接收任务优先级高因为数据不能丢LED闪烁任务优先级低晚几毫秒无所谓。任务间通信用队列和信号量不要用全局变量裸奔。我做过一个物联网网关项目任务划分是这样的传感器采集任务中优先级、数据处理任务中优先级、网络发送任务高优先级、状态指示任务低优先级。用队列传递传感器数据用事件组触发网络发送。4.2 LwIP协议栈与物联网网关STM32F103加ENC28J60或W5500以太网模块可以跑LwIP协议栈做物联网网关。LwIP有裸机模式和FreeRTOS模式建议用FreeRTOS模式网络处理和业务逻辑分开。移植LwIP需要配置lwipopts.h根据SRAM大小调整内存池。STM32F103只有20KB SRAMLwIP的内存配置要精简MEM_SIZE设4KB左右PBUF_POOL_SIZE设4到8个。做网关的核心是协议转换。比如下位机用Modbus RTU上位机用MQTT网关就要把Modbus数据读上来转成MQTT发布出去。我用STM32F103加RS485收发器读五线四相步进电机的驱动器状态通过W5500发到巴法云手机就能远程监控。这里的关键是RS485方向控制发送时拉高DE引脚发送完拉低。如果方向切换不及时数据会丢。我一般用串口发送完成中断来切换方向比延时靠谱。4.3 CAN通信与多机互联STM32F103自带CAN控制器配合CAN收发器如TJA1050可以做CAN通信。CAN通信突然连不上是常见问题排查思路如下先看终端电阻CAN总线两端各接120欧姆电阻中间节点不接再看波特率所有节点必须一致最后看CAN收发器供电和CANH、CANL接线是否反了。我遇到过CAN通信跑几个小时就断的情况最后发现是收发器供电不稳加了个100uF电容就好了。CAN通信适合多机互联比如两轮差速小车的前后控制器通信、工业设备的分布式控制。配置CAN过滤器时要注意过滤器的编号和FIFO分配。STM32F103有14个过滤器组可以配置为掩码模式或列表模式。我一般用掩码模式只接收特定ID范围的数据减少CPU中断负担。4.4 文件系统与SD卡数据记录做数据记录仪需要文件系统。STM32F103加SD卡模块移植FatFs文件系统可以记录传感器数据到CSV文件。SD卡用SPI模式比SDIO模式简单虽然速度慢但STM32F103的SDIO和USB共用引脚如果同时用USBSD卡只能用SPI。FatFs移植需要实现disk_initialize、disk_read、disk_write等底层函数。我一般用SPI DMA方式读写SD卡速度能到几百KB每秒。数据记录要注意文件同步。FatFs有缓存如果突然断电缓存里的数据会丢。我一般每写一行数据就调用f_sync()虽然慢一点但数据安全。或者用定时器每5秒同步一次平衡速度和安全性。5. 常见问题排查与避坑经验5.1 下载与调试问题速查现象可能原因解决方法Keil找不到芯片芯片包未安装安装STM32F1 Device Family Pack下载失败SWD引脚被占用检查代码是否禁用了SWD下载失败BOOT跳线错误BOOT0拉低BOOT1任意程序不运行晶振未起振换晶振或改内部时钟串口无输出波特率不对检查系统时钟和BRR计算串口乱码晶振频率不符确认外部晶振是8M还是12MUSB识别不到48MHz时钟未配置检查USB预分频CAN通信断终端电阻缺失总线两端加120欧姆ADC值跳动参考电压不稳加滤波电容中断不触发AFIO时钟未使能使能AFIO时钟5.2 那些年我踩过的坑第一个坑STM32芯片第一脚怎么确认。STM32F103C8T6的LQFP48封装第一脚在芯片正面左下角有个小圆点标记。但有些芯片的圆点很浅看不清楚。我的办法是看芯片表面的丝印把芯片摆正丝印文字从左到右读左下角就是第一脚。如果还确认不了用万用表测VDD和VSS引脚VDD引脚组通常在第一脚附近。第二个坑GBK转UTF8。串口输出中文时Keil默认编码是GBK而串口助手可能用UTF8显示导致乱码。解决办法是在Keil里设置编码为UTF8或者串口助手切换编码。我一般统一用UTF8避免跨平台问题。第三个坑定时器捕获测频率时溢出。测低频信号时定时器周期不够长会溢出。我一般把预分频设大一点让定时器周期覆盖被测信号的最大周期。如果还溢出就在溢出中断里累加计数。第四个坑STM32禁用JTAG后无法下载。如果不小心禁用了SWD只能把BOOT0拉高用串口擦除。STM32F103的系统存储器里有Bootloader支持串口下载。用FlyMcu或STM32CubeProgrammer选择串口BOOT0拉高复位然后擦除芯片。第五个坑开发板挂载Ubuntu。有些开发板通过USB挂载到Ubuntu时权限不对需要添加udev规则。我一般把当前用户加入dialout组然后重新登录。如果是USB设备还要确认内核驱动是否加载。5.3 项目选型与扩展建议STM32F103适合做什么项目我列几个我做过且觉得合适的物联网网关加以太网模块、数据记录仪加SD卡、电机控制器加驱动模块、USB设备虚拟串口、HID、简单人机界面加ILI9341屏幕。不适合做什么视频处理、复杂GUI、高速数据采集。这些需要更高性能的芯片比如STM32F4或F7系列。如果你想把STM32F103的项目做产品化要注意芯片供货和替代。STM32F103C8T6有很多国产替代品如GD32F103、APM32F103引脚兼容但外设寄存器有差异移植时要注意。我一般用HAL库写代码换芯片时改底层驱动就行。6. 从开发板到毕业设计再到产品原型很多人买STM32开发板是为了做毕业设计。基于STM32的毕业设计题目很多比如智能鱼缸、报站程序、两轮差速小车、物联网网关。我的建议是选一个能展示完整技术栈的题目不要只做点灯和串口。比如智能鱼缸涉及温度采集ADC或DS18B20、水泵控制继电器或PWM、喂食电机步进电机、WiFi通信ESP8266、手机APP或云平台。这样一个项目能把GPIO、定时器、串口、ADC、外设通信全部串起来答辩时也有东西讲。做毕业设计时代码规范很重要。我见过很多学生的代码全部写在main.c里几千行改一个功能要翻半天。建议按模块分文件bsp_gpio.c、bsp_uart.c、app_sensor.c、app_control.c。头文件里放函数声明和宏定义源文件里放实现。这样代码清晰也方便复用。最后说一个实际体会STM32F103这颗芯片虽然老但它的生态太完善了。你遇到的几乎所有问题网上都有答案。关键是要动手做不要只看教程。我见过太多人收藏了几十个G的教程但一块板子都没跑通。买回来的开发板拆封插线写代码烧录调试这个过程才是真正学到的。点灯只是开始USB设备、物联网网关、电机控制每一个方向都够你折腾几个月。把这块板子用透你再去学其他芯片会发现底层逻辑都是相通的。
返回列表