/******************************************************************************
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
}
//-------------------------------------------------
}
//-----------------------------------------------------------------------------