Skip to content

Instantly share code, notes, and snippets.

@sbright33
Created November 30, 2012 23:11
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save sbright33/4179366 to your computer and use it in GitHub Desktop.
Save sbright33/4179366 to your computer and use it in GitHub Desktop.
Stepper 1 degree/step PWM smoother cooler
//requires additional hardware 1 res 1 cap x4
// This Arduino example demonstrates bidirectional operation of a
// 28BYJ-48, which is readily available on eBay for $4.25 inc shipping,
// using a ULN2003 interface board to drive the stepper. The 28BYJ-48
// motor is a 4-phase, 8-beat motor, geared down by a factor of 64. One
// bipolar winding is on motor pins 1,3 and the other on motor pins 2,4.
// Refer to the manufacturer's documentation of Changzhou Fulling
// Motor Co., Ltd., among others. The step angle is 5.625/64 and the
// operating Frequency is 100pps. Current draw is 92mA.
// Vin w USB power is 4.5v too slow for testing use 5v pin.
// To save space to upload to forum:
#include <Narcoleptic.h>
#define dw digitalWrite
#define dm delayMicroseconds
#define aw analogWrite
#define de delay
#define P(s) Serial.print(s);
#define P32 Serial.write(32);
#define P13 Serial.write(10);
//2.1v to hold weakly
//2.5v to turn 3v strong
#define VOLT 1 //required 1v for topspeed lowp slow()
#define AW11 analogWrite(mp1a,int(VOLT*256/5));
#define AW21 analogWrite(mp2a,int(VOLT*256/5));
#define AW31 analogWrite(mp3a,int(VOLT*256/5));
#define AW41 analogWrite(mp4a,int(VOLT*256/5));
#define AW10 analogWrite(mp1a,0);
#define AW20 analogWrite(mp2a,0);
#define AW30 analogWrite(mp3a,0);
#define AW40 analogWrite(mp4a,0);
#define fastout {pinMode(mp1,OUTPUT);pinMode(mp2,OUTPUT);pinMode(mp3,OUTPUT);pinMode(mp4,OUTPUT);}
#define fastin {pinMode(mp1,INPUT );pinMode(mp2,INPUT );pinMode(mp3,INPUT );pinMode(mp4,INPUT );}
const int mp1 = 2; // Blue - 28BYJ48 pin 1
const int mp2 = 3; // Pink - 28BYJ48 pin 2
const int mp3 = 4; // Yellow - 28BYJ48 pin 3
const int mp4 = 5; // Orange - 28BYJ48 pin 4
// Red - 28BYJ48 pin 5 VCC
const int mp1a = 9;
const int mp2a = 10;
const int mp3a = 11;
const int mp4a = 13; // 13 is not PWM should use 6 todo later
long motorSpeed=3000; // set stepper speed, period actually, changed long for 1A not used?
int stepnum=0; // current microstep 0-7
float err=0; // running total of movedeg - requested move, always negative in degrpm()
int ar[8]; // assigned in ccw() only, to detect abnormal torque load
int movecnt=0; // running total of steps taken in move(), &=4095 in moveto
long m; // millis()
int step2,d; // nowait
int ii,k;
void setup() {
fastout
pinMode(mp1a, OUTPUT);
pinMode(mp2a, OUTPUT);
pinMode(mp3a, OUTPUT);
pinMode(mp4a, OUTPUT);
//Serial.begin(9600);
TCCR1B&=~7; //32khz/30us PWM pins 9-13
TCCR2B&=~7;
TCCR1B|=1;
TCCR2B|=1;
//AW11 AW21 AW31 AW41
//degrpmslowCool4_nowait(0,180*100,1000); //10RPH
//degrpm_nowait(1,180*100,1500);
}
void loop(){
//half step wo 1uf cap 1k res st07()
//10x faster, 10x more deg/step than little motor 64:1 gear
//600 fastest
//1000 stronger
//1600 1/4 duty
//2000 1/4 ideal no vibe but weak
//3200 1/4 slowest wo vibe, smoother=full duty
//5000 slowest full duty
//3000 fastest st03aw (3v critical) same speed as 1500 1/4 duty cuz 4/8 steps
//5000 strong w 1uf caps st03aw
//900 full step st03() is 450 faster than half step
//off();while(1);
//fastout
//degrpm1Arampduty(0,18000,10000); de(500);
//degrpm1Arampduty(1,18000,10000); de(500);
degrpm1Aslow(1,18000,100); de(500);
/*
toppwr(1); de(8);
toppwr(1); de(2); toppwr(1);
for(ii=0;ii<60/2*40/36-3-5;ii++) topspeed_nocap(1);
for(ii=0;ii<5;ii++) {topspeed_nocap(1); de(3*ii);}
off(); de(60);
toppwr(-1); de(8);
toppwr(-1); de(2); toppwr(-1);
for(ii=0;ii<60/2*40/36-3-5;ii++) topspeed_nocap(-1);
for(ii=0;ii<5;ii++) {topspeed_nocap(-1); de(3*ii);}
off(); de(60);
/*
toppwr(-1); de(7); // 3+2 = 1/5 topspeed
toppwr(-1); de(1);
for(ii=0;ii<60/2*40/36-2;ii++) topspeed_nocap(-1);
//off();
de(60);
toppwr(1); de(7); // 3+2 = 1/5 topspeed
toppwr(1); de(1);
for(ii=0;ii<60/2*40/36-2;ii++) topspeed_nocap(1);
//if(k++%6==3){topspeed(1); topspeed(1);} //60 is not even 400/360 perfect
//off();
de(60);
/**/
//for(ii=0;ii<360/2*40/36;ii++) topspeed(1); stophold(210); de(2000);
//slowpwr();
//lowpmidsp();
//topspeed(1);
//fastin;sinemod();
//off();while(1); //halt
}
void unramp(boolean bcw, long deg100, int rpm100, int percslow){
//to prevent bouncing at end of move with DSLR camera mounted on shaft directly
degrpm8(bcw,deg100*(100-percslow*2)/100,rpm100); //limited to 17.00 800 12v?
degrpm8(bcw,deg100*percslow/100,400);
degrpm8(bcw,deg100*percslow/100,100);
}
void unramp1(boolean bcw, long deg100, int rpm100, int percslow){
//to prevent bouncing at end of move with DSLR camera mounted on shaft directly
//faster 20rpm for 8v, 30rpm for 12v
degrpm1(bcw,deg100*percslow/100,1500); //change for 12v
degrpm1(bcw,deg100*(100-percslow*3)/100,rpm100);
degrpm1(bcw,deg100*percslow/100,400);
degrpm1(bcw,deg100*percslow/100,100);
//off for 12v
}
const float STEPERDEG=float(64)*64/360;
//call like this moveto(90.0*STEPERDEG);
//code decides which direction to move is shortest
void moveto(int steppos){
steppos&=4095;
movecnt&=4095; //this will not happen in move() can be >4096
int bcw=0;
if(steppos>movecnt)bcw=1;
if(abs(steppos-movecnt)>2048)bcw=!bcw;
movetodir(bcw,steppos);
}
void movetodir(boolean bcw, int steppos){
//absolute position you decide direction
steppos&=4095;
movecnt&=4095; //this will not happen in move() can be >4096 or <0
while(movecnt!=steppos) {
move(bcw);
movecnt&=4095;
}
//can turn off()
}
void midspeedcool_12v(boolean bcw, long steps){
//use const STEPERDEG
//no reason to use this with 5-8v
//perfect for running motor all day long
//delay 1200us already in move, dm(1200) is 50% duty cycle
//dm(400) is strong, 1200 is like 5v torque?
//<5000 smoother ok with 12v only but Cool4 is better
//change 1200 to fit your desired speed
for(long i=0;i<steps;i++){move(bcw); off(); dm(500);}
}
void ramp(boolean bcw, int rpm100) {
//past 1200 it ramps fast in cwss() also, thats bad, so dont do it
for(int i=50;i<1200;i+=100) //1200 or rpm100 if <1200, can change step 100
degrpmEZ(bcw,900,i); //<9.00deg ignores speed
revRestart(bcw,2,rpm100,1); //can change these
}
void revRestart(boolean bcw, long revo, int rpm100, int xinrev) {
int j=0;
//xinrev small only
//restarts ramp in case it gets stuck due to torque load spike
if(xinrev) //>0 restarts, 0 no restart
for(long i=0;i<revo*xinrev;i++){
if(i%xinrev==0){
//Serial.print(j++);
//Serial.write(32);
}
//EZ does not delay(10) at end
degrpmEZ(bcw,36000/xinrev,rpm100); //no max
} //for
else
degrpmEZ(bcw,36000*revo,rpm100); //64 max or use rev()
}
void rev(boolean bcw, long revo) {
long step2=revo*64*8-12; //not exactly right?
int rpm100=500; //can change
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=1500; //1000 or 1500 needed to pull camera 5v
int step2=deg100*64*8/360/100/2; //rounded down
int d=long(351500)*2/rph100; //see stepper.xls was /2 now *2
for(int i=0;i<step2;i++) {
ccw(); ccw(); off();
//can comment out line below sleeps 10ma Aroboto from 5v regulator 40ma Uno
Narcoleptic.
delay(d);
//can hardcode cw() instead
//if(i%16==0)Serial.println(float(i+1)*360/64/8*2);
} //for
off(); //redundant
}
void degrpm_nowait(boolean bcw, long deg100, int rpm100) {
//bcw not used pass to calloften_micro() instead
motorSpeed=1; //0?
step2=deg100*64*64/360/100;
d=long(1463600)/rpm100-20;
m=micros();
ii=0;
}
int calloften_micro(boolean bcw){
//at least every d micros
if(ii>=step2)return(0); //saves time when done
//if(m+d-micros()<200) //can change this
//while(micros()< m+d){}; //wait until time can change //disable this line
long ms=micros();
//if(ms>=m+d*3)Serial.println("Double-step"); //2 is double, 3 is triple
if((ms>=m+d)&&(ii<step2)){ //while would be too soon, ii< redundant
if(bcw)stepnum++; else stepnum--;
//if(bcw)movecnt++; else movecnt--;
st07();
//off();
m+=d; ii++;
} //if
//steps left until destination
return(step2-ii);
}
void degrpmslowCool4_nowait(boolean bcw, long deg100, int rph100) {
//ccw only for now
motorSpeed=1500; //1000 or 1500 needed to pull camera 5v
//int or global below
step2=deg100*64*8/360/100/2;
d=long(351500)*2/rph100;
m=millis();
ii=0;
//can use global d to determine process time in loop()
//Serial.println(step2);Serial.println(d);
}
int calloften(){
//at least every d ms
//will catch up if behind
if(ii>=step2)return(0); //saves time when done
long ms=millis();
//if(ms>=m+d*3)Serial.println("Double-step"); //2 is double, 3 is triple
while((ms>=m+d)&&(ii<step2)){
ccw(); ccw(); off(); m+=d; ii++;
//if(ii%16==1)Serial.println(float(ii)*360/64/8*2);
} //while
//steps left until destination
return(step2-ii);
}
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++) {
//can comment out line below sleeps 10ma from 5v regulator
//Narcoleptic.delay
ccw4st1(); off(); delay(d); //cools while off
ccw4st2(); off(); delay(d);
//if(i%16==0)Serial.println(float(i+1)*360/64/8);
} //for
off(); //redundant
}
void degrpmslowHot(boolean bcw, long deg100, int rph100) {
//ccw only, more torque, hot w 12v, use for 5v
motorSpeed=1000; //difference#1
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); //difference#2 off()
ccw4st2(); delay(d);
//if(i%16==0)Serial.println(float(i+1)*360/64/8);
} //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++) { //only difference is below
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 degrpm1(boolean bcw, long deg100, int rpm100) {
//do your own ramping past 17RPM
long step2=deg100*64*8/360/100; //rounded down no limit
if(rpm100<50)rpm100=50; //minimum should use degrpmslow()
motorSpeed=long(1463600)/rpm100-20; //see stepper.xls
for(long i=0;i<step2;i++)
if(bcw)cw(); else ccw();
//can move() here to get better resolution
}
void degrpmEZ(boolean bcw, long deg100, int rpm100) {
//no delay(10) at end
//first 5 lines of degrpm
//max 64 turns
//max 3500 rpm
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? never too much
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=800; //800 12v, 1200 5v
long deg100a=deg100; //deg100 used later dont change
if(deg100a<300)deg100a +=4; //now err can be positive, check %=0 instead?
int step2=deg100a*64*64/360/100; //rounds up/down by 1/2 cuz +4 above, error 1/22nd of degree
if(rpm100<50)rpm100=50; //minimum should use degrpmslow()
rpm100=long(1463600)/rpm100-20; //see stepper.xls 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);
//does not adjust position for err like degrpm cuz step 0.044 or 1/22 deg small
float movedeg=float(step2)*360/64/64; //float library adds 2K size to sketch
//Serial.println(movedeg);
err+=(movedeg-(float)deg100/100); //not used
//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--;
if(bcw)movecnt++; else movecnt--;
st07();
//if(movecnt%16==1)Serial.println(float(movecnt)*360/64/64);
}
void ccwss(int steps, int speed) {
int norm=0,last=0,nalarm=0,nar=0;
long sum=0;
//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
//const int readadj=100;
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
//torque load detect code to prevent destroying motor
for(int i=0;i<steps;i++){
if(nar>=1024){ //lower for slow?
k=sum*5/nar; //why not 6? div 0? fixed
if((k==last)&&(!norm)&&(millis()>5*1000)) norm=k; //since program start
if((k==last)&&(k==norm+1)) norm=k; //within 40 sec when if k>norm+0 below
//if((k==last)&&(k==norm-1)) norm=k;
digitalWrite(13,LOW);
if(!norm)digitalWrite(13,HIGH); //ON until normal is found
//10,-10 for 8v level ground
// 0,-10 for 12v >30RPM only
if(((k>norm+20)&&norm)||((k<norm-20)&&norm)){ //0,-10 can change 2B less sensitive with high load
digitalWrite(13,HIGH);
//will never print past 1 min
//Serial.println();Serial.print(millis()/1000/60);Serial.print(" Min ");Serial.print(nalarm+1);Serial.println(" count");
if(millis()>long(40)*1000){ off(); while(1);} //infinite loop
if(nalarm++>10){ off(); while(1);} //can change 10
} //if load
last=k;
sum=nar=0;
} //if 1024
ccw();
//if(i%16==0)Serial.println(float(i+1)*360/64/8);
//can detect individual outliers here
nar+=8; for(int j=0;j<8;j++) sum+=ar[j];
} //for
} //ccwss()
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
//load detect code is ccwss only for now
}
void ccw4st1(){
dw(mp1, HIGH);
dw(mp2, LOW);
dw(mp3, LOW);
dw(mp4, LOW);
dm(motorSpeed);
//dw(mp1, HIGH);
dw(mp2, HIGH);
//dw(mp3, LOW);
//dw(mp4, LOW);
dm(motorSpeed);
dw(mp1, LOW);
//dw(mp2, HIGH);
//dw(mp3, LOW);
//dw(mp4, LOW);
dm(motorSpeed);
//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(){
dw(mp1, LOW);
dw(mp2, LOW);
dw(mp3, HIGH);
dw(mp4, LOW);
dm(motorSpeed);
//dw(mp1, LOW);
//dw(mp2, LOW);
//dw(mp3, HIGH);
dw(mp4, HIGH);
dm(motorSpeed);
//dw(mp1, LOW);
//dw(mp2, LOW);
dw(mp3, LOW);
//dw(mp4, HIGH);
dm(motorSpeed);
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);
}
//////////////////////////////////////////////////////////////////////////////
//set pins to ULN2003 high in sequence from 1 to 4
void ccw (){
//may throw off rev() and slow() by 14us
//for j loop in ccwss() takes <2ms/rev
int ms=motorSpeed-114; //114 cuz ar 100 calibrated inc code in ccwss()>cwss()
// 1
dw(mp1, HIGH);
dw(mp2, LOW);
dw(mp3, LOW);
dw(mp4, LOW);
ar[0]=analogRead(0);
dm(ms);
// 2
dw(mp1, HIGH);
dw(mp2, HIGH);
dw(mp3, LOW);
dw(mp4, LOW);
ar[1]=analogRead(0);
dm(ms);
// 3
dw(mp1, LOW);
dw(mp2, HIGH);
dw(mp3, LOW);
dw(mp4, LOW);
ar[2]=analogRead(0);
dm(ms);
// 4
dw(mp1, LOW);
dw(mp2, HIGH);
dw(mp3, HIGH);
dw(mp4, LOW);
ar[3]=analogRead(0);
dm(ms);
// 5
dw(mp1, LOW);
dw(mp2, LOW);
dw(mp3, HIGH);
dw(mp4, LOW);
ar[4]=analogRead(0);
dm(ms);
// 6
dw(mp1, LOW);
dw(mp2, LOW);
dw(mp3, HIGH);
dw(mp4, HIGH);
ar[5]=analogRead(0);
dm(ms);
// 7
dw(mp1, LOW);
dw(mp2, LOW);
dw(mp3, LOW);
dw(mp4, HIGH);
ar[6]=analogRead(0);
dm(ms);
// 8
dw(mp1, HIGH);
dw(mp2, LOW);
dw(mp3, LOW);
dw(mp4, HIGH);
ar[7]=analogRead(0);
dm(ms);
}
//////////////////////////////////////////////////////////////////////////////
//set pins to ULN2003 high in sequence from 4 to 1
void cw(){
// 1
dw(mp4, HIGH);
dw(mp3, LOW);
dw(mp2, LOW);
dw(mp1, LOW);
dm(motorSpeed);
// 2
//dw(mp4, HIGH);
dw(mp3, HIGH);
//dw(mp2, LOW);
//dw(mp1, LOW);
dm(motorSpeed);
// 3
dw(mp4, LOW);
//dw(mp3, HIGH);
//dw(mp2, LOW);
//dw(mp1, LOW);
dm(motorSpeed);
// 4
//dw(mp4, LOW);
//dw(mp3, HIGH);
dw(mp2, HIGH);
//dw(mp1, LOW);
dm(motorSpeed);
// 5
//dw(mp4, LOW);
dw(mp3, LOW);
//dw(mp2, HIGH);
//dw(mp1, LOW);
dm(motorSpeed);
// 6
//dw(mp4, LOW);
//dw(mp3, LOW);
//dw(mp2, HIGH);
dw(mp1, HIGH);
dm(motorSpeed);
// 7
//dw(mp4, LOW);
//dw(mp3, LOW);
dw(mp2, LOW);
//dw(mp1, HIGH);
dm(motorSpeed);
// 8
dw(mp4, HIGH);
//dw(mp3, LOW);
//dw(mp2, LOW);
//dw(mp1, HIGH);
dm(motorSpeed);
}
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);
break;
case 1:
dw(mp4, HIGH);
dw(mp3, HIGH);
dw(mp2, LOW);
dw(mp1, LOW);
break;
case 2:
dw(mp4, LOW);
dw(mp3, HIGH);
dw(mp2, LOW);
dw(mp1, LOW);
break;
case 3:
dw(mp4, LOW);
dw(mp3, HIGH);
dw(mp2, HIGH);
dw(mp1, LOW);
break;
case 4:
dw(mp4, LOW);
dw(mp3, LOW);
dw(mp2, HIGH);
dw(mp1, LOW);
break;
case 5:
dw(mp4, LOW);
dw(mp3, LOW);
dw(mp2, HIGH);
dw(mp1, HIGH);
break;
case 6:
dw(mp4, LOW);
dw(mp3, LOW);
dw(mp2, LOW);
dw(mp1, HIGH);
break;
case 7:
dw(mp4, HIGH);
dw(mp3, LOW);
dw(mp2, LOW);
dw(mp1, HIGH);
break;
}
//for all cases
dm(motorSpeed);
}
void st03(){
if(stepnum==-1)stepnum=3;
if(stepnum== 4)stepnum=0;
switch(stepnum){
case 0:
dw(mp4, HIGH);
dw(mp3, LOW);
dw(mp2, LOW);
dw(mp1, LOW);
break;
case 1:
dw(mp4, LOW);
dw(mp3, HIGH);
dw(mp2, LOW);
dw(mp1, LOW);
break;
case 2:
dw(mp4, LOW);
dw(mp3, LOW);
dw(mp2, HIGH);
dw(mp1, LOW);
break;
case 3:
dw(mp4, LOW);
dw(mp3, LOW);
dw(mp2, LOW);
dw(mp1, HIGH);
break;
}
//for all cases
dm(motorSpeed);
}
void st03aw(){
if(stepnum==-1)stepnum=3;
if(stepnum== 4)stepnum=0;
switch(stepnum){
case 0:
AW41
AW30
AW20
AW10
break;
case 1:
AW40
AW31
AW20
AW10
break;
case 2:
AW40
AW30
AW21
AW10
break;
case 3:
AW40
AW30
AW20
AW11
break;
}
//for all cases
dm(motorSpeed);
}
void sinemod(){
//sine wave modulation smoother
//fastest is 0,126,128,1 = 3ms if less use lowpmidsp()
//slower than 100 use slowpwr()
//motorspeed=((hi-lo+1)*de1+sp) or 9*2+5 not x4
const int sp=22;
const int lo=120; //was110, 120-126 fastest
const int hi=128; //was128
const int de1=2;
const int pwrsav=110; //50-130 almost 255 need 130 for pin 13 only cuz NOT PWM
//5,50 15,110 500,120 is good pwrsave depends on sp, 112 useful when slow
//de(1) is weak
int i;
for(i=hi;i>=lo;i--){aw(mp1a,i);aw(mp2a,hi-i+lo);de(de1);}aw(mp1a,0);aw(mp2a,pwrsav);de(sp);
for(i=hi;i>=lo;i--){aw(mp2a,i);aw(mp3a,hi-i+lo);de(de1);}aw(mp2a,0);aw(mp3a,pwrsav);de(sp);
for(i=hi;i>=lo;i--){aw(mp3a,i);aw(mp4a,hi-i+lo);de(de1);}aw(mp3a,0);aw(mp4a,130);de(sp); //difference cuz NOT PWM
for(i=hi;i>=lo;i--){aw(mp4a,i);aw(mp1a,hi-i+lo);de(de1);}aw(mp4a,0);aw(mp1a,pwrsav);de(sp);
}
void stophold(int v){
//210-250 is 2.1-2.5v
off();
//aw(mp1a,v*25/5/10); //test 256/5/100 or just /2
switch(stepnum){
//case 0:aw(mp4a,130); break;
case 0:aw(mp3a,v*25/5/10);break; //mp4 off mp3 twice bug cuz 13 NOT PWM
case 1:aw(mp3a,v*25/5/10);break;
case 2:aw(mp2a,v*25/5/10);break;
case 3:aw(mp1a,v*25/5/10);break;
}}
void topspeed(int cw){
//define volt 1
motorSpeed=1;
stepnum-=cw;
movecnt++;
st03();
st03aw();
fastout;
//500 OK 700 safe can add 100-200 any of 3 places below
//sum of 3 dm range 800-1000 stronger
if(movecnt%100)dm(500); else dm(800);
fastin; //matters less
dm(250); //was 250
AW10 AW20 AW30 AW40 //how can this matter? It really does try it!
dm(250); //was 50. 250 best for a little power savings
}
void topspeed_nocap(int cw){
motorSpeed=1;
stepnum-=cw;
movecnt++;
st03();
//900,1200 works
if(movecnt%100)dm(1500); else dm(1800);
}
void toppwr(int cw){
//define volt 1 no need
motorSpeed=1;
stepnum-=cw;
movecnt++;
st03();
fastout; //already?
dm(2000);
}
void lowpmidsp(){
motorSpeed=1;
stepnum++;
movecnt++;
st03();
st03aw(); //define volt 1v
fastout;
//20 less power
//if 20,50 smoother at slow speeds
//dm 50,1200 borderline safe long term temp driver IC hotter than motor
//dm 20,3000 body temp
if(movecnt%100)dm(20); else dm(100); //if 20,50 or 500 makes click to restart stalled
fastin;
dm(3000); //1200-3000 1/speed slower use sinemod()
}
void slowpwr(){
motorSpeed=1;
stepnum++;
movecnt++;
fastout;
st03();
st03aw(); //define volt 1
de(1);
fastin;
stophold(210); //210-250, 220 warm, 210 cool
de(40); //speed <100 use sinemod
AW10 AW20 AW30 AW40
}
void fastcam(){
//req 1uf cap or use alternative code topspeed_nocap()
toppwr(1); de(80);
toppwr(1); de(3); // 3+2 = 1/5 topspeed
toppwr(1);
for(ii=0;ii<60/2*40/36-3-5;ii++) topspeed(1);
for(ii=0;ii<5;ii++) {topspeed(1); de(12*ii);}
stophold(220); de(2000);
toppwr(-1); de(7);
toppwr(-1); de(5);
for(ii=0;ii<60/2*40/36-2;ii++) topspeed(-1);
stophold(210); de(2000);
}
void degrpm1A(boolean bcw, long deg100, int rpm100) {
int cw;
if(bcw) cw=1; else cw=-1;
//rpm100=10000; //300RPM max 100RPM 5v runs cold
//motorSpeed overflow when RPM=1 use d in 1Aslow() instead
//use mydelayus() in st07() for multitasking untested
motorSpeed=(long(14630)*4096/4 )/rpm100-20;
//motorSpeed/=4; //1/4 duty warm 10RPM still ok full duty? IC hotter than motor?
for(int i=0;i<deg100*40/36/100;i++) {
stepnum+=cw;
movecnt++;
st07(); //st07 is half step 1500 fastest
//off();dm(motorSpeed*3); //1/4 duty
}}
void degrpm1Arampduty(boolean bcw, long deg100, int rpm100) {
int cw;
if(bcw) cw=1; else cw=-1;
rpm100=5000; //300RPM max 100RPM 5v runs cold 100RPM max 1/4 duty >250 skips on start no load
//cannnot spin DSLR at 100RPM?
//use mydelayus() in st07() for multitasking and dm and delay at bottom untested
motorSpeed=2*(long(14630)*4096/4 )/rpm100-20;
for(int i=0;i<10;i++) {
stepnum+=cw;
movecnt++;
st07();
}
motorSpeed= (long(14630)*4096/4 )/rpm100-20;
for(int i=0;i<10;i++) {
stepnum+=cw;
movecnt++;
st07();
}
motorSpeed/=4;
for(int i=0;i<deg100*40/36/100-20;i++) {
stepnum+=cw;
movecnt++;
st07();
off();dm(motorSpeed*3); //1/4 duty
}
st07();delay(500); //hold for 1/2s
off();
}
void degrpm1Aslow(boolean bcw, long deg100, int rpm100) {
int cw,d;
if(bcw) cw=1; else cw=-1;
//motorSpeed overflow when RPM=1 use d instead
//jerky like drum beat when 5v half step st07() cuz cannot drive 2 coils on same side of board/LED's adjacent
//use st03() instead?
motorSpeed=(long(14630)*4096/4 )/rpm100-20; //*1000 below microsec
d= (long(1463 )*4096/400)/rpm100; motorSpeed=1;
//d/=2; //1/2 duty continuous only warm at 10RPM
for(int i=0;i<deg100*40/36/100;i++) {
stepnum+=cw;
movecnt++;
st07(); //st07 is half step 1500 fastest
mydelay(d); //motorSpeed tiny in st07
//off();mydelay(d); //1/2 duty
}}
void mydelay(long d){
long ms=millis();
while(millis()<ms+d) {
//10RPM is 15ms
//do anything here instead of delay(1)
delay(1);
}}
void mydelayus(long d){
long ms=micros();
while(micros()<ms+d) {
//100RPM is 1500us
//do anything here instead of delay
delayMicroseconds(100);
}}
/*
need 1uf cap and 1k res:
sto3aw
sinemod
stophold
topspeed
lowpmid
slowpwr
!toppwr
!st03
*/
#define dw digitalWrite
#define dm delayMicroseconds
#define de delay
#define P(s) Serial.print(s);
#define P32 Serial.write(32);
#define P13 Serial.write(10);
#define fastout {pinMode(mp1,OUTPUT);pinMode(mp2,OUTPUT);pinMode(mp3,OUTPUT);pinMode(mp4,OUTPUT);}
#define fastin {pinMode(mp1,INPUT );pinMode(mp2,INPUT );pinMode(mp3,INPUT );pinMode(mp4,INPUT );}
const int mp1 = 2; // Blue - 28BYJ48 pin 1
const int mp2 = 3; // Pink - 28BYJ48 pin 2
const int mp3 = 4; // Yellow - 28BYJ48 pin 3
const int mp4 = 5; // Orange - 28BYJ48 pin 4
// Red - 28BYJ48 pin 5 VCC
long motorSpeed=3000; // set stepper speed, period actually, changed long for 1A not used?
int stepnum=0; // current microstep 0-7
int movecnt=0; // running total of steps taken in move(), &=4095 in moveto
long m; // millis()
void setup() {
fastout
//Serial.begin(9600);
}
void loop(){
//half step wo 1uf cap 1k res st07()
//10x faster, 10x more deg/step than little motor 64:1 gear
//600 fastest
//1000 stronger
//1600 1/4 duty
//2000 1/4 ideal no vibe but weak
//3200 1/4 slowest wo vibe, smoother=full duty
//5000 slowest full duty
//3000 fastest st03aw (3v critical) same speed as 1500 1/4 duty cuz 4/8 steps
//5000 strong w 1uf caps st03aw
//900 full step st03() is 450 faster than half step
//degrpm1Arampduty(0,18000,10000); de(500);
//degrpm1Arampduty(1,18000,10000); de(500);
degrpm1A(1,180000,100); de(1000);
}
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);
break;
case 1:
dw(mp4, HIGH);
dw(mp3, HIGH);
dw(mp2, LOW);
dw(mp1, LOW);
break;
case 2:
dw(mp4, LOW);
dw(mp3, HIGH);
dw(mp2, LOW);
dw(mp1, LOW);
break;
case 3:
dw(mp4, LOW);
dw(mp3, HIGH);
dw(mp2, HIGH);
dw(mp1, LOW);
break;
case 4:
dw(mp4, LOW);
dw(mp3, LOW);
dw(mp2, HIGH);
dw(mp1, LOW);
break;
case 5:
dw(mp4, LOW);
dw(mp3, LOW);
dw(mp2, HIGH);
dw(mp1, HIGH);
break;
case 6:
dw(mp4, LOW);
dw(mp3, LOW);
dw(mp2, LOW);
dw(mp1, HIGH);
break;
case 7:
dw(mp4, HIGH);
dw(mp3, LOW);
dw(mp2, LOW);
dw(mp1, HIGH);
break;
}
//for all cases
dm(motorSpeed);
}
void st03(){
if(stepnum==-1)stepnum=3;
if(stepnum== 4)stepnum=0;
switch(stepnum){
case 0:
dw(mp4, HIGH); //can do 4 steps 2 coils at once, but need bigger power supply 12v 2A -> 5A
dw(mp3, LOW); //no improvement with current PS runs much hotter with 5A PS
dw(mp2, LOW);
dw(mp1, LOW);
break;
case 1:
dw(mp4, LOW);
dw(mp3, HIGH);
dw(mp2, LOW);
dw(mp1, LOW);
break;
case 2:
dw(mp4, LOW);
dw(mp3, LOW);
dw(mp2, HIGH);
dw(mp1, LOW);
break;
case 3:
dw(mp4, LOW);
dw(mp3, LOW);
dw(mp2, LOW);
dw(mp1, HIGH);
break;
}
//for all cases
dm(motorSpeed);
}
void off(){
dw(mp1, LOW);
dw(mp2, LOW);
dw(mp3, LOW);
dw(mp4, LOW);
}
void topspeed_nocap(int cw){
motorSpeed=1;
stepnum-=cw;
movecnt++;
st03();
//900,1200 works
if(movecnt%100)dm(1500); else dm(1800);
}
void toppwr(int cw){
//define volt 1 no need
motorSpeed=1;
stepnum-=cw;
movecnt++;
st03();
fastout; //already?
dm(2000);
}
void degrpm1A(boolean bcw, long deg100, int rpm100) {
int cw;
if(bcw) cw=1; else cw=-1;
//rpm100=30000; //300RPM max 100RPM 5v runs cold
//motorSpeed overflow when RPM=1 use d in 1Aslow() instead
//use mydelayus() in st07() for multitasking untested
motorSpeed=(long(14630)*4096/4 )/rpm100-20;
//motorSpeed/=4; //1/4 duty warm 10RPM still ok full duty? IC hotter than motor?
for(int i=0;i<deg100*40/36/100;i++) {
stepnum+=cw;
movecnt++;
st07(); //st07 is half step 1500us fastest, st03 faster 32RPM
//off();dm(motorSpeed*3); //1/4 duty
}}
void degrpm1Arampduty(boolean bcw, long deg100, int rpm100) {
int cw;
if(bcw) cw=1; else cw=-1;
rpm100=5000; //300RPM max 100RPM 5v runs cold 100RPM max 1/4 duty >250 skips on start no load
//cannnot spin DSLR at 100RPM?
//use mydelayus() in st07() for multitasking and dm and delay at bottom untested
motorSpeed=2*(long(14630)*4096/4 )/rpm100-20;
for(int i=0;i<10;i++) {
stepnum+=cw;
movecnt++;
st07();
}
motorSpeed= (long(14630)*4096/4 )/rpm100-20;
for(int i=0;i<10;i++) {
stepnum+=cw;
movecnt++;
st07();
}
motorSpeed/=4;
for(int i=0;i<deg100*40/36/100-20;i++) {
stepnum+=cw;
movecnt++;
st07();
off();dm(motorSpeed*3); //1/4 duty
}
st07();delay(500); //hold for 1/2s
off();
}
void degrpm1Aslow(boolean bcw, long deg100, int rpm100) {
int cw,d;
if(bcw) cw=1; else cw=-1;
//motorSpeed overflow when RPM=1 use d instead
//jerky like drum beat when 5v half step st07() cuz cannot drive 2 coils on same side of board/LED's adjacent
//use st03() instead
motorSpeed=(long(14630)*4096/4 )/rpm100-20; //*1000 below microsec
d= (long(1463 )*4096/400)/rpm100; motorSpeed=1;
//d/=2; //1/2 duty continuous only warm at 10RPM
for(int i=0;i<deg100*40/36/100;i++) {
stepnum+=cw;
movecnt++;
st07(); //st07 is half step 1500 fastest
mydelay(d); //motorSpeed tiny in st07
//off();mydelay(d); //1/2 duty
}}
void mydelay(long d){
long ms=millis();
while(millis()<ms+d) {
//10RPM is 15ms
//do anything here instead of delay(1)
delay(1);
}}
void mydelayus(long d){
long ms=micros();
while(micros()<ms+d) {
//100RPM is 1500us
//do anything here instead of delay
delayMicroseconds(100);
}}
/*
need 1uf cap and 1k res:
sto3aw
sinemod
stophold
topspeed
lowpmid
slowpwr
!toppwr
!st03
*/
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment