如何驱动步进电机

本文旨在帮助初学者了解步进电机的工作原理以及如何驱动步进电机。控制步进电机是一个广泛的话题,本文帮你有个好的开始。有两种类型的步进电机:双极和单极。

双极电机:

image

双极步进电机有四根电线和两个线圈。要使其旋转,需要通过线圈发送电流。每根电线都需要能够被高低驱动。以下是如何驱动电流使步进电机旋转。

要理解为什么这样做,请考虑一个只有四个步骤的简单步进电机。在第一阶段,它将磁体与第一线圈对齐。下一步将磁体旋转90度。通过第一线圈反向发送电流会反转磁体极性。相反的线圈被连接,但相对于中心磁体产生相反的磁场。

当然,大多数步进电机的步数超过4步。你的标准步进电机每转200步。以这种方式旋转电机称为全步进。一旦你完成了全步工作,半步是非常简单的。你可以同时通过两个线圈发送电流,这将使分辨率加倍。
步进电机驱动器也可以使用微步进,微步进调节通过线圈的电流。典型的电机控制器可以在每一个完整的步骤中执行16个微步骤。一些芯片负责调制电流,但较旧的芯片需要为其驱动的步进电机“调谐”。微步进进一步将整个步进划分为256微步进,使典型的200步进电机变成51200步进电机!微步进还降低了电机的噪音,使其运行更平稳、更高效。

image

完整步骤1和2之间的半步

如何控制线圈中的电流:

控制通过绕组的电流的最常见设置是使用所谓的H桥。它是一组四个晶体管,可以将每条导线拉高或拉低。你也可以用MOS管代替晶体管,但布线会有点不同。该图显示了如何通过H桥向任意方向发送电流。你只需要打开路径中的晶体管。

你必须确保同一侧的两个晶体管不能同时导通。这将通过提供从电源到接地的低电阻路径使电路短路。你还应注意,晶体管可能需要一段时间才能从接通切换到断开。除非你知道自己在做什么,否则不建议快速切换通过线圈的电流。

这仍然不是全貌。旋转电机将产生电压。为了保护晶体管,最好放置反激二极管。

这将防止电机产生高压,这可能会破坏晶体管甚至驱动器。如果驱动步进电机的电压高于MCU输出的电压,则需要添加另一个晶体管来控制PNP晶体管。

当你打开额外的NPN晶体管时,它将允许电流从PNP晶体管的基极(引脚1)流出,从而打开它。现在所需要的只是所有NPN晶体管基极上的限流电阻。

就是这样!该H桥将控制通过其中一个绕组的电流。由于有两个绕组,我们需要将这个电路加倍。

现在,你可以很好地计算所需的组件。使用双H桥并不是驱动步进电机的唯一方法。你也可以购买步进电机驱动器,它将内置双H桥(尽管驱动器通常使用MOS管和其他技巧)。如果你想减少BOM数量(有时获得更多功能),我建议你看看步进电机驱动器。你需要查看数据表以了解芯片提供的功能。一些芯片只提供晶体管和二极管,而其他芯片则完全控制通过线圈的电流。

微步进:

微步进包括向晶体管发送脉宽调制信号。这是一种控制电机线圈电流的简单方法。预先选择的PWM值被放置在正弦查找表中。典型地,选择20-40kHz的PWM频率。任何低于20千赫的声音,人类耳朵都能听到。频率保持低于40kHz以提高效率并减少晶体管中的功耗。当PWM信号为高时,电流流过晶体管。当PWM信号低时,电流流过二极管。这是一个非常粗糙的微步进实现,但它给出了它如何工作的一般概念。使用MOS管的电机驱动器可以控制电机电流降低或衰减的速度。驱动器的电流波形更像这样:

必须为其驱动的电机手动优化快速衰减周期和慢速衰减周期。一些新芯片会根据其感应到的电流自动调整衰减周期,但旧芯片可能需要优化(或调整)。

晶体管基础知识:

晶体管是一种电流控制限流装置。晶体管有三个引脚:基极、集电极和发射极。(用c、b和e表示)。

NPN 晶体管:

NPN晶体管大部分已被MOS管所取代,但仍有一些应用需要晶体管。它们不易受到静电放电(ESD)的影响,使用电压也较低。最大的缺点是,它们不能像MOS管那样推动更多的电流,而且效率也不高。使用5mA提供的TIP120,我可以控制高达5A的60V负载(阅读数据表了解具体操作特性)。

这是一个典型的小信号NPN晶体管。当小电流从基极流向发射极时,允许较大电流从集电极流向发射极。记住它们是基于电流的设备很重要。

image

达林顿对是由两个晶体管组成的封装。增益是正向电压的两倍。

任何晶体管都可以被认为是二极管+电流源。

通过相关电流源的电流是(β)乘以通过二极管的电流(ib)。β称为晶体管的增益。不同的晶体管有一个相当大的差异,所以不要依赖这个值是真的!该模型仅在晶体管未饱和时有效。如果有足够多的电流流过基极,使得晶体管不再限制通过集电极-发射极的电流,则晶体管被称为饱和。(如果将晶体管用作开关,则应使晶体管饱和或关闭,以防止发热和断电。)

二极管在阳极和阴极两端的标称压降为0.7V。因此,从基极到发射极的电压降是0.7伏(对于达林顿来说,这是1.4伏)。

image

二极管是晶体管的一个组成部分,这就是为什么你应该放置NPN晶体管来控制接地,放置PNP晶体管来控制电源。考虑两个几乎相等的电路。

