Learning a Mini Stepper Motor

Stepper motors are widely used in modern industry and homemade products. They are used where it is necessary to ensure the accuracy of the positioning of mechanical components, without resorting to feedback and accurate measurements.

Today I want to talk about a special kind of stepper motors - miniature stepper motors, which are used in the construction of optical systems. We will take a closer look at their device and how to control such tiny motors.



A stepper motor is a brushless (brushless) electric motor with several windings (phases) located on the stator and magnets (often permanent) on the rotor. By applying voltage to the stator windings, we can fix the position of the rotor, and by applying voltage to the windings, we can successively obtain the movement of the rotor from one position to another (step), and this step has a fixed angular value.

We will not dwell on the consideration of each type of stepper motor. A lot has been written about this on the network and well, for example, here .

I want to talk about a special kind of stepper motors - miniature stepper motors, which are used in the construction of optical systems. These kids are available for sale. But on the network, especially in the Russian-speaking, there is very little information on such motors. Therefore, when I needed to use them in my project, I had to prettyly look for information and conduct a couple of experiments.

I will share the results of my searches and experiments in this article.

We will consider the management of such small motors, namely:

  • driver L293D + microcontroller ATtiny44;
  • TMC2208 driver + ATtiny44 microcontroller;
  • microcontroller ATtiny44 (without driver).

Actually, only the last point can cause questions here. Believe me, I was also surprised when I came across a video clip ( here it is ), where the guy just picks up and directly hooks the stepper motor to the pins of the microcontroller! But let's talk about everything in order.

Acquaintance


First, a little look at the appearance of our hero:



He is really very small! According to the smart book Petrenko S.F.
"Piezoelectric motors in instrumentation", smaller electromagnetic motors, in principle, is impossible to create ... that is, it is possible, but with a decrease in the diameter of the wire from which the windings are made, more and more energy is dissipated as heat into the environment, which leads to a decrease in motor efficiency and makes their use is irrational.

Of the remarkable, it can be noted that its shaft is very short and has a special groove for installing the gear or lever.

Two windings are clearly visible, which are even covered with insulation of different colors. So, our motor most likely belongs to the class of bipolar stepper motors.
Let's see how it works:



I think our acquaintance with these motors will not be complete if we do not see what is inside of it. It is always interesting to look inside the mechanism! Is not it so?

Actually, we did not see anything unusual. The rotor is magnetized. There are no bearings anywhere, everything is on the bushings. The rear hub is pressed into the engine housing. The front is not fixed by anything. Interestingly, the engine body was assembled by spot welding. So the front cover had to be cut.

Now we turn to the issue of connection and its electrical characteristics.

Make sure that he is bipolar by ringing the windings. Really bipolar, just like in the picture above. The winding resistance is about 26 ohms , although the seller indicated 14 ohms.
The description says that the supply voltage is 5V . Although we all know that for a stepper motor, the current that its windings will consume is important.
We are trying to connect.

Experiment No. 1. L293D + ATtiny44


As we know, to control a bipolar stepper motor, it is necessary not only to apply voltage to the two windings in the desired sequence, but also to change the direction of the current in these windings, and do it independently of each other. For this, each winding needs its own H-bridge. In order not to fence him out of transistors, a ready-made L293D chip was taken. Another of its advantages - the chip has special pins Enable1 and Enable2, which turn each bridge on and off. They can be used to provide a PWM signal, thus, it is possible to control the supply voltage of each bridge. Why this may be needed, we will see further.

In addition, the L293D can switch voltages up to 36V and output up to 1.2A per channel, which should be enough to power the windings of our motor.

So, the diagram:



The L293D control inputs are connected to the OC0A and OC0B outputs, which will allow us to send a PWM signal to them in the future.

We will flash the controller through the in-circuit programmer (not shown in the diagram).
Here's what the assembled circuit looks like on a breadboard:



And this is how our test



pilot is located: Now you can start experimenting.

We calculate the current that will flow through the motor windings when they are connected to a voltage of 5V:

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

Very small. I wonder how long he can hold such a current and not overheat.

