学习迷你步进电机

步进电机广泛用​​于现代工业和自制产品。它们用于需要确保机械部件定位精度的位置,而无需求助于反馈和精确的测量。

今天,我想谈一谈一种特殊的步进电机-微型步进电机,它们用于光学系统的构造。我们将仔细研究它们的设备以及如何控制这种微型电机。



步进电动机是一种无刷(无刷)电动机,在定子上具有多个绕组(相),在转子上具有多个磁体(通常是永久性的)。通过向定子绕组施加电压,我们可以固定转子的位置,并且通过向绕组施加电压,我们可以连续地获得转子从一个位置到另一位置的运动(步长),并且该步长具有固定的角度值。

我们不会过多地考虑每种类型的步进电机。在网络上已经写了很多有关此的内容,例如,这里

我想谈一谈一种特殊的步进电机-微型步进电机,它们用于光学系统的构造。这些孩子可以出售。但是在网络上,特别是在俄语中,关于此类电动机的信息很少。因此,当我需要在项目中使用它们时,我不得不寻找信息并进行一些实验。

我将在本文中分享搜索和实验的结果。

我们将考虑对此类小型电动机的管理,即:

  • 驱动程序L293D +微控制器ATtiny44;
  • TMC2208驱动程序+ ATtiny44微控制器;
  • 微控制器ATtiny44(无驱动程序)。

