4、STM32基础工程搭建:使用CubeMX生成HAL库工程、配置GPIO、USART、SysTick定时器
好,咱们正式开始动手了。
这一章,我带你从零搭建一个STM32的基础工程。说白了,就是让芯片先“活”起来——能点灯、能打印、能跑时间。这是后面所有云端通信的基石。
我个人习惯用STM32CubeMX来生成初始化代码。为什么?省事。你想想看,以前用标准库的时候,配置一个时钟树就得翻半天手册,现在图形化点一点,代码自动生成,多舒服。
4.1 使用CubeMX生成HAL库工程
打开CubeMX,第一步是选芯片。我这边用的是STM32F103C8T6,也就是大家常说的“蓝色 pill”板子。你在实际项目中可能用F4、F7或者G0系列,操作流程完全一样。
选好芯片后,进入Pinout & Configuration界面。这里我要配置三样东西:
- GPIO —— 控制LED,作为运行指示灯
- USART —— 串口打印,调试必备
- SysTick —— 系统滴答定时器,HAL库的时基
嗯,这里要注意:SysTick其实CubeMX默认就帮你配好了,但我们要理解它怎么工作的。
4.2 配置GPIO:让LED亮起来
我习惯把LED接在PC13上,因为很多STM32最小系统板默认就是这个引脚。你在自己的板子上可能不一样,记得查原理图。
在CubeMX的Pinout视图中,找到PC13,右键选择GPIO_Output。然后去GPIO配置页面:
| 参数 | 设置值 | 说明 |
|---|---|---|
| GPIO output level | High | 初始状态高电平,LED灭 |
| GPIO mode | Output Push-Pull | 推挽输出,驱动能力强 |
| GPIO Pull-up/Pull-down | No pull-up/pull-down | 外部已有上拉,内部不用 |
| Maximum output speed | Low | LED不需要高速,Low省电 |
我在项目中遇到过一个问题:LED死活不亮。查了半天,发现是GPIO的初始电平设反了。你想想看,如果外部电路是低电平点亮,你初始设成High,那LED当然不亮。所以一定要先看原理图。
4.3 配置USART:让芯片开口说话
串口是嵌入式开发者的“眼睛”。没有串口打印,调试就像蒙着眼睛走路。
我选USART1,引脚是PA9(TX)和PA10(RX)。在Pinout视图中把这两个引脚配成USART1_TX和USART1_RX。然后去USART1配置页面:
| 参数 | 设置值 | 说明 |
|---|---|---|
| Mode | Asynchronous | 异步模式,最常用 |
| Baud Rate | 115200 | 波特率,我习惯用这个 |
| Word Length | 8 Bits | 数据位8位 |
| Parity | None | 无校验 |
| Stop Bits | 1 | 1位停止位 |
配置完USART后,记得在NVIC设置中使能USART1全局中断。虽然我们暂时只用轮询方式发送,但后面做数据接收时要用到中断。
4.4 SysTick定时器:HAL库的心跳
SysTick是Cortex-M内核自带的24位递减计数器。HAL库用它来做HAL_Delay()和超时判断。
在CubeMX的SYS配置页面,Timebase Source默认就是SysTick。我建议你不要改它。为什么?因为SysTick是内核级的外设,所有Cortex-M芯片都有,移植性最好。
SysTick的配置其实很简单:
- 时钟源:一般是HCLK/8,或者直接HCLK
- 重装载值:决定中断频率
- 使能中断:让HAL库的
HAL_IncTick()每1ms调用一次
CubeMX会自动帮你算好这些参数。你只需要在SystemClock_Config()里确认时钟树正确就行。
HAL_GetTick()返回的就是从启动到现在经过的毫秒数。所有延时、超时判断都依赖这个计数器。
4.5 生成代码与验证
点击GENERATE CODE,CubeMX会生成一个完整的MDK-ARM或IAR工程。我用的是MDK,所以选MDK-ARM V5。
生成后,打开工程,在main.c的while(1)里写点测试代码:
int main(void)
{
HAL_Init();
SystemClock_Config();
MX_GPIO_Init();
MX_USART1_UART_Init();
while (1)
{
HAL_GPIO_TogglePin(LED_GPIO_Port, LED_Pin);
HAL_Delay(500);
printf("Hello from STM32!\r\n");
}
}
等等,printf怎么用?你需要重定向fputc函数:
int fputc(int ch, FILE *f)
{
HAL_UART_Transmit(&huart1, (uint8_t *)&ch, 1, 1000);
return ch;
}
把这个函数加到main.c里,记得包含<stdio.h>。这样printf就能通过串口输出了。
fputc时忘了加FILE *f参数,编译报错。还有一次是HAL_UART_Transmit的超时时间设得太短,数据没发完就返回了。建议超时时间至少设100ms。
4.6 验证结果
编译下载后,打开串口工具(我用的是Putty或SSCOM),设置115200波特率。你应该能看到:
- 板子上的LED以1Hz的频率闪烁
- 串口每500ms打印一次"Hello from STM32!"
如果LED不闪,检查GPIO引脚和电平配置。如果串口没输出,检查波特率、引脚连接、还有fputc重定向是否正确。
嗯,到这里,基础工程就搭好了。你想想看,一个能点灯、能打印、能跑时间的STM32,是不是已经活过来了?下一章,我们就让它连上网络,开始和云端对话。