ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

从Arduino到STM32 HAL库:快速掌握配置-初始化-使用开发流程

从Arduino到STM32 HAL库:快速掌握配置-初始化-使用开发流程 1. 从 Arduino 到 STM32 HAL 库到底要解决什么问题如果你刚开始接触单片机或者只用过 Arduino现在想转向更主流的 STM32那这个学习路径最核心要解决的问题其实就一个如何把“简单能用”的 Arduino 思维平滑地升级到“可控、可调、可量产”的 STM32 工程思维。Arduino 很好它用封装好的库函数让你几行代码就能点亮 LED、驱动舵机快速获得成就感。但它的“黑盒”特性也让你很难理解底层硬件比如定时器、中断、DMA到底是怎么工作的。当你的项目需要更精确的时序控制、更低的功耗、更复杂的通信协议或者需要为产品量产考虑代码体积和运行效率时Arduino 的局限性就显现出来了。STM32 则代表了另一种思路它把硬件的控制权交还给你。通过标准外设库StdPeriph或更现代的 HAL 库Hardware Abstraction Layer你可以直接操作寄存器和外设。这听起来复杂但好处是巨大的你知道每一行代码在硬件层面做了什么可以针对性地优化性能能处理更复杂的任务并且代码的可移植性和可维护性也更强。所以这个“极速入门”的关键不是让你从零开始死磕寄存器而是借助你已有的 Arduino 经验快速理解 STM32 HAL 库的工作模式建立起“配置-初始化-使用”的标准开发流程。我会带你绕过那些一开始容易让人放弃的复杂概念直接抓住最核心的、能让你项目跑起来的主干。2. 环境准备别在工具链上卡住第一天在写第一行代码之前把环境搭对、搭顺能避免 80% 的“玄学”问题。STM32 开发环境的选择比 Arduino 复杂一些但核心思路不变一个写代码的 IDE一个编译代码的工具链一个下载调试的硬件工具。2.1 核心三件套IDE、工具链、调试器集成开发环境IDE首推STM32CubeIDE。它是 ST 官方推出的免费 IDE基于 Eclipse但集成了 STM32CubeMX 图形化配置工具和调试器。对于从 Arduino 过来的你最大的好处是“一站式”芯片选型、引脚配置、时钟树设置、外设初始化代码生成都可以在图形界面里完成然后直接跳转到写业务逻辑代码的界面。这大大降低了从零配置项目的门槛。编译器工具链STM32CubeIDE 已经内置了 GNU Arm Embedded Toolchain也就是 arm-none-eabi-gcc你不需要单独安装。这解决了最令人头疼的编译环境问题。程序下载与调试工具你需要一个硬件调试器。最常见、最便宜的是ST-LinkV2 或 V3。它通过 SWD 接口连接你的 STM32 开发板负责下载程序、在线调试设置断点、单步执行、查看变量。这是深入理解程序运行、排查 Bug 的必备工具是 Arduino 通过串口监控所无法比拟的深度。2.2 硬件准备开发板与连线STM32 开发板选择一款主流、资料多的核心板或最小系统板比如基于STM32F103C8T6蓝色小板常称“Blue Pill”或STM32F401系列的。F1 系列经典资料海量F4 系列性能更强有浮点单元。对于入门F103 完全足够。ST-Link 调试器购买时注意接口通常需要杜邦线连接到开发板的SWDIO、SWCLK、GND和3.3V引脚。USB 数据线用于给开发板和 ST-Link 供电如果开发板无独立供电。LED 和按键用于最基础的输入输出测试。开发板上通常自带用户 LED 和复位按键但准备一两个外接的有助于理解 GPIO 的输入输出模式。连线确认清单ST-Link 的3.3V- 开发板3.3VST-Link 的GND- 开发板GNDST-Link 的SWDIO- 开发板SWDIO(通常是PA13)ST-Link 的SWCLK- 开发板SWCLK(通常是PA14)注意务必先确认开发板供电方式。如果通过 ST-Link 供电开发板上的供电跳线帽要接到3.3V来自调试器一侧如果开发板通过 USB 口独立供电则 ST-Link 只连接GND、SWDIO、SWCLK三根线即可不要接3.3V以防电源冲突烧毁芯片。2.3 软件安装与初步验证从 ST 官网下载并安装 STM32CubeIDE。安装路径建议全英文避免后续奇怪问题。安装完成后打开软件它会自动初始化工作空间Workspace选择一个空文件夹即可。连接 ST-Link 和开发板到电脑。在 IDE 中尝试创建一个最简单的项目来验证环境File - New - STM32 Project在芯片选择器中输入你的芯片型号如STM32F103C8选择正确的型号。项目名取为Test_LED其他选项默认。在接下来的图形化配置界面CubeMX先不做任何配置直接点击右上角GENERATE CODE。代码生成后在main.c的while(1)循环里先不写代码直接点击工具栏的Build小锤子编译。应该能编译成功0错误0警告。点击Debug小虫子按钮IDE 会尝试连接 ST-Link 并下载程序。如果一切正常程序会运行并停在main函数的开始处。如果能走到这一步恭喜你最磨人的环境关已经过了。接下来我们进入正题理解 HAL 库的做事逻辑。3. 思维转换从digitalWrite到“配置-初始化-使用”Arduino 里点灯是digitalWrite(LED_PIN, HIGH)。在 STM32 HAL 库里这背后至少有三步。理解这三步就理解了 HAL 库的核心。3.1 第一步外设与引脚配置CubeMX 图形化完成在 Arduino 里你声明pinMode就完成了配置。在 STM32 里你需要告诉芯片哪个引脚GPIOA 的 Pin 5工作模式是什么推挽输出开漏输出输入上拉输出速度多快低速、中速、高速、超高速影响功耗和噪声这个引脚是否复用为其他外设功能比如串口的 TX、RX手动写代码配置这些寄存器非常繁琐。所以我们使用 CubeMX 图形化工具。在项目初始化时你通过点击芯片图上的引脚选择其功能GPIO_Output然后在右侧的配置面板设置模式和速度。CubeMX 会根据你的图形化操作自动生成所有初始化代码。关键思维在 STM32 项目里硬件配置是一次性的、前置的工作。在写业务逻辑前你必须想清楚每个引脚要干嘛并在 CubeMX 里配好。这就像盖房子先画好施工图。3.2 第二步外设初始化HAL 库函数完成配置好图形化界面后点击生成代码。CubeMX 会在main.c文件之前的MX_GPIO_Init()等函数里生成调用 HAL 库初始化函数的代码。例如static void MX_GPIO_Init(void) { GPIO_InitTypeDef GPIO_InitStruct {0}; // ... 时钟使能代码HAL 库自动处理了 // 配置结构体赋值 GPIO_InitStruct.Pin GPIO_PIN_5; GPIO_InitStruct.Mode GPIO_MODE_OUTPUT_PP; // 推挽输出 GPIO_InitStruct.Pull GPIO_NOPULL; GPIO_InitStruct.Speed GPIO_SPEED_FREQ_LOW; // 调用初始化函数 HAL_GPIO_Init(GPIOA, GPIO_InitStruct); }这个函数会在main函数一开始由HAL_Init()和SystemClock_Config()之后调用。它的作用是把第一步的“图纸”变成硬件里的实际电路状态。3.3 第三步业务逻辑控制你写的代码初始化完成后在while(1)主循环里你就可以像 Arduino 那样“使用”这个引脚了只不过函数名变了输出高电平HAL_GPIO_WritePin(GPIOA, GPIO_PIN_5, GPIO_PIN_SET);输出低电平HAL_GPIO_WritePin(GPIOA, GPIO_PIN_5, GPIO_PIN_RESET);读取输入电平HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_0);翻转输出电平HAL_GPIO_TogglePin(GPIOA, GPIO_PIN_5);现在把这三步连起来看CubeMX 配置决定了硬件资源的分配和基础参数图纸。MX_xxx_Init初始化将配置写入硬件寄存器施工。HAL_xxx_yyy控制在初始化好的硬件上进行操作入住和使用。这就是 HAL 库的标准工作流。UART、I2C、SPI、ADC、定时器等所有外设都遵循这个“配置 - 初始化 - 使用”的模式。掌握这个模式你就拿到了打开 STM32 所有外设大门的通用钥匙。4. 第一个实战用 HAL 库实现 LED 闪烁与按键检测理论懂了我们立刻实战。这个例子将涵盖 GPIO 输出LED和输入按键并引入延时函数和按键消抖这两个实际项目必用的概念。4.1 硬件设计与 CubeMX 配置假设硬件连接如下LED 连接在PA5低电平点亮共阴极接法。按键连接在PB0一端接地另一端通过电阻上拉到 3.3V按下为低电平。在 CubeMX 中操作打开之前创建的Test_LED项目或新建一个。找到PA5左键点击选择GPIO_Output。找到PB0左键点击选择GPIO_Input。在左侧System Core-GPIO中分别点击PA5和PB0进行详细配置PA5GPIO output level先设High初始高电平LED 灭。Mode选Output Push Pull。Pull-up/Pull-down选No pull-up and no pull-down。Maximum output speed选Low点灯不需要高速。PB0Mode选Input。Pull-up/Pull-down选Pull-up启用内部上拉电阻这样按键未按下时引脚被拉高到 3.3V。点击GENERATE CODE覆盖原有代码。4.2 编写业务逻辑代码打开main.c找到while (1)循环。我们将实现按下按键时LED 快速闪烁作为指示松开按键时LED 慢速闪烁。/* 在 main.c 的 while(1) 循环中 */ while (1) { /* 1. 读取按键状态 */ if(HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_0) GPIO_PIN_RESET) // 按键被按下引脚为低电平 { /* 按键按下消抖延时一小段时间再次检测 */ HAL_Delay(20); // 延时20ms避开机械按键的抖动期 if(HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_0) GPIO_PIN_RESET) // 确认仍然按下 { /* 快速闪烁亮100ms灭100ms */ HAL_GPIO_WritePin(GPIOA, GPIO_PIN_5, GPIO_PIN_RESET); // LED 亮 HAL_Delay(100); HAL_GPIO_WritePin(GPIOA, GPIO_PIN_5, GPIO_PIN_SET); // LED 灭 HAL_Delay(100); } } else { /* 慢速闪烁亮500ms灭500ms */ HAL_GPIO_WritePin(GPIOA, GPIO_PIN_5, GPIO_PIN_RESET); // LED 亮 HAL_Delay(500); HAL_GPIO_WritePin(GPIOA, GPIO_PIN_5, GPIO_PIN_SET); // LED 灭 HAL_Delay(500); } }代码解析与经验点HAL_Delay()这是 HAL 库提供的毫秒级延时函数基于系统滴答定时器SysTick。在入门阶段可以放心用但它是一个“阻塞式”延时意味着 CPU 在这段时间里什么也干不了。后续学习定时器中断后可以做出更高效的“非阻塞”闪烁效果。按键消抖机械按键在按下和松开的瞬间会产生一段时间的电平抖动多次快速的高低变化。如果不处理一次按压会被误判为多次。HAL_Delay(20)后再次检测是最简单的软件消抖方法。电平逻辑注意你的 LED 电路是低电平点亮还是高电平点亮代码中的SET和RESET要对应。4.3 编译、下载与调试编译点击 Build 按钮。确保 0 错误0 警告。如果有警告通常是一些未使用的变量或参数初期可以忽略但最好养成消除警告的习惯。下载点击 Debug 按钮。程序会自动编译、下载并进入调试视图。运行与观察在调试视图点击Resume(F8) 让程序全速运行。观察开发板上的 LED应该处于慢速闪烁状态。按下按键LED 应变为快速闪烁松开恢复慢闪。基础调试技巧设置断点在if语句那一行左侧双击可以设置断点。当程序运行到此处时会暂停你可以查看变量、外设状态。单步执行按 F5 或点击Step Into可以一行一行执行代码观察程序流。查看变量/外设寄存器在Window - Show View - Variables或SFRs(特殊功能寄存器) 中可以查看内存和硬件状态。这个简单的例子已经完整走通了 STM32 HAL 库开发的整个闭环CubeMX 配置 - 生成初始化代码 - 编写应用逻辑 - 编译下载 - 调试验证。你接下来要学的任何其他外设都是在这个闭环上增加新的“配置模块”和“HAL 库函数调用”。5. 进阶一步理解时钟树与使用串口打印信息点亮 LED 后下一个最常用的功能就是串口打印。它相当于 STM32 的 “Serial.print()”是调试和输出信息的生命线。配置串口会引出 STM32 另一个核心概念时钟树。5.1 为什么需要配置时钟在 Arduino 中你几乎不用关心 CPU 跑多快外设的时钟从哪里来。但在 STM32 中时钟是芯片的“脉搏”每个外设GPIO、USART、SPI等要工作都必须有时钟信号驱动。时钟源可以是芯片内部的 RC 振荡器精度较低也可以是外部晶振精度高。时钟树配置决定了CPU 主频HCLK有多快这直接影响代码执行速度。外设总线时钟PCLK1,PCLK2是多少这决定了 UART 的波特率、SPI 的速率等。使用哪个时钟源这关系到系统稳定性和功耗。经验之谈对于初学者在 CubeMX 的Clock Configuration选项卡里一个安全的做法是点击HCLK输入框然后按回车键让 CubeMX 根据你选择的芯片和外部晶振自动计算并配置出一套最大、最稳定的时钟树。你可以看到各个时钟频率的数值变化。先接受这个自动配置让它跑起来以后再深究细节。5.2 配置 USART 串口通信假设我们使用 USART1其 TX 引脚是PA9RX 引脚是PA10通过 USB 转 TTL 模块连接电脑。CubeMX 引脚配置在引脚图上将PA9设置为USART1_TXPA10设置为USART1_RX。左侧找到Connectivity-USART1。Mode选择Asynchronous异步模式。Basic Parameters中设置Baud Rate为115200常用波特率。Word Length为8 Bits。Parity为None。Stop Bits为1。其他保持默认。生成代码点击生成代码。CubeMX 会自动在main.c中生成MX_USART1_UART_Init()函数并配置好时钟和引脚。5.3 使用 HAL 库函数打印信息HAL 库提供了阻塞式和非阻塞式中断/DMA的串口收发函数。我们先从最简单的阻塞式开始。在main.c的/* USER CODE BEGIN 2 */和/* USER CODE END 2 */之间这是 CubeMX 为你保留的、不会被覆盖的代码区域可以添加初始化后的用户代码。我们在这里重定向printf函数到串口。添加头文件和重定向代码在main.c的顶部/* USER CODE BEGIN Includes */区域#include stdio.h重定向printf在/* USER CODE BEGIN 0 */区域// 重写 _write 函数将 printf 输出到串口 int _write(int file, char *ptr, int len) { HAL_UART_Transmit(huart1, (uint8_t *)ptr, len, HAL_MAX_DELAY); return len; }HAL_UART_Transmit是阻塞式发送函数HAL_MAX_DELAY表示无限等待直到发送完成。在代码中使用printf在while(1)循环中uint32_t counter 0; while (1) { printf(Hello STM32! Counter: %lu\r\n, counter); // \r\n 是换行 HAL_GPIO_TogglePin(GPIOA, GPIO_PIN_5); // 翻转 LED指示程序在运行 HAL_Delay(1000); // 延时1秒 }连接与查看将 USB 转 TTL 模块的 TX 接开发板的PA10(RX)RX 接PA9(TX)GND 互连。电脑上打开串口调试助手如 Putty、SecureCRT 或 Arduino IDE 的串口监视器选择正确的 COM 口波特率设为115200。下载程序并运行。你应该能在串口助手看到每秒打印一次的消息同时 LED 每秒闪烁一次。成功关键点接线正确TX 对 RXRX 对 TX。波特率一致代码和串口助手必须都是115200。供电稳定确保开发板供电充足。代码位置用户代码要写在USER CODE BEGIN/END注释对之间否则下次用 CubeMX 重新生成代码时会被覆盖。6. 从阻塞到中断更高效的串口接收上面的HAL_UART_Transmit和printf是阻塞式的发送数据时 CPU 只能等待。对于接收数据阻塞式 (HAL_UART_Receive) 更糟糕因为你不知道数据何时会来。这时就需要中断。6.1 中断是什么你可以把它理解为一个“硬件级别的插队机制”。当某个事件发生时如串口收到一个字节、按键按下、定时器时间到CPU 会暂停当前正在执行的代码转去执行一段你预先写好的特殊函数中断服务函数处理完这个紧急事件后再回来继续执行原来的代码。6.2 配置串口接收中断CubeMX 配置在 USART1 的配置界面NVIC Settings选项卡下勾选USART1 global interrupt使能中断。生成代码。编写中断接收代码在main.c的/* USER CODE BEGIN 2 */区域启动串口中断接收// 启动串口中断接收设置一个缓冲区 uint8_t rx_buffer[1]; // 每次接收1个字节 HAL_UART_Receive_IT(huart1, rx_buffer, 1);在main.c文件末尾/* USER CODE BEGIN 4 */区域编写中断回调函数。当串口收到一个字节后会自动进入此函数void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart) { if(huart-Instance USART1) // 判断是哪个串口触发的中断 { // 在这里处理接收到的数据rx_buffer[0] 就是收到的字节 printf(Received: %c (0x%02X)\r\n, rx_buffer[0], rx_buffer[0]); // 重要重新启动中断接收否则只接收一次 HAL_UART_Receive_IT(huart1, rx_buffer, 1); } }测试编译下载后在串口调试助手向开发板发送任意字符。开发板会立即将收到的字符及其十六进制值打印回来。整个过程主循环的printf和 LED 闪烁不受任何影响这就是非阻塞的优势。中断模式的核心优势CPU 解放了。主循环可以专心做其他事情比如扫描按键、刷新显示只有当数据真正到达时才被中断短暂打断去处理。这极大地提高了系统的响应效率和实时性。7. 项目实战框架构建一个简单的多任务系统当你掌握了 GPIO、延时、串口和中断后就可以尝试把这些组合起来构建一个简单但结构清晰的小项目。这能帮你建立“前后台”或“超级循环”系统的初步概念。项目目标创建一个系统实现以下功能任务 A后台LED 以 1Hz 频率闪烁指示系统“活着”。任务 B中断驱动通过串口接收命令。收到字符1时点亮一个额外的 LED或蜂鸣器响收到字符0时关闭它。任务 C主循环每 5 秒通过串口发送一次系统运行状态报告。7.1 硬件与 CubeMX 配置LED1 (PA5)系统心跳灯。LED2 (PA6)命令控制灯。USART1 (PA9/PA10)串口通信。在 CubeMX 中配置好以上引脚并使能 USART1 全局中断。7.2 代码结构设计/* 在 main.c 的合适位置定义变量 */ /* USER CODE BEGIN PV */ uint32_t sys_tick 0; // 系统滴答计数器在 SysTick 中断中递增 uint8_t uart_rx_byte; uint8_t led2_state 0; // 0off, 1on /* USER CODE END PV */ /* 在 main 函数初始化部分 */ /* USER CODE BEGIN 2 */ // 启动串口接收中断 HAL_UART_Receive_IT(huart1, uart_rx_byte, 1); /* USER CODE END 2 */ /* 主循环 */ while (1) { /* 任务A心跳LED使用 sys_tick 非阻塞实现 */ static uint32_t led1_last_toggle 0; if((sys_tick - led1_last_toggle) 500) // 500ms 0.5s, 周期1s { led1_last_toggle sys_tick; HAL_GPIO_TogglePin(GPIOA, GPIO_PIN_5); } /* 任务C每5秒发送状态报告 */ static uint32_t report_last_sent 0; if((sys_tick - report_last_sent) 5000) // 5000ms 5s { report_last_sent sys_tick; printf([SysReport] Tick: %lu, LED2 State: %d\r\n, sys_tick, led2_state); } /* 主循环还可以做其他事情比如扫描矩阵键盘等 */ // ... 其他任务 /* 短暂延时避免主循环空转耗光CPU。也可以用更优雅的方式。 */ HAL_Delay(1); } /* 串口接收中断回调函数 */ void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart) { if(huart-Instance USART1) { /* 任务B处理命令 */ if(uart_rx_byte 1) { HAL_GPIO_WritePin(GPIOA, GPIO_PIN_6, GPIO_PIN_SET); led2_state 1; printf(CMD: LED2 ON\r\n); } else if(uart_rx_byte 0) { HAL_GPIO_WritePin(GPIOA, GPIO_PIN_6, GPIO_PIN_RESET); led2_state 0; printf(CMD: LED2 OFF\r\n); } // 重新启动中断接收 HAL_UART_Receive_IT(huart1, uart_rx_byte, 1); } } /* SysTick 中断处理HAL库已实现我们需要在其中递增自己的计数器*/ // 在 main.c 中找到 void HAL_IncTick(void) 函数在 USER CODE 区域添加 /* USER CODE BEGIN IncTick */ sys_tick; // 每毫秒递增一次 /* USER CODE END IncTick */7.3 这个框架带来的经验时间管理使用sys_tick配合时间戳比较 (sys_tick - last_time) 来实现定时任务替代了纯粹的HAL_Delay()。这是实现多任务非阻塞调度的基础。事件驱动串口命令处理是典型的事件驱动由中断触发不占用主循环时间。状态变量使用led2_state这样的变量来记录系统状态方便在任务间传递信息如状态报告任务。代码结构将不同功能的代码模块化放在不同的区域主循环、中断回调逻辑更清晰。这个框架虽然简单但已经包含了嵌入式系统最核心的几种编程模式。在此基础上你可以引入定时器中断来更精确地管理sys_tick或者学习 FreeRTOS 这样的实时操作系统来更优雅地管理多任务。8. 避坑指南与下一步学习路径从 Arduino 过渡到 STM32 HAL初期一定会遇到各种问题。下面是我总结的几个最常见“坑”和解决思路。8.1 编译下载与调试常见问题问题现象可能原因排查步骤编译错误未定义引用1. 未包含必要的头文件。2. 未将对应的.c文件加入编译。3. 拼写错误。1. 检查#include是否正确。2. 在 CubeMX 中确认所需外设已开启如 I2C、SPI。3. 仔细核对函数名、变量名。下载失败无法连接目标1. ST-Link 驱动未安装或异常。2. 接线错误SWDIO, SWCLK, GND。3. 开发板供电不足或未供电。4. 芯片被锁读保护。1. 检查设备管理器是否有 ST-Link 设备感叹号则重装驱动。2. 核对 SWD 四根线确保接触良好。3. 测量开发板 3.3V 电压是否正常。4. 尝试使用 CubeProgrammer 连接并解除读保护。程序无反应1. 时钟配置错误尤其是外部晶振。2. 中断优先级冲突导致死锁。3. 堆栈溢出。1. 先用内部时钟HSI测试排除晶振问题。2. 简化代码屏蔽所有中断看主循环能否运行。3. 在startup_stm32f1xx.s等启动文件中适当增大堆栈大小。串口无输出1. TX/RX 线接反。2. 波特率、数据位、停止位不匹配。3.printf未重定向或重定向函数未实现。4. 串口助手未正确打开端口或设置。1. 交换 TX/RX 线序测试。2. 核对代码和串口助手设置确保完全一致。3. 使用HAL_UART_Transmit直接发送固定字符串测试绕过printf。4. 换一个串口调试工具试试。8.2 下一步学习路径建议不要试图一次性学完所有外设。按照“需求驱动循序渐进”的原则巩固基础把 GPIO输入输出、外部中断、定时器基本定时、PWM输出、USART串口这四大件玩熟。它们构成了 80% 项目的基础。学习通信协议I2C用于连接 OLED 屏幕、温湿度传感器、EEPROM 等。重点理解地址、起始信号、停止信号、应答。SPI用于连接 Flash、SD 卡、显示屏如 ILI9341。重点理解主从模式、时钟极性相位。学习时先用逻辑分析仪或示波器抓取波形对照协议手册看理解远比死记函数重要。掌握模拟功能ADC采集模拟信号电位器、光敏电阻。理解分辨率、采样时间、参考电压。DAC输出模拟信号生成波形。深入理解中断与 DMA中断嵌套与优先级理解 NVIC避免优先级倒置导致的问题。DMA实现数据在内存和外设间“自动”搬运极大解放 CPU。从串口 DMA 收发、ADC 连续采样 DMA 传输开始学。引入 RTOS当你的项目需要同时处理多个周期性或事件性任务时如同时控制电机、读取传感器、处理通信、更新显示就该学习 FreeRTOS 了。理解任务、队列、信号量、互斥锁这些核心概念。关注功耗与优化学习睡眠、停机、待机模式以及如何关闭不用的外设时钟来降低功耗。从 Arduino 到 STM32 HAL最大的转变不是语法而是思维从“调用一个魔法函数”到“理解并配置硬件然后驱动它”。这个过程开始会有些陡峭但一旦你跨过去面对任何复杂的嵌入式需求你都会拥有拆解和实现的能力。记住多动手多调试从让一个 LED 听话开始逐步增加复杂度每一步都确保理解透彻。
返回列表