文章目录
-
- 一、环境没配好,后面每一步都在还债
- [二、安装 Keil MDK5](#二、安装 Keil MDK5)
- [三、安装 STM32CubeMX](#三、安装 STM32CubeMX)
- [四、ST-Link 驱动](#四、ST-Link 驱动)
- 五、串口驱动与串口助手
-
- [5.1 安装 USB 转 TTL 驱动](#5.1 安装 USB 转 TTL 驱动)
- [5.2 串口助手参数](#5.2 串口助手参数)
- [5.3 两个细节](#5.3 两个细节)
- 六、本地起一个网页服务(H5)
- [七、最重要的一条纪律:只写 USER CODE](#七、最重要的一条纪律:只写 USER CODE)
-
- 自己新增的文件放哪里
- [7.1 `.c` 文件:加进 Keil 工程组](#7.1
.c文件:加进 Keil 工程组) - [7.2 `.h` 文件:靠 Include Paths,不靠 Add Files](#7.2
.h文件:靠 Include Paths,不靠 Add Files) - [7.3 顺带说清 `.c` 和 `.h` 的分工](#7.3 顺带说清
.c和.h的分工)
- 八、装完先做一次冒烟测试
- 九、本章易错点总结
- 十、小结与下一篇
系列第二篇。上一篇把"要做什么、模块怎么连、数据怎么流"定下来了;这一篇把写代码之前的工具链全部装好,并且立下一条贯穿全项目的纪律。
适合人群:已经想清楚项目结构,准备真正打开 Keil 动手的同学。
一、环境没配好,后面每一步都在还债
我做第一个 STM32 项目时,最崩溃的不是代码写不出来,而是根本不知道问题出在哪一层:
- 烧录失败,是 ST-Link 驱动没装,还是芯片没识别?
- 编译报错,是缺固件包,还是路径里有中文?
- 串口没打印,是波特率错了,还是
printf重定向没生效?
这三类问题,只要环境本身是干净的,都能在几分钟内定位。但如果环境带着毛病,你就会在"写代码"和"修环境"之间反复横跳,最后连自己改了什么都不知道。
所以这一篇的目标很明确:装完、配完、验证完,一个都不留到后面。
装完之后你应该达到这个状态:
| 检查项 | 达标标准 |
|---|---|
| Keil | 能新建工程并选到 STM32F411RETx |
| 固件包 | Pack Installer 里 Keil::STM32F4xx_DFP 已安装 |
| CubeMX | 能生成 F4 系列工程,且固件包版本确定 |
| ST-Link | Keil 的 Debug 设置里能读到芯片 IDCODE |
| 串口助手 | 115200 8N1 能收到板子打印的文本 |
| H5 | 本地 http://localhost:8000 能打开页面 |
二、安装 Keil MDK5
-
安装 Keil MDK 5.36 及以上。
-
安装路径必须是纯英文、无空格 ,例如
D:\Keil_v5。这一点别嫌麻烦。路径里带中文或空格,轻则编译报奇怪的错误,重则链接阶段直接失败,而且报错信息完全指不到真正原因。
-
打开 Keil → 点工具栏的 Pack Installer → 搜索
STM32F4→ 安装 Keil::STM32F4xx_DFP。DFP 就是"器件支持包"。没有它,Keil 根本不认识 STM32F411 这颗芯片,新建工程时设备列表里是空的。
-
验证:
Options for Target → Device里能选到 STM32F411RETx,才算真的装好。
小提醒:Pack Installer 下载慢是常态,可以挂着去装 CubeMX,不用干等。
三、安装 STM32CubeMX
- 安装 CubeMX 6.x,同样放英文路径。
- 首次启动 →
Help → Manage embedded software packages→ 安装 STM32F4 固件包,建议 1.27.x 或 1.28.x。 - 把固件包版本记下来。
为什么一定要记版本?因为 CubeMX 生成的 Keil 工程会引用这个固件包路径,版本对不上时,换一台电脑打开工程就可能满屏红叉。团队协作时这一步尤其重要。
四、ST-Link 驱动
- 插上 ST-Link,打开设备管理器,出现
STMicroelectronics STLink dongle就说明驱动正常。 - Keil 里配置:
Options for Target → Debug选 ST-Link Debugger → 点Settings。 - 在
SW Device区域能看到一列 IDCODE,才说明电脑真正连上了芯片。
如果这里显示 No target connected,先别怀疑程序,按顺序查:
- 板子有没有供电(只插 ST-Link 不一定给板子供电);
- SWDIO / SWCLK / GND 三根线是否接对;
- 芯片是否处于复位或低功耗状态(按住复位再点连接试试)。
五、串口驱动与串口助手
串口助手是我们后面调试的"眼睛"。但在打开它之前,得先让电脑"看见"这个串口------没有 COM 口,串口助手装得再好也白搭。
5.1 安装 USB 转 TTL 驱动
STM32 输出的是 TTL 电平,电脑只认 USB,中间靠一块 USB 转 TTL 模块(常见芯片 CH340、CP2102、FT232)做转换。这个模块需要驱动。
第一步:确认你手上模块的芯片型号。
模块背面或芯片丝印上一般能直接看到:
| 芯片 | 常见丝印 | 驱动来源 |
|---|---|---|
| CH340 / CH341 | CH340G、CH340C |
沁恒官网 CH341SER.EXE |
| CP2102 / CP2104 | CP2102 |
Silicon Labs CP210x VCP Driver |
| FT232 | FT232RL |
FTDI 官网 VCP 驱动 |
第二步:装驱动。
- 优先用芯片厂商官网的驱动,别用来路不明的"万能串口驱动",这类驱动经常版本老旧,装上反而频繁蓝屏。
- Windows 10/11 有时会通过 Windows Update 自动装好,插上就有 COM 口,那就什么都不用做。
- CH340 的安装包右键 以管理员身份运行,装完建议重启一次。
第三步:验证。
-
插上 USB 转 TTL(先别接 STM32,排除接线干扰);
-
右键"此电脑" → 管理 → 设备管理器;
-
展开 端口 (COM 和 LPT),应该出现类似:
textUSB-SERIAL CH340 (COM6) -
记住这个 COM 号,串口助手打开时要选它。
如果看不到这一项,或者出现一个带黄色感叹号的未知设备,按下面顺序排查:
| 现象 | 原因 | 处理 |
|---|---|---|
| 完全没有任何新设备 | USB 线是"只充电"线,没有数据线芯 | 换一根确定能传数据的线 |
| 黄色感叹号 / 未知设备 | 驱动没装或装错型号 | 卸载设备,重装对应芯片驱动 |
| 有 COM 口但打不开 | 被其他软件占用(另一个串口助手、Keil 的串口窗口) | 关掉占用它的软件再打开 |
| 端口号是 COM10 以上,助手列表里没有 | 部分老版本串口助手只枚举 COM1~COM9 | 设备管理器 → 端口属性 → 端口设置 → 高级 → 改成 COM3 之类 |
| 换了个 USB 口,COM 号变了 | Windows 按"设备+端口"分配号 | 正常现象,重新在助手里选新号 |
还有一个新手常忽略的点:USB 转 TTL 必须和 STM32 共地 ,并且接线要交叉------模块的 RX 接 STM32 的 TX(PA9) ,模块的 TX 接 STM32 的 RX(PA10)。接反的典型现象是:能发不能收,或者干脆一片空白。
5.2 串口助手参数
驱动装好、COM 口出现之后,打开串口助手,参数必须固定:
| 参数 | 值 |
|---|---|
| 端口 | 设备管理器里看到的 COM 号 |
| 波特率 | 115200 |
| 数据位 | 8 |
| 停止位 | 1 |
| 校验 | 无 |
| 流控 | 无 |
5.3 两个细节
- 接收区不要勾"十六进制显示"。 我们要看的是
[MODE] Manual ...这种文本日志,勾了十六进制就只剩一串5B 4D 4F 44 45 5D,没法读。 - 编码选 UTF-8 或 GBK 都行。本项目的
printf全部是纯 ASCII,所以不会出现中文乱码问题。
六、本地起一个网页服务(H5)
后面的 H5 页面用了 mqtt.js 的 CDN 和 wss 连接。直接双击 index.html(也就是 file:// 协议)有时会被浏览器的安全策略拦住,表现为页面能开、但 MQTT 一直连不上。
推荐用 Python 起一个本地静态服务器:
powershell
cd "d:\IOT_Experiment\ZLRC_Experiment\STM32_SCH_project\project\8.HAL_SmartHome\3.H5界面\4班智能家居"
python -m http.server 8000
然后浏览器打开:
text
http://localhost:8000
这样页面就走 http:// 协议,WebSocket 和 CDN 都不会被限制。
页面改完记得按 Ctrl + F5 硬刷新。浏览器缓存非常顽固,"代码改了但页面没变"十有八九是缓存,不是代码。
七、最重要的一条纪律:只写 USER CODE
这一节比前面所有安装步骤都重要,因为它是唯一一个会让你白干几小时的坑。
CubeMX 生成的 .c/.h 文件里,到处是这种成对出现的标记:
c
/* USER CODE BEGIN 2 */
// 你的代码写这里
/* USER CODE END 2 */
规则只有一条:
| 位置 | 点 GENERATE CODE 之后 |
|---|---|
| 两个标记中间 | 保留你的代码 |
| 两个标记外面 | 直接覆盖,写了也会丢 |
我第一次踩这个坑时,在 main.c 的 while(1) 外面加了一整段初始化代码,调通之后回 CubeMX 改了一个引脚,再点生成------那段代码连同当时的调试思路一起消失了。更痛苦的是,我一开始还以为是 Keil 工程坏了。
所以请从现在开始养成习惯:
- 所有人工代码,只写在
USER CODE BEGIN/END之间; - 每次点
GENERATE CODE之前,先确认没有代码写在标记外面; - 生成后先编译一次,确认没有丢东西再继续。
自己新增的文件放哪里
除了改生成代码,我们还要写三个自己的驱动模块:
text
HAL_SmartHome\
└─ App\
├─ DHT11.c / DHT11.h 温湿度(单总线)
├─ ens160.c / ens160.h 空气质量(I2C)
└─ mqtt.c / mqtt.h ESP-AT + MQTT
放在 App\ 目录下有两个好处:
- CubeMX 不管这个目录,所以怎么改都不会被覆盖;
- 结构清晰,和生成代码彻底分开,出问题一眼就知道该看哪边。
但要注意:文件放进文件夹 ≠ 加入工程 。而且 .c 和 .h 的处理方式完全不同,这一步必须分开做。
7.1 .c 文件:加进 Keil 工程组
.c 文件里是真正的函数实现,必须参与编译。做法:
- 在 Keil 左侧工程树里右键
Target 1→ Manage Project Items; - 在
Groups里新建一个组,命名为App; - 选中
App组,点右侧 Add Files ,把DHT11.c、ens160.c、mqtt.c三个文件加进去; - 点 OK 保存。
只放文件夹不加工程,编译时不会报错,但链接时会报:
text
L6218E: Undefined symbol ReadData (referred from main.o)
看到这个错误,第一反应就应该是".c 没加进 Keil 工程"。
7.2 .h 文件:靠 Include Paths,不靠 Add Files
.h 文件里只有函数声明、宏定义和类型定义,它不参与编译,不需要(也不应该)加进 App 组去编译。编译器找头文件靠的是"搜索路径",不是"工程文件列表"。
所以真正要做的是告诉 Keil:App 这个目录也要去搜。做法:
- 点魔术棒 Options for Target → 切到 C/C++ 选项卡;
- 找到 Include Paths ,点右边的
...; - 新增一行,填
..\App(相对于.uvprojx所在目录); - 确定保存,然后重新编译。
..\App 是相对路径,工程整体挪到别的电脑上也不会失效;用绝对路径 D:\...\App 换台电脑就会找不到。
验证方法很简单:在 main.c 的 USER CODE BEGIN Includes 里写
c
#include "DHT11.h"
编译。如果报下面的错误,就是 Include Paths 没加对:
text
error: cannot open source input file "DHT11.h"
如果编译通过,说明头文件已经能被正确找到。
可以在
Manage Project Items里顺手把.h也 Add 进App组,这样工程树里能直接双击打开、方便查看。但要清楚:它只是"显示在树里",并不解决"找不到头文件"的问题,Include Paths 该加还得加。
7.3 顺带说清 .c 和 .h 的分工
| 文件 | 放什么 | 是否需要加入工程 |
|---|---|---|
DHT11.c |
函数实现、私有变量 | 必须 Add Files 到 App 组 |
DHT11.h |
函数声明、宏、extern 声明 |
不需要,但要加进 Include Paths |
main.c 顶部 |
#include "DHT11.h" |
已有文件,无需操作 |
头文件里记得加"防重复包含"保护,否则多个 .c 互相包含时会报重复定义:
c
#ifndef __DHT11_H
#define __DHT11_H
/* 声明写这里 */
#endif
八、装完先做一次冒烟测试
环境全部装好后,不要急着写传感器代码。先做一个最小的"冒烟测试":
-
用 CubeMX 新建一个 F411 工程,只开 USART1;
-
生成代码,Keil 里勾上 Use MicroLIB;
-
在
main()的while(1)里加一句:cprintf("hello stm32\r\n"); HAL_Delay(1000); -
编译、烧录、打开串口助手(115200)。
如果每秒能看到一行 hello stm32,说明这几件事同时成立了:
- 时钟配置正确(否则波特率会偏,收到乱码);
- 下载链路正常;
- 串口助手参数正确;
printf重定向和 MicroLIB 都生效了。
这一步通过,后面的所有调试才有"可信的观察窗口"。
九、本章易错点总结
| 现象 | 真正原因 | 正确做法 |
|---|---|---|
| 编译或链接报莫名其妙的错误 | Keil 装在带中文或空格的路径下 | 装到 D:\Keil_v5 这类纯英文无空格路径 |
| 新建工程时找不到 STM32F411RETx | 没装 Keil::STM32F4xx_DFP |
Pack Installer 里安装 DFP 后再新建 |
| 串口全是乱码,或完全没输出 | 波特率不是 115200,或 printf 没重定向 |
串口助手固定 115200 8N1;重定向到 USART1 |
printf 有代码但一个字符都不出 |
Keil 没勾 Use MicroLIB | Options for Target → Target → Use MicroLIB |
| 改了一次引脚,之前写的代码全没了 | 代码写在 USER CODE 标记外面 |
只写在 BEGIN/END 之间,生成前检查一遍 |
编译通过但链接报 L6218E Undefined symbol |
新增的 .c 只放进文件夹,没加进 Keil 工程 |
Manage Project Items 里 Add Files |
| H5 页面能打开但 MQTT 连不上 | 用 file:// 直接双击打开的 |
用 python -m http.server 8000 起本地服务 |
| 改了 H5 代码但页面没变化 | 浏览器缓存 | 按 Ctrl + F5 硬刷新 |
十、小结与下一篇
这一篇做完,工具链已经齐了,而且验证过:
- Keil 能识别 F411,DFP 已装;
- CubeMX 能生成工程,固件包版本已记录;
- ST-Link 能读到芯片,串口助手能收到文本;
- H5 能用本地服务器打开;
- 最重要的:所有代码只写在
USER CODE里,自己的驱动统一放App\。
下一篇开始动硬件:电源与共地怎么接、每个模块接哪个引脚、拨码开关怎么做 USART2 二选一,以及上电前的自检清单。接线是后面所有问题的源头,值得单独用一篇讲透。
如果这篇文章对你有帮助,欢迎点赞收藏。系列更新中,下一篇见。