Stepper motor are used in CNC (computerised numerical control) machines, industrial robotic arms, 3D printers and in many such applications where precise motion/movement is required. The stepper motor controller controls mainly three parameters of motor – speed, directions and number of rotations. Some applications requires only speed control, some requires only rotation control or may be control of two parameters like speed and directions or speed and rotations. But some applications require controlling of all three parameters. For example
1. In robotic arm, it is required to alter the direction of motor to open-&-close grip, to move up-&-down to stir left-&-right etc. To move the hand to specific position it is required to control number of rotations of motor. And to speed up/down the working it is required to vary speed of motor
2. In 3D printer motor has to rotated CW (clockwise) and CCW (counter clockwise), also it has to be rotated to desire number of rotations only. And speed control is required for smooth motion.
3. In CNC machine it is required to rotate motor forward and reverse with different speed. And to cut the object in precise shape it is required to rotate motor to specific number of rotations
Here the given project demonstrates how to control speed, direction and rotations of stepper motor. Its auto reversible stepper motor means after rotating desire number rotations, it automatically reverses. It’s an example of close loop control system. It utilizes feedback loop. It counts actual number of motor rotations and gives as a feedback to system. The system compares set rotations with actual motor rotations and reverse the motor when they match. This cycle continues. It also controls speed of motor from 10% to 100%. The project utilizes micro controller ATMega32 to control stepper motor, LCD for display parameters and opto-interrupt sensor count motor rotations and provide feedback.
Circuit description: as shown in figure, the circuit is built using AVR micro controller ATMega32, darlington chip ULN2003A, 16×2 LCD, opto-interrupt sensor MOC7811 and other few components like push buttons, resistors, crystal etc.
Four push buttons are connected to PORTA pins PA0 – PA3 such that when button is pressed it gives logic ‘1’ input to pin. They are used to enter rotation and speed and to rotate motor.
LCD is connected to PORTC and PORTD. Its data pins are connected to PORTC and two control pins Rs and En are connected to PD0 and PD1 respectively. LCD displays number of rotations and speed of motor.
PORTD pins PD4-PD7 drives motor through Darlington pair chip ULN2003A. These pins are connected to inputs (1-4) of ULN2003A and the outputs (16-13) of ULN2003A are connected to four coil terminals of motor. Common terminal of motor is connected to 5 V supply.
Reset pin (9) is connected to Vcc through pull up resistor of 1K. One push button is connected to it as shown to apply manual reset.
Opto-interrupt sensor MOC7811 internally consists of IR LED and photo transistor. The internal IR LED is forward biased to make it continuously on. A current limiting resistor of 330E is used to limit the current through it. The output of photo transistor is given as input to another NPN transistor that is connected in switch mode. The final output of sensor circuit is taken from collector of NPN transistor. This output is given to external interrupt 0 input pin PD2 (17) of ATMega32.
Here are the snaps of circuit arrangement
Circuit operation:
The motor is stop initially. The message is display on LCD to enter required number of motor rotations as “Set rotations”
User can select required number of rotations by pressing button 1 or 2. Button 1 is used to increase number of rotations by 1 and button 2 is to decrease number of rotations by 1. Minimum numbers of rotations are 5.
Once desire numbers of rotations are selected, user has to press enter (button 3). The LCD shows message as “Rotations set to xx”
After 2 second, the user is asked to enter required speed. The message is displayed on LCD as “Set motor speed”
User can set speed from 10% to 100% in step of 10 by pressing same button1 and button2. Button 1 is used to increase speed by 10% and button 2 is to decrease speed by 10%.
Once desire speed is set, again user has to press enter. The LCD shows message as “Speed is set to xx%”
Now user is asked to start the motor and LCD shows message “press rotate”. When user presses rotate button (button 4), the micro controller starts applying pulse sequence with selected delay (as per selected speed) to motor and motor starts rotating at desired speed in CW direction (or CCW direction). The LCD shows speed and rotations of motor.
As the motor rotates one revolution, a strip attached to the shaft of motor passes through the gap of opto-interrupt sensor. That interrupts IR light falling on photo transistor for fraction of second. So photo transistor gives very short duration positive pulse. This positive pulse is inverted by NPN transistor and it gives short duration negative pulse. This negative pulse generates interrupt for micro controller. Micro controller counts these numbers of interrupts as numbers of rotations of motor.
When motor completes desire numbers of rotations, micro controller starts applying reverse pulse sequence to rotate motor in CCW direction. Again micro controller counts number of rotations and when desire numbers of rotations are complete, the pulse sequence is reversed. So motor rotates CW direction.
This cycle continues and motor rotates CW and CCW continuously. To stop the operation user has to press reset
Software program:
The micro controller ATmega32 is the main building block of this project because it performs all the tasks like
1) Take user input from push buttons to set speed and rotations, run motor etc
2) Rotates motor at desire speed by varying delay between applied pulses
3) Displays motor speed, rotations and various messages on LCD
4) Counts actual motor rotations
5) Change the direction of motor when it completes desire number of rotations
To implement all above functionalities the software program is downloaded into internal ROM (FLASH) of this micro controller. Here is the C program with necessary comments (Explore the program in code section).
Project Source Code
Project Source Code
#include
#include
#include
#include
#define lcd_databus PORTC // PORTC is LCD data bus
#define lcd_cntr_port PORTD // PORTD is LCD control port
#define rs PD1
#define en PD0
//////////////////////// variable declaration /////////////////////////////
unsigned int speed_set_flag=0,rotation_set_flag=1,reverse_flag=0;
unsigned int delay_ms=12,speed_value=10,num_of_rotations=10, motor_rotations=0;
/////////////////// variable delay for motor pulse sequence////////////////
void delay_in_us(int d)
{
int z;
for(z=0;z
}
///////////////// function to send data to LCD/////////////////////////////
void senddata(unsigned char data)
{
_delay_ms(2); // wait till LCD is busy
lcd_cntr_port=(1<
lcd_databus=data; // send data
lcd_cntr_port=(1<
lcd_cntr_port =(1<
}
/////////////////// function to send command to LCD /////////////////////
void sendcmd(unsigned char cmd)
{
_delay_ms(2); // wait till LCD is busy
lcd_cntr_port = (0<
lcd_databus=cmd; // send command
lcd_cntr_port = (1<
lcd_cntr_port = (0<
}
////////////////////// function to print string on LCD ////////////////
void printstr(char *s)
{
unsigned int l,i;
l = strlen(s); // get the length of string
for(i=0;i
{
senddata(*s); // write every char one by one
s++;
}
}
/////////////////// function to print integer value on LCD ///////////////
void display_data(unsigned int value)
{
unsigned char ascii_value[3];
unsigned int tmp,t;
if(value>=100) // if value is of 3 digits
{
tmp = value%10; // separate last digit
ascii_value[2] = tmp+0x30; // convert it into ASCII
value = value/10;
tmp = value%10; // separate second digit
ascii_value[1] = tmp+0x30;
value = value/10; // convert it into ASCII
ascii_value[0] = value+0x30; // convert 1st digit in to ASCII
}
else if (value>=10) // if value is of 3 digits
{
tmp = value%10; // separate both digits
ascii_value[1] = tmp+0x30; // convert them into ASCII
value = value/10;
ascii_value[0] = value+0x30;
ascii_value[2] = 0x20; // last digit is space
}
else if(value<10) // if only 1 digit value
{
ascii_value[0] = value+0x30; // convert it into ASCII
ascii_value[2] = 0x20; // other two digits as space
ascii_value[1] = 0x20;
}
for(t=0;t<3;t++) senddata(ascii_value[t]); // print value
}
////////////////////// function to initialize LCD ////////////////////////
void lcd_init()
{
sendcmd(0x3C); // 8-bits/char 7x5 dots/char
sendcmd(0x0E); // screen and cursor ON
sendcmd(0x01); // clear LCD
printstr("Auto reversible"); // display project name
sendcmd(0xC1);
printstr("Stepper Motor");
}
/////////////////////// function for up-arrow key //////////////////////
void up_arrow_key()
{
if(speed_set_flag==1) // either set speed
{
if(delay_ms>1) delay_ms--; // decrease delay to inc speed
if(speed_value<100) speed_value+=10; // inc display value
sendcmd(0xC0);
display_data(speed_value); // display speed value
senddata('%');
}
else if(rotation_set_flag==1) // or set rotations
{
num_of_rotations++; // inc rotations
sendcmd(0xC0);
display_data(num_of_rotations); // display its value
}
}
///////////////////// function for down-arrow key ///////////////////////
void down_arrow_key()
{
if(speed_set_flag==1) // either set speed
{
if(delay_ms<9) delay_ms++; // inc delay to dec speed
if(speed_value>10) speed_value-=10; // dec display value
sendcmd(0xC0);
display_data(speed_value); // display speed value
senddata('%');
}
else if(rotation_set_flag==1) // or set rotations
{
if(num_of_rotations>5) num_of_rotations--; // dec rotations
sendcmd(0xC0);
display_data(num_of_rotations); // display its value
}
}
///////////////////////// function for enter key ////////////////////////
void enter_key()
{
if(rotation_set_flag==1) // when pressed to set rotation
{
sendcmd(0x80);
printstr("rotations set to "); // display message and
sendcmd(0xC0);
display_data(num_of_rotations); // set value
rotation_set_flag=0; // clear flag
_delay_ms(2000); // and after 2 second
sendcmd(0x01);
printstr("set motor speed"); // again display message
sendcmd(0xC0);
display_data(speed_value); // and speed value
senddata('%');
speed_set_flag=1; // set flag for speed
}
else if(speed_set_flag==1) // when pressed to set speed
{
sendcmd(0x01);
printstr("speed is set to"); // display message
sendcmd(0xC0);
display_data(speed_value); // and set value
senddata('%');
speed_set_flag=0; // clear flag
_delay_ms(2000); // after 2 seconds
sendcmd(0x01);
printstr("press rotate"); // again display message
}
}
//////////////////////// function to rotate motor ///////////////////////
void rotate_motor()
{
sendcmd(0x01); // clear LCD
printstr("motor speed="); // show current motor speed
display_data(speed_value);
senddata('%');
sendcmd(0xC0);
printstr("Rotations="); // and current rotations
display_data(motor_rotations);
while(1) // in continuous loop
{
motor_rotations=0; // start rotation count with 0
reverse_flag=0; // clear reverse flag
PORTC = 0x01;
///////// rotate motor CW till desire rotations complete///////
while(num_of_rotations!=motor_rotations)
{
PORTD = 0x84; // pulse sequence 1000
delay_in_us(delay_ms);
PORTD = 0x44; // 0100
delay_in_us(delay_ms);
PORTD = 0x24; //0010
delay_in_us(delay_ms);
PORTD = 0x14; //0001
delay_in_us(delay_ms);
}
motor_rotations=0; // again reset motor rotations
sendcmd(0xCB);
display_data(motor_rotations);// display value
reverse_flag=1; // set reverse flag
PORTC = 0x02;
///////// rotate CCW till desire rotations complete//////////
while(num_of_rotations!=motor_rotations)
{
PORTD = 0x14; // pulse sequence 0001
delay_in_us(delay_ms);
PORTD = 0x24; //0010
delay_in_us(delay_ms);
PORTD = 0x44; //0100
delay_in_us(delay_ms);
PORTD = 0x84; //1000
delay_in_us(delay_ms);
}
}
}
//////////////////////////// main function ////////////////////////////////
int main(void)
{
DDRB=0xFF; // configure all ports as input or output
DDRC=0x07;
DDRD=0xF3;
DDRA=0x00;
PORTD=0x00;
PORTB=0x00;
PORTC=0x00;
MCUCR = (1<
GICR=(1<
sei(); // enable global interrupt
lcd_init(); // initialize LCD
_delay_ms(2000); // wait for 2 sec
sendcmd(0x01); // clear LCD and
printstr("Set rotations"); // display message
sendcmd(0xC0);
display_data(num_of_rotations);
while(1)
{
while(PINA==0xF0); // wait till no key is pressed
switch(PINA)
{
case 0xF1: // if 1st button is pressed
up_arrow_key(); // inc speed or rotations
_delay_ms(200); // key debounce delay
break;
case 0xF2: // if 2nd button is pressed
down_arrow_key(); // dec speed or rotations
_delay_ms(200);
break;
case 0xF4: // if 3rd button is pressed
enter_key(); // set speed or rotations
_delay_ms(200);
break;
case 0xF8: // if 4th button is pressed
rotate_motor(); // start rotating motor
_delay_ms(200);
break;
}
}
}
////////////////////// external interrupt 0 function //////////////////////
ISR(INT0_vect)
{
int y;
PORTC |= 0x04;
if(reverse_flag==0) // if motor is running CW
{
for(y=0;y<58;y++) // continue to rotate it further
{
PORTD = 0x84;
delay_in_us(delay_ms);
PORTD = 0x44;
delay_in_us(delay_ms);
PORTD = 0x24;
delay_in_us(delay_ms);
PORTD = 0x14;
delay_in_us(delay_ms);
}
}
Else // or else if motor is running CCW
{
for(y=0;y<58;y++) // continue to rotate
{
PORTD = 0x14;
delay_in_us(delay_ms);
PORTD = 0x24;
delay_in_us(delay_ms);
PORTD = 0x44;
delay_in_us(delay_ms);
PORTD = 0x84;
delay_in_us(delay_ms);
}
}
motor_rotations++; // inc motor rotation by 1
PORTC &= 0xFB;
sendcmd(0xCB);
display_data(motor_rotations); // display value
}
Circuit Diagrams
Project Video
Filed Under: Electronic Projects
Filed Under: Electronic Projects
Questions related to this article?
👉Ask and discuss on Electro-Tech-Online.com and EDAboard.com forums.
Tell Us What You Think!!
You must be logged in to post a comment.