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