256 microstepping example for stepper motors

Status
Not open for further replies.

JBeale

Well-known member
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

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:
Code:
  ...
  analogWriteFrequency(CH1, 46875);  // ideal PWM freq for 10 bits, CPU @ 48MHz
  analogWriteFrequency(CH3, 46875);  // ideal PWM freq for 10 bits, CPU @ 48MHz
  ...

Hello, JBeale.

Thank you for such a good solution.

I am just bit worried if I have Teensy 3.1(2) should I put here a 70312 or something?
 
Status
Not open for further replies.
Back
Top