Day30 —【STM32F103C8 + Keil5 + Proteus】没有开发板也能学 STM32:从环境搭建到 LED 流水灯仿真
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 创建原理图
新建工程时按下面选择:
- 原理图模板选择
DEFAULT; - 不创建 PCB Layout;
- 固件页面选择“没有固件项目”;
- 完成向导后进入 Schematic Capture。
这样设置的原因是:当前目标只是做虚拟电路仿真,不进行 PCB 制板;固件已经由 Keil 管理,Proteus 只负责加载结果。
4.2 放置元件
按 P 打开 Pick Devices,搜索并放置:
STM32F103C8LED-REDRESLOGICPROBE(推荐)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 始终不亮,应优先检查:
- LED 是否接反;
- LED 和电阻是否真正连接到同一网络;
- 是否缺少 GND;
- GPIO 是否配置成推挽输出;
- 切换速度是否快到肉眼看起来像常亮。
六、Keil 创建 STM32F103C8 工程
6.1 芯片包
在 Pack Installer 中确认 STM32F103C8 可以被搜索到,并安装 Keil::STM32F1xx_DFP。Device Pack 提供:
- STM32F103C8 的寄存器定义;
- 启动文件;
- 系统时钟文件;
- Keil 对该芯片的工程支持。
如果没有芯片包,即使能写 C 代码,工程也缺少启动入口、内存布局和寄存器地址定义。
6.2 运行环境组件
新建工程并选择 STM32F103C8 后,在 Manage Run-Time Environment 中至少选择:
CMSIS → COREDevice → 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。最可靠的验证顺序是:
- Simulation Log 能否成功读取 HEX;
- PA0 逻辑探针是否在
0和1之间切换; - 电压表是否在约 0 V 和 3.3 V 之间变化;
- 示波器是否出现周期方波;
- 最后再看 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 不闪
依次检查:
- 使用逻辑探针确认 GPIO 是否真的切换;
- 检查 LED 极性;
- 每个 LED 是否有独立电阻;
- GPIO 是否为推挽输出;
- HEX 是否为最新一次编译生成;
- Proteus MCU 的 Program File 是否仍指向旧文件;
- 延时时间和 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。没有硬件并不会阻止前期学习,但仿真结果最终仍应在真实开发板上验证。
更多推荐


所有评论(0)