//******************************* StepCon.C *********************************** // // Function: This program implements a two stepper motor controller. A // function word is input on the least 4 significant bits of PORTA and the // 8 bits output on PORTB must be fed into a suitable driver (such as the // ULN2803A for unipolar steppers or the L293D for bipolar steppers). // // The 4 bit function word is broken into two two bit function words, one for // each motor. See the motor states in the constant section below (the order // may be changed). // // PORTA<4> is an output pin pulsed for each motor step. One can monitor this // pin and command the motors appropriately. // // The excitation table can also be changed; you may also need to change the // EXCITATION_TABLE_SIZE (eg for half-stepping). // // The motor speeds can be adjusted via the the TMR0 prescaler and the TMR0 // duration; they cannot be individually adjusted. // // Author: Jean-Louis Girard // Copyright: This program may be distributed freely, without profit, // subject to proper acknowledgement. // // Date: August, 2001 // //******************************* Constants *********************************** // #define EXCITATION_TABLE_SIZE 4 // number of excitations in sequence #define TMR0_CNT_UP 100 // 256 - duration (motor speed) #define T0IF 2 // Motor states #define RIGHT_FORWARD 0 #define RIGHT_BACKWARD 1 #define RIGHT_HOLD 2 #define RIGHT_IDLE 3 #define LEFT_FORWARD 0 // RIGHT_FORWARD << 2; #define LEFT_BACKWARD 4 // RIGHT_BACKWARD << 2; #define LEFT_HOLD 8 // RIGHT_HOLD << 2; #define LEFT_IDLE 12 // RIGHT_IDLE << 2; // //**************************** Global Variables ******************************* // char leftExcitationCntr; // current left motor excitation number char rightExcitationCntr; // current right motor excitation number char motorState; // 4 bit function word for both motors (PORTA<3:0>) // Excitation table const char excitations[] = {11000000b, 01100000b, 00110000b, 10010000b}; // //********************************* Functions ********************************* // void motorISR(void) // Modifies global variables leftExcitationCntr and rightExcitationCntr as a // function of motorState. It uses these excitation counters as indices to // read the motor excitation from the table and outputs it to PORTB. { char leftExcitation, rightExcitation; if (((motorState & 0011b) ^ RIGHT_FORWARD) == 0) { if (rightExcitationCntr == EXCITATION_TABLE_SIZE-1) rightExcitationCntr = 0; else rightExcitationCntr++; rightExcitation = excitations[rightExcitationCntr]; } else if (((motorState & 0011b) ^ RIGHT_BACKWARD) == 0) { if (rightExcitationCntr == 0) rightExcitationCntr = EXCITATION_TABLE_SIZE-1; else rightExcitationCntr--; rightExcitation = excitations[rightExcitationCntr]; } else if (((motorState & 0011b) ^ RIGHT_HOLD) == 0) rightExcitation = excitations[rightExcitationCntr]; else // IDLE rightExcitation = 0; rightExcitation >>= 4; // shift high order nibble into low order position if (((motorState & 1100b) ^ LEFT_FORWARD) == 0) { if (leftExcitationCntr == EXCITATION_TABLE_SIZE-1) leftExcitationCntr = 0; else leftExcitationCntr++; leftExcitation = excitations[leftExcitationCntr]; } else if (((motorState & 1100b) ^ LEFT_BACKWARD) == 0) { if (leftExcitationCntr == 0) leftExcitationCntr = EXCITATION_TABLE_SIZE-1; else leftExcitationCntr--; leftExcitation = excitations[leftExcitationCntr]; } else if (((motorState & 1100b) ^ LEFT_HOLD) == 0) leftExcitation = excitations[leftExcitationCntr]; else leftExcitation = 0; PORTB = leftExcitation + rightExcitation; } // //************************ Interrupt Service Routine ************************** // void interrupt(void) { if (INTCON & (1 << T0IF)) // if (TMR0 interrupt) { set_bit(PORTA,4); // { signal motor step on motorISR(); // call motor interrupt service routine clear_bit(PORTA,4); // signal motor step off TMR0 = TMR0_CNT_UP; // reset TMR0 to proper count clear_bit(INTCON,T0IF); // clear TMR0 interrupt flag } // } } // //****************************** Main Program ********************************* // void main(void) { set_bit(STATUS, RP0); // Switch to bank1 TRISA = 00001111b; TRISB = 00000000b; OPTION_REG = 11010101b; // 1:64 TMR0 prescaler clear_bit(STATUS, RP0); // Switch back to bank0 clear_bit(PORTA,4); // clear motor step signal leftExcitationCntr = 0; rightExcitationCntr = 0; TMR0 = TMR0_CNT_UP; clear_bit(INTCON, T0IF); // clear TMR0 interrupt flag enable_interrupt(T0IE); // enable TMR0 interrupts enable_interrupt(GIE); // enable enabled interrupts while (1) // continuously update motorState (and wait motorState = PORTA; // for a TMR0 interrupt) }