单片机:实现使用PWM驱动电机转动(附带源码)

单片机:实现使用PWM驱动电机转动

1. 项目背景与目标

脉宽调制(PWM)是一种通过改变信号的占空比来控制功率的技术,广泛应用于控制电机、LED亮度、音频信号生成等领域。PWM信号的占空比(即高电平持续的时间与周期时间之比)决定了输出功率的大小。在电机控制中,PWM可以用来控制电机的转速和方向。

本项目的目标是通过单片机使用PWM信号来驱动直流电机的转动。通过调整PWM信号的占空比,来实现对电机转速的调节,从而控制电机的运行。

2. 硬件设计
2.1 硬件组件
  1. 单片机:使用STM32系列单片机(如STM32F103)或8051系列单片机(如AT89C51),根据具体需求选择。
  2. 直流电机:普通直流电机,可以是小型电动机,常用于实验和小型项目中。
  3. 电机驱动模块:如L298NL293D,它们是常见的用于控制直流电机的H桥驱动模块。可以通过控制输入端的PWM信号来调节电机的转速。
  4. 外部电源:为电机提供稳定的电源,通常与单片机的电源分开。电机驱动模块需要的电压可能会大于单片机工作电压(如电机驱动模块使用12V,单片机使用5V)。
  5. 电位器(可选):用于模拟调节PWM信号的占空比,进而控制电机的转速。
  6. 显示设备(可选):如LCD显示器,用来显示当前PWM占空比或者电机转速。
2.2 硬件连接
  1. 单片机PWM输出端口(如STM32的TIM1或TIM2模块)通过GPIO口输出PWM信号,连接到电机驱动模块的输入端。
  2. 电机驱动模块的输出端连接到电机的正负极。
  3. 电源管理:为电机驱动模块和电机提供单独的电源,同时保证单片机的电源稳定。
3. 软件设计
3.1 PWM信号原理

PWM信号通过调节高电平持续时间和低电平持续时间的比例(即占空比)来控制输出功率。当占空比为100%时,信号始终为高电平,电机处于最大速度;当占空比为0%时,信号始终为低电平,电机不转动;占空比介于0%和100%之间时,电机的转速与占空比成正比。

3.2 控制电机转动
  1. 占空比调节:通过单片机的PWM模块,设置一个定时器来输出不同占空比的PWM信号,从而控制电机的转速。
  2. 电机方向控制:使用H桥电路(如L298N)控制电机的转动方向。可以通过设置PWM信号的两个输入端,来改变电机的转动方向(正转或反转)。
3.3 程序设计思路
  1. 初始化PWM输出:配置单片机的定时器(如STM32的TIM2)产生PWM信号。
  2. PWM占空比调节:通过调节PWM的占空比来控制电机的转速。可以使用外部电位器来调整占空比,或者通过串口命令来动态调整。
  3. 电机方向控制:通过改变H桥驱动模块的输入信号来控制电机的转动方向。
  4. 显示与调试:将当前PWM占空比和电机状态(如转速、方向)通过串口或LCD显示出来,方便调试。
3.4 代码实现

以下是基于STM32单片机的PWM驱动电机转动的程序实现,使用STM32的定时器(如TIM2)产生PWM信号来控制电机转速,同时使用L298N电机驱动模块来控制电机方向

#include "stm32f4xx_hal.h"

// PWM输出引脚
#define MOTOR_PWM_PIN    GPIO_PIN_6  // 假设PWM输出连接到PA6
#define MOTOR_PWM_PORT   GPIOA

// 电机方向控制引脚
#define MOTOR_DIR_PIN1   GPIO_PIN_7  // 假设方向控制连接到PA7
#define MOTOR_DIR_PIN2   GPIO_PIN_8  // 假设方向控制连接到PA8
#define MOTOR_DIR_PORT   GPIOA

// 定义PWM占空比的初始值
#define PWM_MAX          1000    // 最大占空比
#define PWM_MIN          0       // 最小占空比

// 全局变量
TIM_HandleTypeDef htim2;  // 定时器2,用于PWM产生
int pwm_value = 500;       // 初始占空比(50%)

// 初始化PWM输出
void PWM_Init(void) {
    __HAL_RCC_GPIOA_CLK_ENABLE();   // 使能GPIOA时钟
    __HAL_RCC_TIM2_CLK_ENABLE();    // 使能TIM2时钟

    // 配置GPIOA6为PWM输出模式
    GPIO_InitTypeDef GPIO_InitStruct = {0};
    GPIO_InitStruct.Pin = MOTOR_PWM_PIN;
    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;  // 推挽复用
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
    HAL_GPIO_Init(MOTOR_PWM_PORT, &GPIO_InitStruct);

    // 配置TIM2作为PWM输出
    htim2.Instance = TIM2;
    htim2.Init.Prescaler = 84 - 1;    // 预分频器设置为1us
    htim2.Init.CounterMode = TIM_COUNTERMODE_UP;
    htim2.Init.Period = PWM_MAX - 1;  // PWM频率1kHz
    htim2.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
    htim2.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
    HAL_TIM_PWM_Init(&htim2);

    // 配置PWM通道
    TIM_OC_InitTypeDef sConfigOC = {0};
    sConfigOC.OCMode = TIM_OCMODE_PWM1;
    sConfigOC.Pulse = pwm_value;   // 初始占空比
    sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH;
    sConfigOC.OCFastMode = TIM_OCFAST_DISABLE;
    HAL_TIM_PWM_ConfigChannel(&htim2, &sConfigOC, TIM_CHANNEL_1);

    // 启动PWM输出
    HAL_TIM_PWM_Start(&htim2, TIM_CHANNEL_1);
}

// 控制电机的方向
void Motor_Direction(int direction) {
    if (direction == 1) {  // 顺时针
        HAL_GPIO_WritePin(MOTOR_DIR_PORT, MOTOR_DIR_PIN1, GPIO_PIN_SET);
        HAL_GPIO_WritePin(MOTOR_DIR_PORT, MOTOR_DIR_PIN2, GPIO_PIN_RESET);
    } else if (direction == -1) {  // 逆时针
        HAL_GPIO_WritePin(MOTOR_DIR_PORT, MOTOR_DIR_PIN1, GPIO_PIN_RESET);
        HAL_GPIO_WritePin(MOTOR_DIR_PORT, MOTOR_DIR_PIN2, GPIO_PIN_SET);
    } else {  // 停止
        HAL_GPIO_WritePin(MOTOR_DIR_PORT, MOTOR_DIR_PIN1, GPIO_PIN_RESET);
        HAL_GPIO_WritePin(MOTOR_DIR_PORT, MOTOR_DIR_PIN2, GPIO_PIN_RESET);
    }
}

// 调节PWM占空比
void Set_PWM_DutyCycle(int dutyCycle) {
    if (dutyCycle < PWM_MIN) {
        dutyCycle = PWM_MIN;
    } else if (dutyCycle > PWM_MAX) {
        dutyCycle = PWM_MAX;
    }
    pwm_value = dutyCycle;  // 更新占空比
    __HAL_TIM_SET_COMPARE(&htim2, TIM_CHANNEL_1, pwm_value);  // 更新PWM占空比
}

// 主程序
int main(void) {
    HAL_Init();
    PWM_Init();  // 初始化PWM

    // 设置电机顺时针转动
    Motor_Direction(1);

    // 循环调节PWM占空比,控制电机转速
    while (1) {
        for (int i = PWM_MIN; i <= PWM_MAX; i += 10) {
            Set_PWM_DutyCycle(i);  // 增加占空比
            HAL_Delay(100);  // 延时100ms
        }
        for (int i = PWM_MAX; i >= PWM_MIN; i -= 10) {
            Set_PWM_DutyCycle(i);  // 减少占空比
            HAL_Delay(100);  // 延时100ms
        }
    }
}
3.5 代码解释
  1. PWM初始化PWM_Init()函数通过配置STM32的TIM2定时器生成PWM信号,使用GPIOA6作为PWM输出。
  2. 电机方向控制Motor_Direction()函数通过控制L298N电机驱动模块的方向引脚来控制电机的转动方向。
  3. PWM占空比调节Set_PWM_DutyCycle()函数根据给定的占空比调节PWM信号的占空比,从而控制电机的转速。
  4. 主程序:主程序中,首先设置电机为顺时针转动,然后通过改变PWM的占空比来控制电机转速,形成一个动态调节电机转速的效果。
4. 仿真与测试
4.1 电路设计
  1. 在Proteus中创建STM32单片机的仿真项目。
  2. 连接PWM输出端口(如PA6)到L298N电机驱动模块的PWM输入端。
  3. 将L298N的输出端连接到直流电机。
  4. 配置电源:单片机使用3.3V电源,电机驱动模块使用12V电源。
4.2 仿真步骤
  1. 编译并上传代码到仿真环境。
  2. 运行仿真,观察电机的转速变化(通过改变PWM占空比)。
  3. 检查电机转动的方向是否可以通过调整方向控制引脚来改变。
5. 总结

本项目成功实现了使用PWM信号控制直流电机的转速和方向。通过调节PWM信号的占空比,可以精确控制电机的转速,达到精细调节电机运转的目的。此外,通过使用L298N电机驱动模块,我们能够实现电机的正反转控制。该项目展示了如何结合单片机的PWM功能和外部电机驱动模块,实现对电机的精准控制。

作者:Katie。

物联沃分享整理
物联沃-IOTWORD物联网 » 单片机:实现使用PWM驱动电机转动(附带源码)

发表回复