New Libray for L298N

I modified my 28BYJ library for L298N with 1.8 degrees per step on a big powerful motor (<1 deg per half step)
http://arduino-info.wikispaces.com/MotorDrivers
You can buy the boards for cheap above.

In addition to this simple library attached as zip, I have another more complex Sketch which requires lots of wiring to 8 pins on the Uno. It uses PWM to vary the average voltage on each pin. This drives the stepper in Sine step mode. It is much smoother without vibration and runs cooler at slow speeds. It also goes significantly faster. Yet without removing the hardware you can run in digital mode with the sketch below. This sketch does not require any special circuit beyond the driver board itself. That's why I decided to start with this one first. You will recognize the variables and function names because I got them from my old library. Like before you can supply my 1v motor with 5v and it will run very cold. I used the regulator on the Uno. Or 12v using 1/4 duty cycle and it will only get warm, with much more torque. At the full voltage you cannot stop a 3/4" bolt from turning with your fingers no matter how hard you squeeze. I've gotten it to go 350RPM with PWM or 300RPM without using this sketch. There is a torque difference.

I've included limited simple speed ramping, and the ability to run other tasks at the same time, even at full speed.
The functions look like this:

void degrpm1A(boolean bcw, long deg100, int rpm100)

Please test it.
Questions?
Steve

step1p1dps.zip (1.74 KB)

Here it is much easier to see:

#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);
degrpm1Aslow(1,18000,100); de(500);
}
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 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=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
*/

A quick look with one remark to improve your work: use function and variable names that are descriptive and you can leave out 98% of the comments..

e.g.

const int mp1 = 2;	// Blue   - 28BYJ48 pin 1   ==>    const uint8_t bluePIn = 2;  //uint8_t == byte    or  use #define BLUEPIN 2 

long m;                 // millis()   ==>   unsigned long millisec;     // millis() returns unsigned long ; duration might be better name?

