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("> ");
	
	}