您的位置:首页 > 运维架构 > Linux

基于步进电机在LINUX平台下的调试(之一)

2014-05-04 11:59 190 查看
工作接到一个项目是需要在LINUX平台(LK3.0 JZ4775)调试一个步进电机的驱动,功能要求不是很严格,主要实现步进电机正反向的稳定转动即可.主要功能是通过两个按键控制步进电机的正反向转动.因此,先了解一下步进电机的原理.

1.步进电机的基本原理:

 以四相电机为例,如下所示,为步进电机的原理示意图:



 步进电机转动的原理阐述如下:

当上电时,如果SB通电同时SA、SC、SD断开时,由于通电后的磁力作用,SB对应的B相磁极要求转子「0 ,3」对齐,其他的产生的错齿,从而引起了电机的转动;
同样,当SC通电时,SA、SB、SD断开时,由于通电后的磁力作用,SC对应的C相磁极要求转子「1,4」对齐,其他的产生错齿,从而引起了电机的转动.以此类推.
 也就是说,通过控制SA、SB、SC、SD通断电的顺序,可以实现步进电机的转动.

2.步进电机的基本编程:
在步进电机编程中一定要明确的是步进电机的步距角.
步距角:定子绕组每改变一次通电状态,转子转过的角度.
 例如:

 以四相电机为例,有四相四拍运行方式即AB-BC-CD-DA-AB,四相八拍运行方式即A-AB-B-BC-C-CD-D-DA-A,转子齿为50齿电机为例,四拍运行时步距角为
θ=360度/(50*4)=1.8度,八拍运行时步距角为θ=360度/(50*8)=0.9度.


 编程的最基本思想:

 步进电机是将电脉冲信号转变为角位移或线位移的控制元件,即给电机加一个脉冲信号,电机则转过一个步距角.即一个脉冲对应步进电机的一个步距角,
因此,我们编程中只需要对步进电机进行脉冲输出就可以了.


 
 2-1.步进电机的速度控制:
 由上述可知,想控制步进电机的转速,只需要控制脉冲的宽度就可以了.但是需要注意的是脉冲的宽度不能太宽或太窄,否则在一些比较简单的电路控制下电机会启动不起来,需要手动转一下电机才可以正常转动(一般为几个毫秒).在调试过程中我就遇到过这样的情况,我这边用的是小型的步进电机,直接通过四个三极管去驱动四相步进电机,通过调整脉冲宽度解决.

 2-2.步进电机的正反转:
步进电机要带动外在机械模块的转动,一般需要两个方向调节:正转和反转.

这通过控制其通断电顺序来实现.


 四相步进电机按照通电顺序的不同,可分为单四拍、双四拍、八拍三种工作方式.单四拍与双四拍的步距角相等,但单四拍的转动力矩小.八拍工作方式的步距角是单四拍与双四拍的一半,因此,八拍工作方式既可以保持较高的转动力矩又可以提高控制精度.单四拍、双四拍、八拍电源通电时序及波形分别如下所示:



 以上述四相八拍的时序图为例,见上图最后一个时序图.假设这是正转的话,以脉冲周期为单位分析其通断电顺序为:

DA->A->AB->B->BC->C->CD->D->DA
那么,要步进电机反转的话,其通断电顺序为:

A->AD->D->DC->C->CB->B->BA->A
「注:」四相步进电机中,用的比较多的为八拍方式,因此八拍工作方式有其独特的优点:

1).保持较高的转动力矩;
2).较高的精度;
3).较高的稳定性;
4).噪音比较少.

「注:」网上很多步进电机是基于单片机开发的,因此,批量对相关引脚赋值(如P0 = 0x09),对无效引脚清零而对有效引脚赋1.但是针对比较复杂的CPU,往往引脚操作不是连续的实现不了对应的引脚的批量写入,很多情况都是单独的引脚操作,因此一定要清除无关的引脚不能使它有效,否则将会出现电机转向是对的,但是很慢,而且发烫很严重!!!例如下面两份代码,第一份存在BUG,现象为步进电机转向是对的,但是速度明显不对而且发烫很严重;第二份是修复后的代码.

  修复前的代码:

static void stepMotorTurnRight(const unsigned int timeVal)
{
//->A
__gpio_set_pin(stepMotorA);
usleep(timeVal);
//->AD
__gpio_set_pin(stepMotorD);
usleep(timeVal);
//->D
__gpio_clear_pin(stepMotorA);
usleep(timeVal);
//->DC
__gpio_set_pin(stepMotorC);
usleep(timeVal);
//->C
__gpio_clear_pin(stepMotorD);
usleep(timeVal);
//->CB
__gpio_set_pin(stepMotorB);
usleep(timeVal);
//->B
__gpio_clear_pin(stepMotorC);
usleep(timeVal);
//->BA
__gpio_set_pin(stepMotorA);
usleep(timeVal);
}
  修复后的代码:

static void stepMotorTurnRight(const unsigned int timeVal)
{
//->A
__gpio_clear_pin(stepMotorD);
__gpio_clear_pin(stepMotorB);
__gpio_clear_pin(stepMotorC);
__gpio_set_pin(stepMotorA);
usleep(timeVal);
//->AD
__gpio_set_pin(stepMotorD);
usleep(timeVal);
//->D
__gpio_clear_pin(stepMotorA);
usleep(timeVal);
//->DC
__gpio_set_pin(stepMotorC);
usleep(timeVal);
//->C
__gpio_clear_pin(stepMotorD);
usleep(timeVal);
//->CB
__gpio_set_pin(stepMotorB);
usleep(timeVal);
//->B
__gpio_clear_pin(stepMotorC);
usleep(timeVal);
//->BA
__gpio_set_pin(stepMotorA);
usleep(timeVal);
}
  主要添加了下面代码:

__gpio_clear_pin(stepMotorD);
__gpio_clear_pin(stepMotorB);
__gpio_clear_pin(stepMotorC);

  清除了一些还没有用到有脉冲引脚.

下面是四机步进电机采用四机八拍驱动的用户空间的简单功能测试程序(核心部分).下面用GPIO去承载,后续如果对性能要求比较严格,再挪到底层.如下:

static void stepMotorInit(void)
{
__gpio_as_output(stepMotorA);
__gpio_as_output(stepMotorB);
__gpio_as_output(stepMotorC);
__gpio_as_output(stepMotorD);

__gpio_clear_pin(stepMotorA);
__gpio_clear_pin(stepMotorB);
__gpio_clear_pin(stepMotorC);
__gpio_clear_pin(stepMotorD);
}

//A->AB->B->BC->C->CD->D->DA->A
static void stepMotorTurnLeft(const unsigned int timeVal)
{
//->A
__gpio_clear_pin(stepMotorB);
__gpio_clear_pin(stepMotorC);
__gpio_clear_pin(stepMotorD);
__gpio_set_pin(stepMotorA);
usleep(timeVal);
//->AB
__gpio_set_pin(stepMotorB);
usleep(timeVal);
//->B
__gpio_clear_pin(stepMotorA);
usleep(timeVal);
//->BC
__gpio_set_pin(stepMotorC);
usleep(timeVal);
//->C
__gpio_clear_pin(stepMotorB);
usleep(timeVal);
//->CD
__gpio_set_pin(stepMotorD);
usleep(timeVal);
//->D
__gpio_clear_pin(stepMotorC);
usleep(timeVal);
//->DA
__gpio_set_pin(stepMotorA);
usleep(timeVal);
}

//A->AD->D->DC->C->CB->B->BA->A
static void stepMotorTurnRight(const unsigned int timeVal) { //->A __gpio_clear_pin(stepMotorD); __gpio_clear_pin(stepMotorB); __gpio_clear_pin(stepMotorC); __gpio_set_pin(stepMotorA); usleep(timeVal); //->AD __gpio_set_pin(stepMotorD); usleep(timeVal); //->D __gpio_clear_pin(stepMotorA); usleep(timeVal); //->DC __gpio_set_pin(stepMotorC); usleep(timeVal); //->C __gpio_clear_pin(stepMotorD); usleep(timeVal); //->CB __gpio_set_pin(stepMotorB); usleep(timeVal); //->B __gpio_clear_pin(stepMotorC); usleep(timeVal); //->BA __gpio_set_pin(stepMotorA); usleep(timeVal); }
static void stepMotorStop(void)
{
__gpio_clear_pin(stepMotorA);
__gpio_clear_pin(stepMotorB);
__gpio_clear_pin(stepMotorC);
__gpio_clear_pin(stepMotorD);
}

int main(int argc, char **argv)
{
unsigned int timeVal = 2000;
const unsigned char *pLeft = "left";
const unsigned char *pRight = "right";

if(argc != 3)
{
printf("Pls Input The Direction Of Motor:'left' or 'right' And Set The Speed Of Motor:NHZ\n ");
printf("For Example:./xxx left 200\n");
exit(-1);
}

timeVal = atoi(argv[2]);

timeVal = THOUSNADUS/timeVal;

gpio_open();

stepMotorInit();
while(1)
{
if(0 == (strcmp(pLeft,argv[1])))
{
stepMotorTurnLeft(timeVal);
}
else if(0 == (strcmp(pRight,argv[1])))
{
stepMotorTurnRight(timeVal);
}
else
{
printf("What Are You Doing Here!!!\n");
exit(-1);
}
}

gpio_close();

return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: