在我们的项目中,经常使用到低电压小功率的步进电机,此类步进电机若采用驱动器控制不断成本高也过于复杂,我们可以直接使用场效应管或者达林顿管来实现对其的驱动。在本篇中,我们就来讨论一下基于ULN2003A达林顿管实现对步进电机的驱动。

1、功能概述

  我们先来了解一下基本的功能。ULN2003A达林顿管为7个输出通道,当导通时该通道连接到负端,所以非常适合于驱动4相5线步进电机。

1.1、ULN2003A达林顿管

  ULN2003A 器件是高电压大电流达林顿晶体管阵列。每 款器件均由7个NPN 达林顿对组成,这些达林顿对具有高压输出,带有用于开关感性负载的共阴极钳位二极管。 单个达林顿对的集电极电流额定值为500mA。将达林 顿对并联可以提供更高的电流。应用包括继电器驱动器、电锤驱动器、灯驱动器、显示驱动器(LED 和气体放电)、线路驱动器和逻辑缓冲器。其基本结构图如下:

步进电机驱动技术3:基于ULN2003的步进电机驱动_步进电机

1.2、步进电机基本原理

  在我们的测试中,我们使用4相5线步进电机。所谓4相5线步进电机就是该电机具有4组线圈5根连接线,实际上可能不只5根线,但公共端不管抽出多少根线,实际状态与1根无异。

  我们一般将这4组线圈记为A相、B相、C相和D相,当然,也可以用别的称呼,只要便于标记分别就好。4相5线步进电机一般采用单极性直流电源供电。只要对步进电机的各相绕组按合适的时序通电,就能使步进电机步进转动。一般电机都会提供控制表,具体如下所示:

步进电机驱动技术3:基于ULN2003的步进电机驱动_初始化_02

  结合ULN2003A结构和4相5线步进电机的驱动要求,我们可以设计ULN2003A达林顿管驱动4相5线步进电机的驱动电路。

步进电机驱动技术3:基于ULN2003的步进电机驱动_初始化_03

1.3、步进电机驱动模式

  步进电机的驱动虽然按照电机的驱动表就可以实现,但实际的驱动方式有多种,常见的如单波驱动方式、全步驱动方式、半步驱动方式以及微步驱动方式等。这里我们可以看一看前面三种比较简单的驱动方式。

  单波驱动方式又称之为单四拍工作方式。此种方式按固定次序依次驱动每一个线圈以达到使电机转动的目的。其波形如下:

步进电机驱动技术3:基于ULN2003的步进电机驱动_ULN2003A_04

  全步驱动方式又称之为双四拍工作方式。此种方式按固定次序依次驱动两组线圈以达到使电机转动的目的。其波形如下:

步进电机驱动技术3:基于ULN2003的步进电机驱动_初始化_05

  半步驱动方式又称之为八拍工作方式。此种模式实际上是前两种模式的组合,以固定的次序依次激励一组或两组线圈以达到驱动电机的目的。其波形如下:

步进电机驱动技术3:基于ULN2003的步进电机驱动_步进电机_06

  上述波形即是在单波驱动方式、全步驱动方式以及半步驱动方式下使用示波器抓取的A相和C相的波形图,基本可以展示这几种驱动工作方式波形特征。

2、驱动设计与实现

  我们已经了解了ULN2003A驱动4相5线步进电机的基本工作情况,接下来我们就需要据此来实现ULN2003A驱动4相5线步进电机驱动程序的设计与实现。

2.1、对象定义

  我们依然是基于对象来实现相关的操作。所以我们首先要定义对象,出于适用性考虑,我们要定义对象的类型并将具体的对象实例化,接下来我们就来抽象对象类型和实例化对象的操作。

2.1.1、对象的抽象

  对于一个对象最主要包括属性与方法两方面内容,所以我们先来考虑驱动一个步进电机对象具有哪些属性和方法,并抽象出较为通用的步进电机的对象类型。

  首先,我们来考虑对象的属性情况。对电机的操作包括启停命令、方向命令、运行状态、实际运转方向、节拍数、周期等,这些信息控制电机的运转并表征其具体工作状态,所以我们将其作为对象的属性。驱动模式和运行模式用以配置电机的具体工作方式,所以我们也将其作为对象的属性,以完成对象的配置。

  其次我们再来考虑对象的方法问题。对相位的具体操作与具体的硬件平台有关,根据对应的引脚定义相应的相位引脚。这依赖于具体的硬件和软件操作平台,所以我们将其定义为对象的方法。为了控制操作时序,我们需要延时处理,而延时操作函数同样依赖于具体的软硬件平台,所以我们也将其定义为对象的方法,通过回调函数的方式来实现。

  根据上述对对象属性和方法的分析,我们可以定义步进电机对象的类型如下:

/*定义步进电机对象类型*/
typedef struct StepperObject {
uint8_t startStop; //启动停止命令
uint8_t runStatus; //运行状态
uint8_t directSet; //方向设定
uint8_t directRun; //当前方向
uint8_t beat; //当前节拍
uint8_t period; //速度控制周期
DriveModeType driveMode; //驱动模式
StepperModeType runMode; //运行模式
void (*PhaseAction)(uint8_t cmd);
void (*Delayms)(uint32_t period);
}StepperObjectType;

2.1.2、对象初始化

  我们定义了对象类型,可以实现基于对象的操作,但定义的对象变量需要进行初始化才能让不同的对象按照我们的配置的方式去运行。所以在开始对象的使用之前我们先对其进行初始化,这就需要我们设计一个对象的初始化函数。

  这个初始化函数,将构造一个具体的操作对象。对于步进电机来说,我们需要初始化其相关的参数,如:工作模式、运行模式以及相位操作函数等。具体的初始化函数如下:

