尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

STM32F103入门不迷路:环境搭建、GPIO点灯到串口调试全攻略

STM32F103入门不迷路:环境搭建、GPIO点灯到串口调试全攻略 STM32F103的开发板买回来了拆快递那一刻确实很兴奋但接上电脑之后大概率会愣住这玩意儿到底从哪开始如果你也是刚入手STM32想学又怕被一堆术语劝退这篇东西就是写给你的。我会从认板子讲起一路聊到环境搭建、第一个点灯程序、中断定时器串口这些躲不开的基础最后把我踩过的坑和排查思路全部摊开。不管你手里是十几块的裸板还是百来块的完整开发板跟着这条线走一遍就能把STM32从“听说过”变成“真上手”。1. 先认识手里的开发板别急着写代码1.1 F103这块芯片为什么是入门首选STM32F103是意法半导体Cortex-M3内核的32位单片机主频最高72MHzFlash从16KB到512KBRAM从4KB到64KB型号后缀不同容量也不同。大家手里最常见的STM32F103C8T6就是那种蓝色pill板子64KB Flash、20KB RAM价格便宜到像白送但功能一点都不缩水USART、I2C、SPI、CAN、USB、ADC、定时器全都有。这个配置放在十年前属于中高端放在今天依然是学习单片机底层逻辑的最佳平台。为什么入门都推F103而不是直接上H7或者G4因为F103的资料最多文档最全你想搜的任何问题基本都有前人踩过坑写了帖。而且它内部结构足够简单寄存器数量适中用来理解ARM内核的工作方式、中断系统、时钟树这些概念刚刚好。用个不太恰当的比喻F103之于嵌入式学习就像手动挡教练车之于考驾照你先把手动挡开明白以后换自动挡、新能源都是降维操作。1.2 拿到开发板先做这三个检查说实话第一次拿到板子最容易犯的错就是直接插电写程序结果驱动没装、跳线帽没插、芯片锁死一顿折腾心态直接裂开。我建议你按下面这个顺序来每一步都花不了两分钟。第一看芯片丝印。找到主控芯片上面会印着STM32F103C8T6之类的字样旁边有个小圆点或者斜切角那是1脚的位置。以C8T6为例1脚在左上角从1脚开始逆时针数贴着圆点往左边数就行。这个一定要会认后面接杜邦线、查引脚功能全靠它。第二看电源和调试接口。开发板一般会带一个USB口用来供电和串口通信还有一个SWD调试口通常是4个针脚3.3V、SWDIO、SWCLK、GND有些板子还会带复位脚。你需要确认板子上有没有焊接排针如果没焊的话先用电烙铁把排针焊上。第三检查BOOT0跳线帽。绝大多数开发板BOOT0默认接地也就是从Flash启动这是正常状态。如果BOOT0被拉高芯片就会进入ISP下载模式你点了下载却跑不起来程序先查这里。1.3 学习主线怎么安排很多新手死在东看一眼西看一眼今天学I2C明天学CAN后天又想搞USB最后哪个都没成。以我带过的经验和自己的血泪教训F103学习路线应该是线性的顺序不要乱GPIO输出点灯 - GPIO输入读按键 - 外部中断 - 定时器定时和PWM - 串口收发 - ADC采样 - I2C/SPI总线协议。这一趟走完你已经具备做一个小项目的全部能力后面什么OLED屏、超声波、温湿度传感器都是在这条主线上加外设而已。为什么要这么排因为每一步都在给下一步铺路。GPIO点灯教你配置引脚和时钟读按键教你输入模式和上拉下拉中断让你理解CPU怎么响应外部事件定时器是很多外设的时间基准串口则是你调试所有程序的眼睛。把这条主线走通之后你再看那些热词里提到的ILI9341屏、五线四相步进电机、超声波测距思路会非常清晰无非就是把数据从GPIO或者总线送出去再把读回来的数据处理一下。2. 搭建开发环境与工程模板Keil MDK从安装到新建工程2.1 安装Keil MDK、芯片支持包与驱动开发环境这一步是劝退重灾区很多人卡在Keil安装上。我直接说标准操作去Keil官网下载MDK-Arm安装到默认路径然后打开Pack Installer在搜索框输入STM32F1找到STM32F1xx的Device Family Pack点Install。这个包就是芯片支持包没有它Keil不认识你的芯片编译的时候会报错说找不到设备。安装完芯片包之后把开发板通过USB线连电脑装USB转串口驱动。大部分板子用的是CH340或者CP2102芯片装上驱动后在设备管理器里能看到COM口。注意别把调试器驱动和串口驱动搞混SWD调试器通常是ST-Link或者DAP-Link插上后设备管理器里会出现对应设备。如果板载的是ST-Link一般用ST官方驱动Win10以上系统大部分能自动识别识别不了就手动更新驱动。有个细节值得提前说下载程序用SWD四根线就够串口只是用来收发数据打印日志的两个功能独立。很多人以为“能下载程序说明串口也能用”其实不是一回事排查问题时先分清。2.2 标准库和HAL库到底怎么选这是新手问得最多的问题答案其实很简单学习底层原理用标准库做实际项目用HAL库。标准库是ST官方早年推出的固件库把寄存器操作封装成了函数比如GPIO_Init、USART_SendData代码直白函数名长但逻辑清楚。HAL库是新版HAL配合STM32CubeMX图形化配置工具可以自动生成初始化代码开发效率高但封装层级深出错时跟踪起来比较费劲。我个人建议第一遍学习走标准库原因是它离寄存器近你能清楚地看到每一步初始化在干什么以后看数据手册写寄存器代码也不会发怵。用HAL库的话CubeMX帮你把时钟树和外设配置好你反而不知道自己改了哪里出了问题说不清道不明。等标准库的套路熟悉了你再转HAL库会发现配置界面里那些选项你全都知道是什么意思完全是降维使用。2.3 手把手新建一个空白工程这一步几乎劝退所有新手因为Keil新建工程确实反人类。但只要你理解了一个工程文件里必须有启动文件、系统初始化文件、外设库源文件这三样后面无论怎么建都不会迷路。以标准库建工程为例先建一个项目文件夹里面分四个子文件夹User放main.c和stm32f10x_it.c这类用户代码CMSIS放内核相关文件FWLIB放外设驱动库Project放Keil工程文件。在Keil里新建工程芯片型号选STM32F103C8然后添加启动文件startup_stm32f10x_md.s这是汇编写的启动代码负责设置堆栈、中断向量表、调用SystemInit和main是整个程序的第一行必须有。接着添加系统文件和库文件。CMSIS文件夹里放system_stm32f10x.cFWLIB里把src目录下的stm32f10x_gpio.c、stm32f10x_rcc.c、stm32f10x_usart.c这些用得到的添加进去头文件路径加到工程配置里。最后还有一个容易被忽略的步骤在C/C选项卡的Define里填STM32F10X_MD,USE_STDPERIPH_DEVICE这两个宏一个告诉编译器你的芯片是中容量一个告诉它你要用标准库。少这一个宏编译至少几十个报错。Keil里还需要设置一下Debug选项选择你的调试器型号ST-Link或者DAP然后在Settings里确认能读到芯片ID。读不到ID就点不了下载这是后面排查程序下载问题的重要分界线。3. 从点灯开始GPIO输出的第一课3.1 点灯背后的硬件逻辑点灯之所以被叫“单片机的Hello World”是因为它涵盖了嵌入式开发最核心的思维配置时钟、配置引脚模式、操作寄存器输出电平。先看硬件开发板上的LED通常接在某个GPIO引脚上串一个限流电阻到地或者电源。你要是看了原理图会发现有些LED是高电平点亮有些是低电平点亮这个极性决定了你代码里写1还是写0。所以拿到板子先翻原理图别想当然。GPIO引脚在F103上默认是浮空输入状态要用作输出必须先做两件事打开GPIO所在总线的时钟然后初始化引脚的输出模式。在标准库代码里第一步是RCC_APB2PeriphClockCmd第二步是填一个GPIO_InitTypeDef结构体指定引脚号、模式、翻转速度。这就是F103外设初始化的通用套路时钟使能 - 结构体赋值 - 调用Init函数。你后面学UART、I2C、SPI全他妈是这个套路只是结构体成员不同。把这三个步骤变成肌肉记忆STM32就学通了一半。3.2 代码逐行解读我直接给一段最简单的点灯代码LED接在PA0、高电平点亮#include stm32f10x.h void delay_ms(uint32_t t) { while(t--) { volatile uint32_t i 7200; while(i--); } } int main(void) { GPIO_InitTypeDef GPIO_InitStructure; RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); GPIO_InitStructure.GPIO_Pin GPIO_Pin_0; GPIO_InitStructure.GPIO_Mode GPIO_Mode_Out_PP; GPIO_InitStructure.GPIO_Speed GPIO_Speed_50MHz; GPIO_Init(GPIOA, GPIO_InitStructure); while(1) { GPIO_SetBits(GPIOA, GPIO_Pin_0); delay_ms(500); GPIO_ResetBits(GPIOA, GPIO_Pin_0); delay_ms(500); } }逐行看。GPIO_InitTypeDef声明了一个结构体变量这个结构体就是GPIO的“配置表”。GPIO_Pin指定位0GPIO_Mode设为GPIO_Mode_Out_PP这是推挽输出模式意思是引脚能主动输出高电平和低电平驱动能力足够点亮LED。GPIO_Speed_50MHz设的是翻转速度对点灯来说设成2MHz都行这个参数影响的是引脚输出波形的上升沿时间不是电压大小。GPIO_Init(GPIOA, GPIO_InitStructure)把这个配置写进寄存器至此PA0变成输出口。while循环里的GPIO_SetBits和GPIO_ResetBits就是置位和清零分别让引脚输出高电平和低电平中间夹着软件延时。这个延时用的是简单的while循环空转注意volatile关键字不能去掉否则编译器优化后延时可能变成几微秒。这是第一个会踩的坑先记着。3.3 灯不亮怎么办硬件排查清单如果程序编译下载成功了LED纹丝不动先别怀疑代码。按这个顺序排查第一确认LED的负极或者正极接对没有拿万用表量一下引脚电压PA0有没有在0V和3.3V之间切换。第二检查接线如果你用的是杜邦线插面包板很可能是因为杜邦线接触不良很多新手灯不亮是这种低级原因。第三确认程序确实下载进去了重新点一下下载按钮看Keil有没有提示Flash Download成功。第四看开发板上有没有其他负载把电流拉走比如某个外设短路。还有一个特别迷惑的问题有些板子的LED默认接在PC13这种引脚上你代码控制PA0当然没用。我遇到过好几次新手对着原理图写了一个小时程序发现LED压根不在PA0上。所以再次强调先看原理图搞清楚LED在那个引脚、什么极性再写代码。这一步看似简单实际节省的时间是最多的。4. 进阶路线中断、定时器与串口调试4.1 外部中断让CPU学会响应事件GPIO轮询练熟之后下一步就是外部中断。中断的概念用大白话解释就是CPU正在干正事突然有人敲门CPU把手头活存档开门看看来干啥处理完再回来继续干。F103的PA0可以配置成EXTI0外部中断线按键按下产生一个上升沿或者下降沿CPU暂停主循环跳到中断服务函数。配置外部中断比GPIO多几个步骤先把PA0配置成输入模式通常是上拉输入然后配置AFIO时钟这个时钟是复用功能时钟外部中断映射就是复用功能不开它中断不生效。接着配置EXTI和NVICNVIC是嵌套向量中断控制器负责管理中断优先级。新手的第一个大坑就在这里不配置NVIC或者优先级分组方式设置错误导致中断一直进不去。标准库里的外部中断服务函数名是固定的叫EXTI0_IRQHandler里面要先判断中断标志位再清除标志位。忘了清除标志位中断服务函数会被反复调用表现就是程序卡在主循环里出不来看起来像死机。这个现象很多新手遇到过但不知道是中断标志位没清排查半天。4.2 定时器不只是用来延时定时器是F103另一个核心外设最常见的应用是定时中断。比如你要做一个LED每100ms翻转一次用软件延时CPU就一直空转啥也干不了但用定时器CPU该干嘛干嘛时间到了中断自动来通知你效率完全不一样。以通用定时器TIM2为例初始化思路也很固定开TIM2的时钟设置预分频器PSC和自动重装载值ARR打开定时器更新中断配置NVIC最后TIM_Cmd使能定时器。PSC和ARR的配合简单说就是分频和定标。比如APB1时钟是36MHz你先设PSC为3599得到10KHz的计数频率再设ARR为100每隔100个计数产生一次更新事件中断频率就是10KHz/100100Hz也就是10ms进一次中断。这个计算过程在以后做PWM调光、电机控制、超声波测距里会反复用到一定得自己算两遍。我做过的几个入门小项目里定时器中断加一个变量计数就能实现多路LED跑马灯加一个超声波传感器就能测距加一个编码器就能测转速。定时器是那种你越用越觉得强大的外设但前提是先把PSC和ARR算明白。4.3 串口调试开发的另一只眼睛串口是嵌入式开发的“输出通道”没有它你只能看灯亮不亮来判断程序状态有了它你可以打印变量、打印运行流程、甚至调试协议数据。第一次配置串口其实也是一个套路开串口和GPIO时钟配置TX/RX引脚为复用推挽输出和浮空输入配置串口波特率、字长、停止位然后使能串口。USART_InitTypeDef结构体里最关键的是USART_BaudRate也就是波特率。常见的波特率是9600和115200发送端和接收端必须一致否则收到的全乱码。乱码问题我见了无数回大概率是两边波特率没对上或者时钟频率算错了。别小看这个串口数据收发是后面做物联网模块、DBUS遥控器、IMU通信的基本功。串口还有一个知识值得提前讲中断接收。单纯发送字符串不需要中断但你要接收数据就必须开USART接收中断在中断服务函数里把收到的字节存下来。很多人到这里又开始先查“为什么接收不到”绝大多数是没开接收中断或者没有在中断里读数据寄存器导致标志位一直被置位。5. 新手最容易踩的坑与排查实录5.1 SWD或者JTAG连接不上设备这个问题出现的频率排在第一位。现象是Keil下载时报错No Target Connected。排查思路先软件后硬件先检查Debug设置里的调试器型号是不是选对了ST-Link就选ST-Link DebuggerDAP-Link要选CMSIS-DAP。再检查设备管理器里有没有识别到调试器没识别是驱动问题识别了却连不上是接线问题。硬件方面SWD四根线别接反SWDIO和SWCLK这两根不能换换错了绝对连不上GND必须共地否则信号电平参考不一致。如果你之前烧过一个把SWD引脚复用掉的程序会导致调试接口失效解决办法是把BOOT0拉高重新上电进ISP模式这时SWD引脚恢复默认状态再连一次下载正常程序然后把BOOT0拉回低电平。这个方法对很多“板子变砖”的新手来说是救命稻草。5.2 Keil编译报错说找不到芯片装了MDK还是编译不过提示Unknown Device先检查Pack Installer里STM32F1xx的包有没有装上。装好了还报错检查Target选项卡里的芯片型号选没选对C8T6就选STM32F103C8别选成F407。另外工程里如果用了标准库那个宏定义很容易漏报错内容通常是找不到stm32f10x.h说明头文件路径没加或者宏没定义。有时候同一个错误会出现几十上百条别慌先看第一条报错因为后面的通常是连锁反应。比如头文件路径没配编译器会顺着每一处引用都报一遍。把第一条解决了剩下大概率自己消失。这是排查所有编译错误的通用做法。5.3 delay函数卡死和中断标志位问题我大量见到“程序下载进去之后跑了一会儿就卡住”或者“一进延时函数就出不来”。延时卡死最常见的原因是SysTick定时器配置有问题SysTick是内核里的一个24位倒计时定时器很多延时函数都在使用它。如果你在其他地方重新初始化了SysTick或者中断优先级分组被修改可能导致Systick中断永远进不去延时函数就死循环了。另一个非常常见的问题是串口接收中断里收到数据之后没有读DR数据寄存器。因为只要RXNE标志置位中断就会一直触发服务函数进进出出主函数永远拿不到CPU。如果程序表现为“正常跑但特别卡”优先检查所有中断服务函数里有没有清除标志位以及有没有不用延时等待的方式处理外设状态。5.4 扩展外设的典型翻车现场很多人点灯学会了就想加OLED屏结果ILI9341或者SSD1306怎么都点不亮。以ILI9341为例读ID总是0xA1A1这个值你如果去翻数据手册会发现是默认厂商ID它意味着LCD芯片根本没通过SPI接到正确指令大概率是SPI模式选错了ILI9341一般用Mode 0也就是CPOL0、CPHA0很多人的代码却配成了Mode 3。其次是CS引脚的电平逻辑很多屏是低电平选中你如果把它长期拉高屏收不到任何命令。还有一个隐蔽的坑读ID需要先给屏发送0x04命令但那之前要初始化RESET引脚时序直接用默认电平大概率失败。超声波测距模块HC-SR04也是新手的保留项目。Trig要拉高至少10微秒Echo会输出一个和距离成正比的高电平脉宽你用定时器输入捕获去量这个脉宽就能算距离。但注意HC-SR04的Echo是5V电平STM32引脚是3.3V容忍直接怼上去长期使用有风险最好分压。很多人测距结果漂移很大原因是没做多次测量取平均或者Trig引脚初始化成浮空输入了。还有那个五线四相步进电机很多教程直接让你接GPIO驱动我跟你说绝对驱动不了电机线圈需要的电流远超GPIO输出能力。标准做法是接ULN2003驱动板然后按1-2相励磁的节拍序列输出脉冲比如A-AB-B-BC-C-CD-D-DA这样转一圈。这个项目放在主线学习之后做特别合适能同时复习GPIO、定时器PWM和状态机思想。5.5 那些真正让学习进度起飞的小项目当你把主线内容都过了一遍光靠看着教程敲代码水平提升会非常慢。这时候我建议你找一个自己真正感兴趣的完整小项目做一遍比如用STM32控制鱼缸的灯光和温度检测或者用超声波传感器做一个自动倒车雷达又或者用步进电机加一个丝杆做一个自动窗帘。项目不大但需要你把GPIO、定时器、串口、传感器这些模块串起来用中间会遇到书上没写的问题比如传感器数据抖动怎么滤波、电机噪声怎么消抖、断电后参数怎么保存这才是真正意义上的进步。我当时自己做了一个用LCD显示环境温湿度的桌面小气象站看起来平平无奇但做完之后我对I2C时序的容忍度、对数据手册的阅读习惯、对断点调试的使用熟练度都上了好几个台阶。所以别嫌项目简单简单项目做完一个是一个比光看视频强十倍。6. 最后分享一点实际感受从“开发板买回来了”到“能独立做一个小项目”正常节奏大概两到三周。前提是每天都花一两个小时动手写代码、看原理图、翻数据手册而不是打开视频看别人做。我个人体会最深的两点第一别怕把芯片配置错F103抗造得很软件配置错了重新下载就是除非你把电源接反了第二学会用调试器在线调试远比用printf打印省时间Keil里的断点、Watch窗口、寄存器窗口这些功能早点用起来你的解题速度会快很多。另外一个建议是边学边记笔记。不是让你写详细的学习心得而是每次踩坑之后把现象、原因、解决方案记一条以后遇到类似问题直接翻笔记再也不用重新搜一遍网页。这比收藏一摞教程有用得多因为你搜到的教程往往是别人的思维你自己的笔记才是真正为你定制的避坑手册。STM32的世界很大USB协议栈、实时操作系统、无线通信模块都在远处等着但地基就是这张开发板上的几十行代码把地基打牢了后面的高楼就只是时间问题。
返回列表