28BYJ-48 5-Volt Stepper

New version.
You can easily microstep with move(1) and degrpm8()

#define dw digitalWrite
#define dm delayMicroseconds

const int mp1 = 4;	// Blue   - 28BYJ48 pin 1
const int mp2 = 5;	// Pink   - 28BYJ48 pin 2
const int mp3 = 6;	// Yellow - 28BYJ48 pin 3
const int mp4 = 7;	// Orange - 28BYJ48 pin 4
                                // Red    - 28BYJ48 pin 5 VCC
int motorSpeed=3000;            // set stepper speed
int stepnum=0;
float err=0;

void setup() {
  pinMode(mp1, OUTPUT);
  pinMode(mp2, OUTPUT);
  pinMode(mp3, OUTPUT);
  pinMode(mp4, OUTPUT);
  //Serial.begin(115200);
}
void loop(){
//long m=millis();
//Serial.println(millis()-m);
//if(random(4)) degrpm8(random(2),9*(random(20)+2),3200); else delay(100);
//degrpmslowCool4(1,long(360)*100*5,10*60);
//for(int i=0;i<90;i++) {degrpm(1,400,800);delay(50);}
//for(int i=0;i<8;i++) degrpm8(0,4500,2400);
//revRestart(1,2,2000,4);
//does not work 5v for(int i=0;i<500;i++){move(1); off(); delay(1);}
//for(int i=0;i<500;i++){move(1); off(); delay(1);} //<5ms ok w 12v Cool4 better
degrpm(1,180*100,2000);
//ramp(1,2000);
off();delay(500);
}
void ramp(boolean bcw, int rpm100) {
//past 1200 it ramps in cwss() also that's bad
for(int i=50;i<1200;i+=100) //1200 or rpm100 for <1200
degrpmEZ(bcw,900,i); //<900deg ignores speed
revRestart(bcw,2,rpm100,1);
}  
void revRestart(boolean bcw, long revo, int rpm100, int xinrev) {
//xinrev small only
//in case it gets stuck due to torque load spike
for(long i=0;i<revo*xinrev;i++)
degrpm(bcw,36000/xinrev,rpm100);
}
void rev(boolean bcw, long revo) {  
long step2=revo*64*8-12; //not exactly right?
int rpm100=500;
if(bcw) cwss(12,rpm100); //ramp up speed
else   ccwss(12,rpm100);
for(long i=0;i<step2;i++)
  if(bcw)cw(); else ccw();
off();
}
void degrpmslowCool4(boolean bcw, long deg100, int rph100) {  
//ccw only, more torque, less current, less heat, most efficient code for maH
//but 4x as jerky
motorSpeed=1000;
int step2=deg100*64*8/360/100/2; //rounded down
int d=long(351500)*2/rph100; //div 2? see stepper.xls was /2 now *2
for(int i=0;i<step2;i++) {
ccw(); ccw(); off(); delay(d);
} //for
off();
}
void degrpmslowCool(boolean bcw, long deg100, int rph100) {  
//ccw only, more torque, less current, less heat
motorSpeed=1500; //why 1500 needed?
int step2=deg100*64*8/360/100; //rounded down
int d=long(351500)/2/rph100; //div 2? see stepper.xls
for(int i=0;i<step2;i++) {
ccw4st1(); off(); delay(d); //cools while off
ccw4st2(); off(); delay(d);
} //for
off();
}
void degrpmslowHot(boolean bcw, long deg100, int rph100) {  
//ccw only, more torque, hot w 12v
motorSpeed=1000;
int step2=deg100*64*8/360/100; //rounded down
int d=long(351500)/2/rph100; //div 2? see stepper.xls
for(int i=0;i<step2;i++) {
ccw4st1(); delay(d); 
ccw4st2(); delay(d);
} //for
off();
}
void degrpmslow2(boolean bcw, long deg100, int rph100) {  
//ccw only, more torque, less current, less heat, 50% duty cycle
//compromise Hot,Cool
motorSpeed=1000; //12v
int step2=deg100*64*8/360/100; //rounded down
int d=long(351500)/2/rph100; //div 2? see stepper.xls
for(int i=0;i<step2;i++) {
ccw4st1(); off(); delay(d/4); st1(); delay(d/2); off(); delay(d/4);
ccw4st2(); off(); delay(d/4); st2(); delay(d/2); off(); delay(d/4);
} //for
off();
}
void degrpmEZ(boolean bcw, long deg100, int rpm100) {  
//max 64 turns or 23,000 deg or 2,300,000 deg100 long is bigger
//max 3500 rpm100 with 12v
int step2=deg100*64*8/360/100; //rounded down
if(rpm100<50)rpm100=50; //minimum should use degrpmslow()
rpm100=long(1463600)/rpm100-20;  //see stepper.xls
if(bcw) cwss(step2,rpm100);
else   ccwss(step2,rpm100);
}
void degrpm(boolean bcw, long deg100, int rpm100) {  
//max 64 turns or 23,000 deg or 2,300,000 deg100 long is bigger
//max 3500 rpm100 with 12v
int step2=deg100*64*8/360/100; //rounded down
if(rpm100<50)rpm100=50; //minimum should use degrpmslow()
rpm100=long(1463600)/rpm100-20;  //see stepper.xls
if(bcw) cwss(step2,rpm100);
else   ccwss(step2,rpm100);

//with this code you can step by 2.00 deg 180x will be 360+-1
//0.50 deg 720x works to 360
//even though step size is >0.50 or 0.72?
float movedeg=float(step2)*360/64/8;  //float library adds 2K size to sketch
//Serial.println(movedeg);
//Serial.println(movedeg-(float)deg100/100);  //moved too little only?
//ccw4st1 can help this
err+=(movedeg-(float)deg100/100);
if(err<-1) {
motorSpeed=1200;
if(bcw) cw(); else ccw();
err+=(float(360)/64/8);
//Serial.print("err=");Serial.println(err);
} //if err
//soft stop moves further than it should
//if(bcw) cwss(15,2000);
//else   ccwss(15,2000);
delay(10); //so it stops and holds before off in loop
//off();
}
void degrpm8(boolean bcw, long deg100, int rpm100) {  
//max 8 turns
//max <<3500 rpm100 with 12v cuz no ramping ~17RPM
const int min2start=1200; //700 12v, 1200 5v
int step2=deg100*64*64/360/100; //rounded down
if(rpm100<50)rpm100=50; //minimum should use degrpmslow()
rpm100=long(1463600)/rpm100-20;  //see stepper.xls same SAME
motorSpeed=rpm100;
if(motorSpeed<min2start)motorSpeed=min2start;
for(int i=0;i<step2;i++) {
  if(bcw)stepnum++; else stepnum--;
  st07();
  }
//was if(bcw)cwss(step2,rpm100); else ccwss(step2,rpm100);
//does not adjust for err like degrpm cuz step 0.088 or 1/11 deg
float movedeg=float(step2)*360/64/64;  //float library adds 2K size to sketch
//Serial.println(movedeg);
err+=(movedeg-(float)deg100/100);
//Serial.println(err);
//if(err<-1) {motorSpeed=1200; if(bcw) cw(); else ccw(); err+=(float(360)/64/8);}
//off();
}
void move(boolean bcw){
motorSpeed=1200;
if(bcw)stepnum++; else stepnum--;
st07();
}
void ccwss(int steps, int speed) {
//900 self starting 5v motor 5v ps
//800 most of 100% torque
//700 less torque
//600 almost none
//5v motor 12v supply:
//700 self starting
//400 decent torque
//6.6v 20RPM
//8.3v load 8.5v float 6x NiMh
//20RPM strong 28RPM weak
//15RPM 100% torque
//does not overheat
//5V 10RPM strong
//5V 20RPM weak
//5V 24RPM no torque
//12V 20RPM self start 35 max speed
//if(speed<700) steps-=10;
//ramp up speed
motorSpeed=1000; //<12 steps, 800 for 12v
if(steps>=12) {
motorSpeed=3000; if(speed<1200) {ccw(); ccw(); steps-=2;}
motorSpeed=1200; if(speed<1200) {ccw(); ccw(); steps-=2;}
motorSpeed=800;  if(speed<800 ) {ccw(); ccw(); steps-=2;}
motorSpeed=700;  if(speed<700 ) for(int i=0;i<4;i++) {ccw(); steps--;} 
motorSpeed=speed; 
} //if
for(int i=0;i<steps;i++) ccw();  //64*8 is 1 rev
}
void cwss(int steps, int speed) {
motorSpeed=1000; //<12 steps, 800 for 12v
if(steps>=12) {
motorSpeed=3000; if(speed<1200) {cw(); cw(); steps-=2;}
motorSpeed=1200; if(speed<1200) {cw(); cw(); steps-=2;}
motorSpeed=800;  if(speed<800 ) {cw(); cw(); steps-=2;}
motorSpeed=700;  if(speed<700 ) for(int i=0;i<4;i++) {cw(); steps--;}
motorSpeed=speed; 
} //if
for(int i=0;i<steps;i++) cw();  //64*8 is 1 rev
}
void ccw4st1(){
  // 1
  dw(mp1, HIGH);
  dw(mp2, LOW);
  dw(mp3, LOW);
  dw(mp4, LOW);
  dm(motorSpeed);
  // 2
  dw(mp1, HIGH);
  dw(mp2, HIGH);
  dw(mp3, LOW);
  dw(mp4, LOW);
  dm(motorSpeed);
  // 3
  dw(mp1, LOW);
  dw(mp2, HIGH);
  dw(mp3, LOW);
  dw(mp4, LOW);
  dm(motorSpeed);
  // 4
  dw(mp1, LOW);
  dw(mp2, HIGH);
  dw(mp3, HIGH);
  dw(mp4, LOW);
  dm(motorSpeed);
}
void st1(){
  dw(mp1, LOW);
  dw(mp2, HIGH);
  dw(mp3, HIGH);
  dw(mp4, LOW);
}
void ccw4st2(){
  // 5
  dw(mp1, LOW);
  dw(mp2, LOW);
  dw(mp3, HIGH);
  dw(mp4, LOW);
  dm(motorSpeed);
  // 6
  dw(mp1, LOW);
  dw(mp2, LOW);
  dw(mp3, HIGH);
  dw(mp4, HIGH);
  dm(motorSpeed);
  // 7
  dw(mp1, LOW);
  dw(mp2, LOW);
  dw(mp3, LOW);
  dw(mp4, HIGH);
  dm(motorSpeed);
  // 8
  dw(mp1, HIGH);
  dw(mp2, LOW);
  dw(mp3, LOW);
  dw(mp4, HIGH);
  dm(motorSpeed);
}
void st2(){
  dw(mp1, HIGH);
  dw(mp2, LOW);
  dw(mp3, LOW);
  dw(mp4, HIGH);
}
void off(){
  dw(mp1, LOW);
  dw(mp2, LOW);
  dw(mp3, LOW);
  dw(mp4, LOW);
}
void st07(){
if(stepnum==-1)stepnum=7;
if(stepnum==8)stepnum=0;
switch(stepnum){
case 0:
  dw(mp4, HIGH);
  dw(mp3, LOW);
  dw(mp2, LOW);
  dw(mp1, LOW);
  dm(motorSpeed);
  break;
case 1:
  dw(mp4, HIGH);
  dw(mp3, HIGH);
  dw(mp2, LOW);
  dw(mp1, LOW);
  dm(motorSpeed);
  break;
case 2:
  dw(mp4, LOW);
  dw(mp3, HIGH);
  dw(mp2, LOW);
  dw(mp1, LOW);
  dm(motorSpeed);
  break;
case 3:
  dw(mp4, LOW);
  dw(mp3, HIGH);
  dw(mp2, HIGH);
  dw(mp1, LOW);
  dm(motorSpeed);
  break;
case 4:
  dw(mp4, LOW);
  dw(mp3, LOW);
  dw(mp2, HIGH);
  dw(mp1, LOW);
  dm(motorSpeed);
  break;
case 5:
  dw(mp4, LOW);
  dw(mp3, LOW);
  dw(mp2, HIGH);
  dw(mp1, HIGH);
  dm(motorSpeed);
  break;
case 6:
  dw(mp4, LOW);
  dw(mp3, LOW);
  dw(mp2, LOW);
  dw(mp1, HIGH);
  dm(motorSpeed);
  break;
case 7:
  dw(mp4, HIGH);
  dw(mp3, LOW);
  dw(mp2, LOW);
  dw(mp1, HIGH);
  dm(motorSpeed);
  break;
}
}