void st07()    // I don't know what st07 does from its name...
{...

dw(mp4, HIGH);   ==> digitalWrite(ORANGE, HIGH);  is far more readable, shorter functionNames do not execute faster (unfortunatelly :)

motorSpeed is an example of a excellent descriptive name

Furthermore you could write a function like

void setLines( int blue, int pink, int yellow, int orange)   // the name is not ok but 
{
  digitalWrite(BLUEPIN, blue);
  digitalWrite(PINKPIN, pink);
  digitalWrite(YELLOWPIN, yellow);
  digitalWrite(ORANGEPIN, orange);
}

such a function would change the switch into

switch(stepnum){
case 0:
  setlines(HIGH, LOW, LOW, LOW); 
  break;
case 1:
  setlines(HIGH, HIGH, LOW, LOW); 
  break;
case 2:
  setlines(LOW, HIGH, LOW, LOW); 
  break;
case 3:
  setlines(LOW, HIGH, HIGH, LOW); 
  break;
case 4:
  setlines(LOW, LOW, HIGH, LOW); 
  break;
case 5:
  setlines(LOW, LOW, HIGH, HIGH); 
  break;
case 6:
  setlines(LOW, LOW, LOW, HIGH); 
  break;
case 7:
  setlines(HIGH, LOW, LOW, HIGH); 
  break;
}

The above "screams" for an array which holds these HIGH LOW patterns and then the whole switch could become a oneliner

setLines(pattern[stepnum]);

you need the array:

uint8_t pattern[8] = { B00001000, .... };  // 1 is HIGH, 0 = LOW

setLines(uint8_t val)
{
  if (val & B0001000) digitalWrite(BLUEPIN, HIGH);
  else digitalWrite(BLUEPIN, LOW);
  if (val & B0000100) digitalWrite(PINKPIN, HIGH);
  else digitalWrite(PINKPIN, LOW);
  if (val & B0000010) digitalWrite(YELLOWPIN, HIGH);
  else digitalWrite(YELLOWPIN, LOW);
  if (val & B0000001) digitalWrite(ORANGEPIN, HIGH);
  else digitalWrite(ORANGEPIN, LOW);
}

Hope this helps you to improve your library.

Thanks for your feedback I appreciate your taking the time to look at it. dw and st07 work for me, but I can see it would be difficult for others to know what it means without reading my mind. st07 simply means steps going from 0-7. I could spend time changing it from a case statement to bit arrays, but instead I just copied and pasted that from another Sketch without testing. I will try to do better by either commenting or using longer variable names in the future. You can't make me do both! :wink: Kidding... S

motorSpeed is a horrible example of a descriptive name for a variable. This is an example of where it is a bad idea to try to describe the variable in its name. Really I should have called it motorPeriod or motorPeriodOneOverSpeed. MotorSpeed is literally the opposite of what the variable is meant to do in the code. Yet it works and it's readable! If you overlook the fact that it's exactly wrong. Can you imagine if I used Go for a boolean variable that Stops a motor. Bad idea. Sometimes using n or b is better. Instead of stopWhenItsRainingOutside. I hate all the Caps because you have to push the shift key. I guess it's better than stop_when_its_raining_outside. I prefer to use a comment instead. Just my opinion.

I also like short variable names as I don't like typing long names. However I learned that descriptive names (not necessary long) was the most important improvement to understand my own programs after 6 months much faster. Most newer IDE's like visual Studio have name completion so you don't have to type that much.

There are typical cases when you need a for loop than i and j are still favorite.

In Arduino you could write in shorthand notation like DW(PIN, LOW) and do a global search/replace . But in the end its just a choice, if it is a test program, who care, if it is to be maintained by me at least I care :slight_smile:

Tip: why not using L for LOW and H for HIGH? Everyone would understand those macros.

Often I use 0 or 1. Just as short as L or H.

Very true as long as the defintions of LOW and HIGH are not changed :slight_smile:

from wiring.h
#define HIGH 0x1
#define LOW 0x0

Got another sleep over your code and you could write a library for your abbreviated notations, easy to reuse in all your sketches.

just make a folder abbrev under libraries and put this one in. Not tested and to be extended :slight_smile:

//
//    FILE: abbrev.h
//  AUTHOR: Rob Tillaart
//    DATE: 2012-03-30 
//
// PUPROSE: short notation of many Arduino specific commands
//
#ifndef ABBREV_H
#define ABBREV_H

#define L				LOW
#define H				HIGH

#define po(P)			pinMode(P, OUTPUT)
#define pi(P)			pinMode(P, INPUT)

#define dr(P)			digitalRead(P)
#define dw(P,V)			digitalWrite(P,V)

#define ar(P)			analogRead(P)
#define aw(P,V)			analogWrite(P,V)
#define aref(X)			analogReference(X)

#define si(D,C,B)		        shiftIn(D, C, B) 
#define so(D,C,B,A)		shiftOut(D, C, B, A) 

#endif

Hey you're making it easier for me to do what you told me not to! You forgot to say Simon Says?
Maybe it's some kind of programmer sarcasm...

I've been thinking about my code too. Tried Full step drive with 2 phases always on instead of the obsolete wave drive I'm using. It didn't improve the performance one bit, in fact it got worse. This is due to the limitations of my walwart power supply of only 2 amps. In theory it should improve the torque and maximum speed, but the IC and motor would over heat much faster. I considered adding this function to my older library but that would be even hotter than the big motor.

I fixed an error at the top of my thread. 1.8 degrees.

Saw some motors on sale 24v 200ma? What is the advantage of this higher coil resistance?

http://www.bgmicro.com/mot1070.aspx

What is the advantage of a high coil resistance compared to a 1v motor?

Hey you're making it easier for me to do what you told me not to! You forgot to say Simon Says?
Maybe it's some kind of programmer sarcasm...

No not sarcasm, the idea is, if you choose for a certain style, do it to the max :wink: A reusable library is then the way to go.

Those driver circuits all seem to be skipping the current sense resistor, which means you can't do chopping with the driver. Does't that limit the max voltage and torque you can get out of the stepper?

I found this online:
Inductance / Resistance = time constant of the coil
The higher the time constant of your coil, the greater magnetic field you produced for a given power supply.

You are correct. But it depends on your perspective. I am sending the maximum voltage that I have available from my PS to a motor which is designed to run continuously on 1-2v. The 12v supply can only provide 2A instead of the 4A that it might draw. Because there is no sense resistor I am letting too MUCH current flow. It would overheat if it were allowed to continue without pause. If it is running for only a short movement and period I ignore this limit. At top speeds there is no other choice, the running time is limited before the motor overheats (without PWM). At slower speeds you can choose to apply the maximum voltage for 50-100us, then rest between steps. This keeps it running cool and achieves results similar to chopping, but with a manual adjustment instead of sensing. In effect I am choosing the timing of when to chop manually. Instead of using peak current as my criteria, I am maximizing the temperature after running for 5 minutes, to keep it from overheating. I am forced to work within the current limitations of my small power supply. I don't think 12v is a restraining limit for my motor. 2A is below the maximum current. Alternatively I could buy a bigger supply, or use a large capacitor to supply more current for 50us. A chopper circuit would increase the peak current, if it were available from the supply. This would not lower the temperature at the torque I have already achieved. So I am not motivated to make any changes to my circuit. Summary: In my setup the temperature of the motor and IC are the limiting factors. Chopping would not reduce them at the same torque.

I would love to hear a different point of view?

@joogaa- I do like low resistance coils for that reason!

I don't understand what you did in the code. But I can see some misunderstandings. All the degrpm functions have deg then rpm as parameters. So you put 10RPM where deg goes in loop. I didn't mean for you to call mydelay in loop. You can use it for that instead, but I meant it to be called where I put it in the function. Here's how I would do it. I have verified this does not drift on my motors.

degrpm1A(1,9000,1000);
Serial.println("At 0,9,18,270");

I'd be happy to send you my easing library, but it's not so "easy" as this one is. I'm concerned you might need some help with it.

Yes! I will make it into a class. It's under development.

I'm not really microstepping. In this code I am half stepping. The vibration depends on the speed you choose. For big motors my PWM library helps with this. But the circuit is more complex. What motor are you using? What speed is vibrating? I know some tricks.

For x,y line drawing all you'd have to do is glue a laser on a 28BYJ motor shaft (x). Then glue that to another perpendicular (y). Each step is movement in the x or y direction. I haven't gotten to this yet. Maybe it is not fast enough to be persistent.

Did you try the 2 lines I suggested above?
For every hour:

degrpm(1,3000,1000);

If you are using 28byj motor then you are using the wrong code of mine. Use stepper2.pde instead. Did you see the other thread on this forum?

I don't know what to do about vibration when you are moving at the speed of a clock second hand. You can use the analog pins as digital in or out.

Sorry I'm not following the intentions of your code. That's not how I meant it to be used. That's great if it works for you!

Yes, I used the wrong code :blush: back to the drawing board!

The apparent torque depends on the RPM you choose. You can use up to 10x the rated continuous voltage for a stepper. But you cannot leave this voltage on to hold it into position for long. Be careful! Steppers can run hot safely, but there is a limit.

You can buy a powerful and cheap breakout board with this chip on it.
Only 6 downloads so far? It's very easy to use, don't be afraid to try it!
I guess there's no interest in the longer PWM version...