ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

STM32标准外设库实战指南:从工程结构到GPIO与串口配置

STM32标准外设库实战指南:从工程结构到GPIO与串口配置 简介STM32标准外设库是STMicroelectronics为STM32系列MCU提供的底层驱动软件框架面向嵌入式开发者与电子类学生旨在用统一API屏蔽寄存器操作降低GPIO、定时器、串口、ADC、DAC、DMA、SPI、I2C、USB等外设的使用门槛。这份压缩包采用zip格式总计1007个文件除C源文件、H头文件外还包括启动汇编代码、链接脚本、示例工程文件如uvproj/ewp、CHM帮助文档与PDF手册整体约36.84MB目录按外设模块组织便于检索查阅。目前已有397人学习适合正在学习STM32F1系列或需要快速搭建项目的开发者。解压后可直接获取STM32F10x标准外设库V3.5.0的头文件、库文件、完整示例代码和参考文档示例覆盖系统初始化、GPIO配置、NVIC中断、DMA传输、定时器PWM、ADC采集、串口通信及USB等典型场景并配有工程模板与编译链接脚本能帮助使用者跳过底层寄存器细节把精力集中到应用逻辑可大幅缩短项目开发周期。1. 为什么我还在用标准外设库1.1 标准外设库到底解决了什么问题先说个背景。STM32最早火起来那几年官方主推的开发方式就是标准外设库Standard Peripheral Library简称StdPeriph_Lib。那时候没有HAL库更没有CubeMX这种图形化配置工具大家拿到芯片第一件事就是下个标准库压缩包然后在Keil里手动新建工程、添加外设驱动源文件、配好启动文件一顿操作猛如虎点亮一颗LED。标准外设库干的事情可以概括成一句话把寄存器操作封装成函数和结构体让你不用背那一长串寄存器地址和位定义。举个例子你要把PA5引脚设置成推挽输出、50MHz速度寄存器写法需要操作GPIOA-CRL这个32位寄存器把20到23位改成0100还得用读-改-写的方式避免把其他引脚配置搞坏。标准库写法就是三行代码GPIO_InitTypeDef GPIO_InitStructure; GPIO_InitStructure.GPIO_Pin GPIO_Pin_5; GPIO_InitStructure.GPIO_Mode GPIO_Mode_Out_PP; GPIO_InitStructure.GPIO_Speed GPIO_Speed_50MHz; GPIO_Init(GPIOA, GPIO_InitStructure);这段代码谁看谁懂Pin是哪个引脚、Mode是什么模式、Speed是多快结构体字段一目了然。这正是标准库的核心价值它把芯片手册里那些枯燥的寄存器描述翻译成了可读性极高的C语言接口同时保留了接近底层的控制粒度。哪怕到了2025年的今天HAL库和CubeMX早就是主流我依然推荐新手从标准外设库入手。原因很简单标准库代码逻辑直白每个函数背后对应什么寄存器操作、什么硬件行为基本上一查就能理清楚。你用HAL库配置一个串口HAL_UART_Init背后调了底层一堆函数中间还有超时机制和错误回调初学者根本不知道发生了什么。标准库就没有这层迷雾你能看到GPIO_Init里直接操作CRL和CRH寄存器也能看到USART_Init里一条条往BRR寄存器写波特率分频值。这种“代码到寄存器”的映射关系是人建立硬件直觉最好的教材。1.2 标准库、HAL库、LL库和寄存器开发怎么选经常有人问我现在学STM32应该学标准库还是HAL库我的回答一直是两个都要碰但先后顺序很重要。做产品用HAL没问题CubeMX拖一拖就能生成初始化代码省时省力。但如果你连GPIO输出模式有哪些、USART时钟从哪条总线来、DMA请求映射在哪张表上都没概念直接用HAL就是空中楼阁出了问题抓瞎。开发方式抽象层级上手难度代码体积适合场景寄存器最底层很高最小精简单片机、性能极致优化标准外设库寄存器上封一层适中较小学习原理、快速开发中小项目LL库类似寄存器但更规范较高很小对代码体积和实时性要求高的场景HAL库高层次抽象低较大复杂外设、CubeMX生态、产品开发标准库的位置很巧妙刚好卡在“看得懂寄存器”和“写起来不累”之间。早期ST官方出过一句话叫“Close to the silicon”意思就是贴近硅片本身标准库确实是这个定位。对照来看HAL库是“Close to the application”LL库则是介于两者之间更轻量的选择。现在我带项目或者给学生做培训通常的教学路径是这样的先用标准库点亮LED、跑通串口建立“代码动一下、硬件变一下”的直接反馈然后切到HAL库用CubeMX生成一顿初始化代码对比一下标准库里的手动配置自然就能看懂CubeMX到底帮你做了什么。最后再回去看标准库源码你会惊讶地发现自己已经能读懂底层实现逻辑了。这种路径走完STM32的体系感就建立了。2. 标准库工程的核心结构拆解2.1 一个标准库工程由哪些部分组成标准库官方压缩包解压后目录结构大致是这样的STM32F10x_StdPeriph_Lib_V3.6.0/ ├── Libraries/ │ ├── CMSIS/ │ │ ├── CMSIS/Device/ST/STM32F10x/ │ │ │ ├── Include/stm32f10x.h │ │ │ └── Source/Templates/system_stm32f10x.c │ │ └── Include/core_cm3.h │ └── STM32F10x_StdPeriph_Driver/ │ ├── inc/ // 各外设头文件 │ └── src/ // 各外设源文件 ├── Project/ ├── Utilities/ └── stm32f10x_conf.h这里面最核心的是Libraries目录下的两大部分CMSIS层和外设驱动层。CMSIS是ARM官方定的Cortex-M微控制器软件接口标准它保证了不同厂家芯片比如STM32、GD32、MM32在寄存器定义上有一致的规范。stm32f10x.h是整个芯片的“户口本”里面定义了所有寄存器地址、中断向量、外设基地址没有这个文件所有外设驱动都无法编译。外设驱动层就更好理解了一个外设一对文件比如stm32f10x_gpio.c和stm32f10x_gpio.h管GPIOstm32f10x_usart.c和stm32f10x_usart.h管串口stm32f10x_spi.c和stm32f10x_spi.h管SPI。你用到哪个外设就往工程里添加哪个.c文件用不到的完全可以不添加编译出来的固件体积就很精简。还有一个容易忽略的文件是stm32f10x_conf.h这个头文件用条件编译的方式统一包含了所有外设头文件同时开启了外设库的断言检测功能。所谓断言就是检查你传进去的参数是否合法比如GPIO_Pin最大值不能超过0xFFFF、GPIO_Mode不能填一个不存在的模式值。调试阶段强烈建议开着断言它能帮你抓出一堆低级错误发布固件时再去掉减少代码体积。2.2 从启动文件到main函数的执行流程很多人新建工程时把启动文件当成一个必须放进去但不用关心的“神秘文件”这是个大误区。启动文件startup_stm32f10x_hd.s其实是汇编写的作用包括三件大事设置初始栈指针、建立中断向量表、调用SystemInit和__main。芯片上电后硬件自动从0x08000000地址Flash起始位置取出栈顶地址然后跳转到复位中断服务程序Reset_Handler。这个复位中断服务程序在启动文件里用汇编实现干的第一件事是调用SystemInit函数这个函数在system_stm32f10x.c里作用是把系统时钟从默认的HSI内部8MHz切换到HSE外部晶振并配置PLL锁相环把主频提升到72MHz。没有这一步芯片只能跑在8MHz的HSI上串口波特率、定时器定时时间全部会乱套。SystemInit跑完之后启动文件会跳转到__main注意是C库的入口函数不是我们写的mainC库在这里完成全局变量和静态变量的初始化、零初始化BSS段最后才调用我们写的main函数。所以main函数里看到的全局变量初始值都是正确的这正是启动文件的功劳。在这个流程里有个细节值得提一下。SystemInit里读取的是芯片出厂时烧录在Flash里的校准值来设置Flash等待周期如果外部晶振没焊或者焊错了频率系统时钟配置就会失败芯片的表现就是程序完全跑不起来或者跑得很慢。我之前遇到一个案例客户打样回来程序死活跑不动排查到最后发现是8MHz晶振的负载电容没贴振荡器起振失败SystemInit里等待HSE就绪超时整个初始化卡死。这个问题用标准库的话你能在system_stm32f10x.c的while循环里精确定位到问题点如果换成HAL库这个卡死在系统初始化阶段的现象反而不太好查。2.3 RCC时钟树标准库代码里藏得最深的模块RCCReset and Clock Control是整个STM32系统时钟的“总闸门”。它的核心作用有两个管理系统复位以及控制每个外设时钟的开启和关闭。在标准库中你要用任何外设之前第一步一定是开启对应外设的时钟。以最常用的GPIO为例GPIO是挂在APB2总线上的所以使用前要这样操作RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);这行代码背后的本质是往RCC-APB2ENR寄存器写一个位把GPIOA的时钟使能。为什么必须要做这一步因为STM32为了低功耗考虑默认情况下所有外设时钟都是关闭的。只有时钟信号到达外设模块它的寄存器才能被读写逻辑电路才能工作。打个生活化的比方RCC就像一个建筑的楼层配电箱没合上电闸的房间你进去按什么开关都没反应。标准库里关于RCC的调试心得我提炼三条开外设时钟的顺序建议是先RCC后配置外设寄存器否则外设模块压根没有时钟配置了也白配APB1和APB2的最高频率不同APB1默认36MHzAPB2默认72MHz。挂在不同总线上的外设使用时要注意总线频率对波特率、定时器分频的影响时钟树配置完成后可以用RCC_GetClocksFreq函数回读当前各个总线频率调试时打印出来能快速确认配置是否正确3. 实战从零搭建一个标准库点灯工程3.1 新建工程的具体步骤和避坑点标准库新建工程几乎所有教程的开头都是这个环节但真正一步不错走下来的人不多。我这里以最典型的STM32F103系列比如最常见的C8T6或ZET6为例把操作步骤梳理一遍。第一步准备文件。把标准库压缩包里Libraries目录原样拷到你的工程根目录下另外准备一份启动文件。需要强调的是启动文件选型要看芯片型号的Flash容量。第二步在Keil里新建工程选择芯片型号。选择好之后Keil会弹出对话框问你是否要添加启动文件这里两条路都可以走。如果你自己手工添加正确版本的启动文件这里就选否如果你想用Keil自带的选是。我用标准库的习惯是选否因为Keil自带启动文件有时版本较老和标准库的匹配度不如我从库包里取出来的好。第三步配置工程选项。这个环节小数点最多Target页把晶振频率填成8MHz勾选Use MicroLIBOutput页勾选Create HEX File方便后续下载Debug页选择调试器ST-Link选ST-Link DebuggerJ-Link选J-Link/J-Trace Cortex然后到Settings里确认能识别到芯片IDCODEC/C页在Define框填上USE_STDPERIPH_DRIVER,STM32F10X_HD这里的宏和你芯片型号对应中容量填STM32F10X_MD大容量填STM32F10X_HD。这个宏的作用从命名就能看出来USE_STDPERIPH_DRIVER告诉工程要使用标准外设驱动层的定义STM32F10X_HD则告诉芯片型号驱动代码里会据此选择正确的寄存器映射和中断向量定义。还需要在Include Path里添加所有头文件路径按目录层级逐个添加具体路径是CMSIS核心头文件目录、芯片设备头文件目录、外设驱动门头文件目录、你自己放main函数和配置文件的那个目录一个最容易踩的坑就是C/C页里的宏定义漏填。漏填USE_STDPERIPH_DRIVER不会报错但编译到外设驱动文件时会提示找不到一些通用宏定义漏填型号宏更隐蔽因为它编译不报错但中断向量表和寄存器地址定义是错的程序下载进去跑起来行为诡异。我有一次帮客户排查一个“延时不对、串口乱码”的问题就是大容量芯片填了MD宏导致的。3.2 GPIO配置的底层逻辑GPIO是学习STM32最基础的外设也是标准库封装最成熟的外设之一。GPIO_InitTypeDef结构体里最重要的三个字段是GPIO_Pin、GPIO_Speed和GPIO_Mode。GPIO_Speed只能是三个值GPIO_Speed_2MHz、GPIO_Speed_10MHz、GPIO_Speed_50MHz。很多人不理解这个速度到底是干什么的简单说就是IO口输出驱动电路的翻转速率上限。如果你让GPIO输出一个10MHz的方波但GPIO_Speed配置成了2MHz这个方波的上升沿和下降沿就会被削得很缓波形严重失真。不过常规的LED点灯、按键读取这类应用根本不需要高速选2MHz就行反而还能减少功耗和电磁干扰。GPIO_Mode则是决定引脚工作方式的核心参数。输入模式有模拟输入GPIO_Mode_AIN、浮空输入GPIO_Mode_IN_FLOATING、上拉下拉输入GPIO_Mode_IPU和GPIO_Mode_IPD输出模式有开漏输出GPIO_Mode_Out_OD、推挽输出GPIO_Mode_Out_PP以及对应的复用开漏GPIO_Mode_AF_OD和复用推挽GPIO_Mode_AF_PP。这里最需要注意的是复用模式凡是引脚要作为外设功能使用比如USART的TX、SPI的SCK模式就必须选复用模式如果选成普通推挽虽然有时候也能工作比如I2C这种开漏协议能跑但很多场景下功能会受影响。实操中点灯工程配置PA5的代码模板如下void LED_Init(void) { GPIO_InitTypeDef GPIO_InitStructure; RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); GPIO_InitStructure.GPIO_Pin GPIO_Pin_5; GPIO_InitStructure.GPIO_Mode GPIO_Mode_Out_PP; GPIO_InitStructure.GPIO_Speed GPIO_Speed_50MHz; GPIO_Init(GPIOA, GPIO_InitStructure); GPIO_SetBits(GPIOA, GPIO_Pin_5); }这个函数写完LED初始状态就确定了。GPIO_SetBits把引脚拉高对应的还有GPIO_ResetBits把引脚拉低GPIO_WriteBit和GPIO_WriteBit组合使用可以灵活控制单个或多个引脚。另外还有一组寄存器一次可以操作多个引脚的函数GPIO_Write可以一次性把某个GPIO端口的ODR寄存器写成指定值。3.3 串口和延时调试的基础设施点灯跑通之后串口是第二个优先级最高的模块。串口不熟后面什么调试工具都用不上全靠猜。标准库配置USART的代码可以浓缩为一个函数void USART1_Init(u32 baudrate) { GPIO_InitTypeDef GPIO_InitStructure; USART_InitTypeDef USART_InitStructure; RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_USART1, ENABLE); GPIO_InitStructure.GPIO_Pin GPIO_Pin_9; // TX GPIO_InitStructure.GPIO_Mode GPIO_Mode_AF_PP; GPIO_InitStructure.GPIO_Speed GPIO_Speed_50MHz; GPIO_Init(GPIOA, GPIO_InitStructure); GPIO_InitStructure.GPIO_Pin GPIO_Pin_10; // RX GPIO_InitStructure.GPIO_Mode GPIO_Mode_IN_FLOATING; GPIO_Init(GPIOA, GPIO_InitStructure); USART_InitStructure.USART_BaudRate baudrate; USART_InitStructure.USART_WordLength USART_WordLength_8b; USART_InitStructure.USART_StopBits USART_StopBits_1; USART_InitStructure.USART_Parity USART_Parity_No; USART_InitStructure.USART_HardwareFlowControl USART_HardwareFlowControl_None; USART_InitStructure.USART_Mode USART_Mode_Rx | USART_Mode_Tx; USART_Init(USART1, USART_InitStructure); USART_Cmd(USART1, ENABLE); }这段代码值得注意的有两点TX引脚用复用推挽RX引脚用浮空输入这是串口标准接法USART1是挂在APB2总线上的所以时钟使能用的是RCC_APB2PeriphClockCmd。如果你用的是USART2或USART3就要换成RCC_APB1PeriphClockCmd因为这两个挂在APB1总线上最大频率只有36MHz如果设置波特率超过一定值也会出问题。关于USART1还有一个很实用的经验。标准库里的USART_SendData函数实际上只是往数据寄存器DR里写一个字节并没有检查数据是否发送完毕。如果你连续调用USART_SendData发送多字节不加判断会丢数据。正确的做法是在每次发送前检查发送状态寄存器void USART1_SendByte(u8 data) { while (USART_GetFlagStatus(USART1, USART_FLAG_TXE) RESET); USART_SendData(USART1, data); }延时函数也是调试基础设施的一部分。基于SysTick的延时是标准做法SysTick是Cortex-M3内核自带的24位倒计时定时器用标准库可以轻松实现微秒级和毫秒级延时。核心代码如下static u8 fac_us 0; static u16 fac_ms 0; void delay_init(u8 SYSCLK) { SysTick_CLKSourceConfig(SysTick_CLKSource_HCLK_Div8); fac_us SYSCLK / 8; fac_ms (u16)fac_us * 1000; } void delay_us(u32 nus) { u32 temp; SysTick-LOAD nus * fac_us; SysTick-VAL 0x00; SysTick-CTRL | SysTick_CTRL_ENABLE_Msk; do { temp SysTick-CTRL; } while ((temp SysTick_CTRL_ENABLE_Msk) !(temp SysTick_CTRL_COUNTFLAG_Msk)); SysTick-CTRL ~SysTick_CTRL_ENABLE_Msk; SysTick-VAL 0x00; }这段代码的思路是把SysTick配置为HCLK的8分频这样在72MHz主频下SysTick的计数时钟就是9MHz每计一个数耗时1/9微秒所以1微秒需要的计数值就是fac_us9。毫秒延时就是在微秒延时的基础上乘以1000。这里有个细节值得注意SysTick-CTRL的第16位是COUNTFLAG标志它会在计数器从1数到0时被硬件置1软件读取该位后自动清零。所以判断计数是否完成就是检查这个标志位。4. 标准库开发中高频踩坑与排查记录4.1 下载失败和no target found的排查思路“error: no stm32 target found! if your product embeds debug authentication”这类提示核心意思是调试器没有和芯片建立起连接。出现这个问题的原因按概率排序大概是接线错误或接触不良、芯片进入低功耗模式或调试引脚被禁用、SWDIO和SWCLK引脚被程序复用成了普通IO。最经典的场景是你写了一段程序把PA13和PA14这两个引脚默认复用为SWDIO和SWCLK配置成了普通推挽输出程序一旦跑起来调试器就再也连不上芯片了。解决办法有两种。最狠的办法是按住芯片的复位键不放在Keil里点下载的同时松开复位键利用芯片上电复位后短暂时间内调试接口还是可用窗口期完成连接。另一种办法是把BOOT0引脚拉高让芯片从系统存储器启动这个模式下用户Flash里的程序不会运行调试器自然就能连上。连接成功后先把程序擦除了再说。还有个容易被忽视的点芯片内部有读保护RDP和调试认证机制。如果之前有人用STM32CubeProgrammer开启了读保护级别1或级别2调试器也会报类似错误。用STM32 ST-LINK Utility或者CubeProgrammer先做一次Full Chip Erase把读保护清掉就好了。4.2 delay卡死与中断优先级问题的关联延时函数卡死是标准库新手最容易遇到的问题现象是程序跑着跑着就停在了delay_us里的while循环里怎么都跳不出来。很多人以为是延时函数写错了其实大多数情况下是中断配置出了岔子。SysTick定时器在标准库和HAL库里的处理方式不太一样标准库的delay_us是轮询方式实现的不依赖中断。所以如果延时函数卡死在while循环里大概率不是SysTick本身的问题而是有另一个更高优先级的中断在无限循环里出不来导致CPU一直在跑中断服务程序主循环的延时函数根本没机会执行。一种典型场景是USART串口中断你开启了USART接收中断但中断服务程序里忘记清标志位或者接收处理逻辑有bug导致死循环那么一旦串口收到一帧数据CPU就被钉死在串口中断里主循环看起来就好似“延时卡死”。这时候排查步骤是先在调试器里暂停程序查看当前的PC指针停在哪里是停在delay函数的循环里还是停在某一个中断服务程序里然后用Keil的寄存器窗口查看xPSR的异常编号就能确认当前是不是在处理一个中断最后检查NVIC中断优先级分组配置是否合理不要让一个普通外设中断抢占了一切。4.3 Keil安装芯片包与C51共存的坑很多在学校里先学过51单片机的朋友电脑上装的Keil是C51版本然后学STM32时发现编译不了因为C51版本并不支持ARM芯片。后来又装了Keil MDK结果两个版本装在一起出现了诡异的兼容问题。这里先说清楚Keil C51和Keil MDK其实是两个独立的IDE装在同一个电脑上互不冲突的前提是安装路径不要重叠。建议C51装在C:\Keil_v5MDK装在C:\Keil_v5_ARM这样的目录安装顺序无所谓因为两个IDE的许可证和工具链是分开管理的。真正冲突的坑点是ULINK驱动和注册机共用这个属于使用习惯问题不展开讨论了。芯片支持包则完全是另一码事。Keil MDK从5.0版本开始芯片型号支持不是IDE自带的而是通过Pack Installer安装的不同厂商的芯片有各自的Pack包。你到Keil官网或者芯片厂商官网下载对应的Pack文件双击安装然后在新建工程时就能看到对应型号了。STM32全系列都包含在Keil.STM32F1xx_DFP这一个包里虽然这个包体积比较大大概一两百MB但装一次就能覆盖F1系列所有型号推荐直接装最新版。4.4 标准库常见问题速查表我根据多年使用标准库的实战经验把高频问题整理成了一张速查表方便快速定位问题现象大概率原因排查/解决方法编译报错找不到stm32f10x.hInclude Path没添加在C/C选项卡里添加CMSIS和驱动头文件路径编译报错identifier u8 is undefined缺少类型定义头文件确认包含了stm32f10x.h并定义了USE_STDPERIPH_DRIVER程序下载成功但LED不亮GPIO时钟没开或引脚配错检查RCC_APB2PeriphClockCmd是否调用核对引脚号串口输出乱码波特率不匹配或时钟配置错检查系统主频是否72MHz确认串口挂在APB1还是APB2一进中断就死机中断服务函数名和启动文件不一致核对startup文件中中断向量名比如USART1_IRQHandler要完全一致下载器可以连接但无法读Flash芯片读保护开启用CubeProgrammer做Full Chip EraseADC采样值跳动引脚浮空或参考电压不稳将ADC引脚配置为模拟输入检查VREF引脚滤波电容这张表覆盖了从环境搭建到硬件调试验收的完整链路。最后一个问题顺带提一句ADC引脚的GPIO模式是GPIO_Mode_AIN也就是模拟输入这个和普通输入不一样不少人在这一步翻车。5. 标准库的后续扩展价值标准库的学习路径不会白费它为你后续接触更复杂的生态打下了地基。比如FreeModbus在STM32上的移植核心就是修改串口底层收发函数和定时器接口这些源码最终都会落到寄存器操作上。你在标准库里练熟了“配置GPIO复用为串口”、“处理串口中断”、“用一个定时器产生时间片”再去看FreeModbus的移植示例思路就会非常清晰。再比如LVGL这种图形库移植到STM32上标准库工程同样可以胜任。LVGL需要一个精确的时基tick来驱动内部动画和刷新逻辑方案是在一个定时器中断里周期调用lv_tick_inc函数。这个定时器的初始化用标准库写起来无非就是TIM_TimeBaseInit加TIM_ITConfig加NVIC_Init三步所有环节都在你的掌控范围内。对比CubeMX生成HAL代码的“黑盒式”初始化标准库的方式反而更容易排查时序问题。话说回来我这几年用标准库最多的地方其实是做各类小项目的原型验证。比如宿舍控制灯那种用ESP8266和STM32通讯的玩法STM32端主要工作就是解析AT指令、控制继电器标准库代码写起来效率很高调试也很直观。K210和STM32之间的通讯也一样串口协议定义好了STM32端代码无非是串口收发加状态机解析标准库完全够用。有些项目对成本敏感需要把STM32换成国产兼容型号比如APM32、GD32标准库在这些芯片上几乎不用改动就能编译运行这也是一个很实际的优势。最后说一个关于标准库版本的细节。STM32F1系列官方标准库最后一个版本是V3.6.0发布于2013年左右此后不再更新。虽然官方停止维护但这个库足够稳定成熟社区资料极其丰富你遇到任何问题几乎都能在搜索引擎里找到答案。网上偶尔能看到一些“标准库精简优化版”或者网友改写的版本我的建议是学习阶段用官方原版V3.6.0别折腾那些个人魔改版因为你不知道别人改了什么出现问题很难排查。等基本功扎实了再根据自己的喜好去精简、去魔改也不迟。我个人在实际操作中的体会是标准外设库就像练字时的楷书一笔一画都清清楚楚。虽然现在写文档、做产品都用HAL库更高效快捷但那种对硬件的掌控感只有在标准库的地基上才能真正建立起来。如果你正处在嵌入式入门阶段建议耐着性子用标准库写完十个八个例程再谈下一步这个基本功花的时间后面会加倍还给你。本文还有配套的精品资源点击获取
返回列表