第4章 STM32微控制器入门:从认识芯片到点亮LED

好,咱们进入第四课。前面聊了电机控制的基础理论,现在该碰碰硬件了。做伺服驱动,STM32几乎是绕不开的选择。我个人最早接触STM32是在2010年,那时候还在用F103,现在想想,真是满满的回忆。

这一章,我会带你快速过一遍STM32的核心知识点。别怕,咱们不搞大而全的教科书式讲解,只挑伺服开发最常用的部分。说白了,就是让你能上手写代码、能控制电机。

4.1 STM32系列怎么选?

STM32家族很庞大,从M0到M7,性能跨度很大。做伺服驱动,我建议重点关注两个系列:

系列 内核 主频 适合场景
STM32F4 Cortex-M4F 168-180MHz 通用伺服、FOC控制
STM32G4 Cortex-M4F 170MHz 高性能伺服、数字电源
STM32H7 Cortex-M7 480MHz 多轴控制、复杂算法

我个人习惯用G4系列做伺服。为什么?因为它内置了CORDIC硬件加速器和HRTIM高分辨率定时器。做FOC电流环,这两个外设能省不少事。你想想看,电流环周期做到1us以内,用普通定时器很难,但HRTIM可以。

核心观点:选型不是越贵越好。F103也能做伺服,但性能上限低。G4是性价比之选,H7留给高端应用。

4.2 开发环境搭建

搭建环境这事儿,说简单也简单,说坑也多。我建议你用STM32CubeIDE,它是ST官方基于Eclipse的免费IDE,集成了CubeMX配置工具。

安装步骤很简单:

  1. 去ST官网下载STM32CubeIDE,选对应操作系统版本
  2. 一路Next安装,注意安装路径不要有中文
  3. 安装完成后,打开IDE,它会自动检测你的ST-Link调试器

小技巧:我第一次装的时候,死活连不上开发板。后来发现是驱动没装。记得装ST-Link驱动,或者直接用IDE自带的驱动安装工具。

建一个新项目也很简单:File → New → STM32 Project,然后选你的芯片型号。比如我用的是STM32G474RET6。接下来CubeMX会帮你配置时钟、外设,生成初始化代码。

4.3 GPIO编程——点亮第一盏灯

GPIO是基础中的基础。做伺服驱动,GPIO用来控制使能信号、读取编码器索引、输出报警信号等等。

先看一个最简单的例子:点亮LED。假设LED接在PA5引脚上,高电平点亮。

// 初始化GPIO
void GPIO_Init(void)
{
    GPIO_InitTypeDef GPIO_InitStruct = {0};
    
    __HAL_RCC_GPIOA_CLK_ENABLE();  // 使能GPIOA时钟
    
    GPIO_InitStruct.Pin = GPIO_PIN_5;
    GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;  // 推挽输出
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
    HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
}

// 主循环中点亮
int main(void)
{
    HAL_Init();
    GPIO_Init();
    
    while(1)
    {
        HAL_GPIO_WritePin(GPIOA, GPIO_PIN_5, GPIO_PIN_SET);  // 点亮
        HAL_Delay(500);
        HAL_GPIO_WritePin(GPIOA, GPIO_PIN_5, GPIO_PIN_RESET); // 熄灭
        HAL_Delay(500);
    }
}

嗯,这里要注意:时钟使能这一步很容易忘。我刚开始学的时候,经常忘了开时钟,结果GPIO死活没反应。后来养成了习惯:用哪个外设,先开它的时钟。

4.4 定时器配置——伺服的心脏

定时器在伺服驱动里太重要了。PWM生成、编码器计数、电流采样触发,全得靠它。

STM32的定时器分几类:

  • 基本定时器(TIM6/TIM7): 只能做定时,没有PWM输出
  • 通用定时器(TIM2-TIM5): 有PWM、输入捕获、编码器模式
  • 高级定时器(TIM1/TIM8): 有互补PWM、刹车功能、死区插入

做电机控制,高级定时器是首选。比如TIM1,可以输出三相互补PWM,带死区控制。我曾经在一个项目里,因为死区时间设得太小,导致MOS管直通烧了。嗯,从那以后我再也不敢马虎了。

看一个配置PWM输出的例子:

void TIM1_PWM_Init(uint16_t arr, uint16_t psc)
{
    TIM_OC_InitTypeDef sConfigOC = {0};
    
    __HAL_RCC_TIM1_CLK_ENABLE();
    
    htim1.Instance = TIM1;
    htim1.Init.Prescaler = psc;
    htim1.Init.CounterMode = TIM_COUNTERMODE_CENTERALIGNED1;  // 中央对齐模式
    htim1.Init.Period = arr;
    htim1.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
    htim1.Init.RepetitionCounter = 0;
    htim1.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_ENABLE;
    HAL_TIM_PWM_Init(&htim1);
    
    sConfigOC.OCMode = TIM_OCMODE_PWM1;
    sConfigOC.Pulse = arr/2;  // 50%占空比
    sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH;
    sConfigOC.OCNPolarity = TIM_OCNPOLARITY_HIGH;
    sConfigOC.OCFastMode = TIM_OCFAST_DISABLE;
    sConfigOC.OCIdleState = TIM_OCIDLESTATE_RESET;
    sConfigOC.OCNIdleState = TIM_OCNIDLESTATE_RESET;
    HAL_TIM_PWM_ConfigChannel(&htim1, &sConfigOC, TIM_CHANNEL_1);
    
    HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_1);
    HAL_TIMEx_PWMN_Start(&htim1, TIM_CHANNEL_1);  // 启动互补通道
}

避坑指南:中央对齐模式和边沿对齐模式,产生的PWM波形不一样。做FOC电流采样,我建议用中央对齐模式,因为可以在计数器的上溢和下溢点触发ADC采样,正好避开开关噪声。

4.5 中断系统——别让CPU空转

中断是嵌入式系统的灵魂。做伺服驱动,中断用得特别多:

  • 定时器中断:做周期性的电流环、速度环
  • 外部中断:处理编码器索引信号、限位开关
  • DMA中断:传输ADC数据、通信数据

配置一个定时器中断很简单:

void TIM2_IRQ_Init(void)
{
    __HAL_RCC_TIM2_CLK_ENABLE();
    
    htim2.Instance = TIM2;
    htim2.Init.Prescaler = 84-1;  // 84MHz/84 = 1MHz
    htim2.Init.CounterMode = TIM_COUNTERMODE_UP;
    htim2.Init.Period = 1000-1;   // 1ms中断一次
    HAL_TIM_Base_Init(&htim2);
    
    HAL_NVIC_SetPriority(TIM2_IRQn, 0, 0);  // 最高优先级
    HAL_NVIC_EnableIRQ(TIM2_IRQn);
    
    HAL_TIM_Base_Start_IT(&htim2);  // 启动中断模式
}

// 中断服务函数
void TIM2_IRQHandler(void)
{
    HAL_TIM_IRQHandler(&htim2);
}

// 回调函数
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
    if(htim->Instance == TIM2)
    {
        // 1ms执行一次,适合做速度环
        SpeedLoop();
    }
}

为什么会这样?因为HAL库把中断处理封装好了,你只需要写回调函数。但要注意:中断服务函数里不要做耗时操作。我曾经见过有人直接在中断里做浮点运算,结果导致中断响应超时,电机失控。

个人经验:中断里只做标志位设置或数据拷贝,真正的计算放到主循环或任务里。比如电流环,我习惯在定时器中断里只读取ADC值、设置PWM占空比,速度环计算放到主循环。

4.6 本章知识体系

下面这张图,是我梳理的本章知识结构。你可以把它当作一个思维导图来看:

STM32入门 系列选型 开发环境搭建 GPIO编程 定时器配置 中断系统 F4/G4/H7对比 CubeIDE安装 时钟使能要点 推挽/开漏输出 LED闪烁示例 PWM生成配置 中央对齐模式 死区插入 中断优先级 回调函数写法 核心:时钟→外设配置→中断响应 伺服驱动开发的基础技能栈

这张图把本章内容串起来了。你看,从选型开始,到环境搭建,再到GPIO、定时器、中断,每一步都是环环相扣的。做伺服驱动,这些基础打不牢,后面写FOC算法、做电流环,会非常痛苦。

好了,这一章就到这里。记住:动手实践是最好的学习方式。拿出你的开发板,把LED点亮,把PWM波形调出来,把中断跑通。遇到问题别怕,我当年也是一路踩坑过来的。


公众号:蓝海资料掘金营,微信deep3321