3. STM32基础开发:开发环境搭建与核心外设

各位同学,欢迎来到《Rover差速转向底盘驱动开发实战》的第三讲。今天我们要聊的,是STM32开发中最基础、也最绕不开的几个环节:环境搭建、GPIO、PWM和中断。别小看这些内容,我当年刚入行时,就是在这几个地方栽过跟头。咱们一个一个来拆解。

3.1 开发环境搭建:Keil与CubeMX的配合

做STM32开发,我个人习惯用两套工具配合:STM32CubeMX 负责图形化配置,Keil MDK 负责写代码和调试。说白了,CubeMX帮你生成初始化代码,Keil让你在代码里“折腾”。

第一步:安装Keil MDK

去Keil官网下载MDK-ARM版本,安装时注意选对芯片包。我建议你直接装最新版,省得后面遇到兼容性问题。安装完成后,记得用管理员权限打开一次,否则有些驱动会装不上。

第二步:安装STM32CubeMX

这个工具是ST官方的,免费。下载后直接安装,它会自动识别你电脑上的Keil版本。嗯,这里有个坑:如果你先装CubeMX后装Keil,CubeMX可能找不到Keil路径。解决办法很简单——重装CubeMX,或者手动指定Keil路径。

第三步:生成工程

打开CubeMX,选择你的芯片型号(比如我们常用的STM32F103C8T6)。配置好时钟、外设后,点击“Project -> Generate Code”。生成时选“MDK-ARM”工具链,版本选V5。这样生成的工程,直接用Keil打开就能编译。

我的经验: 生成代码后,别急着改CubeMX里的配置。我建议你先在Keil里编译一次,确认环境没问题,再开始写业务逻辑。否则你改了半天,发现是CubeMX生成的代码有问题,那就白忙活了。

3.2 GPIO配置:从点灯到控制电机

GPIO是STM32最基础的外设。说白了,它就是芯片的“手脚”,用来输出高低电平或读取外部信号。在底盘驱动中,GPIO主要用来控制电机方向、读取编码器信号。

GPIO的几种模式

模式 用途 典型场景
推挽输出 输出高低电平 控制电机方向引脚
开漏输出 需要外部上拉 I2C通信
浮空输入 读取外部电平 按键检测
上拉/下拉输入 带内部电阻的输入 编码器信号读取

配置示例:控制电机方向

假设我们用PA0和PA1控制左电机的正反转。在CubeMX里,把这两个引脚配置为“GPIO_Output”,然后在代码里这样写:

// 左电机正转
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_0, GPIO_PIN_SET);  // 方向1
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_1, GPIO_PIN_RESET); // 方向2

// 左电机反转
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_0, GPIO_PIN_RESET);
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_1, GPIO_PIN_SET);
注意: 电机驱动芯片的输入引脚,通常需要加限流电阻。我曾经因为没加电阻,直接把STM32的GPIO烧了。嗯,那是一次惨痛的教训。

3.3 定时器PWM输出:让电机转起来

PWM(脉宽调制)是控制电机速度的核心手段。说白了,就是通过调整高电平占空比,来改变电机两端的平均电压。STM32的定时器可以输出多路PWM,非常适合驱动差速底盘的两个电机。

PWM配置步骤

  1. 在CubeMX里选择一个定时器(比如TIM2),配置为“内部时钟”
  2. 设置预分频器(PSC)和自动重装载值(ARR),决定PWM频率
  3. 使能某个通道(比如CH1),模式选“PWM Generation CH1”
  4. 设置初始占空比(比如50%)

代码示例:动态调整占空比

// 初始化PWM
HAL_TIM_PWM_Start(&htim2, TIM_CHANNEL_1);

// 设置占空比为75%
__HAL_TIM_SET_COMPARE(&htim2, TIM_CHANNEL_1, 750);

// 设置占空比为25%
__HAL_TIM_SET_COMPARE(&htim2, TIM_CHANNEL_1, 250);

你想想看,差速转向的核心就是左右轮速度不同。左轮PWM占空比大,右轮小,车子就往右转。这个逻辑,说白了就是靠PWM实现的。

避坑指南: 我曾经遇到过PWM频率设置太低,导致电机发出“嗡嗡”声。后来把频率调到20kHz以上,问题就解决了。建议你底盘驱动用10kHz-20kHz的PWM频率。

3.4 中断系统:让CPU“偷懒”

中断是嵌入式系统的灵魂。没有中断,CPU就得一直轮询检查各种事件,效率极低。有了中断,CPU可以该干嘛干嘛,等事件发生了再“被叫醒”。

中断优先级

STM32的中断有抢占优先级和子优先级。抢占优先级高的中断,可以打断正在执行的低优先级中断。在底盘驱动中,我建议把电机控制中断设为高优先级,把通信中断设为低优先级。

配置示例:外部中断读取编码器

编码器每转一圈会产生多个脉冲。我们用外部中断来捕获这些脉冲,从而计算电机转速。

// 在CubeMX中配置PA0为外部中断线0,下降沿触发
// 然后在stm32f1xx_it.c中编写中断服务函数

void EXTI0_IRQHandler(void)
{
    if(__HAL_GPIO_EXTI_GET_IT(GPIO_PIN_0) != RESET)
    {
        // 编码器脉冲计数加1
        encoder_count++;
        
        // 清除中断标志位
        __HAL_GPIO_EXTI_CLEAR_IT(GPIO_PIN_0);
    }
}
重要提醒: 中断服务函数里不要做复杂运算,比如浮点计算或延时。否则会影响系统实时性。我见过有人在中断里做PID计算,结果电机控制周期乱套了。正确的做法是:中断里只做标记,主循环里处理计算。

3.5 本章知识体系

为了让你更直观地理解本章内容,我画了一张结构图。它展示了开发环境、GPIO、PWM和中断之间的关系,以及它们在底盘驱动中的位置。

STM32基础开发知识体系 STM32开发基础 开发环境搭建 GPIO配置 定时器PWM 中断系统 Keil MDK安装 CubeMX配置 工程生成与编译 推挽/开漏输出 上拉/下拉输入 电机方向控制 PSC/ARR配置 占空比调整 电机速度控制 优先级配置 外部中断 编码器脉冲捕获 四个模块相互配合,构成底盘驱动的基础

这张图把本章内容串起来了。你从环境搭建开始,一步步配置GPIO、PWM和中断,最后就能让电机按照你的指令转动。说白了,这就是底盘驱动的基础骨架。


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