/*步进电机对象初始化*/
void StepperInitialization(StepperObjectType *stepper, //步进电机对象
DriveModeType driveMode, //驱动模式
StepperModeType runMode, //运行模式
uint8_t period, //速度控制周期
StepperPhaseActionType action, //相位操作回调函数
StepperDelaymsType delayms //延时操作回调函数
)
{
if((stepper==NULL)||(action==NULL)||(delayms==NULL))
{
return;
}
stepper->PhaseAction=action;
stepper->Delayms=delayms;

stepper->driveMode=driveMode;
stepper->runMode=runMode;

stepper->period=period>0?period:1;
}

2.2、对象操作

  接下来我们考虑对步进电机对象所要进行的操作问题。我们已经将相位的具体面向硬件平台的操作定义为对象的方法。我们需要实现对象在不同的模式下节拍操作的控制。具体实现如下:

//步进电机节拍操作
static void StepperAction(StepperObjectType *stepper)
{
uint8_t Command[BEAT_NUM]={0x01,0x03,0x02,0x06,0x04,0x0C,0x08,0x09};
RunBeatType beat=BEAT_NUM;

if(stepper->beat>=BEAT_NUM)
{
stepper->beat=0;

if(stepper->driveMode==Full_Step)
{
stepper->beat=1;
}
}

beat=stepper->directRun>0?((RunBeatType)(7-stepper->beat)):((RunBeatType)stepper->beat);

if(beat>=BEAT_NUM)
{
return;
}

stepper->PhaseAction(Command[beat]);

stepper->beat++;
if((stepper->driveMode==Full_Step)||(stepper->driveMode==Single_Wave))
{
stepper->beat++;
}

stepper->Delayms(stepper->period);
}

3、驱动的应用

  我们已经设计并实现了基于ULN2003A的步进电机驱动程序,接下来我们实现一个实例来验证这一驱动程序设定是否符合要求。

3.1、声明并初始化对象

  在开始一切操作之前,首先我们需要一个对象。前面的设计中,我们已经定义了一个StepperObjectType对象类型,所以我们使用它定义一个对象变量。

  StepperObjectType chamber;

  定义了chamber对象变量之后,还没有办法使用,因为我们需要对其进行初始化。前面我们已经设计了对象初始化函数,我们需要使用这一函数来初始化chamber对象变量。初始化函数需要如下参数:

  StepperObjectType *stepper, //步进电机对象

  DriveModeType driveMode, //驱动模式

  StepperModeType runMode, //运行模式

  uint8_t period, //速度控制周期

  StepperPhaseActionType action, //相位操作回调函数

  StepperDelaymsType delayms //延时操作回调函数

  第1个参数为我们需要初始化的步进电机对象。而驱动模式、运行模式为枚举,根据实际使用要求输入即可。而速度周期为初始速度设定,只要不是0的整数就可以。主要需要考虑的是后面两个函数指针。其原型定义如下:

  typedef void (*StepperPhaseActionType)(uint8_t cmd);

  typedef void (*StepperDelaymsType)(uint32_t period);

  根据函数指针的原型定义,以及我们项目中具体用到的硬件配置,我们可以实现相位操作函数为:

/*步进电机相位操作*/
static void PhaseOperation(uint8_t cmd)
{
GPIO_PinState AP,BP,CP,DP;

AP=(GPIO_PinState)(cmd&0x01);
BP=(GPIO_PinState)((cmd>>1)&0x01);
CP=(GPIO_PinState)((cmd>>2)&0x01);
DP=(GPIO_PinState)((cmd>>3)&0x01);

HAL_GPIO_WritePin(GPIOE, GPIO_PIN_9, BP);
HAL_GPIO_WritePin(GPIOE, GPIO_PIN_11, DP);
HAL_GPIO_WritePin(GPIOE, GPIO_PIN_13, AP);
HAL_GPIO_WritePin(GPIOE, GPIO_PIN_14, CP);
}

  而延时函数我们直接使用HAL_Delay,所以我们就可以实现步进电机对象的初始化操作如下:

/*步进电机对象初始化*/
StepperInitialization(&chamber, //步进电机对象
Half_Step, //驱动模式
Mode_Speed, //运行模式
10, //速度控制周期
PhaseOperation, //相位操作回调函数
HAL_Delay //延时操作回调函数
);

3.2、基于对象进行操作

  初始化之后,我们就可以使用该对象来实现我们想要的操作了。我们设计一个应用函数调用相关驱动实现操作。

  我们可以实现位置控制模式如下:

  StepperPositionControl(&chamber,5000,Direct_CW);

  我们可以实现速度控制模式如下:

  StepperSpeedControl(&chamber);

  当然具体的操作模式需要在初始化函数中配置。

4、结论

  在本篇中我们设计并实现了基于ULN2003A的步进电机驱动程序。我们设计的测试示例运行正常。事实上该驱动在我们的项目中已经实际使用,到目前为止运行还算稳定。

  我们开篇说是面向低电压的小功率的步进电机,但实际上如果我们通过ULN2003A控制MOS管是可以实现高电压大功率的步进电机的,但我们是直接使用ULN2003A达林顿管所以才限定为低电压小功率的步进电机。

  使用驱动是需要注意,该驱动方式不支持很高的运行速度。速度高时会出现力矩过小而堵转的情形。我们实验中所采用的电机一般控制在250Hz以下都可以稳定运行。

欢迎关注:

步进电机驱动技术3:基于ULN2003的步进电机驱动_初始化_07



如果您希望更方便且及时的阅读相关文章,关注我的微信公众号【木南创智