We include an ammeter and a voltmeter in the circuit of one of the windings, and measure the corresponding values ​​when power is supplied to this winding through the driver.

When the voltage drop across the 2.56V winding , the ammeter shows a current of 150mA , and it is clearly noticeable how the magnitude of the current begins to fall during heating of the windings. It should be noted that it is not so hot.

After making sure that the 5V voltage for the motor is not dangerous, try to twist them in different directions. And now a few words we will say about the operation modes of the stepper motor.

This is pretty well said here .

We will not repeat, but remember that a stepper motor can operate in three modes:

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

Let's try to implement the first two modes on the L293D chip, and for micro-step mode, we will leave a special driver from the second experiment.

The source code of the program is as follows:

WinAVR source code
#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);
		  
    } 

} 


Full step mode. Single phase



The engine takes 16 steps per revolution. Moreover, the steps for the two phases do not have the same angular value. I don’t know what it is connected with. Maybe the design of the engine is this?

Let's look at the maximum frequency of steps that he can provide in this mode without missing them.

The minimum delay between steps is 2ms, which means 500 steps / second. Not bad, it's 31 rpm = 1850 rpm.

Full step mode. Two phases



Please note that in this case the steps are smoother, they are the same in size (in any case, more the same than in the previous case).

Naturally, in this case, two windings are simultaneously energized and the heat transfer increases. After a few seconds, the engine heats up quite strongly, so I stopped the experiment.

What with the maximum frequency of steps? 500 steps / second; 31 rpm = 1875 rpm.
It must be said that for a stepper motor it is quite nimble. This is due to the small number of magnetic poles on the rotor.

We continue ...

Experiment number 2. TMC2208 + ATtiny44


TMC2208 is the name of a driver chip for controlling bipolar stepper motors, a module based on it is also called, which is produced for installation in home-made (and not only) 3D printers and has a unified pin layout.
Much and lucidly said about this module here .

A lot has been written on the Internet about how to install it in your 3D printer, but we are interested in how to connect the module to the microcontroller, so let's understand.

The characteristics of the chip are impressive (only impressionable people):

  • supply voltage of the logical part: 3-5V;
  • motor supply voltage 5.5-36V;
  • peak current 2A;
  • setting the maximum motor current;
  • UART interface support for both managing and configuring internal registers;
  • automatic power off;
  • support for microstepping mode of engine control up to 1/16 of a step.



It is very simple to manage, in fact, you need only two pins of the microcontroller. One is connected to DIR - we indicate the direction of rotation of the motor, the other is connected to STEP - when a pulse is applied, the chip performs the necessary manipulations with currents and voltages on the motor windings and it takes one step.

The connection diagram will look like this:



Additionally, I used the EN pin to turn off the motor and for a long time not to keep the windings energized.

WinAVR source code
#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);
	
	   
	} 

}  


Before starting everything, you need to pre-configure the module. First, set the desired microstep mode. Secondly, set the desired maximum motor current.

With a microstep, everything is simple. The pins MS1 and MS2 are responsible for this.



I note that the microcircuit does not change the voltage stepwise, but does it “smoothly”, but since the microcircuit is digital, the output is not a smooth signal, but a signal with a small step, according to the documentation, it breaks each step into 256 micro steps. This was done to increase ride smoothness, reduce noise from the engine and, in theory, should not allow the structure to which it is screwed to enter resonance. In short, all in order to make the 3D printer quieter.

To set the motor current it is necessary to measure the voltage at the contact Vref, which is indicated in the figure. The voltage value can be changed using a potentiometer installed next to the contact. The voltage at the contact will be proportional to the current of the motor, and the dependence will have the following form:

Vref = I * 1.44;

Our motor needs about 150mA, because Vref = 0.216V . We install ...

It is understood that an increase in current provides the microcircuit by increasing the voltage across the winding. Therefore, you need to make sure that this tension is enough. But, I believe, 5V should be enough for that small motor.

We will test the operation of the motor with various microstep modes and see what happens (the pause between microsteps is 10ms):


