1. 从STM32到国产替代一个嵌入式老兵的年度观察去年这个时候我手里同时开着三个项目一个基于STM32F103的工业采集板、一个用GD32F303做的电机控制方案还有一个客户指定要评估的CH32V103R8T6开发板。说实话刚开始我对后两款芯片是带着试试看的心态——毕竟过去十年STM32几乎是我所有嵌入式项目的默认选项从标准库到HAL库从F1到F4再到H7闭着眼睛都能把工程搭起来。但一年下来这三个平台我都完成了从原型到小批量交付的完整流程踩过的坑、积累的经验、对国产芯片的真实感受远比网上那些国产替代的口号要复杂得多。这篇文章不打算给你灌什么国产崛起或者还是进口香的结论我只想把这十二个月里在STM32、GD32、CH32V103这三个平台上实际遇到的技术细节、选型逻辑、迁移成本、调试技巧原原本本地摊开来讲。如果你正在做嵌入式项目选型或者被供应链逼着考虑国产方案又或者单纯想了解RISC-V内核的MCU到底能不能打那这篇内容应该能帮你省下不少试错时间。先给个整体印象STM32依然是那个最不会出错的选择生态成熟到令人发指但价格和交期在过去两年确实让人头疼GD32作为最像STM32的国产替代在硬件引脚和软件库层面做到了近乎无缝迁移但在某些外设细节和低功耗表现上有自己的脾气CH32V103则是完全不同的技术路线——RISC-V内核、自研工具链、全新的开发习惯它不适合所有人但在特定场景下能给你惊喜。下面我分几个维度把这一年的实战经验拆开来讲。2. 三个平台的核心架构与选型逻辑拆解2.1 为什么是这三款芯片选型背后的真实考量先说说我为什么选这三款。STM32F103C8T6是经典中的经典Cortex-M3内核72MHz主频64KB Flash20KB RAM用来做工业数据采集和简单控制绰绰有余。它的价值在于确定性——你知道它能做什么知道代码怎么写知道出了问题去哪里找答案。我手上这个采集板需要同时跑ADC多通道采样、UART与上位机通信、定时器捕获测频率还要留出CAN总线接口做备份F103的资源刚好卡在够用线上。GD32F303CBT6是客户指定的替代方案原因很简单当时STM32F103的采购周期拉到了26周以上而GD32F303有现货价格还便宜三成。GD32F303是Cortex-M4内核主频120MHz128KB Flash32KB RAM性能比F103强不少。客户的需求是电机控制需要跑FOC算法对运算能力有要求M4内核带FPU和DSP指令集理论上比M3更合适。但问题在于客户原有的代码是基于STM32标准库写的迁移到GD32需要评估工作量。CH32V103R8T6则是另一个客户的产品预研项目要求全国产化BOM主控必须用RISC-V内核。CH32V103是沁恒微电子的产品RISC-V内核80MHz主频64KB Flash20KB RAM外设资源跟STM32F103基本对标。选它的理由很直接这是当时市面上少数能买到现货、有完整中文文档、且价格控制在10元以内的RISC-V MCU。2.2 内核差异对实际开发的影响从Cortex-M3到Cortex-M4再到RISC-V内核差异到底意味着什么我用一个具体场景来说明。在电机控制项目中FOC算法需要做大量的乘加运算和三角函数计算。STM32F103的M3内核没有硬件FPU浮点运算靠软件模拟跑一遍FOC大概需要80微秒GD32F303的M4内核带单精度FPU同样的算法只需要25微秒左右。这个差距在低速运行时影响不大但当电机转速拉到每分钟3000转以上控制周期被压缩到50微秒以内时M3就力不从心了而M4还能留出余量做电流环和速度环的双环控制。CH32V103的RISC-V内核在整数运算上表现不错但浮点性能是短板。我实测下来同样的FOC算法在CH32V103上跑一遍需要120微秒左右比STM32F103还慢。所以这款芯片我最终没有用在电机控制上而是转去做了一个数据采集网关——那里主要是整数运算和通信协议处理RISC-V内核完全够用。这里有个经验选芯片不要只看主频和内核型号一定要把实际算法跑一遍。我见过太多项目在选型时只看参数表结果代码写完了才发现算力不够那时候换芯片的成本就大了。2.3 工具链与开发环境的迁移成本STM32的开发环境不用多说Keil MDK、IAR、STM32CubeIDE、PlatformIO甚至用VSCode加插件都能搭起来。我习惯用Keil MDK加STM32CubeMX的组合图形化配置引脚和时钟树生成初始化代码然后手写业务逻辑。这套流程我用了快八年闭着眼睛都能操作。GD32的迁移成本比我预想的低。GD32官方提供了GigaDevice.GD32F30x_DFP芯片包可以直接装在Keil里新建工程时选GD32F303CBT6就行。更关键的是GD32的标准库函数名和STM32几乎一模一样比如GPIO_Init()、USART_Init()、TIM_TimeBaseInit()连参数结构体的成员名都相同。我把STM32的工程直接复制过来把启动文件换成GD32的把库文件替换掉编译居然一次通过只有几个中断向量表的名称需要调整。但这里有个坑GD32的SystemInit()函数默认把主频设到120MHz而STM32F103的SystemInit()是72MHz。如果你直接移植代码延时函数的时间基准会全部错乱。我当时的串口通信直接乱码排查了半天才发现是时钟频率变了延时函数的循环次数没跟着改。后来我养成了一个习惯每次迁移平台第一件事就是用一个GPIO翻转加示波器测实际延时确认时钟配置无误后再往下做。CH32V103的工具链则是完全不同的体验。它不能用Keil MDK开发官方推荐的是MounRiver Studio一个基于Eclipse的IDE集成了RISC-V GCC工具链和WCH-Link调试器驱动。刚开始我很不适应——Eclipse的界面逻辑和Keil差别很大编译速度也慢一些而且中文资料虽然多但英文资料少遇到问题搜索范围有限。不过用了一周之后我发现MounRiver Studio其实挺好用的尤其是它的代码补全和函数跳转功能比Keil的默认配置要顺手。而且它支持直接导入STM32的工程模板虽然不能直接编译但可以参考它的工程结构来组织代码。3. 外设实操对比GPIO、串口、ADC与定时器3.1 GPIO与引脚映射的差异处理GPIO操作是嵌入式开发中最基础的部分但三个平台在这上面的差异却不小。STM32F103的GPIO配置很直观使能时钟、设置模式、设置速度然后就可以读写。GD32F303的GPIO配置流程完全一样但有一个细节需要注意——GD32的GPIO输出速度等级和STM32的对应关系不同。STM32有2MHz、10MHz、50MHz三档GD32有2MHz、10MHz、50MHz、120MHz四档。如果你从STM32移植代码把速度参数直接照搬可能会发现GPIO翻转速度比预期慢因为GD32的默认速度档位对应的实际频率和STM32不一样。CH32V103的GPIO配置则有自己的风格。它的库函数叫GPIO_Init()但参数结构体是GPIO_InitTypeDef成员包括GPIO_Pin、GPIO_Mode、GPIO_Speed。看起来和STM32很像但模式枚举值不同——STM32的GPIO_Mode_Out_PP在CH32V103里叫GPIO_Mode_Out_PP但复用功能的配置方式不一样。CH32V103需要先调用GPIO_PinRemapConfig()来设置复用功能而且重映射的选项比STM32少一些。我遇到过一个具体问题在STM32上USART2的默认引脚是PA2和PA3如果要重映射到PD5和PD6需要开启AFIO时钟并调用GPIO_PinRemapConfig(GPIO_Remap_USART2, ENABLE)。在GD32上这个操作完全一样。但在CH32V103上USART2的重映射选项只有部分引脚可用而且配置函数是GPIO_PinRemapConfig()参数格式也不同。我当时想把USART2映射到PD5和PD6查了手册才发现CH32V103不支持这个映射只能换到其他引脚。这个教训告诉我国产芯片的外设复用功能往往比STM32少选型时一定要先确认引脚映射表。3.2 串口通信的稳定性与波特率误差串口是嵌入式项目中最常用的通信接口三个平台在这方面的表现差异主要体现在波特率精度和中断响应上。STM32F103的USART波特率发生器精度很高在72MHz主频下115200波特率的误差不到0.1%长时间通信很稳定。GD32F303在120MHz主频下波特率误差同样很小但我发现它在高波特率比如921600下的误码率比STM32略高尤其是在电磁干扰较强的电机控制环境中。后来我在GD32的串口引脚上加了RC滤波电路问题才解决。CH32V103的串口在常规波特率下表现正常但在使用内部RC振荡器作为时钟源时波特率误差会明显增大。我实测过用内部RC振荡器跑115200波特率误差大概在2%左右短帧通信没问题但连续传输大量数据时偶尔会出现帧错误。后来我换成了外部8MHz晶振误差降到0.3%以内通信就稳定了。所以如果你用CH32V103做串口通信强烈建议外接晶振不要图省事用内部RC。还有一个细节STM32和GD32的串口中断标志位清除方式一样都是先读SR寄存器再读DR寄存器。但CH32V103的串口中断标志清除需要调用专门的函数USART_ClearITPendingBit()如果你直接照搬STM32的中断服务程序可能会遇到中断反复触发的问题。我第一次移植时就踩了这个坑串口接收中断一直进不去后来查了CH32V103的参考手册才发现中断标志清除方式不同。3.3 ADC多通道采样的精度与切换速度ADC是我在工业采集板上最关注的外设。STM32F103的ADC是12位逐次逼近型最高采样率1MHz支持16个外部通道。我用它做多通道采样时通常用DMA搬运数据规则组扫描模式每个通道采样时间设为55.5个周期这样在72MHz的ADC时钟下单通道转换时间大概1.17微秒8个通道轮询一遍不到10微秒完全满足我的采集需求。GD32F303的ADC参数和STM32F103基本一致也是12位、1MHz采样率但我在实际使用中发现它的通道切换速度比STM32慢一点。具体表现是当我在两个通道之间快速切换时GD32的ADC需要更长的稳定时间否则第二个通道的采样值会偏高。后来我把采样时间从55.5个周期增加到71.5个周期问题就消失了。这个差异在数据手册里没有明确写是我用标准电压源反复测试才发现的。CH32V103的ADC是12位但最高采样率只有1MHz而且它的通道切换逻辑和STM32不同。STM32的ADC在扫描模式下会自动按顺序转换所有配置的通道而CH32V103需要手动触发每个通道的转换或者用DMA配合定时器触发。我刚开始用CH32V103做多通道采样时发现通道之间的数据会串扰后来仔细看手册才知道CH32V103的ADC在切换通道后需要插入一个延时等采样电容稳定后再启动转换。这个延时大概需要1微秒左右我在代码里加了一个__NOP()循环问题就解决了。3.4 定时器捕获与PWM输出的实测对比定时器捕获测频率是我在采集板上用到的功能用来测量外部传感器的脉冲信号。STM32F103的定时器捕获功能很成熟我配置TIM2为输入捕获模式上升沿触发捕获值减去上一次捕获值就是周期换算一下就是频率。在72MHz主频下捕获分辨率是13.9纳秒测1kHz到100kHz的信号都很准。GD32F303的定时器捕获功能同样好用而且因为主频更高120MHz捕获分辨率提升到8.3纳秒测高频信号更有优势。但我在使用中发现GD32的定时器在捕获溢出时的中断处理需要注意——它的溢出标志清除方式和STM32略有不同如果不清除干净会导致捕获值计算错误。我当时的症状是频率读数偶尔跳变后来在中断里加了溢出标志清除代码问题就解决了。CH32V103的定时器捕获功能让我有点意外。它的定时器资源比STM32少TIM1和TIM2是高级定时器TIM3和TIM4是通用定时器但捕获通道的分配不如STM32灵活。我原本想用TIM3的通道1和通道2同时捕获两路信号结果发现CH32V103的TIM3只有通道1支持捕获通道2只能做PWM输出。后来我改用TIM1和TIM2各捕获一路才实现了双路频率测量。这个限制在选型时一定要提前确认否则硬件设计完了才发现引脚不够用那就麻烦了。PWM输出方面三个平台都能满足常规需求。STM32F103的TIM1和TIM8是高级定时器支持互补输出和死区插入适合驱动电机。GD32F303的高级定时器功能类似但死区时间的计算公式不同需要重新计算。CH32V103的高级定时器也支持互补输出但死区时间的最小分辨率比STM32大如果你需要很精确的死区控制可能需要外接死区生成电路。4. 从零搭建工程的完整实操流程4.1 STM32标准库工程的搭建与配置虽然现在HAL库和STM32CubeMX很流行但我还是习惯用标准库搭建工程因为代码量小、执行效率高、对底层寄存器掌控更直接。下面是我搭建STM32F103标准库工程的完整步骤。首先准备材料STM32F10x标准外设库我从官网下载的V3.5.0版本、Keil MDK5、STM32F103的芯片包。新建工程文件夹在里面创建四个子文件夹Start放启动文件和内核文件Library放标准外设库的.c和.h文件User放main.c和中断服务程序Project放Keil工程文件。在Keil里新建工程选STM32F103C8T6芯片然后把启动文件startup_stm32f10x_md.s添加到Start组把stm32f10x.h、system_stm32f10x.c、core_cm3.c也加进去。Library组里添加stm32f10x_gpio.c、stm32f10x_rcc.c、stm32f10x_usart.c等我用到的外设文件。User组里添加main.c、stm32f10x_it.c。接下来配置头文件包含路径在Keil的Options for Target里C/C选项卡的Include Paths中添加..\Start、..\Library、..\User。然后在Define里加上USE_STDPERIPH_DRIVER, STM32F10X_MD这两个宏定义很关键前者告诉编译器使用标准外设库后者指定芯片型号是中容量产品。最后写main函数。我通常先写一个GPIO翻转的测试代码确认时钟配置和引脚输出正常然后再逐步添加串口、ADC、定时器等外设。这个顺序很重要——先确保最基础的GPIO能工作再往上叠加功能出了问题也容易定位。4.2 GD32工程从STM32迁移的详细步骤GD32的工程搭建可以完全复用STM32的框架只需要替换几个关键文件。我以GD32F303CBT6为例说说具体的迁移步骤。第一步下载GD32F30x固件库里面包含启动文件、外设驱动和示例代码。把STM32工程里的启动文件startup_stm32f10x_md.s替换成GD32的startup_gd32f30x_hd.s注意文件名里的hd表示高密度产品对应GD32F303的128KB Flash。第二步替换外设驱动文件。GD32的库文件名和STM32不同比如STM32的stm32f10x_gpio.c对应GD32的gd32f30x_gpio.c。把Library文件夹里的文件全部替换掉然后在Keil工程里重新添加这些文件。第三步修改头文件包含。把#include stm32f10x.h改成#include gd32f30x.h把#include stm32f10x_gpio.h改成#include gd32f30x_gpio.h以此类推。这一步工作量不大但很繁琐我建议用编辑器的全局替换功能批量处理。第四步修改时钟配置。GD32的SystemInit()默认把主频设到120MHz如果你需要其他频率要修改system_gd32f30x.c里的PLL配置参数。我通常保持120MHz不变因为GD32的Flash等待周期配置已经适配了这个频率。第五步修改中断向量表。GD32的中断向量表名称和STM32略有不同比如STM32的USART1_IRQHandler在GD32里叫USART1_IRQHandler看起来一样但有些外设的中断名称有变化。我建议直接参考GD32的示例代码把中断服务函数的名称核对一遍。完成这五步之后编译工程如果报错就根据错误信息逐个解决。我迁移一个中等复杂度的工程大概5000行代码用了半天时间主要时间花在核对中断向量表和修改时钟配置上。4.3 CH32V103在MounRiver Studio中的工程创建CH32V103的工程创建流程和STM32、GD32完全不同因为它用的是RISC-V工具链和MounRiver Studio IDE。下面是我从零创建CH32V103工程的步骤。首先下载MounRiver Studio安装完成后打开选择New Project然后选CH32V103系列再选具体型号CH32V103R8T6。IDE会自动生成一个包含启动文件、链接脚本和基本外设驱动的工程模板。工程模板里有一个Startup文件夹里面是RISC-V的启动文件startup_ch32v103.S这个文件用汇编编写负责初始化堆栈、设置中断向量表、跳转到main函数。还有一个Ld文件夹里面是链接脚本Link.ld定义了Flash和RAM的地址范围。CH32V103R8T6的Flash起始地址是0x08000000大小64KBRAM起始地址是0x20000000大小20KB。这些信息在链接脚本里都要正确配置否则程序无法正常运行。接下来配置外设。CH32V103的库函数风格和STM32标准库很像但函数名和参数略有不同。比如GPIO初始化STM32是GPIO_Init(GPIOA, GPIO_InitStructure)CH32V103是GPIO_Init(GPIOA, GPIO_InitStructure)看起来一样但GPIO_InitStructure的成员顺序不同。我建议直接参考CH32V103的示例代码不要凭记忆写。编译工程时MounRiver Studio会调用RISC-V GCC工具链生成.elf和.hex文件。下载程序需要用WCH-Link调试器在IDE的下载配置里选择WCH-Link然后点击下载按钮。我第一次下载时遇到了连接失败的问题后来发现是WCH-Link的驱动没有正确安装重新安装驱动后就正常了。4.4 三个平台的调试工具与下载方式对比调试工具方面STM32我用的是ST-Link V2配合Keil MDK的调试功能可以单步执行、查看寄存器、设置断点体验很流畅。GD32可以用GD-Link也可以用ST-Link因为GD32的SWD接口和STM32兼容。我通常直接用ST-Link调试GD32省得再买一个调试器。CH32V103必须用WCH-Link不能兼容ST-Link。WCH-Link的价格很便宜大概二十块钱但它的调试功能比ST-Link弱一些比如不支持实时变量查看单步执行的速度也慢一点。不过对于常规调试来说够用了。下载方式上STM32和GD32都支持SWD和串口下载。SWD下载速度快适合开发阶段串口下载需要配置BOOT引脚适合量产阶段。CH32V103支持SWD下载和串口下载但它的串口下载工具是沁恒自己提供的叫WCHISPTool使用起来还算方便。这里分享一个经验无论用哪个平台我都建议在PCB上预留SWD接口和串口接口。SWD用于调试串口用于下载和通信。有时候调试器不在手边用串口下载也能应急。5. 常见问题与排查技巧实录5.1 STM32工程常见问题速查问题现象可能原因排查方法解决方案程序下载后不运行启动文件选错检查芯片型号和启动文件是否匹配中容量用startup_stm32f10x_md.s大容量用hd.s串口乱码时钟频率不对用示波器测GPIO翻转周期检查SystemInit()里的PLL配置ADC采样值跳动参考电压不稳测量VDDA和VSSA加滤波电容缩短采样时间定时器捕获不准溢出标志未清除检查中断服务程序在中断里清除溢出标志程序卡在延时函数时钟未使能检查RCC配置使能对应外设时钟STM32的生态太成熟了大部分问题都能在网上找到答案。但我发现一个规律很多新手遇到的问题其实是基础问题比如忘记使能外设时钟、中断优先级配置错误、堆栈大小不够。我的建议是遇到问题先检查这三个地方能解决80%的故障。5.2 GD32迁移过程中的典型故障GD32迁移过程中我遇到的最典型故障是串口通信失败。症状是程序能下载GPIO能翻转但串口就是没输出。排查过程如下先用示波器测TX引脚发现没有波形说明串口外设没有工作。然后检查USART的初始化代码发现时钟使能函数写的是RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE)这个在STM32里是对的但在GD32里USART1的时钟使能函数是rcu_periph_clock_enable(RCU_USART1)。原来GD32的库函数命名规则和STM32不同我直接照搬STM32的代码编译能通过但实际没有使能时钟。这个问题的教训是GD32虽然兼容STM32但库函数的命名和参数并不完全一致。迁移时不能只替换文件名还要仔细核对每个函数的调用方式。我后来养成了一个习惯每迁移一个外设就先跑一个最简单的测试程序确认外设能工作后再集成到主工程里。另一个典型故障是GD32的Flash写入问题。我在做参数存储时发现写入Flash后读出来的数据不对。排查后发现GD32的Flash编程需要先解锁再擦除再写入最后锁定。STM32的流程也是这样但GD32的擦除时间比STM32长如果擦除后立即写入可能会失败。我在擦除和写入之间加了一个延时问题就解决了。5.3 CH32V103开发中的坑与解决方案CH32V103的坑主要集中在工具链和中断处理上。第一个坑是中断向量表的重定位。CH32V103的启动文件里定义了中断向量表默认放在Flash起始地址。如果你用了Bootloader需要把应用程序的中断向量表偏移到Bootloader之后。STM32里用NVIC_SetVectorTable()函数来设置CH32V103里需要修改链接脚本和启动文件把向量表的起始地址改到应用程序的Flash地址。第二个坑是RISC-V的中断处理机制和ARM不同。ARM Cortex-M的中断是硬件自动保存现场而RISC-V需要软件保存现场。CH32V103的启动文件里已经写好了中断入口的汇编代码但如果你自己写中断服务函数要注意函数名和中断号的对应关系。我刚开始写串口中断时把函数名写成了USART1_IRQHandler但CH32V103的中断服务函数名是USART1_IRQHandler看起来一样但实际的中断号不同导致中断无法触发。后来查了CH32V103的中断向量表才发现USART1的中断号是25而STM32里是37。第三个坑是CH32V103的Flash编程。它的Flash编程流程和STM32类似但需要先调用FLASH_Unlock()解锁然后FLASH_ErasePage()擦除再FLASH_ProgramWord()写入最后FLASH_Lock()锁定。我遇到的问题是擦除后写入的数据偶尔会丢失后来发现是擦除和写入之间的延时不够CH32V103的Flash擦除需要大概20毫秒我在代码里加了50毫秒的延时问题就解决了。5.4 跨平台代码移植的通用避坑指南经过这一年的跨平台开发我总结了几条通用的避坑经验。第一不要假设库函数的行为一致。即使函数名相同参数含义和返回值也可能不同。每次移植一个外设都要先看目标平台的库函数文档确认调用方式。第二时钟配置是移植中最容易出问题的地方。不同平台的默认时钟频率不同PLL配置不同外设时钟的使能方式也不同。我建议在移植完成后第一件事就是用示波器测一下GPIO翻转频率确认系统时钟正确。第三中断处理要重新核对。中断向量表、中断优先级、中断标志清除方式这三个地方在跨平台时几乎一定会出问题。我通常会把中断服务函数单独拿出来测试确认能正常触发和退出后再集成到主程序里。第四Flash和RAM的地址范围要确认。不同芯片的Flash和RAM大小不同链接脚本要相应修改。如果RAM不够用程序可能会跑飞或者数据出错。我习惯在工程里加一个内存使用统计编译完成后看一下RAM占用了多少留出至少20%的余量。第五调试工具要提前准备好。STM32用ST-LinkGD32可以用ST-Link或GD-LinkCH32V103必须用WCH-Link。如果调试器不兼容开发效率会大打折扣。我建议每个平台都配一个专用调试器省得来回换。6. 一年使用后的真实评价与选型建议6.1 性能、成本与生态的综合对比用了一年之后我对这三个平台的评价可以总结成一张表对比维度STM32F103GD32F303CH32V103内核Cortex-M3Cortex-M4RISC-V主频72MHz120MHz80MHz浮点性能软件模拟硬件FPU软件模拟外设丰富度高高中等库函数兼容性基准高度兼容低工具链成熟度极高高中等中文资料多多多英文资料极多中等少价格千片12-15元8-10元6-8元交期不稳定稳定稳定从性能上看GD32F303凭借M4内核和120MHz主频在运算密集型任务中优势明显。STM32F103胜在均衡和稳定适合大多数常规控制场景。CH32V103的RISC-V内核在整数运算上表现不错但浮点性能是短板适合通信和逻辑控制类应用。从成本上看CH32V103最便宜GD32次之STM32最贵。但成本不能只看芯片价格还要考虑开发成本、迁移成本和维护成本。如果你的团队已经熟悉STM32迁移到GD32的学习成本很低一两天就能上手迁移到CH32V103则需要重新学习工具链和中断处理机制大概需要一到两周。从生态上看STM32的生态优势依然无法撼动。无论是官方文档、社区论坛、第三方库还是开源项目STM32的资源都是最丰富的。GD32的生态在快速追赶官方文档质量不错社区也在壮大。CH32V103的生态相对薄弱但沁恒提供了完整的中文文档和示例代码对于中文用户来说够用了。6.2 什么场景选什么芯片我的实际建议基于这一年的使用经验我给出以下选型建议。如果你的项目对稳定性要求极高团队熟悉STM32生态且预算充足那就继续用STM32。它的确定性是其他平台暂时无法替代的。尤其是工业控制和医疗设备领域STM32的长期供货记录和可靠性验证是重要加分项。如果你需要更高的运算性能同时想降低成本GD32F303是很好的选择。它的M4内核和FPU在电机控制、数字信号处理等场景下优势明显而且迁移成本低适合从STM32升级的项目。但要注意GD32在某些外设细节上和STM32有差异迁移时要仔细测试。如果你对成本极度敏感或者项目要求全国产化CH32V103值得考虑。它的价格优势明显RISC-V内核也符合自主可控的趋势。但你要做好心理准备工具链需要适应中断处理需要重新学习外设资源比STM32少。适合通信网关、数据采集、简单控制等对算力要求不高的场景。如果你在做毕业设计或者学习嵌入式我建议从STM32F103开始。它的资料最多遇到问题最容易找到答案。等熟悉了嵌入式开发的基本流程再尝试GD32和CH32V103你会发现不同平台的设计思路各有千秋。6.3 国产芯片的未来展望与个人体会这一年的使用让我对国产芯片有了更客观的认识。GD32和CH32V103都不是简单的仿制它们在兼容STM32的同时也在探索自己的技术路线。GD32选择了Cortex-M4内核在性能上超越STM32F103CH32V103选择了RISC-V内核在自主可控上迈出了一步。但差距依然存在。最明显的差距不在硬件参数而在生态建设。STM32的生态是十几年积累的结果国产芯片要在短时间内追上并不现实。不过我看到GD32和CH32V103的官方文档在持续更新社区也在慢慢壮大这个趋势是好的。我个人在实际操作中的体会是国产芯片已经能满足大部分常规应用的需求但在一些细节上还需要打磨。比如GD32的ADC通道切换速度、CH32V103的中断响应延迟这些在数据手册里不会写只有实际用过才知道。所以我的建议是选型时不要只看参数表一定要拿样片实际测试把关键功能跑一遍确认能满足需求后再批量采购。最后分享一个小技巧如果你在多个平台之间迁移代码建议把硬件相关的代码抽象成一层接口比如hal_gpio_init()、hal_uart_send()这样换平台时只需要重写接口层的实现业务逻辑不用动。这个习惯我从STM32迁移到GD32时就开始用了后来迁移到CH32V103时省了很多时间。这个内容后续还可以这样扩展把三个平台的HAL层做成一个统一的库支持通过宏定义切换平台这样一套代码就能在三个平台上编译运行。
阅读完成 · 觉得有帮助?