2. CMS32开发环境搭建:Keil MDK安装与配置、CMS32固件库导入、第一个串口工程创建
说实话,做嵌入式开发这么多年,我换过不少IDE。从早期的IAR到后来的Eclipse,再到现在的Keil MDK。但要说上手最快、资料最多的,还得是Keil。尤其是做CMS32这种ARM内核的单片机,Keil MDK几乎是标配。
这一章,咱们就把开发环境从头到尾捋一遍。你跟着我走,保证不出错。
2.1 Keil MDK的安装与配置
先说说版本问题。我建议你用MDK 5.38或更新的版本。为什么?因为老版本对CMS32的器件包支持不够好。我之前有个同事用MDK 5.26折腾了一下午,器件包死活装不上,换了新版五分钟搞定。
2.1.1 安装步骤
- 下载安装包:去Keil官网下载MDK-ARM安装程序。注意区分32位和64位版本。
- 运行安装:双击安装包,一路Next。安装路径我建议用默认的
C:\Keil_v5,别改到中文目录下,否则后面编译会出怪问题。 - 激活License:安装完成后打开Keil,点击
File → License Management。输入你的License ID Code(正版用户)或使用评估版(有代码大小限制,但CMS32的工程一般够用)。 - 安装器件包:点击
Pack Installer图标,在搜索框输入CMS32,找到对应的Device Family Pack,点击Install。
2.1.2 配置编译器与调试器
装完只是第一步,配置才是关键。我个人习惯在安装完成后做两件事:
- 设置编译器路径:点击
Project → Manage → Project Components,在Folders/Extensions标签页确认ARM Compiler版本。我推荐用V6版本,编译速度快,生成的代码也更小。 - 配置调试器:如果你用J-Link,点击
Project → Options for Target → Debug,选择J-LINK/J-TRACE Cortex。然后点Settings,确认SWD接口能识别到设备ID。如果识别不到,八成是接线问题或者驱动没装好。
2.2 CMS32固件库导入
固件库说白了就是官方帮你写好的底层驱动。你想想看,如果每个寄存器都要自己翻手册配置,那项目得做到猴年马月?中微官方提供了完整的CMS32标准外设库,咱们直接拿来用就行。
2.2.1 获取固件库
去中微半导体官网的下载中心,找到 CMS32系列标准外设库。下载后解压,你会看到这样的目录结构:
CMS32_StdPeriph_Lib/
├── Libraries/
│ ├── CMSIS/
│ └── CMS32_StdPeriph_Driver/
├── Project/
│ ├── MDK-ARM/
│ └── Templates/
├── Utilities/
└── Documentation/
嗯,这里要注意:Libraries/CMSIS 是ARM官方的内核抽象层,CMS32_StdPeriph_Driver 才是中微写的外设驱动。这两个都得用上。
2.2.2 导入到Keil工程
我习惯新建一个空白工程,然后手动添加固件库文件。这样做的好处是——你清楚每个文件是干什么的。具体步骤:
- 新建工程:点击
Project → New μVision Project,选择你的芯片型号(比如CMS32L051)。 - 添加分组:在Project窗口右键,
Add Group。我一般建这几个组:Startup— 放启动文件CMSIS— 放内核相关文件StdPeriph_Driver— 放外设驱动源文件User— 放你自己的代码
- 添加文件:在每个组里右键
Add Existing Files to Group,从固件库目录找到对应的.c和.h文件加进来。 - 设置头文件路径:点击
Options for Target → C/C++,在Include Paths里添加:Libraries/CMSIS/IncludeLibraries/CMS32_StdPeriph_Driver/Inc
fatal error: 'CMS32L051.h' file not found。我见过太多新手卡在这一步了。
2.3 第一个串口工程创建
环境搭好了,固件库也导入了。接下来咱们写个串口通信的小程序。说白了就是让单片机通过串口发一句 "Hello CMS32!" 出来。
2.3.1 工程结构
先看看整个工程长什么样:
2.3.2 编写main.c
代码其实不复杂。我直接贴出来,你照着敲一遍:
#include "CMS32L051.h"
#include "cms32l051_uart.h"
void UART0_Init(void)
{
/* 使能UART0时钟 */
CLK_EnableModuleClock(UART0_MODULE);
/* 配置GPIO:PA0为TX,PA1为RX */
SYS->PA_AFS0 &= ~(0x3 << 0); // 清除功能选择
SYS->PA_AFS0 |= (0x1 << 0); // PA0设为UART0_TX
SYS->PA_AFS0 |= (0x1 << 2); // PA1设为UART0_RX
/* 配置UART参数:115200-8-N-1 */
UART_Open(UART0, 115200);
}
int main(void)
{
uint8_t msg[] = "Hello CMS32!\r\n";
UART0_Init();
while(1)
{
/* 发送字符串 */
for(uint8_t i = 0; msg[i] != '\0'; i++)
{
UART_Write(UART0, msg[i]);
}
/* 延时约1秒 */
for(volatile uint32_t delay = 0; delay < 4800000; delay++);
}
}
2.3.3 编译与下载
代码写完了,按 F7 编译。如果没报错,你会看到 0 Error(s), 0 Warning(s)。嗯,这里要注意:如果出现警告,别直接忽略。我见过有人因为一个未使用的变量警告,结果调试时程序跑飞了——其实就是优化等级把变量优化掉了。
编译通过后,按 Ctrl+F5 开始下载。下载成功后,打开串口助手(波特率115200,数据位8,停止位1,无校验),你应该能看到单片机每隔1秒发一次 "Hello CMS32!"。
2.4 常见问题与避坑指南
| 问题现象 | 可能原因 | 解决办法 |
|---|---|---|
| 编译报错 "cannot open source input file" | 头文件路径未添加 | 检查Options→C/C++→Include Paths |
| 下载时提示 "No Cortex-M SW Device Found" | 调试器驱动问题或接线错误 | 重装驱动,检查SWDIO/SWCLK/GND三根线 |
| 串口收到乱码 | 波特率不匹配或时钟配置错误 | 核对串口助手波特率,检查系统时钟初始化 |
| 程序跑不起来,停在while(1) | 启动文件或SystemInit未正确执行 | 检查startup文件是否添加,SystemInit是否调用 |
好了,环境搭好了,第一个串口工程也跑通了。接下来你就可以在这个基础上,开始折腾各种外设了。记住,嵌入式开发没有捷径,多动手、多踩坑,经验就是这么积累起来的。