ARTICLE DETAIL

资讯详情

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

STM32F103开发板入门指南:从环境搭建到第一个程序

STM32F103开发板入门指南:从环境搭建到第一个程序 STM32F103的开发板到手了接下来该干什么板子刚拆封那会儿我盯着那块蓝色PCB看了半天——STM32F103C8T672MHz主频64KB Flash20KB SRAM板载了ST-Link和USB接口还引出了所有GPIO。说实话这玩意儿比当年我用的51单片机强太多了但随之而来的问题是从哪儿下手网上教程铺天盖地有讲寄存器的有讲标准库的有讲HAL的还有直接上RTOS的看多了反而不知道该听谁的。这篇文章就是写给刚拿到STM32F103开发板、想系统入门但不想被各种教程绕晕的人。我会从板子到手后的第一件事开始把环境搭建、工程创建、第一个程序烧录、常见问题排查这条完整链路讲清楚中间穿插我自己踩过的坑和总结出来的经验。不管你是电子专业的学生还是转行做嵌入式的开发者跟着这条路径走至少能少走两三个月的弯路。1. 拿到板子先别急着写代码这几件事决定了后面顺不顺1.1 确认板子型号和核心芯片的具体参数STM32F103这个系列下面有非常多型号C8T6、RCT6、ZET6、VET6等等封装不同、引脚数不同、Flash和RAM大小也不同。我手里这块是C8T6LQFP48封装64KB Flash、20KB SRAM属于入门级里最经典的配置。为什么要先确认这个因为后面你选芯片包、配工程、写链接脚本的时候都要跟具体型号对应。比如你拿的是RCT6256KB Flash、48KB SRAM却按C8T6的配置去建工程编译可能没问题但烧录后跑起来会出各种莫名其妙的问题。板子上一般会印型号如果没有看主控芯片表面的丝印。另外注意板子的晶振频率——大部分F103板子用的是8MHz外部晶振经过PLL倍频到72MHz作为系统时钟。也有少数板子用12MHz晶振这个在配置时钟树的时候要特别留意配错了串口波特率会全乱。1.2 检查板载的调试器和供电方式现在市面上很多F103开发板都板载了ST-Link或者DAP-Link调试器直接用一根USB线就能完成供电、下载、调试三件事。但有些便宜的板子只留了SWD排针需要你外接调试器。拿到板子后先确认这一点因为它决定了你后面用什么方式烧录程序。如果板载了调试器插上USB后设备管理器里应该能看到对应的调试器设备。如果没看到可能需要装驱动。ST-Link的驱动在ST官网可以下载DAP-Link的话Win10以上一般免驱。这里有个细节有些板子的USB接口只负责供电调试接口是另外一个Type-C或者Micro-USB口别插错了。注意插上USB后如果板子上的电源灯不亮先换一根USB线试试。很多便宜的USB线只有充电功能没有数据线芯这个坑我见过太多次了。1.3 准备好必要的软件工具链STM32开发常用的IDE有Keil MDK、IAR EWARM、STM32CubeIDE这几种。Keil在国内用得最多资料也最全但需要单独安装芯片包Pack。STM32CubeIDE是ST官方推出的免费IDE基于Eclipse集成了CubeMX配置工具适合不想折腾License的开发者。VS Code加PlatformIO或者EIDE插件也是一条路适合习惯轻量级编辑器的朋友。我的建议是入门阶段用Keil MDK或者STM32CubeIDE先把流程跑通别一上来就折腾VS Code的各种插件配置。等你对编译、链接、烧录这些环节有了直观感受之后再换工具也不迟。芯片包的安装后面会详细讲这里先有个概念就行。2. 开发环境搭建从零到编译通过的完整路径2.1 Keil MDK的安装与芯片包配置Keil MDK的安装本身没什么难度一路Next就行。关键是装完之后要安装STM32F1系列的Device Family Pack。这个包不在Keil安装包里需要单独下载。打开Keil后点击Pack Installer图标在左侧找到STMicroelectronics展开后找到STM32F1 Series点击对应的Pack进行安装。如果网络环境不好导致在线安装失败也可以去Keil官网手动下载Pack文件然后双击安装。Pack文件的后缀是.pack安装路径一般会自动识别Keil的安装目录。装完之后新建工程时才能在芯片列表里找到STM32F103C8这类型号。这里有个常见问题有些人装完Pack后新建工程还是找不到芯片原因通常是Pack版本和Keil版本不匹配。比如Keil MDK 5.36配STM32F1的Pack 2.3.0一般没问题但如果Keil版本太老比如5.14可能需要用旧版的Pack。遇到这种情况要么升级Keil要么降级Pack没有别的办法。2.2 使用STM32CubeMX生成初始化代码STM32CubeMX是ST官方出的图形化配置工具可以帮你生成引脚配置、时钟树、外设初始化的代码。对于新手来说它能大幅降低入门门槛因为你不需要一上来就对着参考手册写寄存器。具体流程是这样的新建工程选择芯片型号STM32F103C8Tx然后配置时钟源。在RCC里把HSE设为Crystal/Ceramic Resonator然后在Clock Configuration里把HCLK拉到72MHz。接着配置调试接口在SYS里把Debug设为Serial Wire这样SWD接口才能正常工作。最后配置你要用的外设比如GPIO、USART、TIM等。生成代码的时候注意选对工具链。如果你用Keil就选MDK-ARM如果用STM32CubeIDE就选STM32CubeIDE。生成的代码会包含main.c、stm32f1xx_hal_msp.c、stm32f1xx_it.c等文件以及HAL库的驱动文件。提示CubeMX生成的代码里用户代码要写在/* USER CODE BEGIN/和/USER CODE END */之间否则下次重新生成代码时会被覆盖掉。这个规则一定要记住我见过太多人因为把代码写错位置重新生成后全部丢失的。2.3 标准库工程模板的手动搭建虽然HAL库现在是主流但很多老教程和项目还在用标准库Standard Peripheral Library。标准库的好处是代码量小、执行效率高、贴近寄存器操作适合想深入理解底层的人。但ST已经不再维护标准库了新建工程需要手动拷贝库文件。手动搭建标准库工程的步骤大致是新建工程目录在里面创建Startup、Library、User、Output等文件夹。把启动文件startup_stm32f10x_md.s、系统文件system_stm32f10x.c、内核文件core_cm3.c/h以及STM32F10x_StdPeriph_Driver里的外设驱动文件拷贝到对应目录。然后在Keil里新建工程添加这些文件配置头文件包含路径最后在Options for Target里设置好Output和Listing路径。这个过程比较繁琐但做一遍之后你对STM32工程的组成结构会有非常清晰的认识。网上有很多现成的标准库工程模板可以下载但建议至少自己手动搭一次知道每个文件是干什么用的。3. 第一个程序从点亮LED到串口输出3.1 GPIO输出实验点亮板载LED点亮LED是嵌入式开发的Hello World。F103的GPIO配置流程是使能GPIO时钟、配置GPIO模式、设置输出电平。用HAL库的话代码大概长这样// 使能GPIOC时钟 __HAL_RCC_GPIOC_CLK_ENABLE(); // 配置PC13为推挽输出 GPIO_InitTypeDef GPIO_InitStruct {0}; GPIO_InitStruct.Pin GPIO_PIN_13; GPIO_InitStruct.Mode GPIO_MODE_OUTPUT_PP; GPIO_InitStruct.Pull GPIO_NOPULL; GPIO_InitStruct.Speed GPIO_SPEED_FREQ_LOW; HAL_GPIO_Init(GPIOC, GPIO_InitStruct); // 在主循环里翻转电平 while (1) { HAL_GPIO_TogglePin(GPIOC, GPIO_PIN_13); HAL_Delay(500); }这里有个细节很多F103最小系统板的板载LED接在PC13上而且是低电平点亮。也就是说你写HAL_GPIO_WritePin(GPIOC, GPIO_PIN_13, GPIO_PIN_RESET)的时候LED是亮的写SET的时候是灭的。这个跟硬件电路有关拿到板子后最好用万用表测一下LED的正负极方向或者直接看原理图。3.2 串口通信实验printf重定向串口是调试过程中最重要的工具之一。F103一般用USART1引脚是PA9TX和PA10RX。配置好波特率常用115200、数据位、停止位、校验位之后就可以收发数据了。为了能用printf输出调试信息需要重定向fputc函数int fputc(int ch, FILE *f) { HAL_UART_Transmit(huart1, (uint8_t *)ch, 1, HAL_MAX_DELAY); return ch; }然后在Keil的Options for Target里勾选Use MicroLIB否则printf可能无法正常工作。这个坑非常经典很多人写了重定向代码但串口没输出就是因为没勾MicroLIB。串口调试助手可以用SSCOM、XCOM或者PuTTY。注意波特率、数据位、停止位、校验位要和代码里配置的一致否则收到的全是乱码。3.3 定时器实验精准延时与PWM输出HAL_Delay()函数用的是SysTick定时器精度一般而且在中断里调用会有问题。如果需要更精准的延时或者PWM输出就要用通用定时器TIM2~TIM5。配置定时器的时候要算好预分频系数PSC和自动重装载值ARR。比如系统时钟72MHz想要1ms的定时周期可以设PSC71ARR999这样定时器时钟就是72MHz/(711)1MHz计数1000次就是1ms。PWM输出的配置稍微复杂一点需要设置PWM模式、占空比、极性等。用CubeMX配置的话选好定时器和通道设置好PSC和ARR然后在代码里用__HAL_TIM_SET_COMPARE()宏来动态调整占空比。4. 烧录与调试程序怎么进到芯片里4.1 ST-Link烧录的接线与配置SWD接口需要四根线VCC、GND、SWDIO、SWCLK。有些板子还引出了SWO和NRST但最基本的四根线就能完成烧录和调试。接线的时候注意VCC的电压F103是3.3V供电别接5V。在Keil里配置ST-Link调试器Options for Target - Debug - 选择ST-Link Debugger - Settings - 确认Port是SW能识别到芯片ID。然后在Flash Download选项卡里确认编程算法是STM32F10x Medium-density Flash对应64KB/128KB的型号。如果识别不到芯片先检查接线再检查板子是否上电最后检查SWD引脚是否被程序禁用了。有些程序会把SWD引脚配置成普通GPIO导致下次无法烧录。遇到这种情况需要把BOOT0拉高让芯片从系统存储器启动然后重新烧录。4.2 常见烧录失败原因排查烧录失败是新手最常遇到的问题原因五花八门。我整理了一个排查表现象可能原因解决办法找不到芯片接线错误或板子没供电检查SWD四根线确认电源灯亮找不到芯片SWD引脚被禁用BOOT0拉高重新上电后再烧录烧录报错Flash Download failed编程算法选错确认芯片型号对应的Flash算法烧录成功但不运行复位电路问题检查NRST引脚尝试手动复位烧录成功但不运行时钟配置错误检查HSE晶振是否起振还有一个经典问题VS Code里编译成功但怎么也烧录不进开发板。这种情况通常是烧录工具配置不对或者OpenOCD的配置文件跟芯片不匹配。建议先用Keil或者STM32CubeProgrammer确认能正常烧录再回头调VS Code的配置。4.3 使用STM32CubeProgrammer进行独立烧录STM32CubeProgrammer是ST官方的烧录工具支持ST-Link、UART、USB、OTA等多种方式。它的好处是不依赖IDE可以单独用来烧录hex或者bin文件。批量生产的时候特别有用。用ST-Link连接后选择对应的端口加载hex文件点击Download就行。如果要烧录bin文件需要手动指定起始地址一般是0x08000000。烧录完成后可以点击Verify校验确保数据写入正确。5. 入门之后往哪走几个值得深入的方向5.1 中断系统与NVIC配置STM32的中断系统比51复杂得多有优先级分组、抢占优先级、响应优先级等概念。F103的NVIC支持16个优先级通过NVIC_PriorityGroupConfig()来设置分组。分组决定了抢占优先级和响应优先级各占几位。举个例子如果你设置分组为NVIC_PriorityGroup_2那么抢占优先级和响应优先级各占2位取值范围都是0~3。抢占优先级高的可以打断抢占优先级低的中断相同抢占优先级下响应优先级高的先执行但不能打断。外部中断EXTI的配置流程是使能GPIO和AFIO时钟、配置GPIO为输入模式、配置EXTI触发方式、配置NVIC、编写中断服务函数。按键中断是最典型的应用场景。5.2 定时器输入捕获与超声波测距超声波测距模块HC-SR04是很多STM32项目的标配。原理很简单Trig引脚发一个10us的高电平脉冲模块发出超声波Echo引脚变高收到回波后变低。Echo高电平的持续时间就是超声波往返的时间除以2再乘以声速就是距离。用定时器的输入捕获功能可以精准测量Echo引脚的高电平时间。配置TIM的某个通道为输入捕获模式上升沿触发在中断里记录CNT值然后切换为下降沿触发再次记录CNT值两次之差就是高电平时间。这里有个经验超声波测距的精度受温度影响比较大声速在0度时是331m/s每升高1度增加0.6m/s。如果要做高精度测量需要加温度补偿。另外测量周期不要太短HC-SR04建议至少60ms一次否则会有回波干扰。5.3 USB虚拟串口与设备开发F103的USB外设是Full Speed的可以做成虚拟串口CDC、HID设备、大容量存储等。用CubeMX配置USB Device的时候选择Communication Device Class生成代码后安装ST的VCP驱动电脑上就会多出一个串口。USB虚拟串口的好处是不需要额外的USB转串口芯片一根线就能搞定通信。但要注意F103的USB和CAN共用引脚不能同时使用。另外USB的时钟必须精确配置为48MHz否则枚举会失败。5.4 基于标准库和HAL库的取舍标准库和HAL库各有优劣。标准库代码精简、执行效率高、寄存器操作直观适合资源紧张或者需要精细控制的场景。HAL库抽象程度高、跨系列移植方便、配合CubeMX开发效率高但代码体积大、执行效率相对低。我的建议是入门阶段用HAL库CubeMX快速建立信心和整体认知。等你有了一定基础再回头研究标准库或者直接操作寄存器理解底层原理。实际项目中两者可以混用比如用CubeMX生成初始化代码然后关键部分用寄存器操作优化性能。6. 那些教程不会告诉你的实操经验6.1 关于延时函数卡死的问题HAL_Delay()卡死是新手经常遇到的现象。原因通常是SysTick中断优先级配置不当或者在中断服务函数里调用了HAL_Delay()。SysTick的中断优先级默认是最低的如果某个高优先级中断一直在执行SysTick中断就无法触发HAL_Delay()就会一直等待。解决办法是不要在中断里调用HAL_Delay()如果确实需要延时用简单的循环延时或者硬件定时器。另外检查一下NVIC的优先级分组确保SysTick的优先级没有被意外设得太低。6.2 关于JTAG和SWD引脚复用F103的PA13、PA14、PA15、PB3、PB4这几个引脚默认是JTAG功能。如果你想把它们当普通GPIO用需要禁用JTAG只保留SWD。用标准库的话调用GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable, ENABLE)就行。用HAL库的话在CubeMX的SYS配置里把Debug设为Serial Wire生成的代码会自动处理。这个坑很隐蔽因为引脚看起来能用但输出电平不对。我当初调一个SPI屏幕PB3和PB4死活不出信号查了半天才发现是JTAG没禁用。6.3 关于电源和复位电路的细节有些便宜的F103板子为了省成本复位电路只放了一个电容没有上拉电阻。这种板子上电后可能不复位或者复位不可靠。表现就是程序有时候跑有时候不跑或者烧录后要手动按复位键才运行。如果遇到这种情况可以在NRST引脚和VCC之间加一个10K的上拉电阻再并一个100nF的电容到地。这是ST官方推荐的标准复位电路。另外BOOT0引脚最好也加一个10K下拉电阻避免悬空导致启动模式不确定。6.4 关于芯片包安装失败的替代方案Keil的Pack Installer有时候会因为网络问题下载失败。除了手动下载Pack文件之外还有一个办法是用离线Pack。在Keil的Pack Installer里选择File - Import然后选择下载好的.pack文件。如果连官网都打不开可以去一些国内的电子论坛找网友分享的Pack文件注意核对版本号和文件完整性。STM32CubeIDE的话芯片包是集成在安装包里的一般不需要单独安装。但如果你需要更新到最新版的HAL库可以在Help - Manage Embedded Software Packages里在线更新。6.5 关于开发板挂载Ubuntu后的权限问题有些朋友喜欢在Ubuntu下用OpenOCD或者STM32CubeProgrammer烧录。插上ST-Link后可能会提示权限不足这是因为普通用户没有USB设备的访问权限。解决办法是添加udev规则sudo nano /etc/udev/rules.d/99-stlink.rules在里面写入SUBSYSTEMusb, ATTR{idVendor}0483, ATTR{idProduct}3748, MODE0666然后重新加载udev规则sudo udevadm control --reload-rules sudo udevadm trigger不同版本的ST-Link的idProduct可能不同可以用lsusb命令查看。这个配置做一次就行以后插上就能直接用。板子到手只是开始真正有意思的是后面把一个个外设调通、把一个个项目做出来的过程。F103虽然老但资料全、生态好、价格便宜作为入门第一块STM32开发板再合适不过。我到现在还会用F103做一些小项目它的性能和资源对于大多数控制类应用来说完全够用。先把GPIO、串口、定时器、中断这几个基础外设玩熟后面学RTOS、文件系统、网络协议栈都会顺很多。遇到问题别慌先查手册、再查论坛、最后动手验证嵌入式开发就是这样一步步积累起来的。
返回列表