关于通过stm32CubeMax创建模板步骤与解释
一.创建工程
Eg:打开stm32CU->打开MCU->选择stm32F429ZG
1.配置时钟: 主要步骤: 1·选择时钟源:选择内部或外部时钟,内部便捷,外部高精度(此处一般选外部)
选择左边System Care里的RCC,把低速和高速运行的位置改为外部时钟(CR)
2·配置时钟数PLL,在上面的第二个Clock Configuration里,把两个可选择的都改到下面,再把频率调到180
第一个是HES:
HSI (High-Speed Internal) - 内部高速时钟
HSI 是芯片内置的 RC 振荡器。
HSE (High-Speed External) - 外部高速时钟
HSE 是通过引脚连接外部晶体/振荡器产生的时钟。
第二个是PLL
PLLCLK (Phase-Locked Loop Clock):
它是将 HSI 或 HSE 经过“锁相环(PLL)”放大倍频后的结果。
特点: 高性能模式。你想让单片机跑在 180MHz(如你图中所示),必须选这一项。只有通过 PLL,才能把几兆的原始时钟“变”成一百多兆的高频时钟。
最左边的频率选择由晶振决定
这个没改对的话会导致串口发乱码
到此时钟配置完成
然后还要配置SYS(调试接口配置,保证芯片与调速器之间的稳定通信)
使用J-LINK(好处:比JTAG)
注意:他的两个信号线会占用2个引脚,在左边的SYS里配置DEBUG之后会显示,一定要配置之后再生成代码,否则使用到已占用的两个引脚之后会导致板子锁死
(配置完成之后在右边的图上有显示)
SWDIO (Serial Wire Data I/O): 双向数据线。负责传输调试命令和数据,相当于串行通信的“内容”。
SWCLK (Serial Wire Clock): 时钟线。由调试器(如 ST-Link、DAP-link)提供同步时钟信号。
二·配置工程:
在上面的第三个project manager里配置名称,名称避免特殊字符和空格
IDE选MDK,再修改第二个

然后新建文件(APP)然后像添加头文件一样把这个文件夹加进去,
再添加一个mypedef头文件
头文件要加头文件保护,防止互相引用报错
(还有记得在C/C++里加头文件引用)
配置代码步骤:
先可以点击引脚并配置模式
在选完要使用的引脚之后,可以在左边的GPIO里查看引脚的详细配置(点击具体的那个引脚)
第一个初始电平,第二个模式,第三个是否配置上下拉电阻(一般输入和按键检测要),第四个输出速度,第五个是标签

keilADK里面记得改
否则烧录要重启
例子
(此图by-B站Alice_西风)
通过代码配置一个GPIO(通用输入输出)引脚来控制LED的标准“模拟”步骤。
你可以把这6个步骤理解为“写申请表->供电->填充参数->提交申请”的过程。以下是针对每个步骤的通俗阅读:
1.定义GPIO配置结构体并初始化为默认值
代码长相:GPIO_InitTypeDef GPIO_InitStruct = {0};
通俗理解:这就相当于在桌子上铺一张空白的申请表。结构体里包含模式、速度、上下拉等空位,初始化为0是为了防止里面有之前的乱码导致误动作。
2. 使能对应GPIO端口的时钟
代码长相:__HAL_RCC_GPIOx_CLK_ENABLE();(比如__HAL_RCC_GPIOA_CLK_ENABLE())
通俗理解:给模块送电。STM32为了省电,默认所有外设都是断电的。如果不跑这行,后面的配置写得再对,引脚也没有电平反应。
注意:这一步必须在后面所有操作之前完成。
3. 配置引脚模式为推挽输出(Push-Pull)
代码长相:GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
通俗理解:决定引脚的性格。 *推挽(Push-Pull):引脚既能输出高电平(接VCC),也能输出低电平(接GND),驱动能力强,是控制LED的最佳选择。
4. 设置上拉/下拉配置
代码长相:GPIO_InitStruct.Pull = GPIO_NOPULL;
通俗理解:决定没有信号时的状态。
对于LED这种主动输出的设备,通常设为NOPULL(无上下拉)。因为引脚会直接被芯片内部的开关强行推到高或低,不需要额外的电阻来维持。
5. 设定输出速度
代码长相:GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
通俗理解:决定跳跃快慢。 * LED触发只需要几赫兹到几个赫兹,选LOW(低速)即可。速度增益,信号边沿越陡,但产生的电磁干扰(EMI)也越大。
6. 将配置应用到指定的 GPIO 端口和引脚
代码长相:HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
通俗理解:签字盖章,正式下发。
前面的1、3、4、5步都只是在内存里填写“申请表”。只有执行了这一行,HAL库才会根
关于生成后的模板
问题1:为啥代码都要写在BEGIN与END之间(包括include)?
以#include "scheduler.h"为例(RTOS头文件,在main中调用)
在C语言编程中,按理说#include都应该挤在最上面,但是在使用STM32CubeMX或类似工具生成的工程中,你会发现代码被各种类似/* USER CODE BEGIN ... */的切割注释打开。
#include "scheduler.h"没有放在最底层,主要有以下三个原因:
1. 遵守“沙盒”规则(最关键)
你看到这些注释:
C
/* USER CODE BEGIN Includes */
#include "scheduler.h"
/* USER CODE END Includes */
是STM32CubeMX夺回你的“自留地”。
自动生成的代码:如果你把#include "scheduler.h"文件的最下面(不在BEGIN和END之间)放在一起,然后你修改了引脚配置并点击“生成代码”重新生成工程时,CubeMX会把下面它不认识的代码全部删掉。
保护机制:只有放在USER CODE BEGIN里面的代码,才会在重新生成的时候被保留下来。
2. 依赖顺序的要求
在 C 语言中,头文件的包含顺序有时很重要:
main.h通常最先包含:它里面包含了HAL库的核心头文件(如stm32f4xx_hal.h)以及各种引脚宏定义。
scheduler.h依赖基础库:如果你的调度器里使用了uint32_t或者HAL库的任务函数,那么它必须在系统基础库(通过main.h导入)之后被包含,否则编译器会报错说找不到基础类型。
3. 代码组织的逻辑性
这种布局将代码串联了三个逻辑层次:
系统级头文件:main.h(由工具生成,基础硬件描述)。
外部设置级头文件:gpio.h(由工具生成负责,具体模块)。
(上面两个每次都会重置,是模板里的)
应用级头文件:scheduler.h(由用户编写,负责业务逻辑)。
将用户自定义的头文件放在Private includes(包含)区域,可以让阅读代码的人快速看出哪些是芯片底层配置,哪些是你自己写的业务功能。
问题2:HAL_Init();SystemClock_Config();MX_GPIO_Init();这些初始化的顺序怎么排的
在嵌入式开发中,这三个函数的顺序绝对不能乱,它们遵循的是一套从“基础心脏”到“外围肢体”的逻辑。
如果把单片机比作一个人,这三个步骤的顺序就是:醒过来 -> 调准心率 -> 动动手脚。
1. HAL_Init();—— 醒过来(基础环境搭建)
必须放在桌子上。
该函数主要做三件基础的事:
初始化Flash接口:设置好读取Flash的指令预取等,确保CPU能够至少从内存读取程序。
设置中断优先级分组:这决定了以后各个外设抢占CPU的规则。
初始化SysTick(系统滴答计时器):这是最关键的!HAL库里的所有延时函数(如HAL_Delay())都依赖这个计时器。
如果不先执行:后面配置时钟或外设定时间,如果需要等待某个状态超时(Timeout),程序会因为没有心跳计时而死机。
2.——SystemClock_Config();调准心跳频率(动力系统)
通常放在第二位。
单片机刚上电时,默认跑在内部低速时钟(HSI)上,主频较低。该函数的作用是:
开启外部高速晶振(HSE)。
配置PLL(锁相环),把频率从几兆(MHz)拉升到几十兆(MHz)。
给各个入口(AHB, APB)分频。
如果不先执行它:你的单片机会很慢。更重要的是,串口、定时器等外部设定的波特率和运行频率都是基于系统时钟计算的。如果心跳频率没有定下来,后面的外部设定配置(比如串口115200)计算出来的结果都是错的。
3. MX_GPIO_Init();—— 动手动脚(具体功能实现)
之后必须放置时钟配置。
该函数负责把具体的引脚配置成输出(点灯)、输入(按键)或其他复用功能。
逻辑顺序:
先给外设供电:在配置 GPIO 之前,代码里有一句__HAL_RCC_GPIOx_CLK_ENABLE()。必须先有时钟,外设(GPIO 模块)才能通电工作。
重新配置引脚:设置推挽输出、上拉下拉等。
问题3:这三个初始化直接能否写代码
在HAL_Init()、SystemClock_Config()之间MX_GPIO_Init()插入代码,就像是在地基还没打好、水电还没通的时候就开始贴瓷砖,很容易出问题。
以下是具体分析:
1.HAL_Init()与SystemClock_Config()之间
危险程度: ★★★★☆
为什么不建议:此时芯片运行在默认的内部低速时钟(通常只有 16MHz 左右)。
后果:如果你在这中间写了复杂的计算逻辑,速度会慢得离谱;如果你尝试初始化串口打印信息,由于时钟还没定下来,波特率计算出来会完全出错,导致打印全是乱码。
2.SystemClock_Config()与MX_GPIO_Init()之间
危险程度: ★★☆☆☆
为什么不建议:时钟虽然准了,但“手脚”(GPIO)尚未通电。
后果:如果你在这里尝试操作某个引脚(比如点亮一个LED或者给传感器供电),程序不会报错,但硬件完全没有反应。GPIO的时钟使能通常是因为MX_GPIO_Init()内部才开启的。
应该写在哪里?
为了保证项目的健壮,你应该严格遵守生成的意见导向:
情况A:硬件关联的逻辑
如果您只是定义一些变量、清空某个服务器,可以放在HAL_Init()之前的USER CODE BEGIN 1位置。
情况B:所有的初始化逻辑(推荐)
你应该把所有的自定义初始化(比如你的scheduler_init())放在所有MX_XXX_Init()函数之后的USER CODE BEGIN 2位置。
原因:只有到了这里,CPU的频率才是对的,所有的引脚也都配置好了,此时进行操作是最安全的。
一个“特例”:紧急调试
有极特殊的情况,你可能需要在SystemClock_Config()之后、MX_GPIO_Init()之前编写代码:
场景:你的硬件板子有设计缺陷,某个引脚必须在系统启动的一刹那拉高,否则外部设会烧毁。
但做法:这种精巧的底层保护逻辑可以插在中间,通常建议直接修改MX_GPIO_Init()内部的逻辑。
总结:建议
乖乖把代码写在/* USER CODE BEGIN 2 */下面。如果你发现必须插在中间才能解决问题,那通常意味着你的底层驱动设计或者硬件电路顺序产生问题。
更多推荐

所有评论(0)