Dual Stepper Control
This is the header file:
//fcm3 ... 3rd revision //////////////////////////////////////////////// // - - - - stepper control via serial - - - - // // this method uses 8 bit timers, so it has a // // limitation of a maximum delay of around 16 // // milliseconds between steps, not perfect... // //////////////////////////////////////////////// // - * - * - * - * - * - * - * - #include#define F_CPU 14745600UL #include #include #include #define BAUDRATE 9600 //baud prescale will be 95 for 14.7456MHz and 9600 baud rate #define BAUD_PRESCALE (((F_CPU / (BAUDRATE * 16UL))) - 1) #define NO_STEPS 8 #define M1_PORT PORTC #define M1_DDR DDRC #define M1_PIN1 PORTC0 #define M1_PIN2 PORTC1 #define M1_PIN3 PORTC2 #define M1_PIN4 PORTC3 #define M2_PORT PORTD #define M2_DDR DDRD #define M2_PIN1 PORTD4 #define M2_PIN2 PORTD5 #define M2_PIN3 PORTD6 #define M2_PIN4 PORTD7 #define RX_BUFFERSIZE 10 // STRUCTS typedef struct { uint8_t dir; uint16_t noSteps; uint16_t timeDelay; uint16_t counter; } Motor; // INIT FUNCTIONS void initUSART(void); void initMotors(void); void initTimers(void); // MAIN FUNCTIONS void changeStep(char motor, char p1, char p2, char p3, char p4); void delay_ms(int d); void moveHalfStep(char motor, char stepCount); void setMotors(void); // DATA volatile Motor motor1; volatile Motor motor2; int8_t stepCount1, stepCount2; volatile uint8_t rxBuffer[RX_BUFFERSIZE]; //this holds all the serial data volatile uint8_t rxbc; // rx buffer counter
This is the main c file:
#include "fcm3.h" int main (void) { initUSART(); initMotors(); initTimers(); sei(); //give the steppers a nice value to begin with //this just shows that they are working and motor1.dir = 1; motor1.noSteps = 400; motor1.timeDelay = 50; motor1.counter = 0; motor2.dir = 1; motor2.noSteps = 400; motor2.timeDelay = 50; motor2.counter = 0; while (1) { // motor1 if (TCNT2 > motor1.timeDelay && motor1.counter < motor1.noSteps) { moveHalfStep(1, stepCount1); if (stepCount1 == NO_STEPS) stepCount1 = 0; else if (stepCount2 == 0) stepCount2 = NO_STEPS; if (motor1.dir) stepCount1++; else stepCount1--; TCNT2 = 0; motor1.counter++; } // motor2 if (TCNT0 > motor2.timeDelay && motor2.counter < motor2.noSteps) { moveHalfStep(2, stepCount2); if (stepCount2 == NO_STEPS) stepCount2 = 0; else if (stepCount2 == 0) stepCount2 = NO_STEPS; if (motor2.dir) stepCount2++; else stepCount2--; TCNT0 = 0; motor2.counter++; } } return 0; } // INTERRUPT FUNCTIONS ISR(USART_RXC_vect) { rxBuffer[rxbc] = UDR; rxbc++; if (rxbc == RX_BUFFERSIZE) { setMotors(); rxbc = 0; } } // MAIN FUNCTIONS void setMotors(void) { motor1.dir = rxBuffer[0]; motor1.noSteps = (rxBuffer[1] | (rxBuffer[2]<<8)); motor1.timeDelay = (rxBuffer[3] | (rxBuffer[4]<<8)); motor1.counter = 0; motor2.dir = rxBuffer[5]; motor2.noSteps = (rxBuffer[6] | (rxBuffer[7]<<8)); motor2.timeDelay = (rxBuffer[8] | (rxBuffer[9]<<8)); motor2.counter = 0; } void moveHalfStep(char motor, char stepCount) { switch (stepCount % NO_STEPS) { case 0: changeStep(motor, 1, 0, 0, 0); break; case 1: changeStep(motor, 1, 0, 1, 0); break; case 2: changeStep(motor, 0, 0, 1, 0); break; case 3: changeStep(motor, 0, 1, 1, 0); break; case 4: changeStep(motor, 0, 1, 0, 0); break; case 5: changeStep(motor, 0, 1, 0, 1); break; case 6: changeStep(motor, 0, 0, 0, 1); break; case 7: changeStep(motor, 1, 0, 0, 1); break; } } void changeStep(char motor, char p1, char p2, char p3, char p4) { switch (motor) { case 1: if (p1 == 0) M1_PORT |= (1<<M1_PIN1); else M1_PORT &= ~(1<<M1_PIN1); if (p2 == 0) M1_PORT |= (1<<M1_PIN2); else M1_PORT &= ~(1<<M1_PIN2); if (p3 == 0) M1_PORT |= (1<<M1_PIN3); else M1_PORT &= ~(1<<M1_PIN3); if (p4 == 0) M1_PORT |= (1<<M1_PIN4); else M1_PORT &= ~(1<<M1_PIN4); break; case 2: if (p1 == 0) M2_PORT |= (1<<M2_PIN1); else M2_PORT &= ~(1<<M2_PIN1); if (p2 == 0) M2_PORT |= (1<<M2_PIN2); else M2_PORT &= ~(1<<M2_PIN2); if (p3 == 0) M2_PORT |= (1<<M2_PIN3); else M2_PORT &= ~(1<<M2_PIN3); if (p4 == 0) M2_PORT |= (1<<M2_PIN4); else M2_PORT &= ~(1<<M2_PIN4); break; } } void delay_ms(int d) { while (d) { _delay_ms(0.97); d--; } } // INIT FUNCTIONS void initUSART(void) { //enable USART transmissions and reception UCSRB|= (1<<TXEN) | (1<<RXEN) | (1<<RXCIE); //use 8 bit character size UCSRC |= (1<<UCSZ1) | (1<<UCSZ0); UBRRL = BAUD_PRESCALE; //load upper 8 bits to high register UBRRH = (BAUD_PRESCALE>>8); } void initMotors(void) { //set up all pins M1_DDR |= (1<<M1_PIN1) | (1<<M1_PIN2) | (1<<M1_PIN3) | (1<<M1_PIN4); M1_PORT |= (1<<M1_PIN1) | (1<<M1_PIN2) | (1<<M1_PIN3) | (1<<M1_PIN4); M2_DDR |= (1<<M2_PIN1) | (1<<M2_PIN2) | (1<<M2_PIN3) | (1<<M2_PIN4); M2_PORT |= (1<<M2_PIN1) | (1<<M2_PIN2) | (1<<M2_PIN3) | (1<<M2_PIN4); } void initTimers(void) { //set timer0 to prescale of 1024 TCCR0 |= (1<<CS00) | (1<<CS02); //set timer2 to prescale of 1024 TCCR2 |= (1<<CS22) | (1<<CS21) | (1<<CS20); }
For the laptop, with a serial connection set up, I used this:
short int steps1, steps2; float time1, time2; printf("> "); while (scanf("%hd %f %hd %f", &steps1, &time1, &steps2, &time2) == 4) { //convert to 1 byte int asteps1 = abs(steps1); int asteps2 = abs(steps2); unsigned char s10 = (unsigned char) asteps1; unsigned char s11 = (unsigned char) (asteps1>>8); unsigned char s20 = (unsigned char) asteps2; unsigned char s21 = (unsigned char) (asteps2>>8); //we multiply time by 14.4 as it given in milliseconds //and out crystal is running at 14.7456MHz w/ a timer prescale of 1024 //therefore 14.4 timer completions is 1ms short int t1 = (short) floor(time1*14.4); short int t2 = floor(time2*14.4); unsigned char t10 = (unsigned char) t1; unsigned char t11 = (unsigned char) (t1>>8); unsigned char t20 = (unsigned char) t2; unsigned char t21 = (unsigned char) (t2>>8); //steps for motor1 if (steps1 > 0) serial.writeByte(0); else serial.writeByte(1); serial.writeByte(s10); serial.writeByte(s11); //time for motor1 serial.writeByte(t10); serial.writeByte(t11); //steps for motor2 if (steps2 > 0) serial.writeByte(0); else serial.writeByte(1); serial.writeByte(s20); serial.writeByte(s21); //time for motor2 serial.writeByte(t20); serial.writeByte(t21); //these are just for printing out... int ss1 = ((s11<<8) | s10); int ss2 = ((s21<<8) | s20); int tt1 = ((t11<<8) | t10); int tt2 = ((t21<<8) | t20); printf("wrote %i %i %i %i \n", ss1, tt1, ss2, tt2); printf("> "); }