Part I (Maximum Stepper Speed)
Go to Part II (Adjust max Stepper Current)
Go to Part III (Sleep an Enable)
Click Here to see and download the design of a PCB implementing this circuit.
An important thing to knwo about your stepper, is the maximum speed at witch it can be driven.
To know this, you can follow this LINK;
you need to knwo the specs of your stepper.
For my stepper:
Voltage: 12v
Inductance: 46+-20% mH then i take 50
Steps per revolution: Step Angle = 1.8º 360 / 1.8 = 200 Steps/rev
Current: 0.33 A i take 135 mA because with easy
driver you can adjust the maximun current
with the potenciometer
(i will explain this in a future post)
then following the calculs from the previous link:
T = 50 * 0.135 * 2 / 12 = 1.125 ms for a single Step
The default configuration of EasyDriver is eighth stepping then:
T = 1.125 / 8 = 0.140 ms = 140 us for a single Step
given this we take a prescaler of 128 for the Timer2 (see coments in the code)
128 / 16000000 = 0.000008 s-1 = 8 us-1 ( the frequency of the processor in the
Arduino Uno is 16 MHz)
Timer2 actulizes its counter every 8 us then, 140 / 8 = 17.5
then we have to program the counter for the Timer2 to 18 ( 18 = ceil(17.5) ), because of that we have a success of Timer2 every 18 * 8us = 144 us
and the speed for our stepper will be: 144 us * 1600 Steps/Revolution = 0.2304 s/Revolution
that is 1 / 0.2304 = 4.34 Revolutions / s , wich is an aproximation to the real speed, because there is an extra delay between steps introduced by the code itself ( maybe 20 us extra delay ).
To see this working copy the following code to Arduino IDE, set the proper value for this variables
microSteping
stepsPerRev
l
v
iMax
and run it.
This program also implements acceleration-desacceleration. You can change the amount of acceleration, changing the value of 'accelDuring' variable ( for example it accelerates during 10 steps the run at constant speed and finaly it desaccelerates during 10 steps ).
If you don't want acceleration set it to 0 ( accepted values are 0 - 255 ).
//http://www.daycounter.com/Calculators/Stepper-Motor-Calculator.phtml //Rev/sec = V/(L*2*Imax)/(steps/rev) (Imax en A, L en mili Herns) p.e. 12/(46*2*0.33)/200 //T = L*Imax*2/V (T miliSegons/step) #define DIR_PIN 7 #define STEP_PIN 6 #define sbi(sfr,bit) ( sfr |= _BV(bit) ) // a l'antiga manera. cbi() i sbi() son funcions obsoletes #define cbi(sfr,bit) ( sfr &= ~(_BV(bit)) ) // MS1 MS2 Resolution // L L 00 Full step (2 phase) // H L 10 Half step // L H 01 Quarter step // H H 11 Eighth step // // per defecte a la easy driver MS1 = MS2 = HIGH float microStepping = 8; // Valor establert a la easyDriver ( MS1, MS2 ) long stepsPerRev = 200; // característica del motor float l = 50; // = 46 +- 20% (el pitjor dels casos es 55.2) característica del motor float v = 12; // característica del motor float iMax = 0.135; // mesurat amb el tester (cal dividir el resultat per 2 (hi ha 2 bobines)) // amb la EasyDriver podem controlar iMax abm el potenciòmetre float ocr2a; // valor de OCR2A ( que depèn de la velocitat màxima del Stepper ) int ocr2aIni; // valor inicial de OCR2A donada l'acceleració int accelDuring = 10; // Accelera i desaccelera durant 10 Steps int downCounter = accelDuring; // el nombre d'Steps que falten fins acabar la desacceleració int upCounter = accelDuring; // el nombre d'Steps que falten fins acabar l'acceleració int accelDelta; // valor en que varia OCR2A durant l'acceleració // ( p.e. si ha de pasar de 255 a 19 en 10 steps decremeta de 23 en 23 i começa a 249 ) long stepsLeft = 0; // nombre d'Steps que manque per acabar boolean running = false; // motor is running? void setup() { unsigned int usDelay; // temps d'espera entre Steps en us Serial.begin(115200); pinMode(DIR_PIN, OUTPUT); pinMode(STEP_PIN, OUTPUT); usDelay = l * 2000 * iMax / v / microStepping; // temps d'espera entre steps en microsegons ( T= L*Imax*2/V (T miliSegons/step) ) ocr2a = ceil((float)usDelay / 8.0); // l'enter mes proper donat l'interval del Timer2 ( 8 us ) Serial.println(ocr2a); if(accelDuring > 0){ accelDelta = (255 - int(ocr2a) ) / accelDuring; // OCR2A pasarà del enter mes proper a 255 fins a ocr2a // el valor que hem calculat per la velocitat màxima Serial.println(accelDelta); if(accelDelta<=0){ if(ocr2a < 255){ // la durada de l'acceleració no pot ser tan gran com esperem accelDelta =1; ocr2aIni = 255; accelDuring = 255 - ocr2a; // durada màxima de l'acceleració permesa }else{ // ocr2a = 255, no hi pot haver acceleració accelDelta = 0; accelDuring = 0; ocr2aIni = ocr2a; } }else // acceleració segons la definició ocr2aIni = ocr2a + accelDelta * accelDuring; // calcula el OCR2A inicial donada l'acceleració }else // no hi ha acceleració ocr2aIni = ocr2a; Serial.println(ocr2aIni); setTimer2(ocr2aIni); Serial.print("Inter Step Delay: "); Serial.print(usDelay); Serial.println(" us"); Serial.print("Max Speed: "); Serial.print( 60000000.0 / ((float)stepsPerRev * microStepping * (usDelay)) ); Serial.println(" RPM"); Serial.print("Inter Step Delay programat a Timer2: "); Serial.println((int( ceil( (float)usDelay / 8.0 ) ))*8); Serial.print("Max Speed Real: "); Serial.print( 60000000.0 / ((float)stepsPerRev * microStepping * ((int( ceil( (float)usDelay / 8.0 ) ))*8)) ); }//// long nVoltes = 1; long nSteps = nVoltes * stepsPerRev * microStepping; void loop(){ if(!running){ delay(1000); driveStepper(nSteps); nSteps = -nSteps; } }//// void driveStepper(long lnSteps){ int dir = (lnSteps > 0)? HIGH:LOW; digitalWrite(DIR_PIN,dir); lnSteps = abs(lnSteps); OCR2A = ocr2aIni; // reinicialitza el contador (permet acceleració) upCounter = accelDuring; downCounter = accelDuring; running = true; stepsLeft = lnSteps; }//// void setTimer2(int lusDelay) { //http://arduino.cc/en/Tutorial/SecretsOfArduinoPWM // The ATmega328P has three timers known as Timer 0, Timer 1, and Timer 2 // Each timer has two output compare registers // Each of the timers has a prescaler that generates the timer clock by dividing // the system clock by a prescale factor such as 1, 8, 64, 256, or 1024 // Note that Timer 2 has a different set of prescale values from the other timers // The Arduino has a system clock of 16MHz and the timer clock frequency will be // the system clock frequency divided by the prescale factor // The timers can also generate interrupts on overflow and/or match against either output compare register // // TCCRnA and TCCRnB. The Timer/Counter Control Registers hold the main control bits // for the timer. (Note that TCCRnA and TCCRnB do not correspond to the outputs A and B.) // TCCRnA and TCCRnB hold several groups of bits: // Waveform Generation Mode bits (WGM): these control the overall mode of the timer. // (These bits are split between TCCRnA and TCCRnB.) // Clock Select bits (CS): these control the clock prescaler // Compare Match Output A Mode bits (COMnA): these enable/disable/invert output A // Compare Match Output B Mode bits (COMnB): these enable/disable/invert output B // // OCRnA and OCRnB. The Output Compare Registers set the levels at which outputs A and B will be affected // // TIMSK2 – Timer2 Interrupt Mask Register // OCIE2B: Timer2 Output Compare Match B Interrupt Enable // OCIE2A: Timer2 Output Compare Match A Interrupt Enable // TOIE2: Timer2 Overflow Interrupt Enable // // Timer 1 is a 16-bit timer and has additional modes. Timer 2 has different prescaler values // // The Arduino uses Timer 0 internally for the millis() and delay() functions // OC0A pin 6 OC0B pin 5 // OC1A pin 9 OC1B pin 10 // OC2A pin 11 OC2B pin 3 cli(); // plana 10. Bit 7 Clear interrupts cbi(TCCR2A, COM2A0 ); // plana 158. Table 17-2. Normal port operation, OC0A disconnected. cbi(TCCR2A, COM2A1 ); // 00 deconecta el pin A del timer2 cbi(TCCR2A, WGM20 ); // TCCR2A Regitre A de control del timer 2 sbi(TCCR2A, WGM21 ); // plana 160 i 149. Clear Timer on Compare cbi(TCCR2B, WGM22 ); // WGM2 = 010 ==> mode of operation Clear Timer on Compare (CTC) // The counter value TCNT2 increases until TCNT2 == OCR2A, // and then counter (TCNT2) is cleared // repeteix el cilce 0 --> valor ( valor clocks ) sbi(TCCR2B, CS22 ); // TCCR2B Regitre B de control del timer 2 cbi(TCCR2B, CS21 ); // Plana 162 sbi(TCCR2B, CS20 ); // CS2 = 101 prescaler = 128 ==> 128/16.000.000 = 0.000008 s-1 = 8us-1 // màxim temps que es pot contar = 8 * 255 = 2040 us sbi(TIMSK2, OCIE2A ); // Timer2 Output Compare Match A Interrupt Enable. plana 163 cbi(ASSR, AS2); // AS2 = 0 clocked from the I/O clock // plana 164. Asynchronous Status Register // When AS2 is written to zero, Timer/Counter2 is clocked from the I/O clock, clkI/O. // When AS2 is written to one, Timer/Counter2 is clocked from a crystal Oscillator // connected to the Timer Oscillator 1 (TOSC1) pin. OCR2A = lusDelay; // si p.e. OCR2A = 21 --> 21*0.000008 = 168us-1 . cridem la funcio un cop cada 168 us. plana 162 TCNT2 = 0; // reset Timer2 counter sei(); // Enable Interrupts }//// void stopTimer2() { cbi(TIMSK2, OCIE2A ); // Timer2 Output Compare Match A Interrupt Disable. plana 163 }//// ISR(TIMER2_COMPA_vect) { // Timer2 Output Compare Match A Interrupt // definició dels vectors a Arduino\hardware\tools\avr\avr\include\iom328p.h // definitions for ATmega328P if(stepsLeft > 0){ if(stepsLeft == downCounter){ // ha de desaccelerar downCounter--; OCR2A += accelDelta; // incrementa el temps entre Steps en CS22:0 us (el proper Step es produirà 8 us mes tard) } else if(upCounter >0){ // ha d'accelerar upCounter--; OCR2A -= accelDelta; // decrementa el temps entre Steps en CS22:0 us (el proper Step es produirà 8 us abans) } digitalWrite(STEP_PIN, HIGH); // envia el pols a la EasyDriver per avançar 1 Step digitalWrite(STEP_PIN, LOW); // A low-to-high transition on the STEP input sequences the translator // and advances the motor one increment. // Minimum STEP Pulse Width 1.0 μs (plana 7 de 'A3967.pdf') // la intruccio NOP triga 1 Clock ( 0,0625 us = 62.5 ns ) per tant // la instrucció digitalWrite ha de trigar més de 16 Clocks // mirar el codi a 'wiring_digital.c' // segons els forums 'digitalWrite()' sembla trigar entre 6 i 9 us // depenent de si el port es PWM o no // http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1230286016 stepsLeft--; } else // para el motor running = false; }////