1. 为什么STM32F103会被盯上,换国产到底图什么
先说STM32F103为什么能活成一颗现象级芯片。72MHz的Cortex-M3内核、最多512KB Flash、3个USART、2个SPI、2个I2C、5个定时器和2个ADC,这个配置搁在今天是“够用”,搁在十年前是“惊喜”。但真正让它封神的不是性能,而是生态。从标准外设库到HAL库,从Keil到IAR,从STM32CUBEMX到现在满大街的教程,几乎所有嵌入式工程师都在这颗芯片上练过手。它的可替代性差,不是因为性能没人比得上,而是因为“软硬件积累太多了”。
GPS平台尤其依赖这种积累。车载定位器、物流追踪器、手持终端这些产品,MCU的活儿其实相当固定:接手串口进来的NMEA数据、解析经纬度、管理Flash轨迹存储、跑通信协议。STM32F103干这些事属于“大人干小孩活”,绝大多数项目只用了它20%的性能。这也是为什么这颗芯片非常适合做替换试验——运算量不大,外设不多,只要新的国产MCU在串口、定时器、中断这些基础外设上不掉链子,项目就能平稳切换。
从替换驱动力来看,成本只是一方面。2020年以后的供应链波动让很多团队意识到,核心器件全押在一家供应商身上是有风险的。有的项目是客户指定要国产化,有的是采购要求双供应商备份,有的是纯从BOM成本角度想省几块钱。不管哪种原因,落到工程师手里的任务都一样:把STM32F103的方案,平稳移植到一颗国产32位MCU上,功能不能减、性能不能降、产量不能断。
国产MCU能接得住这颗芯片的需求,最直接的原因是一批厂商做了兼容设计。所谓兼容不是说“寄存器一模一样”,而是指引脚排列兼容、供电电压兼容、核心外设功能对应,软件层面通过替换启动文件和库文件,应用代码可以比较大比例地复用。这几年我接触过的国产替换方案里,有些连封装都做成pin-to-pin,PCB几乎不改就能烧录跑起来,项目初期的风险一下降了很多。
回到GPS平台的具体场景,我们要替换的芯片是STM32F103RCT6,主要工作模块是串口接收GPS模块数据、PPS秒脉冲中断、外部Flash存储、LCD显示、按键与状态灯。整机是典型的中低速嵌入式设备,对主频不敏感,对串口稳定性和中断响应有一定要求。选型的思路很明确:引脚兼容、Flash和RAM不低于原芯片、串口数量和定时器数量不能少、供货稳定、参考资料能跟上。用这套标准去筛,能入围的国产芯片其实不少。
2. GPS平台对MCU的真实需求拆解
2.1 一颗GPS模块到底在“说”什么
GPS模块本身是一个独立完成定位功能的组件,它接受天线信号,内部算出位置、时间、速度、航向,然后通过串口把这些数据“吐”出来。市面常见的NEO-8M、NEO-M8N、NEO-M9N这类模块,默认情况下一秒钟向外输出一串NMEA 0183协议的文本帧。
NMEA 0183是一套非常古老的文本协议,核心是若干条由逗号分隔的ASCII语句。最常见的有这几条:
$GGA:定位信息,包含UTC时间、纬度、经度、定位质量、卫星数量、海拔高度。$RMC:推荐最小定位信息,包含UTC时间、定位状态、纬度、经度、地面速度、航向、日期。$GSV:可见卫星信息,包含卫星编号、仰角、方位角、信噪比。$GSA:卫星精度因子,包含HDOP、VDOP、PDOP。
每条语句以$开头,以<CR><LF>结尾,中间各字段用逗号隔开,帧尾有两个字符的十六进制校验和。GPS模块默认波特率一般是9600bps,也支持通过配置改成更高的波特率。
从MCU的角度看,GPS模块本质上就是一个“每隔一秒发一堆文本的串口设备”。性能压力不大,但要求MCU能稳定接收不定长数据、高效切割字段、可靠解析并校验,还得处理好断帧和半帧的情况。
2.2 MCU在这个系统里的三个角色
第一角色是串口数据接收者。GPS模块的串口TX接到MCU的RX引脚,数据是连续的文本流。MCU要么通过中断逐字节接收、要么通过DMA批量接收。逐字节中断最占CPU,但对帧长度小于200字节的GPS数据来说压力不大;DMA更高效,但需要处理好“帧结束判断”。
第二角色是数据解析者。MCU把收到的原始ASCII帧按照NMEA协议切分,转成结构体里的数值字段,比如纬度和经度的度分格式转换、UTC时间转北京时间、验证校验和。这部分是纯软件逻辑,和芯片型号无关,但要注意代码的可移植性,替换芯片时这部分应该一劳永逸。
第三角色是业务逻辑者。GPS平台不只是“拿到定位”就完了。项目里还需要把轨迹写入Flash、通过蓝牙或4G模块把位置上报、在LCD上渲染地图或坐标信息、检测跌落或超速等事件。这些业务逻辑跑在哪颗芯片上其实无所谓,但MCU的资源规格得撑得住。
2.3 选型评估:哪些参数必须够,哪些可以省
替换芯片的选型没必要追求“全面超越”,关键是踩准项目的真实需求。GPS平台对MCU的要求完全可以列成一张清单:
| 需求维度 | 项目实际要求 | 判断标准 |
|---|---|---|
| 主频 | 不敏感,24MHz以上就够 | GPS解析是轻负载,主频不是瓶颈 |
| Flash | 原工程编译后45KB,至少留50%余量 | 128KB起步比较稳妥 |
| RAM | 运行状态约8KB,需要缓冲区和堆栈 | 20KB起步,能留余量更好 |
| USART | 至少2路:GPS模块+蓝牙/调试 | 3路最稳,还能接4G模块 |
| 定时器 | 至少1路做秒级业务定时,1路做PPS捕获 | 主流国产芯片都能满足 |
| 中断优先级 | 串口和PPS中断不能互相阻塞 | 需要支持NVIC分组配置 |
| 功耗 | 无严格低功耗要求,但需要Idle模式 | 普通Stop模式够用 |
| 封装 | 需要和原PCB兼容或微调 | LQFP64最常用 |
选型时最容易犯的两个错误:一是只看参数表,不看软件生态和启动文件是否齐全;二是盲目选主频更高的芯片,结果功耗和发热反而上去了。GPS平台选芯片,最合适的不是“最猛的”,而是“迁移路径最顺手的”。
3. 硬件替换实操:从引脚到电路的关键改动
3.1 引脚兼容不是“复制粘贴”
国产替换芯片最友好的一个设计就是引脚兼容。以LQFP64封装为例,很多国产MCU把电源、地、BOOT、晶振、串口、SPI、I2C的引脚位置排列得和STM32F103一致,目的是让客户在硬件层面少改动、软件层面多复用。
但“引脚兼容”不等于“外围电路完全不用动”。我拿到国产芯片的原理图和参考手册后,对照原PCB的每一路电源、每个去耦电容、每根信号线的上拉/下拉配置逐一核对,其中三个地方特别容易出问题。
第一是芯片的电源去耦建议。STM32F103的参考设计在VDD引脚附近放100nF瓷片电容,国产芯片往往建议额外加一个4.7uF的钽电容或大容量陶瓷电容。如果你沿用旧PCB只放了100nF,低负载时也许看不出差异,但GPS模块和LCD同时工作时,电压纹波可能会偏高,导致串口偶发乱码。
第二是复位电路。有些国产芯片内部复位电路参数和ST不同,外部复位芯片的阈值电压选择要重新核对。我们用了一颗通用的复位芯片,原来在STM32上工作正常,换成国产芯片后出现偶发性上电启动失败,后来查手册发现是复位芯片输出高电平时间不足,换了参数匹配的型号就正常了。
第三是VBAT引脚。原STM32F103用VBAT接电池维持RTC,国产芯片的RTC有些是独立的,有些需要额外配置,如果项目里没有用到RTC,直接在PCB上把VBAT接到VDD即可,但要注意看手册确认引脚的定义没有变化。
3.2 晶振、电源和启动配置:替换的隐藏陷阱
GPS平台对时间基准有刚性需求,外部晶振的精度直接影响PPS捕获和RTC走时。原设计用的是8MHz主晶振加32.768kHz RTC晶振。国产芯片的启动配置里,HSE时钟源可以支持外部晶振或外部时钟输入,但启动时默认使用的是内部HSI,必须检查RCC配置代码是否已经把时钟切到HSE。
这里有个典型的坑:STM32F103用标准库的SystemInit()会自动把时钟从HSI切到HSE并配置到72MHz,但部分国产芯片的启动文件和时钟初始化函数虽然名字长得差不多,内部逻辑却有些差异。直接套用ST的SystemInit文件会导致时钟配置失败,芯片只能跑在HSI 8MHz下。GPS串口波特率如果用9600bps可能还能凑合,但PPS捕获的时间精度和Flash读写速度都会受影响。
电源设计上还有一处需要注意:国产芯片的ADC参考电压(VDDA)建议单独用磁珠或RC滤波隔离,原PCB如果偷懒直接把VDDA和VDD短接,在高精度模拟量采集项目中可能影响不大,但GPS产品往往有蓝牙或4G射频模块,射频发射瞬间的电源跌落会顺着走线干扰到MCU的ADC采样,所以VDDA加一个10Ω电阻和1uF电容是稳妥的。
BOOT0和BOOT1引脚的默认电平也要看一下。STM32F103的BOOT0通过10K电阻接地,国产芯片有的内部有下拉,有的需要外部强下拉。曾经遇到过把国产芯片焊到旧板上、BOOT0悬空,结果芯片偶尔能从系统存储器启动而无法进入主程序,跑起来的表现就是“死一半”,串口有输出但程序逻辑异常,花了不少时间排查。这个问题在量产板上尤其危险,因为焊接一致性不保证每个芯片都能从Flash启动。
3.3 GPS模块接口电路与PCB布局要点
GPS模块的串口电平一般是3.3V,和MCU电平兼容,不需要额外的电平转换。但GPS模块的天线馈电供电往往存在干扰问题。有源天线的供电通常由GPS模块内部提供,模块的VCC需要单独滤波,不能和MCU的数字电源共享同一个LDO输出口,否则天线馈电的瞬态电流会影响MCU电源质量。
PCB布局上最需要注意的就是GPS天线和MCU之间的隔离。项目初版板子因为走线时把GPS天线馈线穿过了MCU晶振下方,导致定位模块的C/N0信噪比整体下降,搜到的卫星数比同型号参考板少了三分之一。后来把天线馈线绕到板边,并在GPS模块下方做了完整的接地铺铜,信噪比才恢复正常。
还有一处是PPS秒脉冲引脚的走线。PPS输出是GPS模块的1PPS信号,脉宽通常只有几十到几百毫秒,是一个精度极高的时间基准。走线如果太长、同时附近又有大电流走线,PPS沿口可能出现抖动,MCU捕获时间戳就会波动。这个信号线尽量短、尽量避免和串口线平行走线,有条件的话做包地处理。
4. 软件移植与GPS数据解析的完整落地
4.1 工程从STM32到国产芯片:移植的真实工作量
软件移植是整个替换过程中最磨人的一环,工作量直接取决于原工程的架构习惯。如果原来的代码是全部基于标准外设库写的,那替换芯片就要换成对应的国产标准外设库,大部分函数名和参数都相近,但需要逐个核对。如果原来用HAL库,不同芯片的HAL库差异会更大一些,好在很多国产芯片目前也提供了类似HAL的驱动层。
我建议的移植路径是这样走的:
- 先把原工程备份,统计用到的外设清单:USART1、USART2、SPI2(Flash存储)、TIM3、EXTI、GPIO、I2C1(LCD)。
- 创建一个新的国产芯片工程模板,启动文件、头文件、系统初始化全部用官方提供的最新版本。
- 把外设初始化代码逐个搬运,重点看GPIO复用功能和时钟源配置。
- 应用层代码(NMEA解析、Flash存储逻辑、LCD绘制、通信协议)基本保持原样。
- 编译烧录,先跑通“空转”,再做GPS实际联调。
实际做下来,底层驱动代码大概只有30%需要改动,主要是头文件包含路径、外设名称写法、部分寄存器级别的操作。应用层代码几乎可以原封不动地复用,这个比例在评估替代方案时很重要,可以直接决定项目是“三天搞定”还是“三周起步”。
4.2 串口驱动与波特率误差:最容易被小看的细节
GPS模块默认9600bps的串口波特率,从软件上看应该是简单到了极点,但替换芯片后最容易翻车的就是这里。波特率误差的直接来源是芯片串口时钟源的分频计算差异。
STM32F103的USART波特率计算是PCLK / (16 * 分频系数),国产芯片的外设挂在不同的APB总线上,分频系数需要重新核对。如果新芯片的主频不是72MHz,而是60MHz或96MHz,原代码里直接写死的波特率参数就会偏离标称值。
串口波特率有一个容忍范围,官方规范是±2%,实际操作中GPS模块对接收端的波特率偏差容忍度稍高一点,但超过±3%就可能出现整包乱码、偶尔能收到但频繁丢字节的情况。我们在替换后出现过“刚开始正常、运行几小时后GPS数据越来越乱”的现象,排查下来不是芯片发热,而是LSE晶振起振后频率偏了,导致USART时钟源不稳定。
稳定的做法是:把GPS串口配置为DMA接收模式,PORT引脚复用配置检查两次,波特率直接按芯片参考手册里的分频表取值,不要沿用原工程的数值。同时给GPS串口引入一个状态机,严格按照“空闲中断+行缓冲”方案来处理不定长NMEA帧,能大幅减少断帧带来的解析压力。
4.3 写一个干净的NMEA 0183解析器
GPS解析部分其实和芯片型号无关,但这里是整个系统最容易藏着Bug的地方,值得把设计思路写细一点。
NMEA解析器不建议用strtok这类直接修改原缓冲区的函数切分字符串,因为GPS数据流是一个连续串口流,缓冲区经常不是完整的一帧。我常用的方案是环形缓冲区加逐字节状态机:
- 串口DMA把数据搬到MBUFFER,每收到一帧就用空闲中断标记。
- 在应用层从缓冲区里逐字节寻找
$,找到后继续寻找连续两个字符的帧头(GP、GN、BD等)。 - 继续读取直到碰到
*,把校验和字符取出来。 - 对
$和*之间所有字符做异或,和帧尾两个十六进制字符比对。 - 校验通过后,把这帧完整内容单独拷到一个结构体缓冲区,再做字段提取。
字段提取阶段要格外小心:NMEA协议里的经纬度是“度分”格式,比如4807.038代表北纬48度07.038分,转成十进制度数的公式是度 + 分 / 60.0。这个转换必须用浮点数,但如果MCU没有FPU,浮点运算会消耗较多CPU周期。好在GPS平台每秒只有几十条帧,整体CPU占用率完全可以接受。
校验和计算是另一个高频出错点。很多新手只对帧头之后、校验码之前的字符串做异或,忽略了$本身也要参与计算。正确做法是把$和*之间所有的字符逐个异或,包括字母、数字和逗号,最终得到两个十六进制字符就是帧尾的校验值。协议里校验字符是ASCII,用0x30 + 值的方式转成可打印字符时,大于9的值要加7偏移,这个细节也容易错。
NMEA解析器写完后,建议用一个真实GPS模块录制的数据文件做离线测试。把几十条典型帧(固定的、动态的、丢星的、冷启动的)灌进串口模拟程序里跑一遍,确保解析器能处理异常帧而不崩溃。
4.4 PPS秒脉冲与定时器协同:同步的细节
GPS模块除了输出定位数据,还会在每秒整点输出一个PPS脉冲,这个脉冲的上升沿和UTC秒对齐,是低成本授时的关键信号。
在GPS平台里,PPS用于两件事:一是校准MCU内部RTC,二是给轨迹数据打精确时间戳。MCU通过中断捕获PPS上升沿,记录定时器的当前计数值,与RTC时间比对,得到时钟偏差后做补偿。
用国产MCU实现时需要注意,定时器输入捕获通道的极性映射可能存在差异。原工程在STM32F103上用的是TIM2的CH1捕获PPS,换成国产芯片后,如果芯片的TIM2CH1输入映射到不同的GPIO引脚,要么改PCB飞线,要么改用其他定时器通道,我建议先在代码里把引脚复用功能确认清楚,涉及到封装的AFIO映射问题。
PPS中断的优先级在整体系统中应该设为最高。GPS数据每秒才来一趟,定位滞后几百毫秒没关系,但PPS时间戳延迟会导致时间基准偏差。我在项目中把PPS中断优先级设为0(最高),串口接收设为1,然后其他外设各自靠后,这个优先级分配在替换前后保持不变。
5. 常见问题与排查实录
5.1 移植后最容易踩的五个坑
| 现象 | 可能的根因 | 排查方向 |
|---|---|---|
| 程序上电后不运行,JTAG连不上 | BOOT引脚电平不对;电源去耦不足 | 检查BOOT0/BOOT1电平;查VDD波形 |
| 串口完全无输出 | 波特率配置错误;GPIO复用没配对;时钟源没切到HSE | 先跑一个LED翻转程序确认主时钟;再单独测串口发送单字节 |
| GPS有数据但解析出来经纬度为0 | 校验和计算错;字段序号偏移 | 用串口助手抓原始NMEA,人工比对解析结果 |
| 运行一段时间后GPS数据中断 | DMA缓冲区溢出;空闲中断处理不及时 | 检查DMA半满/全满中断是否开启;增大缓冲区 |
| PPS时间戳跳动很大 | PPS走线被干扰;捕获通道极性配置错 | 示波器看PPS上升沿质量;检查定时器寄存器配置 |
5.2 项目里几个印象深刻的“翻车现场”
替换初期最头疼的问题之一,是我们把程序烧进国产芯片后,串口能输出数据,但GPS模块那边死活没有响应。排查了大半天,最后发现是GPS模块的波特率配置问题:模块虽然在出厂默认9600bps,但之前调试时往模块里写过配置,把波特率改成了115200。这个配置存到了GPS模块内部Flash里,断电不会丢。STM32F103时代程序按9600跑,是因为原程序启动后重新对模块做了配置;换芯片后我们把初始化流程精简了,漏掉了这一句,GPS模块自然不吐数据。解决方式很简单,把GPS模块的波特率配置代码加回初始化流程,问题立刻消失。
另一个问题是国产芯片的ADC采样值整体比STM32F103偏低。项目里有一个用来检测主电源电压的分压电路,通过ADC读到的数值计算电池电量,替换后电量显示一直偏低。对比了多颗芯片后确认是ADC参考电压和偏移校准的差异,需要在代码里重新做一组偏移校准。这个问题提醒我:替换芯片后,凡是涉及模拟量的外设都必须重新标定,不能沿用原厂参数。
还有一次是设备在低温环境下频繁自动重启。排查后发现国产芯片的掉电复位阈值比STM32F103高了一点,低温时电池电压本来就有所跌落,正好触发了复位条件。把供电电路的LDO输出从3.3V提到3.5V(芯片还在正常电压范围内),同时把复位电路的阈值选型往下调了一档,问题解决。
5.3 72小时连续运行实测与兼容性总结
替换完成后,我们做了一轮72小时连续运行测试,目的是验证GPS定位功能的稳定性和国产MCU的可靠性。测试条件:室温25度,GPS天线放在窗边,设备以10秒间隔上报一次位置,同时记录NMEA解析成功率、PPS时间戳偏差、Flash写入状态。
实测结果如下:72小时内GPS模块输出帧约26万条,NMEA解析成功率为99.98%,只有少量因为天线遮挡导致的残帧被正确丢弃;PPS时间戳偏差在±1.5ms以内,满足项目需求;Flash轨迹数据写读正常,没有出现数据错乱;MCU整机功耗和替换前基本持平,差别在1mA以内。
这个结果说明,在GPS定位这种中低复杂度应用场景里,国产32位MCU已经完全可以胜任STM32F103的活儿。真正决定替换成败的,不是芯片本身的性能,而是软硬件适配的细致程度。
6. 一点个人体会
从项目立项到完成替换,前后大约用了一个半月时间。其中硬件改板大概两周,软件移植和联调三周,其余时间都花在问题排查和可靠性测试上。做完这个项目后我最大的体会是:国产芯片和ST芯片之间早已不是“能不能用”的问题,而是“怎么用更顺手”的问题。
如果你也正在做类似的替换,我特别建议在项目启动前先把原来工程里所有涉及硬件的底层代码彻底梳理一遍。哪些是真正和芯片强相关的,哪些是纯业务逻辑,分清楚之后再动手,移植的时候心里就有底。另一个建议是先不要追求“一次改到位”,可以先做一块小批量样板,把每个外设单独点亮、单独验证,再合到一起跑整机业务,排查问题的成本会低很多。
最后分享一个实用小技巧:替换芯片期间,务必保留一套万用表加示波器的基础调试工具。很多看似是软件问题、协议问题、解析问题的现象,追到最后往往是某个引脚接触不良、某个电阻阻值贴错、某根走线太细。用示波器先确认物理层的信号再谈软件,能省下至少一半的排查时间。这套方法论在STM32时代管用,换了国产芯片一样管用。