实际上,只有最后一点可以引起问题。相信我,当我看到一个视频剪辑(这里是时,我也感到很惊讶,那个家伙刚站起来,直接将步进电机钩到微控制器的引脚上!但是,让我们依次讨论所有内容。

熟人


首先,稍微看看我们英雄的外表:



他真的很小!根据聪明的书Petrenko S.F.
原则上,“仪表中的压电电动机”是较小的电磁电动机,这是不可能的,也就是说,虽然有可能,但是随着制造绕组的导线直径的减小,越来越多的能量会随着热量散发到环境中而耗散掉,这导致电动机效率下降,它们的使用是不合理的。

值得注意的是,它的轴很短,并具有用于安装齿轮或杠杆的特殊凹槽。

两个绕组清晰可见,甚至被不同颜色的绝缘材料覆盖。因此,我们的电动机很可能属于双极步进电动机的类别
让我们看看它是如何工作的:



我认为如果我们不了解其中的内容,那么我们对这些电机的了解将是不完整的。深入研究机制总是很有趣的!是不是

实际上,我们没有发现任何异常情况。转子已磁化。那里没有轴承,所有东西都在衬套上。后轮毂被压入发动机壳体。前面没有任何东西固定。有趣的是,发动机主体是通过点焊组装的。因此,必须剪掉前盖。

现在我们来谈谈连接及其电气特性的问题。

通过使绕组振铃来确保他是双极性的。就像上面的图片一样,确实是双极性的。绕组电阻约为26欧姆,尽管卖方表示为14欧姆。
说明说电源电压为5V尽管我们都知道对于步进电机,其绕组消耗的电流很重要。
我们正在尝试连接。

实验编号1。L293D + ATtiny44


众所周知,为了控制双极步进电动机,不仅需要以所需的顺序向两个绕组施加电压,而且还需要改变这些绕组中电流的方向,并且彼此独立地进行操作。为此,每个绕组都需要自己的H桥。为了不让他脱离晶体管,我们采用了现成的L293D芯片。它的另一个优点-芯片具有特殊的Enable1和Enable2引脚,可以打开和关闭每个网桥。它们可用于提供PWM信号,因此可以控制每个电桥的电源电压。为什么需要这样做,我们将进一步说明。

此外,L293D可以切换高达36V的电压,并且每通道输出高达1.2A的电流,这应该足以为我们的电机绕组供电。

因此,如下图所示:



L293D控制输入连接到OC0A和OC0B输出,这将使我们将来能够向它们发送PWM信号。

我们将通过在线编程器(图中未显示)闪烁控制器。 这是试验
板上的组装电路图:



这就是我们的测试



飞行员所在的位置:现在您可以开始实验了。

我们计算出在连接至5V电压时流经电动机绕组的电流:

I = U / R = 5V / 26Ohm = 190mA

非常小。我不知道他能保持多长时间而不会过热。

我们在一个绕组的电路中包括一个电流表和一个电压表,并在通过驱动器向该绕组供电时测量相应的值。

当跨过2.56V绕组的电压降时,电流表显示150mA的电流,并且可以清楚地看到在绕组加热期间电流的大小如何开始下降。应该注意的是,它并不那么热。

确保电动机的5V电压没有危险之后,请尝试以不同方向扭转它们。现在,我们将介绍一下步进电机的工作模式。

在这里说得很好

我们不会重复,但是请记住,步进电机可以在三种模式下运行:

  • , , .
  • , , , .
  • , , , ( ) . , , ( , , ). .

让我们尝试在L293D芯片上实现前两个模式,对于微步模式,我们将在第二个实验中保留一个特殊的驱动器。

该程序的源代码如下:

WinAVR源代码
#define F_CPU 8000000UL  //    

//    L: E2; H:DF; Ex:FF; 
//    8         (     8)

#include <avr/io.h> //   

#include <util/delay.h> //   

#include <avr/interrupt.h> //   

//   

#define LED_pin PA5

#define LED_ON PORTA |=(1<<LED_pin)

#define LED_OFF PORTA &=(~(1<<LED_pin))

//     L293DD

#define PWM_1 PB2 // OC0A (EN1)

#define PWM_2 PA7 // OC0B (EN2)

#define PWM_1_value OCR0A

#define PWM_2_value OCR0B

//       L293D

#define IN1 PA0 //  PORTA

#define IN2 PA1

#define IN3 PB1 //  PORTB

#define IN4 PB0

void delay_microsecond (unsigned int delay_time) { //     
    
	//      

    for(unsigned int delay_us = 0; delay_us<delay_time; delay_us++) {
	
	    _delay_us(1);
	
	}

}

void delay_millisecond (unsigned int delay_time) { //     

    for(unsigned int delay_ms = 0; delay_ms<delay_time; delay_ms++) {
	
	    _delay_ms(1);
	
	}

}

//      

void step_1_one_phase (void) {

    PORTB &=(~((1<<IN3)|(1<<IN4)));
	
	PORTA &=(~(1<<IN2)); //   
  
    PORTA |=(1<<IN1); //    
}

void step_2_one_phase (void) {

    PORTA &=(~((1<<IN1)|(1<<IN2)));
	
	PORTB &=(~(1<<IN3));
  
    PORTB |=(1<<IN4);
  
}

void step_3_one_phase (void) {

    PORTB &=(~((1<<IN3)|(1<<IN4))); 
	 
	PORTA &=(~(1<<IN1));
  
    PORTA |=(1<<IN2);
  
	
}

void step_4_one_phase (void) {

    PORTA &=(~((1<<IN1)|(1<<IN2))); 
	
	PORTB &=(~(1<<IN4));
    
    PORTB |=(1<<IN3);
  
}

//      

void step_1_two_phase (void) {

    PORTB |=(1<<IN4);  
  
    PORTB &=(~(1<<IN3));
  
    PORTA |=(1<<IN1);
  
    PORTA &=(~(1<<IN2));
}

void step_2_two_phase (void) {

    PORTA &=(~(1<<IN2));//2
	
	PORTA |=(1<<IN1);
  
    PORTB |=(1<<IN3);
  
    PORTB &=(~(1<<IN4));
  
}

void step_3_two_phase (void) {

    PORTB |=(1<<IN3);//3
  
    PORTB &=(~(1<<IN4));
	
	PORTA &=(~(1<<IN1));
  
    PORTA |=(1<<IN2);
  
	
}

void step_4_two_phase (void) {

    PORTA |=(1<<IN2);//4
  
    PORTA &=(~(1<<IN1));
    
    PORTB |=(1<<IN4);
  
    PORTB &=(~(1<<IN3));
  
}

void stepper_OFF (void) { //   

	//    ,       ,    
	
	PORTA &=(~((1<<IN1)|(1<<IN2)));
	
	PORTB &=(~((1<<IN3)|(1<<IN4)));
	
}

unsigned char step_counter = 0; 

//      

void L293D_step (unsigned int step_quantity, unsigned char direction, unsigned int step_delay, unsigned char phase) { //      

    while(step_quantity>0) { //  ,      

        switch(direction) { //           
	
			case 'F':
				if(step_counter<3) { step_counter++; } else { step_counter=0; }
			break;
		
			case 'B':
				if(step_counter>0) { step_counter--; } else { step_counter=3; }
			break;
		
		}
		
		switch(phase) { //     
		
		    case 1: 
			
				switch(step_counter) { //   
	
					case 0:
						step_1_two_phase_DL();
					break;
		
					case 1:
						step_2_two_phase_DL();
					break;
		
					case 2:
						step_3_two_phase_DL();
					break;
		
					case 3:
						step_4_two_phase_DL();
					break;
	
				}
			
			break;
			
			case 2:
			
				switch(step_counter) { //   
	
					case 0:
						step_1_two_phase_DL();
					break;
		
					case 1:
						step_2_two_phase_DL();
					break;
		
					case 2:
						step_3_two_phase_DL();
					break;
		
					case 3:
						step_4_two_phase_DL();
					break;
	
				}
			
			break;
		
		}
		
    delay_millisecond(step_delay); //       
	
	step_quantity--; 
	
	} 

}


void PWM_init (void) { //   

    DDRB |=(1<<PWM_1);

    DDRA |=(1<<PWM_2);

    TCCR0A = (1<<WGM01)|(1<<WGM00)|(1<<COM0A1)|(0<<COM0A0)|(1<<COM0B1)|(0<<COM0B0); //  FAST PWM,   
	
    TCCR0B = (0<<WGM02)|(0<<CS02)|(0<<CS01)|(1<<CS00); //   8
	
    OCR0A = 255; //    (0-255)

    OCR0B = 255;

} //    

int main (void) { 

    DDRA |=(1<<LED_pin);
	
    DDRA |=(1<<IN1)|(1<<IN2);

    DDRB |=(1<<IN3)|(1<<IN4);
	
    PWM_init(); //  
	
    delay_millisecond(2000);
	
    while(1==1) { 
	   
	LED_ON;
		
        L293D_step(16,'F',100,2); //step( ,  F/B,   , / )
		
	//stepper_OFF();
		
	delay_millisecond(2000);
		
	LED_OFF;
		
	L293D_step(16,'B',100,2);
		
	//stepper_OFF();
		
	delay_millisecond(2000);
		  
    } 

} 


全步模式。单相



引擎每转16步。此外,两个阶段的步骤不具有相同的角度值。我不知道它与什么有关。也许是发动机的设计?

让我们看看他在此模式下可以提供的最大步数,而不会遗漏它们。

步距之间的最小延迟为2ms,这意味着500步/秒。不错,是31 rpm = 1850 rpm。

全步模式。两个阶段



请注意,在这种情况下,步骤更平滑,它们的大小相同(无论如何,都比前一种情况更相同)。

自然地,在这种情况下,两个绕组同时通电,传热增加。几秒钟后,发动机发热非常强烈,所以我停止了实验。

最大步数是多少?500步/秒 31 rpm = 1875 rpm。
必须说,对于步进电机,它非常灵活。这是由于转子上的磁极数量少。

我们继续 ...

实验编号2。TMC2208 + ATtiny44


TMC2208是用于控制双极步进电机的驱动器芯片的名称,也称为基于该模块的模块,该模块生产用于安装在自制(不仅是)3D打印机中,并具有统一的引脚布局。这里
关于这个模块的内容很多,也很清楚 互联网上已经有很多关于如何将其安装到3D打印机中的文章,但是我们对如何将模块连接到微控制器感兴趣,因此让我们了解一下。 芯片的特性令人印象深刻(仅印象深刻的人):





  • 逻辑部分的电源电压:3-5V;
  • 电机电源电压5.5-36V;
  • 峰值电流2A;
  • 设置最大电机电流;
  • UART接口支持管理和配置内部寄存器;
  • 自动关闭电源;
  • 支持发动机控制的微步模式,最高可达1/16步。



管理非常简单,实际上,您仅需要微控制器的两个引脚。一个连接到DIR-我们指示电动机的旋转方向,另一个连接到STEP-施加脉冲时,微电路利用电动机绕组上的电流和电压执行必要的操作,这需要一步。

接线图如下所示:



此外,我使用EN引脚关闭了电动机,并且很长一段时间没有使绕组通电。

WinAVR源代码
#define F_CPU 8000000UL  //    

//    L: E2; H:DF; Ex:FF; 
//    8         (     8)

#include <avr/io.h> //   

#include <util/delay.h> //   

#include <avr/interrupt.h> //   

//   

#define LED_pin PA5

#define LED_ON PORTA |=(1<<LED_pin)

#define LED_OFF PORTA &=(~(1<<LED_pin))

//     TMC2208

#define DIR PB2

#define EN PA6

#define STP PA7

#define EN_OFF PORTA |=(1<<EN)

#define EN_ON PORTA &=(~(1<<EN))

#define DIR_FOR PORTB |=(1<<DIR)

#define DIR_BACK PORTB &=(~(1<<DIR))

#define STP_ON PORTA |=(1<<STP)

#define STP_OFF PORTA &=(~(1<<STP))

void delay_microsecond (unsigned int delay_time) { //     
    
	//      

    for(unsigned int delay_us = 0; delay_us<delay_time; delay_us++) {
	
	    _delay_us(1);
	
	}

}

void delay_millisecond (unsigned int delay_time) { //     

    for(unsigned int delay_ms = 0; delay_ms<delay_time; delay_ms++) {
	
	    _delay_ms(1);
	
	}

}

void TMS2208_STEP (unsigned int step_quantity, unsigned char direction, unsigned int step_delay) {

    switch(direction) { //  
	
		case 'F':
			DIR_FOR;	
		break;
		
		case 'B':
			DIR_BACK;	
		break;
		
	}

    while(step_quantity>0) { //      
	
		STP_ON; //   
		
		delay_microsecond(100); //   100
		
		STP_OFF;
		
		delay_millisecond(step_delay);//   
	
	    step_quantity--;
	
	}

}

int main (void) {

        DDRA |=(1<<LED_pin);

        DDRB |=(1<<DIR);

        DDRA |=(1<<EN);

        DDRA |=(1<<STP);
	
	PWM_init(); //  
	
	delay_millisecond(2000);
	
	while(1==1) { 
	   
	   LED_ON;
	   
	   EN_ON;
	
	   TMS2208_STEP(32,'F',10); // TMS2208_STEP ( ,  F/B,   )
	   
	   delay_millisecond(2000);
	   
	   LED_OFF;
	   
	   TMS2208_STEP(32,'B',10);
	   
	   delay_millisecond(2000);
	
	   
	} 

}  


开始一切之前,您需要预先配置模块。首先,设置所需的微步模式。其次,设置所需的最大电动机电流。

只需一步,一切都变得简单。引脚MS1和MS2对此负责。



我注意到,微电路不会逐步改变电压,而是``平滑地''改变电压,但是由于微电路是数字信号,因此输出不是平滑信号,而是信号很小的信号。根据文档,它将每个步分为256个微步。这样做是为了增加行驶平顺性,减少来自发动机的噪音,并且从理论上讲,不应让其拧入的结构产生共振。简而言之,一切都是为了使3D打印机更安静。

为了设置电动机电流,必须测量触点Vref上的电压,如图所示。可以使用接点旁边安装的电位计来更改电压值。触点上的电压将与电动机电流成正比,并且相关性将具有以下形式:

Vref = I * 1.44;

我们的电机需要约150mA的电流,因为Vref = 0.216V。我们安装...

据了解,电流的增加通过增加绕组两端的电压来提供微电路。因此,您需要确保这种张力足够。但是,我相信5V电压对于那个小型电机就足够了。

我们将以各种微步模式测试电动机的运行情况,看看会发生什么情况(微步之间的间隔为10ms):


您会注意到,电动机的运动已变得更加平滑(与之前的实验相比),但是,仍然非常清楚地观察到了特征性的16步。嗯...显然这是具有永磁转子步进电动机的一个特点
还应注意,在此模式下,电动机的加热几乎与两相全步模式下的一样。可以理解的是,绕组不断地通电,不断地产生热量。

我认为,对于此类电动机,建议不要使用此类驱动器,甚至微步模式。

实验编号3。ATtiny44驱动程序


让我们简要回到第一个实验,并回顾一下驱动器微电路的输入EN1和EN2连接到微控制器的OC0A和OC0B引脚。这意味着我们可以在那里发送使用TIMER0定时器生成的PWM信号,从而改变施加到电机绕组的电压,从而调节流过它们的电流。

根据ATtiny44微控制器上的数据表,一个引脚可以提供的最大电流仅为40mA。而且,没有指出该特性是什么类型的电流(脉动的或恒定的)。就在那儿,就像那样……我

必须说,我已经对ATMEL微控制器熟悉了7年以上。我从来没有一次希望从数据表中检查这一行。



也许制造商只是为了安全起见,实际上它可以提供更多,或者实际上它是可以提供一个销的最大数量。

我们会找出答案的。但是首先,您需要找出电动机通常能够旋转的最小电流。

使用第一个实验中的电路,我们将通过绕组的电流值调整为等于40 mA。我们从两步开始进入全步模式(因为扭矩会更高):非常好

在40mA时,发动机成功启动!还检测了电动机稳定运行所需的绕组电流的最小值,该最小值等于30mA。

当然,扭矩会低得多,但是我们设法以如此小的功耗启动电动机这一事实对我们来说很重要。

步进电机与微控制器的连接图如下所示:



由于微控制器的每个引脚都用作半桥(可以将微电路的输出切换到Vcc或GND),因此要控制双极步进电机,我们需要4个微控制器引脚。

程序代码:

WinAVR源代码
#define F_CPU 8000000UL  //    

//    L: E2; H:DF; Ex:FF; 
//    8         (     8)

#include <avr/io.h> //   

#include <util/delay.h> //   

#include <avr/interrupt.h> //   

//   

#define LED_pin PA5

#define LED_ON PORTA |=(1<<LED_pin)

#define LED_OFF PORTA &=(~(1<<LED_pin))

//     L293DD

#define PWM_1 PB2 // OC0A (EN1)

#define PWM_2 PA7 // OC0B (EN2)

#define PWM_1_value OCR0A

#define PWM_2_value OCR0B

//       L293D

#define IN1 PA0 //  PORTA

#define IN2 PA1

#define IN3 PB1 //  PORTB

#define IN4 PB0


void delay_microsecond (unsigned int delay_time) { //     
    
	//      

    for(unsigned int delay_us = 0; delay_us<delay_time; delay_us++) {
	
	    _delay_us(1);
	
	}

}

void delay_millisecond (unsigned int delay_time) { //     

    for(unsigned int delay_ms = 0; delay_ms<delay_time; delay_ms++) {
	
	    _delay_ms(1);
	
	}

}

//        

void step_1_two_phase_DL (void) { // DL - driver less
   
   //  
   OCR0A = 160;
   PORTB &=(~(1<<IN4)); 
   
   //  
   OCR0B = 160;
   PORTB &=(~(1<<IN3)); 
    
}

void step_2_two_phase_DL (void) { 
   
   //  
   OCR0A = 160;
   PORTB &=(~(1<<IN4)); 
   
   //  
   OCR0B = 95;
   PORTB |=(1<<IN3); 
    
}

void step_3_two_phase_DL (void) { 
   
   //  
   OCR0A = 95;
   PORTB |=(1<<IN4); 
   
   //  
   OCR0B = 95;
   PORTB |=(1<<IN3); 
    
}

void step_4_two_phase_DL (void) { 
   
   //  
   OCR0A = 95;
   PORTB |=(1<<IN4); 
   
   //  
   OCR0B = 160;
   PORTB &=(~(1<<IN3)); 
    
}

unsigned char step_counter = 0; 

//      

void L293D_step (unsigned int step_quantity, unsigned char direction, unsigned int step_delay, unsigned char phase) { //      

    while(step_quantity>0) { //  ,      

        switch(direction) { //           
	
			case 'F':
				if(step_counter<3) { step_counter++; } else { step_counter=0; }
			break;
		
			case 'B':
				if(step_counter>0) { step_counter--; } else { step_counter=3; }
			break;
		
		}
		
		switch(phase) { //     
		
		    case 1: 
			
				switch(step_counter) { //   
	
					case 0:
						step_1_two_phase_DL();
					break;
		
					case 1:
						step_2_two_phase_DL();
					break;
		
					case 2:
						step_3_two_phase_DL();
					break;
		
					case 3:
						step_4_two_phase_DL();
					break;
	
				}
			
			break;
			
			case 2:
			
				switch(step_counter) { //   
	
					case 0:
						step_1_two_phase_DL();
					break;
		
					case 1:
						step_2_two_phase_DL();
					break;
		
					case 2:
						step_3_two_phase_DL();
					break;
		
					case 3:
						step_4_two_phase_DL();
					break;
	
				}
			
			break;
		
		}
		
    delay_millisecond(step_delay); //       
	
	step_quantity--; 
	
	} 

}


void PWM_init (void) { //   

    DDRB |=(1<<PWM_1); 
	
    DDRA |=(1<<PWM_2);

    TCCR0A = (1<<WGM01)|(1<<WGM00)|(1<<COM0A1)|(0<<COM0A0)|(1<<COM0B1)|(0<<COM0B0); //  FAST PWM,   
	
    TCCR0B = (0<<WGM02)|(0<<CS02)|(0<<CS01)|(1<<CS00); //   8
	
    OCR0A = 160; 
	
    OCR0B = 160;

} //    

int main (void) { //  

    DDRA |=(1<<LED_pin);
	
	DDRA |=(1<<IN1)|(1<<IN2);
	
	DDRB |=(1<<IN3)|(1<<IN4);
	
	PWM_init(); //  
	
	delay_millisecond(2000);
	
	while(1==1) { //  

	    LED_ON;
		
	    L293D_step(16,'F',100,2); //step( ,  F/B,   , / )
		
            delay_millisecond(2000);
		
	    LED_OFF;
		
	    L293D_step(16,'B',100,2);
		
	    delay_millisecond(2000);
		
	
	   
	} 

} 


让我解释一下该程序的工作原理。这是第一个实验的修改后的代码。正如我上面所说,一个8位TIMER0将用于在输出OC0A和OC0B处生成PWM信号。定时器设置为FastPWM模式,并具有8的预分频器(微控制器时钟的8 MHz处的信号频率为3906 Hz)。

要更改绕组上信号的极性,可通过更改PORTx寄存器中的相应位并通过将值写入OCR0A和OCR0B寄存器(通过实验选择这些值)来更改PWM占空比,从而将微控制器引脚从Vcc切换到GND。

所以:


该研究所第一年开设的电路课程表明,万用表可以显示电动机中电压和电流的均方根值。

步进电机从无驱动器的微控制器引脚旋转!

但是,至少根据文档中的内容,这里我们并没有超出微控制器的功能。在这种模式下,微控制器和电动机可以长时间工作。确实,实验持续了20分钟。在这段时间内,没有跳过步骤,没有控制器复位或过热(发动机和控制器均无)。

抛开所有注意事项


我们从实验中删除了PWM,我们将使用PORTx寄存器直接控制微控制器的引脚。让我们看看之后的微控制器会发生什么。

它的工作原理是……最大电流为51mA……嗯……出乎意料的是,这似乎是可以提供给微控制器一个引脚的最大电流?如果我错了,请纠正我。

无论如何,YouTube的视频都不会被欺骗。确实,您可以在没有任何驱动器的情况下控制该电动机

发现


我们详细研究了微型双极步进电动机,它们的设计以及如何在自己的应用中使用它们。

1.带有永磁转子的微型双极步进电机确实是微型的。

其主要特点:

  • , , ( , , 16);
  • ( ), 1875 /;
  • ( );

2.微型步进电机可以由任何适用于双极步进电机的驱动器控制,您只需选择绕组电流参数即可。

3.使用专用的TMC2208驱动程序是一个有争议的问题,因为引擎本身不支持微步模式,尽管各步之间的转换执行得更平稳。

4.可以将步进电机直接连接到微控制器的端口。但这只是在实验的框架内,因为在这种情况下扭矩很小,甚至很小的电流也不允许高速采取措施。

下次我将告诉您为什么我们需要这么小的步进电机。

All Articles