SparkFun Forums 

Where electronics enthusiasts find answers.

Have questions about a SparkFun product or board? This is the place to be.
By robofreak
#77326
I posted this on the arduino forum and now I'm posting it here.

http://www.arduino.cc/cgi-bin/yabb2/YaB ... 070950/0#0\

That's that link to the arduino website but I'm posting it all here so there's no need to go there.

My project was to control the stepper motor that sparkfun sells over serial down to the microstep using an arduino and an easy driver. In the end well I succeeded. The code that I wrote for the arduino allows bi directional control of the motor down to the microstep. The bulk of the code is mainly converting the stupid ascii values that the arduino reads back into integers the last part at the end is where that magic happens.

Code: Select all
//VERY VERY VERY VERY IMPORTANT!!!!!
//in order to use this code for serial communications and motor control you must send the correct data sequence
//at 115200 bps, it is formated as.....1....how many characters are in the value (1 - 5).......direction (1-2).........value (DEPENDENT ON THE FIRST NUMBER)
//so if I wanted to do 3200 microsteps forward i would send 413200 over serial the first number says there are 4 characters in the value (3200) the second number is 1 which
//tells the motor to go forward (2 would go backward), and the last 4 numbers are the value.
//if I wanted to do 32000 microsteps backward for example I would send 5232000 over serial
//if I wanted to do 400 microsteps forward I would send 31400
//if I wanted to do 80 microsteps forward I would send 2180
//and finally if I wanted to do 8 microsteps backward I would send 128
//also when the program subtracts 48 from the incoming serial value its because the arduino reads the ascii value of the number not its real value so by
//subtracting 48 it converts the ascii value back into its integer value than it multiplys it by its value depending on if its tens of thousands thousands hundreds ect...
//then it adds it up and it has the value that was originally sent from the computer
//make sure the correct data is sent or else the arduino will crash and will require a reset, error handling can be programmed to suit your needs
//THE MAXIMUM INTEGER VALUE IS 65,535 AND HAS BEEN TESTED IF YOU GO OVER ERRORS WILL OCCUR BTW THIS IS ALMOST 41 FULL REVLOUTIONS
//THE MOTOR I AM USING IS THE SPARKFUN STEPPER MOTOR AND THE DRIVER IS THE EASY DRIVER V3
//1600 microsteps is equal to one revolution 

unsigned int val; //pin for storing the value
int info; //variable that stores the latest serial bit from the serial port
int dirPN; //variable that stores the direction that the stepper motor will spin in
int i; //variable for the counter in the for loops
int dirpin = 3; //variable that holds the pin number of the direction pin for the easy driver
int steppin = 12; //variable that holds the pin number of the stepping pin for the easy driver
//you must connect the GND pin on the easy driver to the arduino GND as well

void setup(){
  
Serial.begin(115200); //opens a serial connection at 115200 bps

pinMode(dirpin, OUTPUT); //declares pin 3 as an output for direction control
pinMode(steppin, OUTPUT); //declares pin 12 as an output for stepping control

}

 void loop() {
   

   if (Serial.available() > 0) { //if serial data is sent this if statement will execute
     
   delay(25); //VERY IMPORTANT delay, it can be reduced but if it is to low the arduino will not have receieved all of the serial data so reduce it at your own risk
   
   info = Serial.read(); //reads the first serial bit
   //THIS IS VERY IMPORTANT READ THE BEGINNING INTO   
   info = info - 48; //!!!!!!!!!! The arduino reads the ascii value so to convert it to an integer value you subtract 48      
    
    if (info == 1) { //enters if info is 1 meaning that the value is only 1 character long
      
     dirPN = Serial.read(); //gets the next character which is the direction of the motor 1 is forward, 2 is backward
     dirPN = dirPN - 48;
     
     info = Serial.read(); //reads the single digit then converts it back to an integer and stores it in val for later use
     info = info - 48;
     val = info;
     
    }
    
    if (info == 2) { //enters if info is 2 meaning that the value is only 2 characters long
      
     dirPN = Serial.read(); //gets the next character which is the direction of the motor 1 is forward, 2 is backward
     dirPN = dirPN - 48;
     
     info = Serial.read(); //reads the first digit then converts it and multiples it by 10 because the first digit in a two digit number would
     info = info - 48    ; //be in the 10s
     val = (info * 10);
     info = Serial.read(); //reads the second number then converts it and adds it to the first number it does not need to be multiplied because
     info = info - 48    ; //the second number in a two digit number is a single digit 1 - 9 once added to the first number the original
     val = val + info;     //value that was sent is now in the arduino and will be used at the end of the loop
     
    }
    
    //the below if statments follow the same pattern as the above loops just with higher multiplying values because they are after all
    
    if (info == 3) { //enters if info is 3 meaning that the value is only 3 characters long
      
     dirPN = Serial.read(); //gets the next character which is the direction of the motor 1 is forward, 2 is backward
     dirPN = dirPN - 48; 
     
     info = Serial.read();
     info = info - 48    ; 
     val = (info * 100);
     info = Serial.read();
     info = info - 48     ;
     val = val + (info * 10);
     info = Serial.read();
     info = info - 48   ;  
     val = val + info;
      
    }
        
    if (info == 4) { //enters if info is 4 meaning that the value is only 4 characters long
      
     dirPN = Serial.read(); //gets the next character which is the direction of the motor 1 is forward, 2 is backward
     dirPN = dirPN - 48;
     
     info = Serial.read(); 
     info = info - 48;
     val = (info * 1000);
     info = Serial.read();
     info = info - 48;
     val = val + (info * 100);
     info = Serial.read();
     info = info - 48;
     val = val + (info * 10);
     info = Serial.read();
     info = info - 48;
     val = val + info;
      
    }
    
    if (info == 5) { //enters if info is 5 meaning that the value is only 5 characters long
      
     dirPN = Serial.read(); //gets the next character which is the direction of the motor 1 is forward, 2 is backward
     dirPN = dirPN - 48;
     
     info = Serial.read();
     info = info - 48;
     val = (info * 10000);
     info = Serial.read();
     info = info - 48;
     val = val + (info * 1000);
     info = Serial.read();
     info = info - 48;
     val = val + (info * 100);
     info = Serial.read();
     info = info - 48;
     val = val + (info * 10);
     info = Serial.read();
     info = info - 48;
     val = val + info;
     
    }
       
    if (dirPN == 1) { //if dirPN is 1 then this if statement executes, the value 1 means it goes forward
      
    digitalWrite(dirpin, HIGH); 
    
               for (i = 0; i<val; i++)    //this is the start of the loop and val the value we had to work so hard to get is the number of microsteps or in other words the number
                                          //of times it will loop (each time it loops the easy driver microsteps) so 1 loop is 1 microstep   
  {
    
    digitalWrite(steppin, LOW);  //toggles the stepping pin on and off then delays 200 microseconds
    digitalWrite(steppin, HIGH); 
    delayMicroseconds(200);     
    
  }       

    }
    
        if (dirPN == 2) { //if dirPN is 2 then this if statement executes, the value 2 means it goes backwards
      
    digitalWrite(dirpin, LOW); 
    
               for (i = 0; i<val; i++)    //this is the start of the loop and val the value we had to work so hard to get is the number of microsteps or in other words the number
  {                                       //of times it will loop (each time it loops the easy driver microsteps) so 1 loop is 1 microstep
    
    digitalWrite(steppin, LOW);  //toggles the stepping pin on and off then delays 200 microseconds
    digitalWrite(steppin, HIGH); 
    delayMicroseconds(200);     
    
  }       

    }
     
  } //the serial loop ends and exits
   
 } //the main loop runs again and awaits serial data to repeat this insane cycle all over again.....
 
I am uploading a youtube video of the motor and my code in action right now, it will be posted tomorrow.
By robofreak
#77358
That is a cool board you got there, looks like my design on crack...... I just made this so that people with the arduino can use it, easy plug and play. Your using a microchip pic I could be wrong but you have to use mplab to program this right you couldn't burn the arduino bootloader and use the arduino ide. I am trying to learn how to program microchip pics right now I have about 40 ds pics that are very powerful as well as 20 powerful pics but they sit on the shelf because I don't know how to program them yet!!! The frustration lol

BTW I fixed the url

I am uploading another video of the stepper motor in action but with the new v2 code it allows 100% control of the motor speed, position, and direction plus I beefed up the gui in visual studio to have way more features.

Here is the version 2 arduino code if anyone is interested!


I know I could have used sub routines and switch statements to reduce the size of the code but I kept it in blocks of code to prevent weird problems from occurring, I tried the switch case but it didn't work for some reason. There is a link to a text file so you can copy and paste easily as I edited this code to make it more readable and I could have made an error ect....

download the text file here


http://code.google.com/p/stepperserialc ... loads/list

Code: Select all
//VERY VERY VERY VERY IMPORTANT!!!!!
//in order to use this code for serial communications and motor control you must send the correct data sequence
//at 115200 bps, it is formated as.....1....how many characters are in the value (1 - 5).....direction (1-2)..... number of characters in the speed value (3 or 4).....speed(100 - 999 lower is faster)......value (DEPENDENT ON THE FIRST NUMBER)
//so if I wanted to do 3200 microsteps forward at regular speed i would send 4132003200 over serial the first number says there are 4 characters in the value (3200) the second number is 1 which
//tells the motor to go forward (2 would go backward), the next num tells it that the speed val is 3 digits, the next three numbers is the delay value for motor speed, and the last 4 numbers are the value.
//if I wanted to do 32000 microsteps backward at standard speed for example I would send 52320032000 over serial
//if I wanted to do 400 microsteps forward at fast speed I would send 313150400
//if I wanted to do 80 microsteps forward at SUPER slow speed I would send 214250080
//and finally if I wanted to do 8 microsteps backward at standard speed I would send 122008
//also when the program subtracts 48 from the incoming serial value its because the arduino reads the ascii value of the number not its real value so by
//subtracting 48 it converts the ascii value back into its integer value than it multiplys it by its value depending on if its tens of thousands thousands hundreds ect...
//then it adds it up and it has the value that was originally sent from the computer
//make sure the correct data is sent or else the arduino will crash and will require a reset, error handling can be programmed to suit your needs
//THE MAXIMUM INTEGER VALUE IS 65,535 AND HAS BEEN TESTED IF YOU GO OVER ERRORS WILL OCCUR BTW THIS IS ALMOST 41 FULL REVLOUTIONS
//THE MOTOR I AM USING IS THE SPARKFUN STEPPER MOTOR AND THE DRIVER IS THE EASY DRIVER V3
//1600 microsteps is equal to one revolution 


////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

//VERSION 2 CODE UPADATES
//added support for speed control of the stepper motor by controling the delay value
//the data is now formated as.......how many characters are in the value (1 - 5)......direction (1-2).....number of characters in the speed value (3 or 4).....speed(100 - 9999 lower is faster)......value (DEPENDENT ON THE FIRST NUMBER)
//DO NOT SEND A SPEED VALUE larger or smaller than a three to four digit number it must be a number between 100 and 9999
//LOWERING the value makes it FASTER, INCREASING the value makes it SLOWER..............WARNING your motor may stall at values below 200, at full voltage I have run it slightly below 150 so run it low at your own risk

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////


unsigned int val; //pin for storing the value
int info; //variable that stores the latest serial bit from the serial port
int dirPN; //variable that stores the direction that the stepper motor will spin in
int delayVal; //variable that stores the delay value which controls the speed at which the motor steps
int i; //variable for the counter in the for loops
int dirpin = 3; //variable that holds the pin number of the direction pin for the easy driver
int steppin = 12; //variable that holds the pin number of the stepping pin for the easy driver
//you must connect the GND pin on the easy driver to the arduino GND as well