You can notice that the movements of the motor have become smoother (compared with the previous experiment), however, the characteristic 16 steps are still quite clearly observed. Well ... apparently this is a feature of stepper motors with a permanent magnet rotor .
It should also be noted that the motor in this mode heats up almost as much as in a full-step mode with two phases. It is understandable, the windings are constantly energized, heat is continuously being generated.

I believe that for such motors the use of such a driver, and indeed microstep modes, is not very advisable.

Experiment number 3. ATtiny44 driver


Let us return briefly to the first experiment and recall that the inputs EN1 and EN2 of the driver chip are connected to the pins OC0A and OC0B of the microcontroller. This means that we can send there a PWM signal generated using the TIMER0 timer and thus change the voltage applied to the motor windings and accordingly regulate the current that will flow through them.

According to the datasheet on the ATtiny44 microcontroller, the maximum current that one pin can give is only 40mA. Moreover, it is not indicated for what type of current (pulsating or constant) this characteristic. It’s just there and it’s like that ... I

must say that I have been familiar with ATMEL microcontrollers for more than 7 years. And never once did I have the desire to check this line from the datasheet.



Perhaps the manufacturer is just safe and in fact it can give out more, or maybe it's really the maximum that can give one pin.

We will find out. But first you need to find out at what minimum current the motor is generally able to rotate.

Using the circuit from the first experiment, we adjust the value of the current through the windings equal to 40 mA. We start in full-step mode with two phases (as the torque will be higher):

Excellent! At 40mA, the engine started successfully! The minimum value of the winding current necessary for the stable operation of the motor was also detected, and it is equal to 30mA.

Of course, the torque will be much lower, but the fact that we managed to start the motor with such a small power consumption is important for us.

The connection diagram of the stepper motor to the microcontroller will be as follows:



Since each pin of the microcontroller works as a half-bridge (it can switch the output of the microcircuit to either Vcc or GND), to control the bipolar stepper motor, we need 4 pins of the microcontroller.

Program code:

WinAVR source code
#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);
		
	
	   
	} 

} 


Let me explain a little how this program works. This is a modified code from the first experiment. As I said above, an 8-bit TIMER0 will be used to generate a PWM signal at the outputs OC0A and OC0B. The timer is set to FastPWM mode with a prescaler of 8 (the signal frequency at 8 MHz of the clock of the microcontroller is 3906 Hz).

To change the polarity of the signals on the windings, the microcontroller pin is switched from Vcc to GND by changing the corresponding bit in the PORTx register and changing the PWM duty cycle by writing values ​​to the OCR0A and OCR0B registers (the values ​​were selected experimentally).

And so:


A circuitry course taken in the first year of the institute suggests that the multimeter shows the rms value of the voltage and current in the motor.

The stepper motor rotates from the pins of the microcontroller without drivers!

But here we do not go beyond the capabilities of the microcontroller, at least, according to what is written in the documentation. In this mode, the microcontroller and motor can work for a long time. Indeed, the experiment lasted 20 minutes. During this time, there was no skipping steps, no controller reset, or overheating (neither the engine nor the controller).

Put aside all the precautions


We remove the PWM from the experiment and we will directly control the pins of the microcontroller using the PORTx registers. Let's see what happens to the microcontroller after that.

It works ... with a maximum current of 51mA ... Well ... unexpectedly, it seems that this is the maximum current that can give one pin of the microcontroller? If I'm wrong, correct me.

In any case, the video from YouTube was not deceived. Indeed, you can control this motor without any drivers .

findings


We studied in detail miniature bipolar stepper motors, their design and how to control them, for use in our own applications.

1. The miniature bipolar stepper motor with a permanent magnet rotor is truly miniature.

Its main features:

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

2. The miniature stepper motor can be controlled by any drivers suitable for working with bipolar stepper motors, you only need to select the winding current parameters.

3. Using a specialized TMC2208 driver is a controversial issue, since microstep mode is not supported by the engine itself, although transitions between steps are performed more smoothly.

4. It is possible to connect a stepper motor directly to the ports of the microcontroller. But this is only within the framework of the experiment, since the torque in this case is very insignificant, and even a small current does not allow steps to be taken at high speed.

Next time I’ll tell you why we needed such small stepper motors.

All Articles