XPJ5000 code

 

Schematic

 

 

#include <At89x55.h>

// State Variables

#define WAIT 0

#define TRAINING 1

#define REPLAY 2

// Constants

#define MAXINSTRUCTIONS 64

#define VECTORSIZE 64

// Global variables

bit currdir = 1, nextdir = 1, calculateNext = 0;

bit buttonDown = 0, forward = 1;

unsigned char num16BitIntr = 0, numMotorIntr = 0;

unsigned char dirWrite = 0;

char replayCounter = 0;

unsigned char trainingCounter = 64;

unsigned char nextSpeedH = 0, nextSpeedL = 0, currSpeedH = 0, currSpeedL = 0;

unsigned char currMotorIntrDelay = 4;

char tickCount = 0;

unsigned char mode = WAIT;

// Container to hold instructions. Preloaded with some testing data.

// An instruction is 1 byte where the bit 8 is unused, bit 7 is the direction bit, and bits 6 - 1

//  contain the number of steps to turn the motor.

unsigned char instruction[MAXINSTRUCTIONS] = {

0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,0x0C,0x0D,0x0E,0x0F,

0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1A,0x1B,0x1C,0x1D,0x1E,0x1F,

0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x29,0x2A,0x2B,0x2C,0x2D,0x2E,0x2F,

0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30

};

 

// Lookup table to convert a number of ticks read from encoder into a timer setting

// We used the following formula to convert number of steps into timer setting:

// timer_setting = 2^16-(2^16/(num_steps+1))

// this assumes a 16 bit timer.

code short unsigned int speed_vector[VECTORSIZE] = {

00000,32768,43691,49152,52429,54613,56174,57344,

58254,58982,59578,60075,60495,60855,61167,61440,61681,

61895,62087,62259,62415,62557,62687,62805,62915,

63015,63109,63195,63276,63351,63422,63488,63550,

63608,63664,63716,63765,63811,63856,63898,63938,

63976,64012,64047,64080,64111,64142,64171,64199,

64225,64251,64276,64299,64322,64344,64366,64386,

64406,64425,64444,64462,64479,64496,64512

};

 

 

// interrupts approx. every 1/32 sec.

void timer0_isr() interrupt 1 {

  // slow it down to ~1/4 second

  if(++num16BitIntr >= 8) {

    num16BitIntr = 0;

      if (mode == REPLAY) {

        //Set motor timer to fire at appropriate interval

        if(nextSpeedH == 0) ET1 = 0; //no pulses will be sent

        else // start sending pulses to the motor

        {

          ET1 = 1;

          numMotorIntr = 0;

        }

        // load the precalculated instruction

        currSpeedH = nextSpeedH;

        currSpeedL = nextSpeedL;

        currdir = nextdir;

        // set flag to fetch and parse next instruction

        calculateNext = 1;

        P1_3 = 0;

        P1_2 = 1;

    }

    else if (mode == TRAINING) {

        if(tickCount < 0){

          dirWrite = 0x00;

            tickCount = -tickCount;

        }

        else dirWrite = 0x40;

        // max number of ticks is 63 (6 bits) per 1/4 second

        if(tickCount > 63)

            tickCount = 63;

      instruction[trainingCounter++] = tickCount | dirWrite;

        // OR on the direction bit

        tickCount = 0;

        P1_3 = 1;

        P1_2 = 0;

        if (trainingCounter == MAXINSTRUCTIONS)  // filled up the array, quit training mode

          mode = WAIT;

    }

      else{ // mode == WAIT

      P1_3 = 1;

        P1_2 = 1;

      }

  }

  //reset the timer

  TH0 = 0;

  TL0 = 0;

}

 

// Generated by encoder every time the motor moves.

void extTimer1_isr() interrupt 2 {

  if(INT0){  // If it is moving forward increment count

    tickCount++;

  }

  else{  // else it is moving backward so decrement count

      tickCount--;

  }

  // bounds checking on signed char

  if(tickCount >= 127)

    tickCount--;

  if(tickCount <= -127)

    tickCount++;

}

 

