Day30 —【STM32F103C8 + Keil5 + Proteus】没有开发板也能学 STM32:从环境搭建到 LED 流水灯仿真

Day30 对当前 Proteus 学习阶段进行完整整理。本文记录一次“没有真实硬件”的 STM32 学习实践:使用 Keil µVision 编译 STM32F103C8 程序,生成 HEX 固件,再由 Proteus 搭建虚拟电路并加载固件。文章同时记录单灯闪烁、四灯流水灯、常见故障以及许可证问题,方便初学者复现和排错。

一、为什么选择 Keil + Proteus

暂时没有 STM32 开发板时,仍然可以先学习以下内容:

  • STM32 工程的创建和芯片选择;
  • GPIO、RCC、SysTick 等寄存器的基本使用;
  • 编译、链接以及 HEX 固件的生成过程;
  • LED、电阻、电源、复位和启动引脚的连接方法;
  • 使用逻辑探针、虚拟示波器观察 GPIO 波形;
  • 将“代码行为”和“电路现象”对应起来。

这套组合中,两款软件的分工很明确:

工具 作用
Keil µVision 编写、编译和链接 STM32 程序,输出 HEX 固件
Proteus 搭建虚拟电路,给虚拟 MCU 加载 HEX,观察运行结果

需要特别理解:Proteus 不是用来替代 Keil 编译代码的。本项目在 Proteus 新建工程时选择“没有固件项目”,因为固件统一由 Keil 生成。

二、本次环境

  • MCU:STM32F103C8(ARM Cortex-M3)
  • IDE:Keil µVision 5
  • 编译器:Arm Compiler 6.21
  • Device Pack:Keil STM32F1xx DFP 2.4.1
  • 仿真软件:Proteus 9 Professional 9.0 SP2
  • 开发方式:寄存器级 C
  • 实验项目:
    • Day28:PA0 单灯闪烁;
    • Day29:PA0~PA3 四灯流水灯。

软件版本不必完全相同,但 Keil 必须能够选择 STM32F103C8,Proteus 元件库也必须带有该器件的可仿真模型。

三、整体工作流

Keil 新建 STM32F103C8 工程
          ↓
编写 GPIO 与延时代码
          ↓
开启 Create HEX File 并编译
          ↓
Proteus 绘制 STM32 + LED 电路
          ↓
把 Keil 输出的 HEX 加载到 STM32 元件
          ↓
运行仿真,用逻辑探针或示波器验证

掌握这条链路比单纯记住按钮位置更重要。以后增加按键、串口、定时器、I²C 或 FreeRTOS,基本工作流仍然相同。

四、Proteus 新建工程

4.1 创建原理图

新建工程时按下面选择:

  1. 原理图模板选择 DEFAULT
  2. 不创建 PCB Layout;
  3. 固件页面选择“没有固件项目”;
  4. 完成向导后进入 Schematic Capture。

这样设置的原因是:当前目标只是做虚拟电路仿真,不进行 PCB 制板;固件已经由 Keil 管理,Proteus 只负责加载结果。

4.2 放置元件

P 打开 Pick Devices,搜索并放置:

  • STM32F103C8
  • LED-RED
  • RES
  • LOGICPROBE(推荐)
  • OSCILLOSCOPE(需要观察波形时使用)

电阻设置为 330R。限流电阻的作用是限制 LED 电流;即使是仿真,也应按照真实电路思维设计。

五、单灯电路连接

最小实验使用 PA0 驱动 LED:

PA0 → 330 Ω 电阻 → LED → GND

此外还需要处理以下引脚:

引脚 连接 原因
BOOT0 GND 选择从主 Flash 启动
NRST 10 kΩ 上拉到 VDD 保证复位脚处于稳定高电平
VDDA、VBAT VDD 给模拟域和备份域供电
VSSA GND 模拟地

LED 极性为什么重要

LED 是有方向的器件。GPIO 输出高电平时,必须形成从 GPIO、限流电阻、LED 到 GND 的完整电流路径,LED 才会导通。如果逻辑探针已经在 0 和 1 之间变化,但 LED 始终不亮,应优先检查:

  1. LED 是否接反;
  2. LED 和电阻是否真正连接到同一网络;
  3. 是否缺少 GND;
  4. GPIO 是否配置成推挽输出;
  5. 切换速度是否快到肉眼看起来像常亮。

六、Keil 创建 STM32F103C8 工程

6.1 芯片包

在 Pack Installer 中确认 STM32F103C8 可以被搜索到,并安装 Keil::STM32F1xx_DFP。Device Pack 提供:

  • STM32F103C8 的寄存器定义;
  • 启动文件;
  • 系统时钟文件;
  • Keil 对该芯片的工程支持。

如果没有芯片包,即使能写 C 代码,工程也缺少启动入口、内存布局和寄存器地址定义。

6.2 运行环境组件

新建工程并选择 STM32F103C8 后,在 Manage Run-Time Environment 中至少选择:

  • CMSIS → CORE
  • Device → Startup

Startup 会提供中断向量表和复位入口,CMSIS CORE 提供 Cortex-M3 的统一核心定义。

七、Day28:PA0 单灯闪烁

核心代码如下:

#include "stm32f10x.h"

static void systick_init_1ms(void)
{
    SystemCoreClockUpdate();
    SysTick->LOAD = (SystemCoreClock / 1000U) - 1U;
    SysTick->VAL  = 0U;
    SysTick->CTRL = SysTick_CTRL_CLKSOURCE_Msk |
                    SysTick_CTRL_ENABLE_Msk;
}

static void delay_ms(uint32_t milliseconds)
{
    while (milliseconds > 0U)
    {
        while ((SysTick->CTRL & SysTick_CTRL_COUNTFLAG_Msk) == 0U)
        {
        }
        milliseconds--;
    }
}

int main(void)
{
    RCC->APB2ENR |= RCC_APB2ENR_IOPAEN;

    GPIOA->CRL &= ~0x0000000FUL;
    GPIOA->CRL |=  0x00000002UL;

    GPIOA->BRR = GPIO_BRR_BR0;
    systick_init_1ms();

    while (1)
    {
        GPIOA->ODR ^= GPIO_ODR_ODR0;
        delay_ms(1000U);
    }
}

7.1 RCC 为什么要使能

RCC->APB2ENR |= RCC_APB2ENR_IOPAEN;

STM32 为了节能,外设时钟默认不一定开启。GPIOA 没有时钟时,对它的寄存器配置不会产生预期效果。

7.2 PA0 为什么写成 0x2

STM32F1 的 GPIOx_CRL 每 4 位控制一个引脚。PA0 的配置值 0010 表示:

  • MODE0 = 10:输出模式,最大速度 2 MHz;
  • CNF0 = 00:通用推挽输出。

7.3 SysTick 为什么适合入门

SysTick 是 Cortex-M 内核自带的 24 位定时器。将重装值设为 SystemCoreClock / 1000 - 1,可得到约 1 ms 的计数周期。轮询 COUNTFLAG 比空循环延时更容易解释,也更接近嵌入式工程中的时间基准。

八、生成 HEX 固件

进入:

Options for Target → Output → 勾选 Create HEX File

然后执行 Rebuild。最终构建结果为 0 Error(s),说明程序已经成功编译、链接并生成 HEX。

构建过程中出现过以下警告:

  • 旧版头文件注释包含非 UTF-8 字符;
  • 文件末尾缺少换行;
  • Pack 内系统文件的数组访问和变量声明警告。

这些警告没有阻止 HEX 生成,但仍应区分“警告”和“错误”:错误必须解决后才能生成固件;警告需要分析来源,不能看到数量多就直接忽略。

九、给 Proteus 的 STM32 加载程序

双击原理图中的 STM32F103C8,找到 Program File,选择 Keil 生成的 .hex 文件。

同时建议:

  • OSC Frequency 与程序的系统时钟设定保持一致;
  • Clock Scale 使用默认值;
  • 不要为了“让灯更快”随意设置为 8 Times,否则 Proteus 时间和代码延时不再直观对应。

运行后,Simulation Log 出现 Loading HEX file 和读取字节数,说明固件已被装载到虚拟 MCU。

十、如何判断程序是否真的运行

不要只盯着 LED。最可靠的验证顺序是:

  1. Simulation Log 能否成功读取 HEX;
  2. PA0 逻辑探针是否在 01 之间切换;
  3. 电压表是否在约 0 V 和 3.3 V 之间变化;
  4. 示波器是否出现周期方波;
  5. 最后再看 LED 视觉效果。

如果逻辑探针变化而 LED 不闪,说明“程序与 GPIO 大概率正常”,问题更可能在 LED 极性、连接方式、限流电阻或视觉刷新上。这种分层排错方法比反复修改代码有效得多。

十一、Day29:四灯流水灯

完成单个 GPIO 后,将 PA0~PA3 都配置为推挽输出:

GPIOA->CRL &= ~0x0000FFFFUL;
GPIOA->CRL |=  0x00002222UL;

每个 LED 必须单独串联一个 330 Ω 电阻:

PA0 → 330 Ω → LED0 → GND
PA1 → 330 Ω → LED1 → GND
PA2 → 330 Ω → LED2 → GND
PA3 → 330 Ω → LED3 → GND

流水灯核心逻辑:

while (1)
{
    GPIOA->ODR &= ~0x0000000FUL;
    GPIOA->ODR |= (1UL << led_index);

    delay_ms(300U);

    led_index++;
    if (led_index >= 4U)
    {
        led_index = 0U;
    }
}

1UL << led_index 会让逻辑 1 依次移动到 PA0、PA1、PA2、PA3:

led_index 低四位 点亮引脚
0 0001 PA0
1 0010 PA1
2 0100 PA2
3 1000 PA3

当前已完成 Keil 工程、HEX 和 Proteus 原理图;最终动态现象还需要在有效的仿真许可证下继续复验。

十二、这次遇到的典型问题

12.1 搜不到 STM32F103C8

可能原因:

  • 使用的 Proteus 版本过旧;
  • 元件库不含 Cortex-M3 STM32 模型;
  • 搜索条件勾选了错误的分类或“仅显示带模型元件”。

正确版本中搜索 STM32F103 应能看到 C4、C6、C8 等型号。只有带可执行仿真模型的 MCU 才能运行 HEX,单纯原理图符号不能完成 MCU 仿真。

12.2 引脚显示 0/1,但 LED 不闪

依次检查:

  1. 使用逻辑探针确认 GPIO 是否真的切换;
  2. 检查 LED 极性;
  3. 每个 LED 是否有独立电阻;
  4. GPIO 是否为推挽输出;
  5. HEX 是否为最新一次编译生成;
  6. Proteus MCU 的 Program File 是否仍指向旧文件;
  7. 延时时间和 Clock Scale 是否匹配。

12.3 仿真很慢、CPU 占用很高

同时放置多个仪器、探针或存在不合理连线时,仿真负载会明显上升。排错时先保留最小系统:MCU、一个 LED、一个电阻和一个逻辑探针,确认正常后再逐步增加元件。

12.4 Bad or missing Customer Key

软件修复后能够启动,但主页显示:

Licensing error. Bad or missing Customer Key.
Not Licensed for Simulation

这不是 STM32 工程或 HEX 的问题,而是许可证状态导致仿真功能被禁用。不要从不明来源复制 DLL 覆盖安装目录或 Windows 系统文件,这会带来安全、稳定性和合规风险。

根据 Labcenter 官方说明:普通 Proteus Demo 的微控制器仿真期为 14 天,但不能仿真用户自己创建的 MCU 设计,也不能保存自己的工作;如需完整验证自建 STM32 工程,应申请完整 evaluation license、使用学校提供的教育/云许可证,或者购买相应授权。

十三、工程目录

GitHub 仓库:https://github.com/jdai10590-afk/Embedded-C-Learning-Projects

day28/
├─ README.md
└─ Src/main.c              # PA0 单灯闪烁

day29/
├─ README.md
├─ Src/main.c              # PA0~PA3 流水灯
├─ Keil/                   # Keil 工程与 HEX
└─ Proteus/                # Proteus 原理图工程

day30/
├─ README.md               # 本文(CSDN Markdown)
└─ Images/                 # 本文截图

十四、本阶段总结

目前已经走通以下关键链路:

  • Keil 能识别 STM32F103C8;
  • Device Pack、CMSIS 和 Startup 组件可用;
  • 寄存器级 GPIO 与 SysTick 程序能够编译;
  • Keil 能生成 HEX;
  • Proteus 能识别 STM32F103C8 模型并加载 HEX;
  • 逻辑探针可观察 GPIO 的 0/1 状态;
  • 已搭建单灯和四灯流水灯原理图;
  • 已明确 LED 不闪时的分层排错方法;
  • 已定位当前阻塞项为仿真许可证,而不是缺少所谓 version.dll

下一阶段先在有效许可证下复验 Day28 和 Day29 的动态现象,再学习按键输入、外部中断、定时器 PWM、USART 和 FreeRTOS。没有硬件并不会阻止前期学习,但仿真结果最终仍应在真实开发板上验证。

Logo

智能硬件社区聚焦AI智能硬件技术生态,汇聚嵌入式AI、物联网硬件开发者,打造交流分享平台,同步全国赛事资讯、开展 OPC 核心人才招募,助力技术落地与开发者成长。

更多推荐