别再只会用高低电平了!用STM32的PWM驱动L298N电机,实现小车平滑调速(附完整代码)
2026/6/11 6:17:52 网站建设 项目流程

STM32 PWM精准控制L298N电机:从基础调速到高级应用的完整指南

在智能小车和机器人项目中,电机控制是核心环节。许多开发者虽然能够通过简单的高低电平实现电机启停,但当需要精确控制转速时,常常遇到电机抖动、响应迟滞等问题。本文将深入探讨如何利用STM32的PWM功能,结合L298N电机驱动模块,实现电机的平滑调速控制。

1. L298N驱动模块与PWM控制原理

L298N作为经典的双H桥电机驱动芯片,能够同时控制两个直流电机或一个步进电机。其核心优势在于支持高达46V的驱动电压和2A的持续电流输出,非常适合中小型机器人项目。

1.1 L298N的三种控制模式对比

控制方式接线复杂度调速效果功耗表现适用场景
高低电平简单无调速较高只需启停的简单应用
PWM输入中等优秀较低需要精确调速的项目
使能端控制复杂良好中等特殊隔离控制需求

PWM控制原理:通过快速切换高低电平(典型频率1-20kHz),改变有效电压的平均值。占空比(高电平时间占比)决定电机转速,50%占空比相当于施加一半的电源电压。

提示:L298N的使能端默认通过跳线帽连接至高电平,使用PWM控制时需要移除跳线帽,将ENA/ENB连接到MCU的PWM输出引脚。

1.2 关键参数计算

PWM频率选择需要考虑电机特性:

  • 过低频率(<1kHz):可听噪声明显,电机振动大
  • 过高频率(>20kHz):开关损耗增加,可能超出驱动芯片响应能力
  • 推荐范围:5-10kHz(直流电机),1-5kHz(减速电机)

定时器配置公式:

PWM频率 = 定时器时钟 / (PSC + 1) / (ARR + 1)

例如STM32F103系列APB1定时器时钟为72MHz,若要产生10kHz PWM:

TIM_TimeBaseInitStructure.TIM_Prescaler = 72 - 1; // PSC=71 TIM_TimeBaseInitStructure.TIM_Period = 100 - 1; // ARR=99 // 频率 = 72MHz / 72 / 100 = 10kHz

2. 硬件连接与初始化配置

2.1 典型接线方案

[STM32] [L298N] PA8 (PWM) ----> ENA PA9 ----> IN1 PA10 ----> IN2 GND ----> GND

电源配置注意事项:

  • 驱动电源(VCC):7-12V,直接接电池
  • 逻辑电源(5V):可取自STM32开发板或L298N的5V输出
  • 必须共地:STM32的GND与L298N的GND必须连接

2.2 HAL库初始化代码

void MX_TIM1_Init(void) { htim1.Instance = TIM1; htim1.Init.Prescaler = 71; // 72MHz/72=1MHz htim1.Init.CounterMode = TIM_COUNTERMODE_UP; htim1.Init.Period = 99; // 1MHz/100=10kHz htim1.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1; htim1.Init.RepetitionCounter = 0; htim1.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE; if (HAL_TIM_PWM_Init(&htim1) != HAL_OK) { Error_Handler(); } TIM_OC_InitTypeDef sConfigOC = {0}; sConfigOC.OCMode = TIM_OCMODE_PWM1; sConfigOC.Pulse = 0; // 初始占空比0% 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; if (HAL_TIM_PWM_ConfigChannel(&htim1, &sConfigOC, TIM_CHANNEL_1) != HAL_OK) { Error_Handler(); } HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_1); }

3. 高级调速技巧与问题排查

3.1 实现加速度控制

直接突变更改占空比会导致电机冲击,应逐步过渡:

void set_speed_gradually(uint16_t target_duty) { uint16_t current = __HAL_TIM_GET_COMPARE(&htim1, TIM_CHANNEL_1); int8_t step = (target_duty > current) ? 1 : -1; while(current != target_duty) { current += step; __HAL_TIM_SET_COMPARE(&htim1, TIM_CHANNEL_1, current); HAL_Delay(10); // 10ms间隔 } }

3.2 常见问题解决方案

电机抖动严重

  • 检查PWM频率是否在5-10kHz范围内
  • 确认电源电压稳定,容量足够(建议1000μF以上滤波电容)
  • 测量实际输出波形,排除信号完整性问题

低速运转不平稳

  • 尝试提高PWM分辨率(增大ARR值)
  • 加入死区补偿(特别是有刷电机)
if(duty < 10) duty = 10; // 最小占空比限制

典型接线错误

  • 使能端未连接PWM(仍插着跳线帽)
  • IN1/IN2同时为高电平导致刹车模式
  • 电源未共地导致逻辑混乱

4. 实战应用:智能小车速度控制

4.1 双电机差速控制

通过独立控制左右轮电机实现转向:

typedef struct { int16_t left_speed; int16_t right_speed; } MotorSpeed; void update_motors(MotorSpeed speed) { // 限制速度范围0-100% speed.left_speed = constrain(speed.left_speed, 0, 100); speed.right_speed = constrain(speed.right_speed, 0, 100); // 设置左电机 if(speed.left_speed > 0) { HAL_GPIO_WritePin(IN1_GPIO_Port, IN1_Pin, GPIO_PIN_SET); HAL_GPIO_WritePin(IN2_GPIO_Port, IN2_Pin, GPIO_PIN_RESET); __HAL_TIM_SET_COMPARE(&htim1, TIM_CHANNEL_1, speed.left_speed); } else { // 刹车模式 HAL_GPIO_WritePin(IN1_GPIO_Port, IN1_Pin, GPIO_PIN_RESET); HAL_GPIO_WritePin(IN2_GPIO_Port, IN2_Pin, GPIO_PIN_RESET); } // 右电机同理... }

4.2 PID速度闭环控制

对于要求精确速度的应用,可增加编码器反馈:

typedef struct { float Kp, Ki, Kd; float integral; float prev_error; } PIDController; float pid_update(PIDController* pid, float setpoint, float measurement) { float error = setpoint - measurement; pid->integral += error; if(pid->integral > 100) pid->integral = 100; if(pid->integral < -100) pid->integral = -100; float derivative = error - pid->prev_error; pid->prev_error = error; return pid->Kp * error + pid->Ki * pid->integral + pid->Kd * derivative; }

实际项目中,PWM控制不仅仅是简单的占空比调节。通过结合STM32的高级定时器功能,还可以实现:

  • 互补输出带死区控制(适合大功率驱动)
  • 刹车输入紧急停止
  • 编码器接口速度检测
  • 定时器级联实现超高分辨率PWM

在调试过程中,建议先用示波器验证PWM波形,再连接电机驱动。遇到异常时,按电源→信号→负载的顺序排查,可以快速定位问题根源。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询