1. 环境搭建与工具准备
在开始STM32开发之前,我们需要准备好必要的软件工具链。作为嵌入式开发工程师,我强烈建议使用官方推荐的开发环境组合:STM32CubeMX + Keil MDK。这套组合既能享受图形化配置的便利,又能获得专业IDE的强大调试功能。
1.1 软件下载与安装
首先需要获取STM32CubeMX,这是ST官方推出的免费配置工具。访问ST官网(www.st.com)搜索下载最新版本。安装时注意勾选对应芯片系列的HAL库,比如我们使用的F1系列就选择STM32F1xx HAL库。
对于Keil MDK,这是ARM官方推出的付费IDE。作为学生或爱好者,可以申请教育版license。安装时需要注意:
- 默认安装路径不要包含中文或空格
- 安装完成后立即获取对应芯片的Device Family Pack(DFP)
- 建议安装版本不低于5.25,以确保对新款芯片的支持
提示:Keil的pack包也可以通过离线方式安装。从官网下载后直接双击运行即可,安装路径会自动识别Keil的安装位置。
1.2 开发板硬件确认
在开始配置前,请确认你的开发板硬件信息:
- 主控芯片型号(如STM32F103C8T6)
- 外部晶振频率(通常8MHz)
- LED连接引脚(常见为PC13)
- 串口引脚(通常USART1的PA9/PA10)
这些信息一般可以在开发板原理图或商品说明中找到。如果使用最小系统板,可能需要自行连接外围电路。
2. 工程创建与基础配置
2.1 新建CubeMX工程
启动STM32CubeMX后,点击"New Project",在芯片选择界面输入你的型号关键词。这里有个实用技巧:在右上角筛选栏选择"STM32F1"系列,可以快速定位到目标芯片。
选中芯片后,右侧会显示封装信息。特别注意:
- LQFP封装与QFN封装的引脚排列不同
- 闪存大小要匹配实际芯片(如C8T6是64KB)
- 温度范围选择Commercial(0-70℃)即可
2.2 时钟树配置
时钟配置是STM32开发的关键环节。我们的目标是让芯片运行在最高效的72MHz主频,配置步骤如下:
-
在Pinout视图的System Core→RCC中:
- High Speed Clock(HSE)选择Crystal/Ceramic Resonator
- Low Speed Clock(LSE)保持Disable(除非使用RTC)
-
切换到Clock Configuration标签页:
- 在HCLK输入框直接键入72后回车
- 系统会自动计算各分频系数
- 检查APB1总线时钟是否为36MHz(不能超过此值)
-
重要验证点:
- PLL Source Mux选择HSE
- PLLMUL确保是×9
- SW系统时钟源选择PLL
经验分享:如果后续程序运行不稳定,首先应该检查时钟配置是否正确。可以通过测量MCO引脚输出或使用ST-Link的Clock Viewer功能验证实际时钟频率。
2.3 GPIO与调试接口配置
对于LED控制,找到对应引脚(如PC13):
- 右键选择GPIO_Output
- 在左侧GPIO配置中:
- 输出模式选择Push-Pull
- 上拉/下拉根据电路设计选择
- 输出速度选Low即可(LED无需高速切换)
调试接口必须配置为Serial Wire:
- 在System Core→SYS中:
- Debug选择Serial Wire
- 这会将PA13(SWDIO)和PA14(SWCLK)保留为调试引脚
3. 串口通信配置
3.1 USART外设设置
在Connectivity中选择USART1:
-
Mode选择Asynchronous
-
基本参数:
- Baud Rate:115200
- Word Length:8bits
- Parity:None
- Stop Bits:1
-
GPIO设置自动分配为:
- PA9为USART1_TX
- PA10为USART1_RX
-
NVIC设置中:
- 勾选USART1全局中断
- 设置合适的抢占优先级(如1)
3.2 重定向printf支持
要使printf正常工作,需要:
-
在Project Manager→Code Generator中:
- 勾选"Generate peripheral initialization as a pair of .c/.h files"
-
在main.c中添加以下代码:
c复制#include <stdio.h>
int fputc(int ch, FILE *f) {
HAL_UART_Transmit(&huart1, (uint8_t *)&ch, 1, HAL_MAX_DELAY);
return ch;
}
int fgetc(FILE *f) {
uint8_t ch = 0;
HAL_UART_Receive(&huart1, &ch, 1, HAL_MAX_DELAY);
return ch;
}
- 在Target Options→Target中:
- 勾选"Use MicroLIB"
- 这是Keil提供的简化版C库,适合嵌入式环境
4. 工程生成与代码编写
4.1 生成Keil工程
在Project Manager标签页:
- 设置项目名称和存储路径(建议全英文路径)
- Toolchain/IDE选择MDK-ARM V5
- 在Code Generator中:
- 勾选"Generate peripheral initialization as a pair of .c/.h files"
- 勾选"Backup previously generated files when re-generating"
点击GENERATE CODE按钮后,CubeMX会自动生成完整的Keil工程。首次生成可能会下载所需库文件,请保持网络畅通。
4.2 添加用户代码
在main.c的main函数中,我们需要:
- 在/* USER CODE BEGIN PV */区添加全局变量:
c复制uint8_t rxBuffer[1];
- 在/* USER CODE BEGIN 2 */区添加初始化代码:
c复制HAL_UART_Receive_IT(&huart1, rxBuffer, 1); // 启动串口接收中断
printf("System Initialized!\r\n"); // 测试串口输出
- 在/* USER CODE BEGIN WHILE */区添加主循环代码:
c复制while (1) {
HAL_GPIO_TogglePin(GPIOC, GPIO_PIN_13); // 翻转LED状态
printf("LED Toggled at %lu ms\r\n", HAL_GetTick());
HAL_Delay(500);
}
- 在stm32f1xx_it.c中添加中断回调:
c复制void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart) {
if(huart->Instance == USART1) {
HAL_UART_Transmit(&huart1, rxBuffer, 1, HAL_MAX_DELAY);
HAL_UART_Receive_IT(&huart1, rxBuffer, 1); // 重新启用接收
}
}
5. 编译下载与调试
5.1 工程配置检查
在Keil中打开工程后,需要确认:
- Target Options→Device选项卡选择正确芯片
- Target Options→Output选项卡勾选"Create HEX File"
- Target Options→Debug选项卡选择正确的调试器(如ST-Link)
- 确保所有源文件都已加入工程
5.2 常见编译问题解决
-
未定义HAL库符号:
- 检查是否正确安装了STM32F1xx DFP
- 在Manage Run-Time Environment中确认HAL库已勾选
-
链接错误:
- 检查启动文件(startup_stm32f103xb.s)是否存在
- 确认链接脚本是否正确指定了Flash和RAM大小
-
printf不工作:
- 确认已勾选Use MicroLIB
- 检查fputc函数是否正确定义
- 用逻辑分析仪检查TX引脚是否有信号
5.3 下载与调试技巧
-
下载前确认:
- 开发板供电正常
- 调试器连接正确
- Boot0引脚接地(从Flash启动)
-
调试时建议:
- 在HAL_Delay处设置断点
- 使用SWV ITM Viewer查看printf输出
- 通过Watch窗口监控全局变量
-
如果无法连接:
- 检查调试器驱动是否安装
- 尝试复位开发板
- 检查SWD接口连接是否可靠
6. 进阶优化与扩展
6.1 代码结构优化
建议将用户代码模块化:
- 创建app_led.c/h处理LED相关功能
- 创建app_uart.c/h处理串口通信
- 使用回调机制降低模块耦合度
6.2 低功耗优化
对于电池供电设备:
- 在不需要LED时关闭GPIO时钟
- 使用HAL_Delay替代软件空循环
- 考虑使用STOP模式配合中断唤醒
6.3 扩展功能建议
基于这个框架可以轻松扩展:
- 添加按键中断控制LED
- 实现串口命令解析
- 增加定时器PWM调光
- 移植RTOS实现多任务
我在实际项目中发现,合理使用CubeMX可以节省大量底层配置时间,但要注意:
- 重新生成代码会覆盖用户修改,务必使用USER CODE区域
- 复杂项目建议分模块管理配置
- 定期备份.ioc文件以便追溯配置变更