Raspberry Pi GPIO 教程(5)步进电机控制

在之前的51单片机教程中,我们介绍了步进电机控制的原理和驱动方式,采用GPIO方式,原理也是大同小异,都是通过引脚发送高低电平来控制驱动芯片驱动马达。对于单步进电机应用,像 L293D 这样的驱动就足够了,但如果您想构建自己的 CNC 机器或 3D 打印机,则需要专用的步进电机驱动,例如 A4988。

由于步进电机控制简单且 A4988 驱动器提供多种步进模式,它是构建需要精确可靠步进电机控制的应用的理想解决方案,例如各种 CNC 绘图、铣削和 3D 打印机设计中的床、头和组件的移动控制。

只需两个引脚即可控制 NEMA 17 等双极步进电机的速度和方向,这一点也非常巧妙。

A4988 步进电机驱动器芯片

模块的核心是 Allegro 的微步进驱动器 – A4988。尽管体积小巧(0.8 英寸 x 0.6 英寸),但功能强大。A4988 步进电机驱动器的输出驱动能力高达 35V 和 ±2A。这允许您以每个线圈高达 2A 的输出电流控制双极步进电机(例如 NEMA 17)。此外,输出电流受到调节,从而使步进电机无噪音运行,并消除非调节步进驱动器设计中常见的共振或振铃。

驱动器内置转换器,操作简便。这样可将控制引脚数量减少到两个,一个用于控制步进,另一个用于控制旋转方向。

驱动器提供五种不同的步进分辨率:全步进、半步进、四分之一步进、八分之一步进和十六分之一步进。

为了确保可靠运行,驱动器还具有欠压、直通、短路、过流和热保护等附加功能。技术规格:

马达输出电压8V – 35V
逻辑输入电压3V – 5.5V
每相连续电流1A
每相最大电流2A
微步进分辨率full, 1/2, 1/4, 1/8 and 1/16

A4988 电机驱动器引脚排列

A4988 驱动器共有 16 个引脚,用于与外界连接。引脚排列如下:

Image

让我们逐一了解所有引脚。

电源引脚

A4988 实际上需要两个电源连接。

Image

VDD 和 GND 用于为内部逻辑电路供电,电压范围为 3V 至 5.5V。而VMOT 和 GND 为电机供电,电压范围为 8V 至 35V。根据规格书,为了维持 4A,电机电源需要在靠近电路板的地方安装合适的去耦电容。

微步进选择引脚

A4988 驱动器通过将单个步进分成更小的步进来支持微步进。这是通过用中等电流水平给线圈通电来实现的。

例如,如果您选择以四分之一步进模式驱动 NEMA 17(步进角为 1.8° 或每转 200 步),则电机每转将产生 800 个微步。

Image

A4988 驱动器有三个步长(分辨率)选择器输入:MS1、MS2 和 MS3。通过为这些引脚设置适当的逻辑电平,我们可以将电机设置为五种步进分辨率之一。

MS1MS2MS3步进解析率
全步
半步
四分一步
八分一步
十六分一步

这三个微步选择引脚由内部下拉电阻拉低,因此如果您将它们保持未连接状态,则电机将以全步进模式运行。

控制输入​​引脚

A4988 有两个控制输入:STEP 和 DIR。

Image

STEP 输入控制电机的微步。发送到此引脚的每个高脉冲都会根据微步选择引脚确定的微步数驱动电机。脉冲频率越高,电机旋转越快。

DIR 输入控制电机的旋转方向。将其拉高可使电机顺时针转动,而将其拉低可使电机逆时针转动。

如果您希望电机只朝一个方向转动,可以将 DIR 直接连接到 VCC 或 GND。

注意:STEP 和 DIR 引脚没有被拉到任何特定电压,因此您不应该在应用程序中让它们处于浮动状态。

用于控制电源状态的引脚

A4988 有三个单独的输入用于控制其电源状态:EN、RST 和 SLP。

Image

EN 是低电平有效输入引脚。当此引脚拉低时,A4988 驱动器启用。默认情况下,此引脚拉低,因此除非您将其拉高,否则驱动器始终启用。此引脚在实施紧急停止或关机系统时特别有用。

SLP 是低电平有效输入引脚。将此引脚拉低可使驱动器进入睡眠模式,从而将功耗降至最低。您可以使用它来节省电量,尤其是在电机未使用时。

RST 也是低电平有效输入。当此引脚拉低时,所有 STEP 输入都将被忽略。它还通过将内部转换器设置为预定义的“原点”状态来重置驱动器。原点状态基本上是电机启动的初始位置,并且会根据微步分辨率而变化。

注意:RST 是一个浮动引脚。如果您不使用此引脚,请将其连接到相邻的 SLP/SLEEP 引脚,使其变为高电平并启用驱动器。

