2、主控芯片选型与开发环境搭建:STM32F103系列介绍、Keil MDK安装与配置、标准外设库与HAL库选择

2.1 为什么选STM32F103?

做自动售货机支付模块,主控芯片的选择其实挺讲究的。我个人习惯先看三点:成本、稳定性、生态。STM32F103系列,说白了就是嵌入式界的「万金油」。我最早接触它是在2012年,那时候做一个工业采集器,老板要求成本控制在20块以内,还要带CAN总线。嗯,最后就是靠F103搞定的。

你想想看,自动售货机的支付模块要处理什么?

  • 接收硬币/纸币器的脉冲信号
  • 驱动LCD显示金额
  • 通过串口与扫码枪通信
  • 控制电磁锁动作
  • 偶尔还要跑个加密算法

这些活儿,F103的72MHz主频完全够用。而且它内置的Flash最大到512KB,RAM到64KB,对于支付逻辑来说绰绰有余。我在项目中遇到过最极端的情况,是客户要求同时支持微信、支付宝、银联三种支付方式,外加一个M1卡读头。代码量大概在200KB左右,F103C8T6(64KB Flash)就有点吃紧了,最后换成了F103VET6(512KB Flash)。

核心选型建议:
  • 简单扫码支付 + 硬币器:STM32F103C8T6(48脚,64KB Flash)
  • 多支付方式 + 读卡器:STM32F103RCT6(64脚,256KB Flash)
  • 带以太网或复杂UI:STM32F103VET6(100脚,512KB Flash)

2.2 STM32F103系列速览

F103系列其实分三个子系列:

系列 Flash SRAM 最高主频 典型封装
STM32F103x4/x6 16-32KB 6-10KB 72MHz LQFP48
STM32F103x8/xB 64-128KB 20KB 72MHz LQFP48/64
STM32F103xC/xD/xE 256-512KB 48-64KB 72MHz LQFP64/100/144

这里有个坑,我必须要说。我曾经在采购时没注意后缀,把F103C8T6和F103CBT6搞混了。前者是64KB Flash,后者是128KB。虽然引脚完全兼容,但程序烧进去直接跑飞。嗯,从那以后我每次下单都会在BOM表里用红色标注Flash容量。

2.3 Keil MDK安装与配置

开发环境这块,我推荐Keil MDK。虽然也有IAR和GCC,但Keil在STM32生态里最省心。安装步骤其实很简单:

  1. 去ARM官网下载MDK-ARM(现在叫Keil Studio了,但经典版依然好用)
  2. 安装时记得勾选「C51」?不,那是51单片机的。我们选「ARM Compiler」
  3. 安装完成后,打开Pack Installer,搜索STM32F1系列
  4. 下载并安装对应的Device Family Pack
我的小技巧: 安装路径不要有中文和空格。我见过太多因为路径带「程序文件」导致编译报错的案例了。直接丢在 D:\Keil_v5 最稳。

配置工程时,有几点要注意:

  • 晶振频率:F103默认是8MHz外部晶振,通过PLL倍频到72MHz
  • 调试器:我用的是ST-Link,便宜又稳定。J-Link也行,但贵
  • Flash烧录算法:选「STM32F10x Med-density Flash」或「High-density」,取决于你的芯片

2.4 标准外设库 vs HAL库

这个问题,几乎每个初学者都会问。我直接说结论:

标准外设库(StdPeriph)

  • 优点:代码执行效率高,寄存器操作透明
  • 缺点:ST已经停止更新,不支持新系列
  • 适合:对实时性要求高的场景,比如PWM控制电机

HAL库

  • 优点:跨平台兼容性好,CubeMX自动生成代码
  • 缺点:代码量大,中断响应慢
  • 适合:快速原型开发,复杂外设配置

我个人习惯是:支付模块用HAL库。为什么?因为支付逻辑本身不要求微秒级的响应,但需要频繁配置串口、I2C、SPI这些外设。HAL库的抽象层能让我少写很多寄存器配置代码。

避坑指南: 我曾经在一个项目里混用了StdPeriph和HAL库的定时器函数,结果定时器中断冲突,系统每隔几分钟就死机一次。排查了整整两天才发现是库函数对TIM寄存器的操作互相覆盖了。所以,一个工程里只用一种库,别混着来。

这里给一个简单的HAL库初始化串口的例子:

// 使用CubeMX生成的代码,初始化USART1
UART_HandleTypeDef huart1;

void MX_USART1_UART_Init(void)
{
    huart1.Instance = USART1;
    huart1.Init.BaudRate = 115200;
    huart1.Init.WordLength = UART_WORDLENGTH_8B;
    huart1.Init.StopBits = UART_STOPBITS_1;
    huart1.Init.Parity = UART_PARITY_NONE;
    huart1.Init.Mode = UART_MODE_TX_RX;
    huart1.Init.HwFlowCtl = UART_HWCONTROL_NONE;
    huart1.Init.OverSampling = UART_OVERSAMPLING_16;
    HAL_UART_Init(&huart1);
}

你看,代码很清晰。如果换成标准库,你得手动配置CR1、CR2、CR3寄存器,还要算波特率分频系数。不是说标准库不好,而是对于支付模块这种业务逻辑复杂的项目,HAL库能让你把精力放在「怎么收钱」而不是「怎么配置寄存器」上。

2.5 开发环境验证

装好环境后,我习惯先跑一个LED闪烁程序。不是为了炫技,而是为了验证:

  • 编译器能不能正常编译
  • 烧录器能不能识别芯片
  • 时钟配置是否正确

代码很简单:

HAL_GPIO_TogglePin(GPIOB, GPIO_PIN_0);
HAL_Delay(500);

如果LED以1秒的频率闪烁,恭喜你,环境搭建成功了。如果没反应,先检查硬件连接——我遇到过最蠢的一次,是把LED的正负极接反了,折腾了半小时才发现。

总结一下:
  • F103系列性价比高,适合支付模块
  • Keil MDK安装注意路径和Pack
  • 新项目推荐HAL库,老项目维护用标准库
  • 先跑个LED验证环境,别急着写业务代码

下一章我们会开始搭建支付模块的硬件电路,包括电源设计、串口隔离、电磁锁驱动这些实战内容。到时候我会分享一个我在量产中踩过的坑——关于电源纹波导致支付芯片复位的问题,嗯,那故事可有意思了。