void setup(){
  
Serial.begin(115200); //opens a serial connection at 115200 bps

pinMode(dirpin, OUTPUT); //declares pin 3 as an output for direction control
pinMode(steppin, OUTPUT); //declares pin 12 as an output for stepping control

}

 void loop() {
   

   if (Serial.available() > 0) { //if serial data is sent this if statement will execute
     
   delay(25); //VERY IMPORTANT delay, it can be reduced but if it is to low the arduino will not have receieved all of the serial data so reduce it at your own risk
   
   info = Serial.read(); //reads the first serial bit

   //THIS IS VERY IMPORTANT READ THE BEGINNING INTO   

   info = info - 48; //!!!!!!!!!! The arduino reads the ascii value so to convert it to an integer value you subtract 48      
    
    	if (info == 1) { //enters if info is 1 meaning that the value is only 1 character long
      
    	 dirPN = Serial.read(); //gets the next character which is the direction of the motor 1 is forward, 2 is backward
    	 dirPN = dirPN - 48;
     
     	 info = Serial.read(); //gets the next character which tells the arduino how many characters are in the next speed/delay value
    	 info = info - 48;
     
      		 if (info == 3) { //this code will execute if the third number is 3 which means that the next speed/delay value is three digits
             
   		         info = Serial.read(); //this next portion of code gets the next THREE digits which store the speed or delay value of the motor
                         info = info-48;
   	                 delayVal = (info * 100);
    			 info = Serial.read();
     			 info = info-48;
    			 delayVal = delayVal + (info * 10);
    			 info = Serial.read();
 	                 info = info-48;
     			 delayVal = delayVal + info;
     
  			 }
   
       		if (info == 4) { //this code will execute if the third number is 4 which means that the next speed/delay value is four digits
         
      			 info = Serial.read(); //this next portion of code gets the next FOUR digits which store the speed or delay value of the motor
    			 info = info-48;
    			 delayVal = (info * 1000);
     			 info = Serial.read();
    			 info = info-48;
     			 delayVal = delayVal + (info * 100);
     			 info = Serial.read();
     			 info = info-48;
     			 delayVal = delayVal + (info * 10);
     			 info = Serial.read();
     			 info = info-48;
     			 delayVal = delayVal + info;
     
       			 }
       
       
    	  info = Serial.read(); //reads the single digit then converts it back to an integer and stores it in val for later use
   	  info = info - 48;
   	  val = info;

   	  
  	  }
    
   	  if (info == 2) { //enters if info is 2 meaning that the value is only 2 characters long
      
    	  dirPN = Serial.read(); //gets the next character which is the direction of the motor 1 is forward, 2 is backward
     	  dirPN = dirPN - 48;
     
          info = Serial.read();
          info = info - 48;
     
     		  if (info == 3) { //this code will execute if the third number is 3 which means that the next speed/delay value is three digits
       
    		          info = Serial.read(); //this next portion of code gets the next THREE digits which store the speed or delay value of the motor
    			  info = info-48;
     			  delayVal = (info * 100);
     	   	   	  info = Serial.read();
     			  info = info-48;
    		          delayVal = delayVal + (info * 10);
     			  info = Serial.read();
    			  info = info-48;
    			  delayVal = delayVal + info;
     
  			 }
   
      		   if (info == 4) { //this code will execute if the third number is 4 which means that the next speed/delay value is four digits
         
     			   info = Serial.read(); //this next portion of code gets the next FOUR digits which store the speed or delay value of the motor
                           info = info-48;
                           delayVal = (info * 1000);
                           info = Serial.read();
                           info = info-48;
                           delayVal = delayVal + (info * 100);
                           info = Serial.read();
                           info = info-48;
                           delayVal = delayVal + (info * 10);
                           info = Serial.read();
                           info = info-48;
                           delayVal = delayVal + info;
     
       			}
     

   	  info = Serial.read(); //reads the first digit then converts it and multiples it by 10 because the first digit in a two digit number would
    	  info = info - 48    ; //be in the 10s
          val = (info * 10);
          info = Serial.read(); //reads the second number then converts it and adds it to the first number it does not need to be multiplied because
          info = info - 48    ; //the second number in a two digit number is a single digit 1 - 9 once added to the first number the original
          val = val + info;     //value that was sent is now in the arduino and will be used at the end of the loop
     
         }
    
    //the below if statments follow the same pattern as the above loops just with higher multiplying values because they are after all
    
    	   if (info == 3) { //enters if info is 3 meaning that the value is only 3 characters long
      
    	   dirPN = Serial.read(); //gets the next character which is the direction of the motor 1 is forward, 2 is backward
           dirPN = dirPN - 48; 
     
           info = Serial.read();
    	   info = info - 48;
     
      		 if (info == 3) { //this code will execute if the third number is 3 which means that the next speed/delay value is three digits
       
     			info = Serial.read(); //this next portion of code gets the next THREE digits which store the speed or delay value of the motor
    		        info = info-48;
     			delayVal = (info * 100);
     			info = Serial.read();
     			info = info-48;
    		        delayVal = delayVal + (info * 10);
     			info = Serial.read();
    			info = info-48;
     			delayVal = delayVal + info;
     
 		        }
   
      		 if (info == 4) { //this code will execute if the third number is 4 which means that the next speed/delay value is four digits
         
    			 info = Serial.read(); //this next portion of code gets the next FOUR digits which store the speed or delay value of the motor
     			 info = info-48;
                         delayVal = (info * 1000);
                         info = Serial.read();
                         info = info-48;
                         delayVal = delayVal + (info * 100);
                         info = Serial.read();
                         info = info-48;
                         delayVal = delayVal + (info * 10);
                         info = Serial.read();
                         info = info-48;
                         delayVal = delayVal + info;
     
      			}
     
           info = Serial.read();
           info = info - 48    ; 
           val = (info * 100);
           info = Serial.read();
           info = info - 48     ;
           val = val + (info * 10);
           info = Serial.read();
            info = info - 48   ;  
           val = val + info;
      
          }
        
           if (info == 4) { //enters if info is 4 meaning that the value is only 4 characters long
      
           dirPN = Serial.read(); //gets the next character which is the direction of the motor 1 is forward, 2 is backward
           dirPN = dirPN - 48;
     
           info = Serial.read();
           info = info - 48;
     
       		 if (info == 3) { //this code will execute if the third number is 3 which means that the next speed/delay value is three digits
       
                        info = Serial.read(); //this next portion of code gets the next THREE digits which store the speed or delay value of the motor
                        info = info-48;
                        delayVal = (info * 100);
                        info = Serial.read();
                        info = info-48;
                        delayVal = delayVal + (info * 10);
                        info = Serial.read();
                        info = info-48;
                        delayVal = delayVal + info;
     
                  }
   
                 if (info == 4) { //this code will execute if the third number is 4 which means that the next speed/delay value is four digits
            
                        info = Serial.read(); //this next portion of code gets the next FOUR digits which store the speed or delay value of the motor
                        info = info-48;
                        delayVal = (info * 1000);
                        info = Serial.read();
                        info = info-48;
                        delayVal = delayVal + (info * 100);
                        info = Serial.read();
                        info = info-48;
                        delayVal = delayVal + (info * 10);
                        info = Serial.read();
                        info = info-48;
                        delayVal = delayVal + info;
     
                  }
       
    	  info = Serial.read(); 
          info = info - 48;
     	  val = (info * 1000);
    	  info = Serial.read();
     	  info = info - 48;
     	  val = val + (info * 100);
     	  info = Serial.read();
     	  info = info - 48;
     	  val = val + (info * 10);
     	  info = Serial.read();
     	  info = info - 48;
     	  val = val + info;
      
    	  }
    
          if (info == 5) { //enters if info is 5 meaning that the value is only 5 characters long
      
          dirPN = Serial.read(); //gets the next character which is the direction of the motor 1 is forward, 2 is backward
          dirPN = dirPN - 48;
     
          info = Serial.read();
          info = info - 48;
     
      		  if (info == 3) { //this code will execute if the third number is 3 which means that the next speed/delay value is three digits
       
     		  info = Serial.read(); //this next portion of code gets the next THREE digits which store the speed or delay value of the motor
     		  info = info-48;
     		  delayVal = (info * 100);
     		  info = Serial.read();
     		  info = info-48;
     		  delayVal = delayVal + (info * 10);
     		  info = Serial.read();
     		  info = info-48;
     		  delayVal = delayVal + info;
     
  		   }
   
       		  if (info == 4) { //this code will execute if the third number is 4 which means that the next speed/delay value is four digits
         
     		  info = Serial.read(); //this next portion of code gets the next FOUR digits which store the speed or delay value of the motor
     		  info = info-48;
     		  delayVal = (info * 1000);
     		  info = Serial.read();
     		  info = info-48;
     		  delayVal = delayVal + (info * 100);
     		  info = Serial.read();
     		  info = info-48;
     		  delayVal = delayVal + (info * 10);
     		  info = Serial.read();
     		  info = info-48;
     		  delayVal = delayVal + info;
     
     		  }
     
     	  info = Serial.read();
     	  info = info - 48;
     	  val = (info * 10000);
    	  info = Serial.read();
     	  info = info - 48;
     	  val = val + (info * 1000);
     	  info = Serial.read();
     	  info = info - 48;
     	  val = val + (info * 100);
     	  info = Serial.read();
     	  info = info - 48;
     	  val = val + (info * 10);
     	  info = Serial.read();
     	  info = info - 48;
     	  val = val + info;
     
   	   }
       
    if (dirPN == 1) { //if dirPN is 1 then this if statement executes, the value 1 means it goes forward
      
    digitalWrite(dirpin, HIGH); 
    
               for (i = 0; i<val; i++)    //this is the start of the loop and val the value we had to work so hard to get is the number of microsteps or in other words the number
                                          //of times it will loop (each time it loops the easy driver microsteps) so 1 loop is 1 microstep   
  {
    
    digitalWrite(steppin, LOW);  //toggles the stepping pin on and off then delays 200 microseconds
    digitalWrite(steppin, HIGH); 
    delayMicroseconds(delayVal);  //this is where the speed control delay is, by controlling this delay motor speed control can be obtained  
    
  }       

    }
    
        if (dirPN == 2) { //if dirPN is 2 then this if statement executes, the value 2 means it goes backwards
      
    digitalWrite(dirpin, LOW); 
    
               for (i = 0; i<val; i++)    //this is the start of the loop and val the value we had to work so hard to get is the number of microsteps or in other words the number
  {                                       //of times it will loop (each time it loops the easy driver microsteps) so 1 loop is 1 microstep
    
    digitalWrite(steppin, LOW);  //toggles the stepping pin on and off then delays 200 microseconds
    digitalWrite(steppin, HIGH); 
    delayMicroseconds(delayVal);   //this is where the speed control delay is, by controlling this delay motor speed control can be obtained  
    
  }       

    }
     
  } //the serial loop ends and exits
   
 } //the main loop runs again and awaits serial data to repeat this insane cycle all over again.....
By signal7
#77398
I know you mentioned you're aware that subroutines would be better. I would add that subroutines are better because they make the design process easier and the resulting code would be much easier to read/understand. It's good that you commented the code, but ... subroutines would help a lot. :)
By robofreak
#77429
I don't think I could put the code that actually gets value out of the serial string into a subroutine I wouldn't want to over complicate the calling of the subroutine. But I could definitely put the code that gets the direction value, speed character value, and the speed value into a subroutine. This alone would reduce the code a lot. I'll see what I can do with it.


Here is the new youtube video if you guys are interested

http://www.youtube.com/watch?v=3SzWp0vVAzI

I just added speed control and beefed up the control program to have way more features.