唤醒事件(SLEEP 引脚上的逻辑为高电平)发生后,等待 1 毫秒,然后再发出 Step 命令,让电荷泵稳定下来。

输出引脚

A4988 电机驱动器的输出通道通过引脚 1B、1A、2A 和 2B 引出到模块侧面。

Image

您可以将任何小型到中型双极步进电机(例如 NEMA 17)连接到这些引脚。

每个输出引脚最多可以为电机提供 2A 的电流。但是,提供给电机的电流量取决于系统的电源、冷却系统和电流限制设置。

在wokwi.com中新建一个Raspberry Pico项目,选择MicroPython环境,建立以下电路:

Image

输入以下micropython代码:

from machine import Pin
import time
class A4988StepperMotor:
    def __init__(self, step_pin, dir_pin, enable_pin=None, ms_pins=None):
        """
        Initialize the A4988 stepper motor driver
        
        Args:
            step_pin (int): GPIO pin number for STEP
            dir_pin (int): GPIO pin number for DIR
            enable_pin (int, optional): GPIO pin number for ENABLE
            ms_pins (list, optional): List of GPIO pins for microstepping [MS1, MS2, MS3]
        """
        self.step_pin = Pin(step_pin, Pin.OUT)
        self.dir_pin = Pin(dir_pin, Pin.OUT)
        
        if enable_pin is not None:
            self.enable_pin = Pin(enable_pin, Pin.OUT)
            self.enable_pin.on()  # Disable motor by default (active LOW)
        else:
            self.enable_pin = None
            
        self.ms_pins = []
        if ms_pins:
            for pin in ms_pins:
                ms_pin = Pin(pin, Pin.OUT)
                ms_pin.off()  # Full step by default
                self.ms_pins.append(ms_pin)
    
    def set_microstepping(self, mode):
        """
        Set microstepping mode
        
        Args:
            mode (str): Microstepping mode ('full', 'half', '1/4', '1/8', '1/16')
        """
        if not self.ms_pins or len(self.ms_pins) != 3:
            return
            
        modes = {
            'full': (0, 0, 0),
            'half': (1, 0, 0),
            '1/4':  (0, 1, 0),
            '1/8':  (1, 1, 0),
            '1/16': (1, 1, 1)
        }
        
        if mode in modes:
            for pin, value in zip(self.ms_pins, modes[mode]):
                pin.value(value)
    
    def enable(self):
        """Enable the motor driver"""
        if self.enable_pin:
            self.enable_pin.off()  # Active LOW
    
    def disable(self):
        """Disable the motor driver"""
        if self.enable_pin:
            self.enable_pin.on()  # Active LOW
    
    def step(self, steps, delay=0.005, direction=1):
        """
        Move the motor a specified number of steps
        
        Args:
            steps (int): Number of steps to move
            delay (float): Delay between steps in seconds
            direction (int): 1 for clockwise, 0 for counterclockwise
        """
        self.dir_pin.value(direction)
        
        for _ in range(abs(steps)):
            self.step_pin.on()
            time.sleep_ms(int(delay * 1000))  # Convert to milliseconds
            self.step_pin.off()
            time.sleep_ms(int(delay * 1000))
    
    def rotate(self, degrees, steps_per_revolution=200, delay=0.005, direction=1):
        """
        Rotate the motor by a specified number of degrees
        
        Args:
            degrees (float): Number of degrees to rotate
            steps_per_revolution (int): Steps per full revolution (usually 200)
            delay (float): Delay between steps in seconds
            direction (int): 1 for clockwise, 0 for counterclockwise
        """
        steps = int((degrees / 360) * steps_per_revolution)
        self.step(steps, delay, direction)
# Example usage
def main():
    try:
        # Define GPIO pins (adjust according to your board and wiring)
        STEP_PIN = 3
        DIR_PIN = 2
        ENABLE_PIN = 4
        MS_PINS = [17, 18, 19]  # MS1, MS2, MS3
        
        # Initialize the stepper motor
        motor = A4988StepperMotor(
            step_pin=STEP_PIN,
            dir_pin=DIR_PIN,
            enable_pin=ENABLE_PIN,
            ms_pins=MS_PINS
        )
        
        # Enable the motor
        motor.enable()
        
        # Set microstepping mode
        motor.set_microstepping('full')
        
        # Rotate 180 degrees clockwise
        print("Rotating 360 degrees clockwise...")
        motor.rotate(180, delay=0.001,direction=0)
        time.sleep(1)
        
        # Rotate 180 degrees counterclockwise
        print("Rotating 180 degrees counterclockwise...")
        motor.rotate(180, delay=0.001, direction=1)
        
        # Disable the motor
        motor.disable()
        
    except KeyboardInterrupt:
        print("\nProgram stopped by user")
if __name__ == "__main__":
    main()

运行效果:

将步进改为半步:

motor.set_microstepping('half')

可以看到旋转角度变为原来的一半。