基于Simulink/STM32CubeMX的STM32串口通信代码自动生成与Keil调试实战
本文详细介绍了基于Simulink和STM32CubeMX的STM32串口通信代码自动生成与Keil调试实战。从开发环境搭建、CubeMX基础配置到Simulink模型搭建,再到Keil工程调试技巧,提供了完整的解决方案和常见问题排查方法,帮助开发者高效实现串口通信功能。
1. 从零开始搭建开发环境
第一次接触Simulink和STM32CubeMX联合开发时,我花了两天时间才把环境配置好。这里分享下最稳妥的环境搭建方案,避免大家走弯路。
必备软件清单:
- MATLAB R2020b或更新版本(Simulink已内置)
- STM32CubeMX 6.0+
- Keil MDK-ARM 5.30+
- STM32-MAT/TARGET支持包
安装顺序很重要,建议先装MATLAB,再装STM32CubeMX。我在Windows 11上实测时发现,如果先装CubeMX,有时会导致MATLAB识别不到硬件支持包。安装STM32-MAT/TARGET时,记得勾选"Add to MATLAB path"选项,否则后续会报找不到S函数。
环境变量需要特别检查两个路径:
- MATLAB的STM32工具链路径(默认在C:\MATLAB\STM32-MAT)
- Keil的ARM编译器路径(通常在C:\Keil_v5\ARM\ARMCC\bin)
验证环境是否配置成功,可以在MATLAB命令窗口输入:
target = stm32.target
如果返回STM32硬件信息,说明工具链配置正确。
2. CubeMX基础配置详解
很多新手在CubeMX配置串口时容易忽略时钟树设置。以STM32F103C8T6为例,正确配置步骤如下:
- 在Pinout界面启用USART1
- Mode选择Asynchronous
- 波特率设为115200(与Simulink默认配置匹配)
- Word Length保持8bit
- 开启全局中断(NVIC Settings)
时钟树配置关键点:
- HCLK频率设置为72MHz(STM32F1系列最大值)
- 确保APB2总线时钟与HCLK同步
- USART1挂在APB2总线上,时钟需与总线一致
生成代码前务必检查Project Manager标签页:
- Toolchain/IDE选择MDK-ARM V5
- 勾选"Generate peripheral initialization as a pair of .c/.h files"
- 取消勾选"Generate under root"(避免Keil工程结构混乱)
3. Simulink模型搭建实战
官方Demo虽然能用,但实际项目需要自定义模型。这里以发送"Hello World"为例:
- 新建Simulink空白模型
- 添加"STM32 Config"模块(从STM32 Target库)
- 拖入"Serial Transmit"模块
- 连接Constant模块(值设为'Hello'的ASCII码数组)
关键参数设置:
- Hardware Board选择STM32F103C8
- Solver Type选择Fixed-step
- System target file设为stm32.tlc
- Sample time设为0.001(1ms周期)
有个坑我踩过三次:Simulink的串口缓冲区大小默认只有64字节。如果发送长数据,需要在Model Configuration Parameters的Hardware Implementation里修改Serial Buffer Size参数。
4. S函数问题终极解决方案
遇到"getBuffPtr未定义"错误时,官方Demo的解决方案并不完整。经过多次测试,我总结出更可靠的方法:
- 定位到MATLAB安装目录下的STM32-MAT/TARGET
- 将addSrc整个文件夹复制到项目目录
- 在Keil的Options for Target → C/C++ → Include Paths添加:
- 项目目录\addSrc\inc
- 项目目录\generated\Inc
对于自定义S函数,还需要修改stm32_main.c:
extern void getBuffPtr(void);
/* 在main()初始化部分添加 */
HAL_UART_Init(&huart1);
getBuffPtr();
如果仍然报错,检查Keil的Define标签页是否包含:
USE_HAL_DRIVER
STM32F103xB
5. Keil工程调试技巧
代码生成后,Keil工程自动生成在modelname_stm32文件夹。调试时注意:
-
首次编译前执行以下操作:
- Project → Clean Target
- 点击"Rebuild all target files"
-
下载配置:
- Debug标签页选择ST-Link Debugger
- 点击Settings → Flash Download
- 勾选"Reset and Run"
常见下载错误处理:
- "No ST-Link detected":检查驱动是否安装(ST-LINK USB Driver)
- "Flash timeout":尝试降低下载速度(从4MHz降到1MHz)
- "Core is locked":按住板子复位键点击下载,松开复位键
串口调试建议使用Termite或Putty,设置与CubeMX一致的波特率。如果收不到数据,用逻辑分析仪检查USART_TX引脚是否有波形输出。
6. 性能优化与错误排查
自动生成的代码效率可能不高,可以通过以下方式优化:
-
在Simulink的Configuration Parameters → Code Generation
- 选择Optimization level为Optimize for speed (O3)
- 取消勾选"Support: floating-point numbers"
-
修改stm32f1xx_it.c中的USART1_IRQHandler:
void USART1_IRQHandler(void) {
if(__HAL_UART_GET_FLAG(&huart1, UART_FLAG_RXNE)) {
__HAL_UART_CLEAR_FLAG(&huart1, UART_FLAG_RXNE);
// 添加自定义处理逻辑
}
}
典型问题排查表:
| 现象 | 可能原因 | 解决方案 |
|---|---|---|
| 数据乱码 | 波特率不匹配 | 检查CubeMX和上位机设置 |
| 只能发送一次 | 未启用连续发送 | 在Simulink添加While模块 |
| 接收数据丢失 | 缓冲区溢出 | 增大Serial Buffer Size |
| 编译超时 | 杀毒软件拦截 | 关闭实时防护 |
7. 进阶应用:自定义协议实现
实际项目中往往需要实现自定义通信协议。以Modbus RTU为例:
- 在Simulink创建Subsystem封装协议处理逻辑
- 使用S-Function Builder创建协议解析器
- 在Model Callbacks → PostLoadFcn添加初始化代码:
function InitModbus()
coder.extrinsic('loadlibrary');
loadlibrary('modbus.dll', 'modbus.h');
end
协议测试时,建议先用Simulink的Data Inspector工具监控变量变化,再实际连接硬件。我在实现CRC校验时发现,自动生成的查表法比实时计算效率高10倍以上。
硬件连接方面,RS485模块需要额外配置:
- 在CubeMX启用GPIO控制RE/DE引脚
- 修改HAL_UART_Transmit函数为阻塞模式
- 添加收发切换延迟(实测至少50us)
更多推荐



所有评论(0)