// Clock pulse generator to stepper motor

void timer1_isr() interrupt 3 {

  if (++numMotorIntr >= currMotorIntrDelay) {

    P1_5 = currdir;  // set direction

    P1_4 = !P1_4;  // toggle motor clock 

      numMotorIntr = 0;

  }

  // Set the timer to overflow by using the speed to preload the timer.

  TH1 = currSpeedH;

  TL1 = currSpeedL;

}

 

// used during replay mode

void GetNextSpeed() {

 unsigned short int temp;

 if(forward){

    if(trainingCounter > replayCounter){

        unsigned char speed, inst = instruction[replayCounter++];

        nextdir = inst & 0x40;  // direction is the 7th bit of the instruction

        speed = inst & 0x3F;  // speed is the last 6 bits of the instruction

        temp = speed_vector[speed];  // look up value to preload the motor interrupt timer with

        nextSpeedL = (unsigned char)(0x00FF & temp);

        nextSpeedH = (unsigned char)(temp>>8);

    }

    else{  // once the sequence has been played, rewind so you are back where you started

      replayCounter = trainingCounter;

            forward = 0;

            nextSpeedH = 0;

    }

  }

  else{  // rewind mode

    if(replayCounter > 0){

        unsigned char speed, inst = instruction[--replayCounter];

        nextdir = inst & 0x40; // the seventh bit is direction

        nextdir = !nextdir;  // flip the direction since we are rewinding

        speed = inst & 0x3F;

        temp = speed_vector[speed];

        nextSpeedL = (unsigned char)(0x00FF & temp);

        nextSpeedH = (unsigned char)(temp>>8);

    }

    else{  // after rewind is complete stop sending motor pulses until user starts it up again.

        nextSpeedH = 0;

        nextSpeedL = 0;

        ET1 = 0;

    }

  }

}

 

void main() {

  unsigned int x;

  bit j;

  T2 = 1;

  T2_EX = 1;

  P1_2 = 1;

  P1_3 = 1;

  EA = 1; // enable global interrupts

  TR0 = 1; //enable timer 0

  TR1 = 1; //enable timer 1

  TMOD = 0x11;  // Set timer 0 to 16 bit, Set timer 1 to 16 bit

  EX1 = 1;  // Enable external interrupt 1

  ET1 = 1;  // Enable timer 1 interrupt

  IT1 = 1;  // External interrupt 1 is edge triggered

  ET0 = 1;  // Enable timer 0 interupt

  IT0 = 1;  // External interrupt 0 is edge triggered

 

  PT0 = 0; // timer 0 gets low priority

  PT0 = 0;

  PT1 = 0; // timer 1 gets low priority

  PX1 = 1; // external int 1 gets high priority

  while(1) {

   

    // Ready the next instruction so that it is available when the interrupt occurs

    if (calculateNext) {

        calculateNext = 0;

        GetNextSpeed();

      }

      // T2 is training button

    // T2_EX is replay button

      if (buttonDown){

            if (T2 && T2_EX)

                  buttonDown = 0;

      }

      else if (!T2){

        if (mode != TRAINING){

            ET1 = 0; // turn off motor pulses

              TR1 = 1; // just in case

              trainingCounter = 0;

            buttonDown = 1;

              tickCount = 0;

              mode = TRAINING;

        }

      }

      else if (!T2_EX){

        if (mode != REPLAY){

            if (trainingCounter < 4) // Check for switch bounce

               P1_6 = 1;

            else

               P1_6 = 0;

        replayCounter = 0;

            buttonDown = 1;

            forward = 1;

            mode = REPLAY;

            GetNextSpeed();

          ET1 = 1;

            numMotorIntr = 0;

       }

      }

      else{

        if(mode == TRAINING){ // wait for a bit so we don't get erroneous readings

            for(x =0; x < 20000; x++)

                  j = 0;

      }

        P1_5 = 0;

      mode = WAIT;

      ET1 = 0;

      }

  }

}

 

Schematic