I don't know if anyone has posted similar code, probably they have and I just haven't seen it. So this is mostly just a note to myself, because I find stuff easier here than on my own hard drive.
This code is for Teensy 3/3.1. It uses 1/256 microstepping with 4 channels of PWM to smoothly drive a 5-wire stepper such as the 28BYJ-48 geared stepper together with ULN2003 driver board (about $3 on ebay). If you try it, note the driver board wants the 4 signals connected as 1,3,2,4 instead of 1,2,3,4 as you might expect.
Microstepping doesn't necessarily give you better resolution, due to backlash and torque-dependent offset, but it does give you smoother and quieter motion, particularly at slow speeds, than the usual approach like http://forum.pjrc.com/threads/25526-Teensy-3-0-and-stepper-motors?highlight=28BYJ-48
This code is for Teensy 3/3.1. It uses 1/256 microstepping with 4 channels of PWM to smoothly drive a 5-wire stepper such as the 28BYJ-48 geared stepper together with ULN2003 driver board (about $3 on ebay). If you try it, note the driver board wants the 4 signals connected as 1,3,2,4 instead of 1,2,3,4 as you might expect.
Microstepping doesn't necessarily give you better resolution, due to backlash and torque-dependent offset, but it does give you smoother and quieter motion, particularly at slow speeds, than the usual approach like http://forum.pjrc.com/threads/25526-Teensy-3-0-and-stepper-motors?highlight=28BYJ-48
Code:
// test PWM output on T3.1
// see also: http://www.pjrc.com/teensy/td_pulse.html
// J.Beale 9 Aug. 2014
#define CH1 3 // PWM pin channel 1
#define CH2 4 // PWM pin channel 2
#define CH3 5 // PWM pin channel 3
#define CH4 6 // PWM pin channel 4
#define PI (3.1415926535897932384626433832795) // only slightly excessive
#define PWMRES (10) // bits of PWM resolution
#define MAXPWM (1023) // maximum PWM value
#define ABINS (256) // # of lines in sine lookup table
#define LCMAX (5000) // # of full cycles until we reverse direction
#define LED1 13 // digital output with LED
#define SMIN (1.0/200) // minimum speed
#define SMAX (1.0/20) // maximum speed
#define TSTEP (150) // time in msec between changes in speed
short int SINE_TABLE[ABINS]; // sine lookup table
float sinc; // time delay increment
float spd, dly;
long lcount; // loop count (number of full cycles of 2*pi)
int minima; // how many minimum-speed moments have we passed through?
boolean rev; // true when we are running in reverse
unsigned long tnow, tlast;
void setup() {
digitalWrite(LED1,0);
analogWriteResolution(PWMRES);
analogWriteFrequency(CH1, 46875); // ideal PWM freq for 10 bits, CPU @ 48MHz
analogWriteFrequency(CH3, 46875); // ideal PWM freq for 10 bits, CPU @ 48MHz
pinMode(LED1, OUTPUT); // enable LED as output
for (int i=0; i<ABINS; i++) { // wastefully save full 2*pi rather than just pi/2
float omega = i*2*PI / ABINS;
SINE_TABLE[i] = MAXPWM * sin(omega);
}
sinc = 1.1; // factor for increment in speed
spd = 1/50.0; // actual speed
lcount = 0;
minima = 0;
rev = false;
tlast = millis();
} // end setup
void loop() {
short int A,B,C,D; // PWM setting values
float omega; // current angle in radians
float delta; // stepsize for omega
int k;
digitalWrite(LED1, !rev); // indicate if we are in fwd
lcount++;
tnow = millis();
if ((tnow - tlast) > TSTEP) { // time now for a change in speed?
spd *= sinc;
tlast = tnow;
if (spd > SMAX) { // if now above max speed, start decreasing it
spd = SMAX;
sinc = 1/sinc;
}
if (spd < SMIN) { // if now below minimum speed, start increasing it
sinc = 1/sinc;
spd = SMIN;
minima++;
if ((minima > 2)) { // every so often, change direction of rotation
minima = 0;
rev = !rev;
}
}
}
dly = 1/spd; // delay time is inverse of speed
for (int i=0; i<ABINS; i++) { // do one full cycle of 2pi radians
delayMicroseconds(dly);
int ci = i + ABINS/4;
if (ci >= ABINS) ci = ci - ABINS;
// are we now going in reverse?
if (rev == true) k = (ABINS-1) - i; else k = i;
A = SINE_TABLE[k];
C = SINE_TABLE[ci];
if (A > 0) B=0; else { B = -A; A = 0; } // H-bridge: negative means use 2nd channel
if (C > 0) D=0; else { D = -C; C = 0; }
analogWrite(CH1,A); // update the PWM duty cycle value
analogWrite(CH2,B); // on each of the four outputs...
analogWrite(CH3,C); //
analogWrite(CH4,D); //
}
} // end loop()
Last edited: