← 返回文章库

ESP-IDF → STM32 迁移对照总指南(S 卷收尾)

最后更新 2026-06-22
⏱ 约 20 分钟 🟢 软件/低风险
你将学到
  • 拿到一张 ESP-IDF ↔ STM32 HAL 的全面对照表,把已有的 ESP32-S3 经验逐条平移到 STM32
  • 转过五个最关键的思维弯(menuconfig→CubeMX、ESP_LOGI→自搭 UART、内置 FreeRTOS→CubeMX 勾选、无线优先→有线工业、串口 monitor→SWD 断点调试)
  • 用一张迁移检查清单,在换芯片前把"外设够不够、有没有 HAL 例程、生态认证、团队熟不熟"问清楚
  • 客观认清 STM32 相对 ESP32-S3 的优势(真断点调试/实时性/外设)与劣势(无无线/上手陡)

走到这一篇,说明你已经把主线啃下来了:idf.py build flash monitor 一条龙,gpio_set_levelledci2c_master、FreeRTOS 任务,闭着眼都能写。现在有个项目把 STM32 摆到了你面前——可能是客户指定、可能是要更稳的实时性、要工业级温度范围、要一颗你能稳定拿货的 MCU。你前面 S 卷几篇已经分别学了 CubeMX + HAL 点灯、HAL 常用外设、STM32 上跑 FreeRTOS。这最后一篇不再教新东西,而是把整卷拉成一张总对照地图:你脑子里那套 ESP-IDF 经验,到底哪一条对应 STM32 的哪一条,哪些是换了个名字、哪些是思路要拐弯。看完这篇,你换芯片时心里有谱,不会对着 CubeMX 干瞪眼。

📌 说明

这是 S 卷(STM32 迁移)的收尾篇,承上启下,所以得把丑话再说一遍:下表里 STM32 一侧的函数名、宏、引脚号、句柄名(huart1/hi2c1 之类),都和你具体用的芯片型号、HAL 库版本、CubeMX 版本强相关。 本篇给的是经验平移的对照关系——记住"这件事在 ESP-IDF 叫 A、在 STM32 叫 B"就够了,落到代码时函数签名请以**你 CubeMX 实际生成的工程 + ST 官方 HAL 文档(UM1725 这类)**为准。本篇不把任何一行 HAL 代码呈现为"确定无误"。


大对照表:ESP-IDF ↔ STM32 HAL 全面对照

这是整篇的主干,也是 S 卷的总账。左边是你熟的 ESP-IDF,中间是 STM32 HAL 的对应做法,右边是最该记住的差异。记一条原则:ESP-IDF 把"配置"藏在代码和 menuconfig 里,STM32 把"配置"挪到了 CubeMX 图形界面、把"调用"留在 HAL 代码里。 凡是 ESP-IDF 里在代码里配的(引脚方向、外设参数),到 STM32 大多移到了 CubeMX。

主题 你在 ESP-IDF 里这么做 STM32 HAL 里对应这么做 关键差异
工程/构建 idf.py build / flash / monitor,CMake + 组件管理器 CubeMX 生成工程 → CubeIDE/Keil/Makefile 编译 → CubeProgrammer/OpenOCD 烧 一个命令行一条龙;一个图形配 + IDE 编译,分两件事
依赖管理 idf.py add-dependency,组件注册表 没有统一包管理;HAL 随 CubeMX 生成,第三方库手动拖进工程 STM32 生态散,库要自己找/集成
配置外设 menuconfig(图形 Kconfig)+ 代码里填结构体 CubeMX 图形点引脚/时钟/外设 → GENERATE STM32 时钟树、引脚复用必须在 CubeMX 里配
程序入口 void app_main(void)(IDF 起好 RTOS 后调它) int main(void) + while(1)(裸机风格标准 C) STM32 默认是裸机;要 RTOS 得自己起(见下)
GPIO 方向 gpio_set_direction(.., GPIO_MODE_OUTPUT) 代码里配 在 CubeMX 里把引脚点成 GPIO_Output/Input STM32 方向在 CubeMX 配,不在代码里
GPIO 写 gpio_set_level(GPIO_NUM_2, 1) HAL_GPIO_WritePin(GPIOC, GPIO_PIN_13, GPIO_PIN_SET) 引脚用 GPIOx + GPIO_PIN_y 两段表示
GPIO 读/翻转 gpio_get_level();翻转要自己读后写 HAL_GPIO_ReadPin() / HAL_GPIO_TogglePin() HAL 自带 Toggle,点灯更省
延时 vTaskDelay(pdMS_TO_TICKS(500))(RTOS 让出 CPU) HAL_Delay(500)(裸机阻塞死等) 裸机 HAL_Delay 卡死 CPU;上 RTOS 后用 osDelay
PWM ledc 通道/定时器 + ledc_set_duty 定时器 PWM 模式 + HAL_TIM_PWM_Start + __HAL_TIM_SET_COMPARE STM32 PWM 是定时器的一个输出模式,先在 CubeMX 配 TIMx 通道
ADC adc_oneshot_read / 连续模式 HAL_ADC_Start + HAL_ADC_GetValue(或 DMA 连续) STM32 ADC 分规则/注入组,校准要调 HAL_ADCEx_Calibration_Start
UART uart_driver_install + uart_write_bytes/uart_read_bytes HAL_UART_Transmit / HAL_UART_Receive(含 _IT/_DMA 变体) 句柄 huart1;中断收发回调 HAL_UART_RxCpltCallback
I2C i2c_master_transmit / i2c_master_receive(新驱动) HAL_I2C_Master_Transmit / HAL_I2C_Mem_Read STM32 地址常用8 位左移写法,ESP-IDF 用 7 位,最爱踩这个坑
SPI spi_device_transmit + 事务结构体 HAL_SPI_Transmit / HAL_SPI_TransmitReceive STM32 片选(CS)常要你自己拉 GPIO,HAL 不一定替你管
定时器 esp_timer(软件定时器)/ gptimer(硬件) 硬件 TIMx + HAL_TIM_Base_Start_IT + HAL_TIM_PeriodElapsedCallback STM32 定时器是核心外设,PWM/编码器/输入捕获全靠它
RTOS FreeRTOS 内置xTaskCreate 直接用 CubeMX 勾 FreeRTOS(CMSIS-RTOS) → osThreadNew STM32 要在 CubeMX 里开 RTOS,API 包了层 CMSIS(见 S.5
中断 gpio_isr_handler_add 注册回调 CubeMX 使能 NVIC + 写 HAL_GPIO_EXTI_Callback STM32 中断号、优先级在 CubeMX 的 NVIC 表里配
日志/调试 ESP_LOGI(TAG, "...") 开箱即用 没有! 自己配 UART + 重定向 printf,或用 SWO/ITM STM32 第一个不适应的点,下面详说
下载调试 USB 串口直接下载 + idf.py monitor 看串口 ST-Link + SWD,IDE 里真断点单步调试 STM32 调试体验更强,这是它的一个明显优势
📌 说明

I2C 地址那一行我单独拎出来提醒:ESP-IDF 用 7 位地址(比如 0x48),HAL 的很多函数要的是左移一位后的 8 位地址(0x48 << 1 = 0x90)。从 ESP32 迁过来照搬地址,设备死活不应答,九成是这个。具体哪个 HAL 函数要几位,查 UM1725 对应函数说明,别凭记忆。


思维转变:五个必须拐过来的弯

光记函数对照还不够。从 ESP-IDF 到 STM32,真正卡人的是几个习惯要换掉。我按踩坑频率从高到低排。

① 从 menuconfig/组件管理器 → CubeMX 图形配 + USER CODE 区。 ESP-IDF 你习惯在 menuconfig 里翻菜单、在代码里 idf.py add-dependency 拉库。STM32 把配置全挪到了 CubeMX:在引脚图上点、在时钟树上配、勾外设、点 GENERATE 生成一整套初始化代码。最大的新规矩是——你的代码只能写在 /* USER CODE BEGIN x *//* USER CODE END x */ 之间,写外面,下次回 CubeMX 改配置重新 GENERATE 时会被整段冲掉。这个机制在 ESP-IDF 里没有对应物,是 STM32 新手最常丢代码的地方。

② 从 ESP_LOGI 的日志习惯 → STM32 要自己搭打印。 这是从 ESP32 过来最不适应的一点。ESP-IDF 一行 ESP_LOGI(TAG, "temp=%d", t) 就有带颜色、带时间戳、可分级过滤的日志。STM32 的 HAL 什么都没有——你得自己在 CubeMX 配一个 USART,再把 C 库的 _write(GCC)或 fputc(Keil)重定向到这个串口,才能用 printf。或者走 SWD 调试器的 SWO/ITM 通道打印(不占额外引脚)。搭好之前,你连个变量都不知道怎么看。

/* STM32: 重定向 printf 到 UART(GCC 工具链),放 USER CODE 区或单独 .c
   这是 ESP-IDF 里 ESP_LOGI 一行就有、STM32 要自己补的一课 */
int _write(int fd, char *ptr, int len)
{
  HAL_UART_Transmit(&huart1, (uint8_t *)ptr, len, 100);  // huart1 由 CubeMX 生成
  return len;
}
/* 之后才能 printf("temp=%d\r\n", t); */

③ 从内置 FreeRTOS → CubeMX 勾选 + CMSIS-RTOS。 ESP-IDF 里 FreeRTOS 是地基,app_main 本身就跑在一个任务里,xTaskCreate 张手就来。STM32 默认是裸机 main() + while(1),想用 RTOS 得在 CubeMX 里把 FreeRTOS(CMSIS-RTOS v2) 勾上、配好任务,生成后用 osThreadNewosDelay 这套 CMSIS 包装 API。注意 HAL_Delay 在 RTOS 下别乱用(它是阻塞死等),任务里要用 osDelay。这块怎么从 xTaskCreate 平移到 osThreadNewS.5 STM32 上跑 FreeRTOS 那篇讲透了。

④ 从无线优先 → 有线/工业优先。 ESP32-S3 你的默认设定是"先连上 WiFi/蓝牙再说",整个主线 L3 都围着无线转。STM32(指主流 F/G/H 系列)自身不带无线——要联网得外挂模组(ESP32 当通信协处理器、或接 4G/LoRa 模块)。但 STM32 强在另一头:CAN 总线、RS485、以太网 MAC、更多更准的定时器和 ADC、工业级温度范围。换芯片往往就是换需求重心:从"这东西要联网"变成"这东西要稳、要实时、要扛工业环境"。脑子里那根"先联网"的弦,迁过来得先松一松。

⑤ 从串口 monitor → ST-Link + SWD 断点调试。 这条是好消息。ESP32 调试你大概率靠 ESP_LOGI 打印满天飞(虽然 ESP32 也能 JTAG 调试,但日常多是打印流)。STM32 配 ST-Link + SWD 后,在 CubeIDE/Keil 里能打真断点、单步执行、悬停看变量和寄存器、看调用栈——这套硬件断点调试体验比 ESP32 日常顺手得多,定位"卡在哪一行""这变量啥时候变的"快太多。从"加打印重新烧"的循环,升级成"断点停下来直接看",这是 STM32 给你的一个实打实的红利。


迁移检查清单:换芯片前先问这四件事

别一拍脑袋就换。换 MCU 是有成本的(重学工具链、重画 PCB、重测)。下决定前,对着这张表过一遍:

维度 要问清楚的问题 怎么查
外设够不够 你要的 UART/SPI/I2C/CAN/ADC 通道数、定时器路数、Flash/RAM 大小,目标型号够不够? CubeMX 选型器(按外设需求筛芯片)+ ST 官网产品选型表
有没有现成 HAL 例程 你要接的传感器/屏/通信,这颗芯片有没有官方或社区的 HAL 例程能抄? ST 的 STM32CubeFx 固件包自带 examples;GitHub 搜型号+外设
生态/认证 量产要不要过认证?这颗芯片有没有现成的认证参考设计、长期供货承诺(LTS)? ST 官网 longevity 承诺页;你客户/行业的认证要求
团队熟悉度 团队(或你)有没有人碰过 STM32 + CubeMX?学习曲线的时间成本算进项目排期了吗? 诚实评估;CubeMX 上手陡,第一个项目要留学习 buffer

一句话:换芯片是工程决策,不是技术炫技。 外设和例程决定能不能做,生态认证决定能不能量产,团队熟悉度决定多久能做出来——四个维度有一个塌了,就得重新想想。


常见误区:从 ESP32 过来最容易栽的几个跟头

  • 以为 STM32 也"开机就联网"。 没有。主流 STM32 不带 WiFi/蓝牙,联网要外挂模组。把 L3 那套无线思路直接搬,第一步就卡住。
  • 照搬 I2C 7 位地址。 ESP-IDF 用 7 位,HAL 很多函数要 8 位(左移一位)。设备不应答先查这个,前面表里专门标了。
  • 代码写在 USER CODE 区外。 重新 GENERATE 一次就没了。所有自己的代码只往 BEGIN/END 之间塞。
  • RTOS 任务里用 HAL_Delay 它是阻塞死等,会卡死整个调度。RTOS 下用 osDelay,这点和 ESP-IDF 用 vTaskDelay 同理,但函数名变了。
  • 指望 printf 开箱即用。 不重定向 _write/fputc,printf 什么都打不出来。日志这件 ESP-IDF 免费的事,STM32 要自己搭一次。
  • 时钟树不配就开干。 ESP32 默认时钟帮你定好了,STM32 不配时钟树 HAL_Delay 都不准、外设全乱。CubeMX 时钟页别留红。

小结 · S 卷收尾

到这儿,STM32 迁移卷走完了。把这一卷攥成一句话:STM32 不比 ESP32 难,是把 ESP-IDF 替你藏起来的"配置"摊到了 CubeMX 面前,把"无线优先"换成了"有线/实时/工业优先"。

  • 你拿到了一张 ESP-IDF ↔ STM32 HAL 全面对照表:工程/构建、入口、GPIO、延时、PWM、ADC、UART、I2C、SPI、定时器、RTOS、中断、日志,逐条能平移。最该记的原则——ESP-IDF 在代码/menuconfig 里配的东西,STM32 大多挪到了 CubeMX
  • 你转过了五个思维弯:menuconfig→CubeMX + USER CODE 区、ESP_LOGI→自搭 UART/SWO 打印、内置 FreeRTOS→CubeMX 勾 CMSIS-RTOS、无线优先→有线工业优先、串口 monitor→ST-Link + SWD 真断点调试。
  • 你有了一张迁移检查清单:换芯片前问清外设够不够、有没有 HAL 例程、生态认证、团队熟悉度——换芯片是工程决策不是炫技。
  • 客观说 STM32 的优劣:优势是真断点调试体验、实时性、更强更准的定时器/ADC/工业总线;劣势是自身无无线、CubeMX 上手陡、生态散库要自己集成。选它还是选 ESP32-S3,看你这个项目要的是"联网方便"还是"稳和实时"。
  • 最重要的一条:全卷的 HAL 代码都是对照/主干参考,函数名/宏/引脚强依赖芯片型号与 HAL 版本,以 CubeMX 实际生成的工程 + ST 官方文档为准,别当成确定无误。

S 卷是条小支线,目的是让你"够用即迁移"——不是把你培养成 STM32 专家,而是让吃透 ESP-IDF 主线的你,换芯片时不慌、能上手、知道去哪查。想从头回看这条迁移路线,去 STM32 迁移卷总览;想回主线继续把 ESP32-S3 的产品级能力往深里挖,回 学习路线总览

📄 来源 / 自校链接

本文为公开资料整理,非亲测。关键参数与代码请结合实物与下列官方来源验证。

内容有错、看不懂、或想看下一期?告诉我们 →

本文为公开资料的学习整理,非亲测。涉接线/花钱/合规的步骤请结合实物与官方最新资料验证,风险自负。见免责声明