3、开发环境搭建:Keil MDK安装与配置、STM32CubeMX初始化工程、HAL库与LL库的选择

好,咱们正式开始动手了。做加密狗,第一步不是写代码,而是把“厨房”搭好。我见过不少新手,上来就写,结果编译报错半天找不到原因,最后发现是工具链没配对。嗯,咱们别走弯路。

3.1 Keil MDK 安装与配置

Keil MDK,说白了就是ARM内核单片机最主流的IDE。我个人习惯用MDK 5.38或更新的版本,对STM32G0、L0这些新系列支持更好。

安装步骤其实很简单:

  • 去ARM官网下载MDK-Arm安装包。注意,别下成C51了,那是给51单片机用的。
  • 双击安装,一路Next。路径我建议别带中文,也别有空格。比如 D:\Keil_v5 就挺好。
  • 安装完成后,打开Keil,点 Pack Installer。这里要装你芯片对应的器件包。比如咱们用STM32G0,就搜“STM32G0xx_DFP”。
  • 下载安装对应的Pack。这一步很多人会忘,结果新建工程时找不到芯片型号。
我的小技巧: 装完Pack后,建议把Keil的“自动更新”关掉。有一次我在项目交付前,Keil自动更新了编译器版本,结果工程编译不过,折腾了一下午。你想想看,多耽误事。

配置方面,有几个关键点:

  • 编译器版本: 我建议统一用AC6(ARM Compiler 6)。AC5虽然老牌,但AC6的编译速度和代码密度都更好。在 Project -> Options for Target -> Target 里选。
  • 调试器设置: 如果你用ST-Link,在 Debug 选项卡里选 ST-Link Debugger,然后点 Settings,把 Reset and Run 勾上。这样下载完程序自动运行,不用手动按复位键。
  • Flash Download: 记得在 Utilities 选项卡里勾选 Reset and Run,并确认编程算法选对了。比如STM32G0系列,选 STM32G0xx 128KB Flash
注意: 我曾经遇到过一个问题:下载程序时提示“No Algorithm found for ...”。后来发现是Pack没装全,或者Flash算法选错了。解决办法很简单,重新安装对应芯片的DFP包就行。

3.2 STM32CubeMX 初始化工程

STM32CubeMX,这是ST官方出的图形化配置工具。说白了,就是帮你自动生成初始化代码,省得你对着寄存器手册一行行敲。我个人觉得,对于加密狗这种对时钟、外设要求精确的项目,用CubeMX能减少很多低级错误。

新建工程的流程:

  1. 打开CubeMX,点 New Project
  2. Part Number 里搜你的芯片,比如 STM32G070KBT6。双击选中。
  3. 进入 Pinout & Configuration 界面。这里咱们要配几个关键外设:
    • RCC: 高速外部时钟(HSE)选 Crystal/Ceramic Resonator。咱们加密狗一般用8MHz晶振。
    • SYS: Debug 选 Serial Wire。这样只用SWD两根线就能调试,省IO口。
    • RNG(随机数发生器): 如果芯片支持,一定要使能。加密狗的核心就是真随机数。
    • I2C或SPI: 用来外挂加密芯片(比如ATECC608A)或存储芯片。
  4. 配好引脚后,点 Clock Configuration。我习惯把系统时钟配到最高,比如64MHz。注意看HCLK、APB1、APB2的时钟树,别超频。
  5. 最后点 Project Manager,设置工程名、路径,以及IDE选 MDK-ARM V5。然后点 GENERATE CODE
重点: 生成代码后,不要直接去改CubeMX生成的 main.c 里的初始化部分。如果你想改外设配置,回CubeMX里改,再重新生成。否则下次一生成,你手动改的全没了。我刚开始就吃过这个亏。

3.3 HAL库与LL库的选择

这个问题,几乎每个用STM32的人都会纠结。HAL库(硬件抽象层)和LL库(低层库),到底用哪个?

先说说我的理解:

  • HAL库: 封装得比较厚,函数名长,但用起来方便。比如 HAL_UART_Transmit(),一个函数搞定发送。适合快速开发,对实时性要求不高的场景。
  • LL库: 更接近寄存器操作,代码精简,执行效率高。比如 LL_USART_TransmitData8(),直接操作数据寄存器。适合对时序要求严苛的场景,比如加密狗的通信时序。

那加密狗项目怎么选? 我个人建议:混合使用

什么意思呢?对于初始化部分,比如时钟配置、GPIO模式设置,这些一次性的工作,用HAL库。代码清晰,不容易出错。但对于加密通信、随机数读取、定时器PWM这些对时间敏感的操作,用LL库。

举个例子,咱们读取RNG随机数:

// HAL库方式
uint32_t random_num;
HAL_RNG_GenerateRandomNumber(&hrng, &random_num);

// LL库方式
while(!LL_RNG_IsActiveFlag_DRDY(RNG));
uint32_t random_num = LL_RNG_ReadRandData32(RNG);

你看,LL库少了函数调用的开销,直接读寄存器。在加密狗需要高速产生随机数时,这点时间差就很关键。

避坑指南: 我曾经在一个项目中,全部用HAL库做SPI通信,结果发现每次传输都有几十微秒的延迟。后来换成LL库,延迟降到几微秒。所以,对于加密狗这种对实时性有要求的设备,关键路径一定要用LL库。

最后,怎么在CubeMX里配置?

Pinout & Configuration 界面,每个外设的 Parameter Settings 下面,有个 Library 选项。你可以选 HALLLBoth。我一般选 Both,这样两个库的API都能用。但注意,不要混用同一个外设的HAL和LL函数,容易出问题。

好了,环境搭好了,工程也初始化了。下一章咱们就开始写加密狗的核心逻辑——随机数生成与密钥存储。到时候你会看到,今天选的这些工具和库,到底有多顺手。