Linistepper Equatorial Drive Source

/******************************************************************************
  Lini_Telescope.c   v1.0    10th Dec 2011 - Roman Black
  written in MikroC, open-source (but please credit me as the author)
  Code size is small, this should compile ok in the free version of MikroC.

  This code drives the LiniStepper open-source stepper motor controller
  at either of 2 fixed speeds. The speeds can be adjusted to a very high
  resolution (suitable for telescope or other precision movement).

  The stepper motor always drives in microsteps (usteps), 6 usteps to a
  full step, which gives 1200 usteps per motor rotation.

  PIC 16F628A, using 3 control input pins;
  PORTA.F0 = INPUT_RUN run; (0v=run, 5v=stop)
  PORTA.F1 = INPUT_DIR motor direction; (0v=forward, 5v=reverse)
  PORTA.F2 = INPUT_SPEED selects speed 1 or speed 2; (0v=speed1, 5v=speed2)
  (note! the 2 dipswitches on the LiniStepper are not used).

// NOTE! Set TABS to 2 for best viewing
******************************************************************************/
/*
PIC16F628A;
_BODEN_OFF   // these configs are set in MikroC compiler options.
_PWRTE_ON
_WDT_OFF
_LVP_OFF
_MCLRE_ON
_HS_OSC
*/

// PIC pin defines for the user control pins
#define INPUT_RUN    PORTA.F0
#define INPUT_DIR    PORTA.F1
#define INPUT_SPEED  PORTA.F2

// set these values to the periods you want, to set the 2 possible motor speeds
// these set the period for a ustep. period is in nanoseconds,
// so a period of 15 million = 15mS = 15 milliSeconds
// 15mS times 1200 usteps (1 motor rev) is 1200*0.015 or 18 seconds per motor rev.
// (the largest value you can use here is about 1 billion, as signed long vars are used)
#define SPEED1   15000000     // approx 18 secs/rev
#define SPEED2     833000     // approx 1 sec/rev

// set the value of the XTAL you are using with the PIC
// value is in Hz, so a 16MHz XTAL = 16 million
#define XTAL_HZ  8000000      // tested with 8MHz xtal

// DO NOT CHANGE this define below! it calculates the nanoseconds of 1 interrupt
#define PERIOD_INT (1024000000 / (XTAL_HZ/4000))


// variables
unsigned char ustep;      // used for motor microstep sequencing
signed long bres;         // used for ustep period generation
signed long speed;        // "

// table of stepper currents; CCCCxxxx and phasing; xxxxPPPP, all on PORTB
const unsigned char table[24] = {
                  // CURRENT              PHASING
  0b11001010,     // 1100xxxx (100:0)     A+ B+  xxxx1010
  0b11011010,     // 1101xxxx (100:25)
  0b11101010,     // 1110xxxx (100:55)
  0b11111010,     // 1111xxxx (100:100)
  0b10111010,     // 1011xxxx (55:100)
  0b01111010,     // 0111xxxx (25:100)

  0b00110110,     // 0011xxxx (0:100)     A- B+  xxxx0110
  0b01110110,     // 0111xxxx (25:100)
  0b10110110,     // 1011xxxx (55:100)
  0b11110110,     // 1111xxxx (100:100)
  0b11100110,     // 1110xxxx (100:55)
  0b11010110,     // 1101xxxx (100:25)

  0b11000101,     //                      A- B-  xxxx0101
  0b11010101,     //
  0b11100101,     // 
  0b11110101,     //
  0b10110101,     //
  0b01110101,     //

  0b00111001,     //                      A+ B-  xxxx1001
  0b01111001,     //
  0b10111001,     // 
  0b11111001,     //
  0b11101001,     //
  0b11011001      //
};


//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//  INTERRUPT
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
void interrupt(void)
{
  //---------------------------------------------
  // this is the TMR0 overflow interrupt, TMR0 is prescaled at
  // 4:1 so int occurs every 1024 instructions.
  // this int is a bresenham system that generates a very precise AVERAGE
  // time period for every ustep (which gives a precise motor speed).
  //---------------------------------------------
  // if motor running is selected, add one more interrupt time period (in nS)
  // to bresenham accumulator
  if(INPUT_RUN == 0) bres += PERIOD_INT;

  // set the motor ustep period, depending on speed control input pin
  if(INPUT_SPEED == 0) speed = SPEED1;
  else                 speed = SPEED2;

  // test for bresenham overflow, and if so, move one ustep
  if(bres >= speed)
  {
    bres -= speed;              // remove one ustep from bres accumulator
    if(INPUT_DIR == 0)
    {
      ustep++;                  // move forward a ustep
      if(ustep >= 24) ustep = 0;
    }
    else
    {
      ustep--;                  // else move backward a ustep
      if(ustep >= 24) ustep = 23;
    }
    PORTB = table[ustep];       // set motor currents to the new ustep
  }
  //---------------------------------------------
  INTCON.T0IF = 0;              // must clear TMR0 overflow flag before exit
}
//-----------------------------------------------------------------------------



//=============================================================================
//  MAIN
//=============================================================================
void main()
{
  //---------------------------------------------
  // setup the PIC port registers etc
  CMCON = 0x07;      // set all pins to digital, comparators off

  PORTA =  0b00000000;    // start values for pins
  TRISA  = 0b00011111;    // all PORTA pins are inputs

  PORTB =  0b00000000;    // start values for pins
  TRISB  = 0b00000000;     // all PORTB pins are outputs

  //-------------------------------------------------
  // PIC TIMER setups;
  // TMR0 is used for generating the ustep period
  OPTION_REG = 0b10000001;  // TMR0 ON, at 4:1, PORTB pullups OFF

  //-------------------------------------------------
  // setup variables etc
  delay_ms(200);            // a small delay to allow voltages to stabilise

  ustep = 0;                // start with motor on ustep 0 (of 0-23)
  PORTB = table[ustep];

  INTCON.T0IE = 1;          // turn the TMR0 interrupt on
  INTCON.GIE = 1;           // and enable interrupts

  //-------------------------------------------------
  // as everything is done in the interrupt, the main loop
  // does nothing!
  //-------------------------------------------------
  // main run loop here
  while(1)
  {
    // do nothing and allow interrupt to do its job
  }
  //-------------------------------------------------
}
//-----------------------------------------------------------------------------