在第一电路中,假设你有足够的电流从3.3V电源进入基极,使晶体管完全饱和(晶体管不会限制负载图像中的任何电流。集电极和发射极之间的电压降很小,但很小。负载两端有11.8伏。限流电阻两端的电压为2.6V。这在计算电阻大小时很重要。

在第二个电路中,相同的电阻用于理论上限制相同的电流。但由于晶体管在基极和发射极之间的作用类似二极管,发射极必须比基极低0.7伏。2.6伏是发射极所能达到的最大绝对值(由于两个电阻的分压,它可能会小得多。)此时晶体管并不是限制电流,而是限制电压。无论如何,晶体管将多余的功率作为热量散发出去。负载两端的电压仅为2.6V。

PNP 晶体管:

这是典型的PNP晶体管在示意图中的样子。它类似于NPN晶体管,只是电流必须从发射极流向基极,以允许电流从发射极流到集电极。当一个小电流通过二极管时,允许一个更大的电流流过发射极和集电极。

image

晶体管可以被认为是二极管+电流源。来自从属电流源的电流为。就像NPN一样,二极管存在于基极到发射极之间。二极管两端仍有0.7V的压降。它正对着另一个方向。

下面是在电路中使用它的方法。要打开它,让针脚1比针脚3低0.7V。为了关闭晶体管,引脚1需要与VCC处于相同的电压。在使用运算放大器控制它时,这一点很重要。如果运算放大器不是轨到轨运行,它不会完全关闭PNP晶体管。这也使得驱动更高的电压变得困难。如果你试图用3.3v控制12v电源,你永远无法关闭晶体管。3.3v总是小于12v。这就是为什么我通常将它们与小信号NPN配对。如果NPN关闭,电流不能流过二极管,PNP关闭。

如何选择离散组件:

二极管: 选择适合你应用的额定电流二极管。当从接通切换到断开时,电机中的电流必须通过二极管。为了避免过热,请尝试寻找具有较低正向电压的二极管。如果你计划实施微步进,则尤其如此。

晶体管: 你的H桥晶体管也必须为你的应用额定电流。可以通过选择较低的集电极-发射极饱和电压来避免过热。更高的转换频率也可能是有益的,因为它将减少晶体管处于激活状态的时间量。最大功率值表示晶体管可以消耗多少功率。低功耗意味着晶体管将用作开关。

小信号晶体管: 这些可能很不起眼。要查找的最大属性是集电极-发射极击穿电压高于电机电源。更高的频率转换也是好的。过渡时间将叠加在两个晶体管之间(给出总体上低得多的过渡频率)

电阻: 电阻应容易选择。他们将保证一小部分电流通过晶体管。两个NPN电阻也将看到最小电压电平。连接到PNP基极的电阻是唯一需要注意的电阻。一旦你知道流经晶体管的电流量,电压基本上就是电机电源电压。额定功率超过¼瓦对于大多数应用来说应该绰绰有余。

场景举例:

我将用一个例子来说明如何计算电阻所需的值。这是一个场景:

电机
12V ,0.33 A

电源

微处理器

EFM32GG-STK3700。该板的逻辑电平为3.3v。每个引脚能够提供高达20mA的电源。

晶体管

我正好有一些TIP120TIP125晶体管,我将用它们来驱动H桥。它们能够驾驶5A。


这两个晶体管似乎都具有4V的集电极-发射极饱和!在两个晶体管之间,这只会让我的电机运行4V。我们最好深入研究一下这个参数。

数据表吓了我一跳!看起来我的应用程序的典型饱和电压低于1V。在更高的电流情况下,饱和电压增加到约1.2V。小信号NPN通常具有0.2V的饱和电压。为什么达林顿对如此高?

image

考虑点D。如果第一个晶体管饱和,D将比C小0.2V。请记住,第二个晶体管内置二极管。E必须比D小0.7V,否则电流将不会流动。总的来说,E比C低0.9V。这可以解释为什么达林顿对具有更高的饱和电压。当考虑电路中的电流时,最好依靠简单的事实来避免过于复杂。

现在我们需要电阻和二极管。我手头有一些1N4148二极管。它们目前不适合我的应用程序。然而,我并没有计划对电机进行微步进。

如果你仔细看看当前的能力,数据表显示它可以处理300毫安的正向电流。此外,它可以处理1秒的1A浪涌。电机中的电流在1秒内不应超过1A。

计算 H 桥中的电阻:

现在零件选择已经完成,我们可以将重点放在电阻上。首先,你需要考虑通过晶体管的电流。

image

我们的负载电流为0.33A。因此,image

PNP电阻消耗的功率为VI=120.001=12mW。实际上,任何尺寸的电阻都可以工作。Digi-key提供的表面安装电阻的最小额定功率为12.5mW。

我的晶体管在工作区附近的增益在25摄氏度时接近1000。

因此,我应该为晶体管的基极提供330 uA。为了安全起见,我将提供1mA的电流(三倍于此。因为我的电流是330 mA,所以我不在乎另外1 mA。通常双倍的电流是安全的。)

现在我们知道了所需的电流,我们可以看看电压。

由于PNP内置二极管,B点的电压将比VDD(12V)低1.4V,因此Vb=10.6V。

如果最左边的NPN饱和,集电极-发射极电压将为0.2V。因此,Va=0.2V。

这意味着电阻两端的电压是10.4V。我们需要1mA才能通过电阻。使用V=I*R,

R=V/I=10400。10k电阻就可以了。这个值不需要精确,因为当我们将电流增加三倍时,我们已经考虑了任何增益容差。

image

下一个晶体管将是另一对达林顿晶体管。集电极电流为330mA。在我的操作点附近,增益也在1000左右。我应该只需要330uA,但我会将其增加三倍至1mA,以确保考虑到任何公差。

D点的电压是1.4V。我的C点MCU可以提供3.3V。电阻两端的电压是1.9V。使用V=I*R,R=V/I=1900。2k2电阻或1k8电阻将工作。

image

最后要计算的电阻是控制PNP晶体管的电阻。集电极电流为1mA。典型的小信号晶体管的增益为100。在较低的电流下,它也会较低。仔细检查晶体管的数据表。为这个晶体管供电所需的电流只有10uA。为了安全起见,我将计算100uA。F处的电压为0.7V。E处的电压再次为3.3V。电阻两端的电压为2.6V。使用R=V/I,R=26k。从20公里到50公里的任何距离都可以。我用了28k电阻。

image

这就是你设置H桥的方式!要控制它,你需要为电线供电:

警告:要么不要将电机电源电压连接到VM,要么在连接所有设备之前不要打开电源。当重新连接插针和移动的电线时,请确保高压电源已关闭。你可以很容易地将所有的IC烧断。不要说我没有警告你。

只打开针脚1,然后3,然后2,然后4,旋转电机。或者,按照相反的顺序(4,2,3,1)。为了确保不会发生电源对地故障,请在切换状态时关闭所有引脚。

H 桥的示例代码:

使用完整步骤的示例代码:

/**************************************************************************//**
 * @file
 * @brief Empty Project
 * @author Energy Micro AS
 * @version 3.20.2
 * @section License
 * <b>(C) Copyright 2014 Silicon Labs, http://www.silabs.com</b>
 *******************************************************************************
 *
 * This file is licensed under the Silicon Labs Software License Agreement. See
 * "http://developer.silabs.com/legal/version/v11/Silicon_Labs_Software_License_Agreement.txt" 
 * for details. Before using this software for any purpose, you must agree to the
 * terms of that agreement.
 *
 ******************************************************************************/
#include "em_device.h"
#include "em_chip.h"
#include "em_cmu.h"
#include "em_system.h"
#include "em_gpio.h"
volatile uint32_t msTicks;
#define TOTAL_STEPS      4
uint32_t STEPS[TOTAL_STEPS] = {0b1000, 0b0010, 0b0100, 0b0001};             //1,3,2,4
uint16_t STEP = 0;
/* ************* Systick Handler ***************** */
void SysTick_Handler(void) {
    msTicks++;
}
/* ************* Delay function ****************** */
void Delay(uint32_t dlyTicks) {
    uint32_t curTicks = msTicks;
    while((msTicks - curTicks) < dlyTicks);
}
/* ************* Output to H-bridge ************** */
void setStep(void) {
      GPIO->P[3].DOUTCLR = 0xF;                  //Shut off all pins.
      GPIO->P[3].DOUTSET = STEPS[STEP];          //Output the steps
}
/* ************* Main function ******************* */
int main(void)
{
    CHIP_Init();
    CMU->HFRCOCTRL = 0x30; // Set RC clock to 1 MHz
    CMU->HFPERCLKEN0 =(1<<13); //Enable GPIO clock

    if (SysTick_Config(CMU_ClockFreqGet(cmuClock_CORE) / 1000)) while (1) ;         //Setup SysTick

/* ****************** Setup pushbuttons and H-bridge outputs ****************** */
    GPIO->P[1].MODEH = 0x110;                //Setup RB9 and RB10 as input
    GPIO->P[3].MODEL = 0x5555;               //Setup PD0-PD3 as push pull output. These go directly to the H-bridge
    GPIO->P[3].CTRL = 2;                     //High drivemode
    GPIO->P[3].DOUT = 0x0000;                //They should already be all low.
                                            //H-bridge pins 1,2,3,4 map to pins 3,2,1,0 on port D.
  /* Infinite loop */
  while (1) {
      if(!GPIO_PinInGet(gpioPortB,9)) {                         //If button 0 is pressed
          STEP = (STEP + 1) % TOTAL_STEPS;                      //Increment the step
          setStep();                                            //Output to the H-bridge
      }
      else if(!GPIO_PinInGet(gpioPortB, 10)) {                  //If button 1 is pressed.
          STEP = (STEP + TOTAL_STEPS-1) % TOTAL_STEPS;          //Decrement the step
          setStep();                                            //Output to the H-bridge
      }
      Delay(10);                                                //Short delay to let motor rotate
  }
}

使用半步的示例代码:

/**************************************************************************//**
     * @file
 * @brief Empty Project
     * @author Energy Micro AS
 * @version 3.20.2
 ******************************************************************************
 * @section License
 * <b>(C) Copyright 2014 Silicon Labs, http://www.silabs.com</b>
 *******************************************************************************
 *
 * This file is licensed under the Silicon Labs Software License Agreement. See
 * "http://developer.silabs.com/legal/version/v11/Silicon_Labs_Software_License_Agreement.txt" 
 * for details. Before using this software for any purpose, you must agree to the
 * terms of that agreement.
 *
 ******************************************************************************/
#include "em_device.h"
#include "em_chip.h"
#include "em_cmu.h"
#include "em_system.h"
#include "em_gpio.h"
volatile uint32_t msTicks;
#define TOTAL_STEPS      8
uint32_t STEPS[TOTAL_STEPS] = {0b1000, 0b1010, 0b0010, 0b0110, 0b0100, 0b0101, 0b0001, 0b1001};   
//1, 1and3, 3, 3and2, 2, 2and4, 4, 4and1

/* ************* Systick Handler ***************** */
void SysTick_Handler(void) {
    msTicks++;
}
/* ************* Delay function ****************** */
void Delay(uint32_t dlyTicks) {
    uint32_t curTicks = msTicks;
    while((msTicks - curTicks) < dlyTicks);
}
/* ************* Output to H-bridge ************** */
void setStep(uint32_t STEP) {
      GPIO->P[3].DOUTCLR = 0xF;                                  //Shut off all pins.
      GPIO->P[3].DOUTSET = STEPS[(STEP % TOTAL_STEPS)];          //Output the steps
}
/* ************* Main function ******************* */
int main(void)
{
    CHIP_Init();
    CMU->HFRCOCTRL = 0x30; // Set RC clock to 1 MHz
    CMU->HFPERCLKEN0 =(1<<13); //Enable GPIO clock

    if (SysTick_Config(CMU_ClockFreqGet(cmuClock_CORE) / 1000)) while (1) ;         //Setup millisecond tick counter

    /* ****************** Setup pushbuttons and H-bridge outputs ****************** */
    GPIO->P[1].MODEH = 0x110;                //Setup RB9 and RB10 as input
    GPIO->P[3].MODEL = 0x5555;               //Setup PD0-PD3 as push pull output. These go directly to the H-bridge
    GPIO->P[3].CTRL = 2;                     //High drivemode
    GPIO->P[3].DOUT = 0x0000;                //They should already be all low.
                                            //H-bridge pins 1,2,3,4 map to pins 3,2,1,0 on port D.
int32_t STEP = 0;

  /* Infinite loop */
  while (1) {
      if(!GPIO_PinInGet(gpioPortB,9)) {                         //If button 0 is pressed
          STEP += 1;                                            //Increment the step
          setStep(STEP);                                        //Output to the H-bridge
      }
      else if(!GPIO_PinInGet(gpioPortB, 10)) {                  //If button 1 is pressed.
          STEP -= 1;                                            //Decrement the step
          setStep(STEP);                                        //Output to the H-bridge
      }
      Delay(10);                                                //Short delay to let motor rotate
  }
}

使用分立组件的替代方案:

首先,你必须决定留给芯片的控制级别。步进驱动器可以像H桥封装一样简单。产品系列逐渐变得更加复杂,你可以准确地选择出发点。德州仪器提供了一系列具有不同控制程度的驱动程序。对于任何步进电机应用,德州仪器公司都会为其提供芯片。Allegro也有各种各样的驱动器。内置功能最多的驱动程序是Trinamic芯片。

STMicroelectronics L293D – 四桥半桥,每个通道可驱动600mA电流。这将替代上述示意图。你仍然需要控制哪些引脚可以驱动高和低。像Arduino电机这样的电路板将使用这种芯片

TMCSILENTSTEPSTICK – 步进电机驱动器,由步进和方向控制。Trinamic在一个小巧实惠的包装中提供了大量功能。该芯片能够进行256微步进内插和电流检测(无需调整)。这是 TMC2100的评估板。它将达到1.2A。

TMC5130-EVAL-KIT –步进电机驱动器由SPI/单线UART或步进和方向控制。该芯片是步进电机驱动器的劳斯莱斯。评估套件有助于确定哪些设置最适合你的电机。当心高压VM线

芯片本身就是TMC5130

无声运行:

这是 TMC2100的突破。它由Watterott设计,用于3D打印。它有两个0.11欧姆的感测电阻,最大RMS电流为1.74A。电位计允许你将电流控制在0到1.7A之间。

image

购买链接–Digi-key的网站

焊接接头:

将接头焊接到电路板上。如果您想使用配置输入引脚3,请先焊接该间隙(99%的人不需要担心)。如果你计划使用面包板或插座,请确保底部朝上(标有顶部)。这样可以更容易地接近电位计。如果您计划运行大量的电机电流(大于半安培),请在暴露的过孔上添加一个带有导热双面胶带的小型散热器。板顶部的通孔与TMC2100的底部和接地平面(用作芯片和冷却的接地)热连接和电连接。

连接引脚:

警告:不要将电机电源电压连接到VM,或者在连接好所有电源之前不要打开电源。重新连接引脚和移动导线时,请确保高压电源已关闭。您可以很容易地将所有IC烧坏。不要说我没有警告你。

这是芯片的功能设置。电位计控制通过电机的电流。Diag0和Diag1是芯片的诊断输出。你可以在TMC2100数据表中找到更多信息。Vref是电位计中间引脚处的电压。它连接到引脚AIN_REF(用于计算电机中的电流)。Trinamic配置输入为三态:它们可以检测引脚是否接地、连接到VCC或未连接(开路)。SilentStepStick上有四个配置销。

配置输入1和2:如果未连接,芯片上的默认连接为CFG1=打开,CFG2=打开。不要永久连接这些针脚,因为你可能会在以后改变主意。

配置输入3:此芯片上的默认连接是打开的。要将配置输入连接到配置引脚,需要桥接板上的焊料间隙。还有一个smd跳线未连接。其他三个已经焊接了0欧姆电阻。强烈建议使用显微镜,但如果你知道焊接哪个间隙,你可以使用放大镜。你可以选择在间隙上加一个0201电阻(0欧姆),但我不建议这样做。

![image|690x216](upload://eiF6KH771KETvdcXhO


fsr8j87Sf.png)
image
该引脚为N.C.,即使你为收割台上的引脚供电。

配置输入6:如果未连接,则此芯片上的默认连接是打开的。我建议将其打开,除非你的应用程序需要电机提供静态扭矩。

斩波器配置引脚:

该板还允许你硬接线一些其他配置引脚。看起来 Watterott 先生留下了剩余的三个引脚可配置。

引脚0、4和5可以硬连线到不同的状态。如果查看示意图,可以看到每个引脚的位置。它还显示,默认情况下,引脚0和4接地,而引脚5连接到VCC_IO。

以下是数据表上的内容


计算电流:

如果你没有在CFG 3上提供跳线,驱动器将使用AIN_REF和感测电阻来调节通过线圈的电流。该板使用0.11欧姆的感测电阻。Vref的电压将与通过线圈的电流成比例。如果要在连接电机之前设置电流,请确保在连接电机前关闭电路板的电源。如果在连接或断开电机时驱动程序通电,可能会损坏驱动程序。监测Vref引脚上的电压。要降低电流,逆时针转动螺钉。另一种校准电流的方法是查看电机的性能。降低电流,直到电机运行不良。然后,增加电流,直到电机达到期望的性能。

Vref (V) I RMS (A)
2.5 1.74
2.0 1.39
1.5 1.04
1.0 0.70
0.5 0.35

请记住,数据表中显示1.2A RMS(均方根)是驾驶员应该驾驶的最大值。如果你与散热器连接良好,你可能会通过驱动更多电流来逃避。

使用EFM32巨型壁虎的示例代码:

/**************************************************************************//**
 * @file
 * @brief Empty Project
 * @author Energy Micro AS
 * @version 3.20.2
 ******************************************************************************
 * @section License
 * <b>(C) Copyright 2014 Silicon Labs, http://www.silabs.com</b>
 *******************************************************************************
 *
 * This file is licensed under the Silicon Labs Software License Agreement. See
 * "http://developer.silabs.com/legal/version/v11/Silicon_Labs_Software_License_Agreement.txt" 
 * for details. Before using this software for any purpose, you must agree to the
 * terms of that agreement.
 *
 ******************************************************************************/
#include "em_device.h"
#include "em_chip.h"
#include "em_gpio.h"
#include "em_cmu.h"
#include "em_timer.h"
#include "em_emu.h"
volatile uint32_t msTicks;
void SysTick_Handler(void) {
    msTicks++;
}
void Delay(uint32_t dlyTicks) {
    uint32_t curTicks = msTicks;
    while((msTicks - curTicks) < dlyTicks);
}
void setDir(bool dir) {
    if(dir) GPIO->P[4].DOUTSET = 1 << 3;
    else GPIO->P[4].DOUTCLR = 1 << 3;
}
bool getPushButton(bool button) {
    return !(GPIO->P[1].DIN & (1 << (button + 9)));
}
/**************************************************************************//**
 * @brief  Main function
 *****************************************************************************/
/* This code isn't optimized for anything. Rather, it was just proof that i could get the motor spinning and test ou the maximum velocities. If you change the step configuration pins, you
could probably get faster speeds out of the driver. */

int main(void)
{
  /* Chip errata */
  CHIP_Init();
  CMU_ClockEnable(cmuClock_GPIO,true);
  CMU_ClockEnable(cmuClock_TIMER3,true);
  TIMER3->CTRL = 1 << 6;                                                       //Run in debug mode
  TIMER3->ROUTE = (1 << 16) | (1 << 2);                                          //Location 1, CC2 output enable
  TIMER3->CC[2].CTRL = (1 << 10) | 2;                                          //On timer overflow, toggle output. Enable compare output.
  if (SysTick_Config(CMU_ClockFreqGet(cmuClock_CORE) / 1000)) while (1) ;       //Setup system tick handler
  GPIO->P[1].MODEH |= (1 << 4) | (1 << 8);                                       //Enable pushbuttons as inputs (B9, B10)
  GPIO->P[4].MODEL |= 0x4400;                                                    //Enable outputs E2 and E3
  int16_t time_delay = 32767;                                                   //32767 is the largest value for this signed int. If i     increment by one more, it will overflow to -32768. Good.
  /* Infinite loop */
  while (1) {
      if(getPushButton(1)){                                                     //If button one is pressed
          if((time_delay > 0) | (time_delay < -500)) time_delay++;                //Make sure it isn't in the dead zone,     then increment time_delay
      }
      else if(getPushButton(0)) {                                               //If button zero is pressed
          if((time_delay < 0) | (time_delay > 500)) time_delay--;             //Make sure it isn't in the dead zone, then decrement time_delay
      }
      if((time_delay > 32000) | (time_delay < -32000))TIMER3->CMD = 0x2;       //If the time delay is large, i probably wanted to stop the motor entirely.
      else TIMER3->CMD = 0x1;
      if(time_delay < 0) {                                                       //This is not optimized for keeping position absolute. I ignored the direction-to-step transition time here.
          setDir(0);
          TIMER3->TOPB = (time_delay * -1);
      }
      else {
          setDir(1);
          TIMER3->TOPB = time_delay;
      }
  }
}

控制速度:

已经显示了两种步进电机的方法。我建议使用计时器来步进电机。如果你使用H桥,你可以在定时器中断内步进电机。如果使用step/dir驱动程序,可以通过将比较/捕获引脚设置为PWM模式来自动切换引脚。电机的速度将由你的延时决定。此外,你可以选择在计时器溢出时切换比较通道,或设置PWM通道。驾驶员数据表将包含有关定时特性的信息。在这种情况下,如果我运行一个1MHz的时钟,我需要在操作之间等待20个时钟。我最初忽略的一个重要值是,步骤设置时间的方向。如果你忽略了时间特征,你可能会失去你的位置。芯片会认为电机在别处。幸运的是,Trinamic的数据表很容易阅读。

速度是距离除以时间。在步进电机中,它是步数d(revolution)除以时间t(s)。你可以通过除以每转的总步数来计算速度。这将包括微步。总步数(total steps)=电机步数*微步数

image

我们可以乘1。每总步数有1转。

image

如果要在代码中实现这一点,则需要找到递增或递减步骤的时间段。求解作为速度函数的时间周期(time
period (s))

image

其中,V是每秒转数,时间段以秒为单位。秒对于微控制器来说是非常长的时间。最好乘以每秒时钟数(clocks/(s))。

image

我们可以通过忽略与变量相关的数字来检查单位

image

每秒时钟也称为频率(fclk)。

image

如果你的计时器使用的是一个预分频器(prescalar),那么这个预分频器应该被分频。如果1秒在预缩放之前是1024个时钟,并且你预缩放了1024个,那么正好1个时钟是1秒。

image

只要电机在每个时间段后步进,这将起作用。如果你将计时器设置为溢出(就像我在上面的代码中所做的那样),如果你除以2,所有这些等式都会起作用(因为这需要两个时间段。将时间段除以2可以恢复这一点。)

你的预检很大程度上取决于你的最高速度Vmax。如果你知道你的最高速度,你可以用这个公式来计算出定时器时钟的最低数量会使你达到这个速度。如果你不知道自己的最高速度,你可以通过反复试验来找出答案。持续缩短时间,直到电机运行不稳定。小心,当负载增加到接近最高速度时,电机可能会跳跃。玩各种电机速度和负载。

image

此实现的最大问题是,对于0的速度,你需要等待无限长的时间。无限对于微控制器来说太大了,无法计数。此外,接近0的速度也会导致非常长的时间延迟。解决这个问题的一个好办法是找到可达到的最慢速度,并创建一个死区。在我的芯片中,顶部计时器值是一个16位数字。最长延迟为65535个时钟。最低可实现速度(Vlowest)为:

image

给你!这应该会让你开始你的项目,但它需要更多的工作才能使用。以恒定速度发送目标位置非常容易。在中断内部,检查目标位置是否不等于实际位置。如果是这种情况,请踩下电机。

现在速度控制已经解决,你可以使用它来扩展控制。尝试实现一个可以提高或降低速度的函数。然后,尝试设定一个目标位置,并向上/向下倾斜以到达目标位置。如果这听起来工作量太大,还有另一个解决方案:进入TMC5130!

TMC5130 的示例案例:

Trinamic的步进驱动器TMC5130提供了太多的功能,很难涵盖所有内容。要启动,可以通过step/dir、SPI或单线UART控制驱动程序。如果使用步进/方向控制,芯片将模拟TMC2100。如果你使用SPI或单线UART,你可以访问速度模式和位置模式。这两种模式都会告诉你电机在哪里,旋转速度有多快。最大速度和加速度可编程。你可以给芯片一个目标位置,它将负责加速到最大速度,并在到达该位置之前减速。

以下是驱动程序提供的TLDR:

SpreadCycle–自动快速衰减。无需调整电机

CoolStep–使用电机产生的EMF在线圈中使用最小电流

StealthChop–低速时电机几乎无声运行。

StallGuard2–检测电机何时停止。

DcStep–自动降低速度以应对更高的负载。

在我最近的一个项目中,我使用了stealthChop、spreadCycle和stallGuard2。我将详细介绍如何设置偷切芯片,并安装Guard2。

你需要做的第一件事就是把芯片放到板上。TMC5130-EVAL-KIT是一个良好的开端。如果你想制作一个自定义板,你需要参考数据表以了解详细信息。这里要传达的信息太多了。唯一的曲线球是引脚29,DRV_ENN_CFG6是驱动器的使能。当该引脚处于高位时,所有电机输出保持浮动。将此针脚接地,以启用电机输出。此外,如果你没有为CLK引脚提供时钟,则必须将其接地。以下是我如何连接芯片:

引脚 序号 类型 连接
TST_MODE 1 DI GND
CLK 2 DI 外部CLK或接地
CSN_CFG3 3 DI (tpu) SPI芯片选择输入
SCK_CFG2 4 DI (tpu) SPI时钟
SDI_NAI_ CFG1 5 DI (tpu) SPI数据输入
N.C. 6, 31, 36 未使用的引脚;连接GND以兼容未来版本。
SDO_NAO_ CFG0 7 DIO (tpu) SPI数据输出
REFL_STEP 8 DI 浮动
REFR_DIR 9 DI 浮动
VCC_IO 10 连接到MCU电源电压
SD_MODE 11 DI (pu) GND
SPI_MODE 12 DI (pu) 浮动
GNDP 13, 48 电源接地。连接到引脚附近的GND平面。
DNC. 14, 16, 18,20, 22, 41,43, 45, 47 不要连接这些引脚。提供用于增加PCB上的爬行距离,以便在没有涂层的情况下提供更高的电源电压。
OB1 15 电机线圈B输出1
BRB 17 线圈B的感测电阻器连接。将感测电阻器置于引脚附近的GND。为了获得最佳性能,建议在GND(GND平面)上增加一个100nF电容器。
OB2 19 电机线圈B输出2
VS 21, 40 电机电源电压。在引脚附近提供滤波容量,并将短环路连接到最近的GNDP引脚(分别通过GND平面)。
ENCN_DCO 23 DIO GND
ENCB_DCEN_ CFG4 24 DI (tpu) GND
ENCA_DCIN_ CFG5 25 DI (tpu) GND
SWN_DIAG0 26 DIO 浮动
SWP_DIAG1 27 DIO 浮动
SWSEL 28 DI (pd) 浮动
DRV_ENN_ CFG6 29 DI GND–您也可以将其连接到拨动开关或MCU。
AIN_IREF 30 AI 浮动
GNDA 32 模拟GND。连接到GND平面。
5VOUT 33 内部5V调节器的输出。将2.2µF或更大的陶瓷电容器连接到引脚附近的GNDA,以获得最佳性能。提供芯片VCC的输出。
VCC 34 芯片和电荷泵内数字电路的5V电源输入。将470nF电容器连接到GND(GND平面)。可由5VOUT提供。建议使用2.2或3.3欧姆电阻器将噪声从5VOUT解耦。当使用外部电源时,请确保VCC在5VOUT或VCC_IO之前或并行出现,以较晚出现的为准!
CPO 35 电荷泵电容器输出。
CPI 37 电荷泵电容器输入。使用22nF 50V电容器连接至CPO。
VCP 38 充电泵电压。使用100nF电容器连接到VS。
VSA 39 5V调节器的模拟电源电压。通常连接到VS。提供一个100nF的滤波电容器。
OA2 42 电机线圈A输出2
BRA 44 线圈A的感测电阻器连接。将感测电阻器置于引脚附近的GND。为了获得最佳性能,建议在GND(GND平面)上增加一个100nF电容器。
OA1 46 电机线圈A输出1
Exposed die pad - 将暴露的管芯焊盘连接到GND平面。提供尽可能多的通孔,用于将热量传递到GND平面。用作数字电路的GND引脚。

参考设计的另一个好来源是数据表的第121页。这是Eval板的示意图。 TMC5130-Eval_v15_01_Schematic.pdf (69.0 KB)

确保垫的底部与接地平面有良好的热连接。如果可能,使用通孔将热量传递到接地平面。如果你用数控机床铣成两层板,在芯片下面留一个大钻孔,并用焊料填充,以连接接地平面。如果你不热连接底部衬垫,你将无法驱动那么多的电流。

一旦芯片就位,你将需要向芯片发送设置数据。我的经验效率不高。我嗅探了评估套件中发送的设置,并在设置中进行了模拟。当它不起作用时,我必须仔细检查每一个寄存器,看看我可能在哪里关机了。最后,spi总线的时钟线出现了短路。如果我必须再做一次,我会参考5130数据表的第109页。这是这一页的副本。你可以参考数据表中的每个寄存器,以查看哪些设置可以工作。注意:请仔细检查当前设置。此初始化将电流设置为最大值。这是在考虑到eval套件的情况下设计的,它在芯片下具有难以置信的散热能力(严重的是,当我用高压油炸芯片时,更换芯片很痛苦。)此外,一些PWMCONF寄存器可能会增加电流。配置此寄存器时,监控通过电机的电流或检查芯片的温度。

25.1 初始化示例

SPI datagram example sequence to enable the driver for step and direction operation and initialize the chopper for spreadCycle operation and for stealthChop at <60 RPM:
SPI send: 0xEC000100C5; // CHOPCONF: TOFF=5, HSTRT=4, HEND=1, TBL=2, CHM=0 (spreadCycle)
SPI send: 0x9000061F0A; // IHOLD_IRUN: IHOLD=10, IRUN=31 (max. current), IHOLDDELAY=6
SPI send: 0x910000000A; // TPOWERDOWN=10: Delay before power down in stand still
SPI send: 0x8000000004; // EN_PWM_MODE=1 enables stealthChop (with default PWM_CONF)
SPI send: 0x93000001F4; // TPWM_THRS=500 yields a switching velocity about 35000 = ca. 30RPM
SPI send: 0xF0000401C8; // PWM_CONF: AUTO=1, 2/1024 Fclk, Switch amplitude limit=200, Grad=1
SPI sample sequence to enable and initialize the motion controller and move one rotation (51200 microsteps) using the ramp generator. A read access querying the actual position is also shown.
SPI send: 0xA4000003E8; // A1 = 1 000 First acceleration
SPI send: 0xA50000C350; // V1 = 50 000 Acceleration threshold velocity V1
SPI send: 0xA6000001F4; // AMAX = 500 Acceleration above V1
SPI send: 0xA700030D40; // VMAX = 200 000
SPI send: 0xA8000002BC; // DMAX = 700 Deceleration above V1
SPI send: 0xAA00000578; // D1 = 1400 Deceleration below V1
SPI send: 0xAB0000000A; // VSTOP = 10 Stop velocity (Near to zero)
SPI send: 0xA000000000; // RAMPMODE = 0 (Target position move)
// Ready to move!
SPI send: 0xADFFFF3800; // XTARGET = -51200 (Move one rotation left (200*256 microsteps)
// Now motor 1 starts rotating
SPI send: 0x2100000000; // Query XACTUAL - The next read access delivers XACTUAL
SPI read; // Read XACTUAL

希望这应该是移动电机的开始。如果它不工作,请仔细检查SPI总线通信。我碰巧在同一个SPI总线上有一个加速计,以确保它的一部分正常工作。

设置 StealthChop

上面的示例还显示了如何设置stealthChop。有三个寄存器需要从当前未使用stealthChop的工作代码中修改。

GCONF–0x00:设置位2(1<<2)以启用PWM模

TPWMTHRS–0x17:设置最高速度(较低时间延迟),使斩波器工作。不要将此设置得太低,否则电机切换时会跳动。这个例子用了500,但我用了5000。

PWMCONF–0x70:这是主悄悄斩配置寄存器。如果stealthChop行为异常,请检查此寄存器设置。

•设置自动缩放位(1<<18),以快速设置潜行斩波。

•如果电机仍然发出噪音,请尝试在pwm_frequency位字段中设置更高的频率。

•将PWM_GRAD位字段设置为至少1。

•PWM_AMPL字段建议至少为64。值越高,电机电流越高。

数据表也广泛涵盖了这个主题。

使用 stallGuard2 归位:

使用带有硬停止的stallGuard2不像设置参考开关那样容易。参考开关的公差比stallGuard2好得多。在紧急情况下,这仍然是一个非常方便的解决方案。在一个只需几个步骤就能产生巨大差异的应用程序中,不要使用此功能。在绝对位置不那么关键的应用程序中,这是一条路。

triWrite(0x27,0)                        //To start, set the motor velocity to 0.
triWrite(0x20,1)                        //Put the chip in velocity mode                                   //Or 2 if other direction
triWrite(0x14,5000)                     //Set the coolStep upper velocity                                 //I suspect lower numbers may work better
triWrite(0x34, (1 << 10))             //Enable stop by stallGuard2                                      //Clear this bit to disable stallGuard2
triWrite(0x6D,(11 << 16))                 //Set Stall Guard Threshold                                       //This field will change if anything else changes. It will also vary from motor to motor. The EVAL kit is nice for this.
triWrite(0x27, 60000)                   //Start a motion                                                  //My application was geared down
Delay(1000)                             //Wait for motor to start                                         //Motor will stop when it stalls
while(triGetVel())                      //Poll vActual, wait for it to be 0                               //Poll the velocity instead of the     flags
triWrite(0x27,0)                        //Set the target velocity to 0                                    //This prevents the motor from moving
triWrite(0x34,0)                        //Clear the sg_stop bit                                           //Alternatively, read the     RAMP_STAT register
/*
To set where "home" is, you need to set xActual. If where you stopped is home, set xActual to 0. In my case, home was +187300 microsteps. So, I set xActual to -187300. Then, I set xTarget to 0. This will send the stepper home once you switch to position mode.
    */
triWrite(0x21,-187300)                  //Set home                                                        //I'm here in reference to home
triWrite(0x2D, 0)                       //Go home                                                         //I want to be here
triWrite(0x20,0)                        //Now set into position mode                                      //Position mode
triWrite(0x27,0x249F0)                  //Set upper velocity limit                                        //This is your upper operating velocity

这应该行了!在我的项目中,我在进入定位模式之前将xTarget设置为xActual。这是我设置的宏的结果。这个命令也应该有效。根据你的应用程序,你需要更改速度和失速防护阈值,但过程应该相同。清除sg_stop位将关闭stallguard。如果你想让你的应用程序继续运行,只需读取RAMP_STAT寄存器即可。

数据表还介绍了如何从第78页开始设置stallGuard2。stallGuard2功能需要一些时间才能正确校准。其他汽车驾驶员可以检测到失速,但这是一个令人印象深刻的特征。其他驱动程序可以检测到过大电流,但迄今为止,没有一个驱动程序允许你配置过大电流限制。

单极电机:

单极电机是双极电机,其线圈为中心抽头。这意味着电流控制要容易得多。缺点是只能使用一半的线圈,因此效率较低。这是单极上的电线通向的地方。如果电机只有五根电线,则两条中心抽头电线已经连接。

image
这就是双极电机的步进方式。在双极电机中,你需要能够发送每个引脚的高或低。

在单极电机中,只需将线圈端接地即可。

驱动这一点的电路很简单。

与双极电机不同,当你打开两个相邻的晶体管时,事情不会爆炸。要使电机步进,按以下顺序打开线圈:A1、B1、A2、B2。要反转电机,请反转顺序。下面是一些示例代码:

使用完整步骤的示例代码:


/**************************************************************************//**
 * @file
 * @brief Empty Project
 * @author Energy Micro AS
 * @version 3.20.2
 ******************************************************************************
 * @section License
 * <b>(C) Copyright 2014 Silicon Labs, http://www.silabs.com</b>
 *******************************************************************************
 *
 * This file is licensed under the Silicon Labs Software License Agreement. See
 * "http://developer.silabs.com/legal/version/v11/Silicon_Labs_Software_License_Agreement.txt" 
 * for details. Before using this software for any purpose, you must agree to the
 * terms of that agreement.
 *
 ******************************************************************************/
#include "em_device.h"
#include "em_chip.h"
#include "em_cmu.h"
#include "em_system.h"
#include "em_gpio.h"
volatile uint32_t msTicks;
#define TOTAL_STEPS      4
uint32_t STEPS[TOTAL_STEPS] = {0b1000, 0b0010, 0b0100, 0b0001};             //1,3,2,4
uint16_t STEP = 0;
/* ************* Systick Handler ***************** */
void SysTick_Handler(void) {
    msTicks++;
}
/* ************* Delay function ****************** */
void Delay(uint32_t dlyTicks) {
    uint32_t curTicks = msTicks;
    while((msTicks - curTicks) < dlyTicks);
}
/* ************* Output to H-bridge ************** */
void setStep(void) {
      GPIO->P[3].DOUTCLR = 0xF;                  //Shut off all pins.
      GPIO->P[3].DOUTSET = STEPS[STEP];          //Output the steps
}
/* ************* Main function ******************* */
int main(void)
{
    CHIP_Init();
    CMU->HFRCOCTRL = 0x30; // Set RC clock to 1 MHz
    CMU->HFPERCLKEN0 =(1<<13); //Enable GPIO clock

    if (SysTick_Config(CMU_ClockFreqGet(cmuClock_CORE) / 1000)) while (1) ;         //Setup SysTick

    /* ****************** Setup pushbuttons and H-bridge outputs ****************** */
    GPIO->P[1].MODEH = 0x110;                //Setup RB9 and RB10 as input
    GPIO->P[3].MODEL = 0x5555;               //Setup PD0-PD3 as push pull output. These go directly to the H-bridge
    GPIO->P[3].CTRL = 2;                     //High drivemode
    GPIO->P[3].DOUT = 0x0000;                //They should already be all low.
                                        //H-bridge pins 1,2,3,4 map to pins 3,2,1,0 on port D.
  /* Infinite loop */
  while (1) {
      if(!GPIO_PinInGet(gpioPortB,9)) {                         //If button 0 is pressed
          STEP = (STEP + 1) % TOTAL_STEPS;                      //Increment the step
          setStep();                                            //Output to the H-bridge
      }
      else if(!GPIO_PinInGet(gpioPortB, 10)) {                  //If button 1 is pressed.
          STEP = (STEP + TOTAL_STEPS-1) % TOTAL_STEPS;          //Decrement the step
          setStep();                                            //Output to the H-bridge
      }
      Delay(10);                                                //Short delay to let motor rotate
  }
}

使用半步的示例代码:

/**************************************************************************//**
 * @file
 * @brief Empty Project
 * @author Energy Micro AS
 * @version 3.20.2
 ******************************************************************************
 * @section License
 * <b>(C) Copyright 2014 Silicon Labs, http://www.silabs.com</b>
 *******************************************************************************
 *
 * This file is licensed under the Silicon Labs Software License Agreement. See
 * "http://developer.silabs.com/legal/version/v11/Silicon_Labs_Software_License_Agreement.txt" 
 * for details. Before using this software for any purpose, you must agree to the
 * terms of that agreement.
 *
 ******************************************************************************/
#include "em_device.h"
#include "em_chip.h"
#include "em_cmu.h"
#include "em_system.h"
#include "em_gpio.h"
volatile uint32_t msTicks;
#define TOTAL_STEPS      8
uint32_t STEPS[TOTAL_STEPS] = {0b1000, 0b1010, 0b0010, 0b0110, 0b0100, 0b0101, 0b0001, 0b1001};                     //1, 1and3, 3, 3and2, 2, 2and4, 4, 4and1

/* ************* Systick Handler ***************** */
void SysTick_Handler(void) {
    msTicks++;
}
/* ************* Delay function ****************** */
void Delay(uint32_t dlyTicks) {
    uint32_t curTicks = msTicks;
    while((msTicks - curTicks) < dlyTicks);
}
/* ************* Output to H-bridge ************** */
void setStep(uint32_t STEP) {
      GPIO->P[3].DOUTCLR = 0xF;                                  //Shut off all pins.
      GPIO->P[3].DOUTSET = STEPS[(STEP % TOTAL_STEPS)];          //Output the steps
}
/* ************* Main function ******************* */
int main(void)
{
 CHIP_Init();
    CMU->HFRCOCTRL = 0x30; // Set RC clock to 1 MHz
    CMU->HFPERCLKEN0 =(1<<13); //Enable GPIO clock

    if (SysTick_Config(CMU_ClockFreqGet(cmuClock_CORE) / 1000)) while (1) ;         //Setup millisecond tick counter

    /* ****************** Setup pushbuttons and H-bridge outputs ****************** */
    GPIO->P[1].MODEH = 0x110;                //Setup RB9 and RB10 as input
    GPIO->P[3].MODEL = 0x5555;               //Setup PD0-PD3 as push pull output. These go directly to the H-bridge
    GPIO->P[3].CTRL = 2;                     //High drivemode
    GPIO->P[3].DOUT = 0x0000;                //They should already be all low.
                                            //H-bridge pins 1,2,3,4 map to pins 3,2,1,0 on port D.
    int32_t STEP = 0;

  /* Infinite loop */
  while (1) {
      if(!GPIO_PinInGet(gpioPortB,9)) {                         //If button 0 is pressed
          STEP += 1;                                            //Increment the step
          setStep(STEP);                                        //Output to the H-bridge
      }
      else if(!GPIO_PinInGet(gpioPortB, 10)) {                  //If button 1 is pressed.
          STEP -= 1;                                            //Decrement the step
          setStep(STEP);                                        //Output to the H-bridge
      }
      Delay(10);                                                //Short delay to let motor rotate
  }
}

在这段代码中,我修改了步进增加和减少的方式。我没有在STEPS向量中循环,而是在设置步骤时跟踪向量的位置并进行分割。这对于跟踪位置和移动电机非常有效。唯一要注意的地方是0交叉口,当数字下溢时。只要总步数是2的倍数,你就应该没事。另一个变化是,我将STEP声明为一个有符号整数,但当我使用它设置输出时,我将其称为无符号整数。这使我能够在不影响输出的情况下跟踪负面步骤。

单极电机驱动器将替换上图,或允许你按步进/方向控制。这些都很容易设置,所以我不会详细介绍。请务必检查数据表中的驱动程序规格。

其他来源:

H 桥的秘密–这是一篇关于H桥如何工作的深入文章。

琼斯谈步进电机–这是爱荷华大学教授于1995年撰写的教程。它非常详细地介绍了步进电机的物理特性。如果你想更全面地了解驾驶踏板背后的物理原理,请阅读本文。