STM32CubeMX 使用方式与典型场景
四、使用方式与典型场景
示例一:从零配置一个「串口收发 + 定时器中断 + 按键」的工程
配置步骤(以 STM32F4 系列为例,具体引脚按你的板子调整)
1) 选芯片型号,或直接选对应的 Nucleo / Discovery 开发板
2) System Core → RCC:高速时钟源选外部晶振(HSE Crystal/Ceramic Resonator)
3) System Core → SYS:Debug 选 Serial Wire(不选会丢掉 SWD 调试口)
4) Connectivity → USART2:
Mode = Asynchronous
波特率 115200,8 位数据,无校验,1 位停止位
NVIC 里勾选全局中断
5) Timers → TIM2:
Clock Source = Internal Clock
预分频与计数周期按目标中断频率计算(中断频率 = 定时器时钟 / (PSC+1) / (ARR+1))
NVIC 里勾选 TIM2 全局中断
6) GPIO → 找一个引脚设为 GPIO_Input,开启上拉,用户标签写 BTN1
7) Clock Configuration:把 HCLK 拉到芯片允许的频率,确认各 APB 不超频,无红色报错
8) Project Manager:
工程名与路径(纯英文)
Toolchain = MDK-ARM / STM32CubeIDE / Makefile
勾选「Generate peripheral initialization as a pair of .c/.h files」
9) 点 GENERATE CODE
生成后需要自己补的代码(都写在 user code 区域里)
/* USER CODE BEGIN 2 */
uint8_t rx_byte;
HAL_UART_Receive_IT(&huart2, &rx_byte, 1); // 挂上首次接收中断
HAL_TIM_Base_Start_IT(&htim2);
/* USER CODE END 2 */
/* USER CODE BEGIN 4 */
// 串口接收完成回调:收一个字节就回显一个字节,并重新挂中断
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
if (huart->Instance == USART2) {
HAL_UART_Transmit(&huart2, &rx_byte, 1, 100);
HAL_UART_Receive_IT(&huart2, &rx_byte, 1);
}
}
// 定时器周期中断回调
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
if (htim->Instance == TIM2) {
// 放周期任务,注意这里在中断上下文,不要做耗时操作
}
}
/* USER CODE END 4 */
这段代码里有两个高频错误:忘记重新挂接收中断(HAL 的 Receive_IT 是单次的,回调里不重新挂就只能收一次);在中断回调里做耗时操作(比如串口打印长字符串),会拖慢整个系统甚至丢中断。
示例二:用 CubeMX 起一个 FreeRTOS 工程
1) Middlewares → FREERTOS → Interface 选 CMSIS_V2
2) Config parameters:
USE_PREEMPTION = Enabled
TICK_RATE_HZ 按需要设置(常见 1000)
3) Timers and Semaphores 标签页:
New Timer → 名字 LedTimer,周期 500ms,回调里翻转 LED
New Semaphore → 二值信号量,用于中断与任务之间同步
4) Tasks and Queues 标签页:
默认任务 defaultTask 栈设 128 words,优先级 osPriorityNormal
新增 SensorTask 栈 256 words,优先级略低于 defaultTask
5) System Core → SYS:Timebase Source 改成 TIM6 之类
原因:SysTick 已被 FreeRTOS 接管,HAL 时基必须让出来
6) 生成代码后,在对应任务函数里写业务逻辑(同样在 user code 区域)
FreeRTOS 工程最容易踩的坑是时基冲突:不把 HAL 时基从 SysTick 换走,会出现「任务能跑但 HAL_Delay 卡住」或「调度异常」。第二个坑是栈开太小,任务里用了 printf 这类吃栈的函数,栈溢出后表现为随机死机,且很难定位——建议配合 vTaskList 之类的栈使用量接口做长期观察。
适合与不适合的场景
适合:新项目起手;需要快速验证外设可行性;团队要统一初始化风格;换芯片型号需要重做初始化;教学与培训场景。
不适合:对代码体积极度敏感、需要逐字节抠的极限优化项目(HAL 有额外开销,此时应改用 LL 或寄存器直写);已经稳定的老工程(重新生成反而引入风险);需要用到 CubeMX 尚未支持的冷门外设组合(这时以参考手册为准手写)。

