/* * stepper driver attempting smooth positioning * using multiple semi-binary resistor values * and a lookup table for sine wave current levels * * Revision 1.0 30-Aug-21 Initial release * * The lookup table has 250 entries per quadrant * * Total number of steps per full cycle is 250 * 4 = 1000 * * Total steps per revolution is 1000 * 50 = 50000 * * Uses 5 resistors per port plus 3 sink resistors * PB4:0 with 5 resistors driving into PC2:0 with 3 resistors * PD6:2 with 5 resistors driving into PC5:3 with 3 resistors * * Driving resistors are 100, 220, 470, 1000, and 2200 ohms * The 5 resistor values selected are reasonably monotonic for all values * Sinking resistors are 3X 100 ohms in parallel * Stepper motor is 30-35 ohms (very important) * * Full code routine has 1000 steps (DIRECTION = -1) * Steps: portD portB portC DirD DirB * init: 0x00 0x00 111111 31 0 * 0-249: 0x00 0x00 111111 31->0 0->31 * 250-499: 0x7c 0x00 000111 0->31 31->0 * 500-749: 0x7c 0x1f 000000 31->0 0->31 * 750-999: 0x00 0x1f 111000 0->31 31->0 (step 999 starts over as step 0) * * Full code routine has 1000 steps (DIRECTION = 1) * Steps: portD portB portC DirD DirB * init: 0x00 0x1f 111000 31 0 * 0-249: 0x00 0x1f 111000 31->0 0->31 * 250-499: 0x7c 0x1f 000000 0->31 31->0 * 500-749: 0x7c 0x00 000111 31->0 0->31 * 750-999: 0x00 0x00 111111 0->31 31->0 (step 999 starts over as step 0) */ ////////////////////////////////////////// // Settings used to calibrate the clock // ////////////////////////////////////////// // // MAJOR_DELAY is used 1000 times per cycle (for setting coarse delay) // Adding one step to MAJOR_DELAY slows the rate around 10.84 seconds per hour // // MINOR_DELAY is used only once per cycle (for fine tuning overall loop time) // Adding one step to MINOR_DELAY slows the rate around 0.01084 seconds per hour // Keep this value within the range of 10 to 1000 // If it gets above 1000, reset to 10 and add 1 to MAJOR_DELAY // // MICRO_DELAY is used once every 100 cycles (for really minor fine tuning) // Adding one step to MICRO_DELAY slows the rate around 0.078 seconds per 30 days // Keep this value within the range of 10 to 110 // If it gets above 110, subtract 100 and add 1 to MINOR_DELAY #define MAJOR_DELAY 331 #define MINOR_DELAY 393 #define MICRO_DELAY 10 // direction can be changed by setting the following variable to 1 or -1 #define DIRECTION -1 void setup() { // put your setup code here, to run once: PORTB = 0x00; if (DIRECTION == 1) { PORTB = 0x00; PORTD = 0x00; PORTC = 0x3f; } else { PORTB = 0x1f; PORTD = 0x00; PORTC = 0x38; } DDRB = 0x20; // portB starts off (except for status LED) DDRD = 0x7c; // portD starts on DDRC = 0x3f; // portC is always on // turn off ALL internal pullups MCUCR |= _BV(PUD); } void loop() { // put your main code here, to run repeatedly: int i; // minor loop step counter int cycle_count = 0; // counter used to run MICRO_DELAY every 100 cycles // lookup table optimized for 100, 220, 470, 1000, and 2200 ohm resistors static unsigned char stepper_data[] = {0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 10, 10, 10, 10, 10, 11, 11, 11, 11, 11, 11, 11, 12, 12, 12, 12, 12, 12, 12, 13, 13, 13, 13, 13, 13, 14, 14, 14, 14, 14, 15, 15, 15, 15, 15, 15, 16, 16, 16, 16, 16, 17, 17, 17, 17, 17, 17, 18, 18, 18, 18, 18, 19, 19, 19, 19, 19, 19, 19, 20, 20, 20, 20, 20, 20, 21, 21, 21, 21, 21, 22, 22, 22, 22, 22, 22, 23, 23, 23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 25, 25, 25, 25, 25, 25, 26, 26, 26, 26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27, 28, 28, 28, 28, 28, 28, 28, 28, 28, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31}; // main loop while (1) { // add additional minor delay (only once per cycle) delayMicroseconds(MINOR_DELAY); // check if MICRO_DELAY needs to be added (once every 100 cycles) if (cycle_count++ >= 100) { delayMicroseconds(MICRO_DELAY); cycle_count = 0; } // steps 0 to 249 for (i = 0; i <= 249; i++) { DDRB = stepper_data[i]; // count portB 0 to 31 DDRD = stepper_data[249 - i] << 2; // count portD 31 to 0 delayMicroseconds(MAJOR_DELAY); } // changes needed between steps 249 and 250 if (DIRECTION == 1) { PORTC = 0x07; PORTD = 0x7c; } else { PORTC = 0x00; PORTD = 0x7c; } // steps 250 to 499 for (i = 0; i <= 249; i++) { DDRD = stepper_data[i] << 2; // count portD 0 to 31 DDRB = stepper_data[249 - i]; // count portB 31 to 0 delayMicroseconds(MAJOR_DELAY); } // changes needed between steps 499 and 500 if (DIRECTION == 1) { PORTC = 0x00; PORTB = 0x1f; } else { PORTC = 0x07; PORTB = 0x00; } // steps 500 to 749 for (i = 0; i <= 249; i++) { DDRB = stepper_data[i]; // count portB 0 to 31 DDRD = stepper_data[249 - i] << 2; // count portD 31 to 0 delayMicroseconds(MAJOR_DELAY); } // changes needed between steps 749 and 750 if (DIRECTION == 1) { PORTC = 0x38; PORTD = 0x00; } else { PORTC = 0x3f; PORTD = 0x00; } // steps 750 to 999 for (i = 0; i <= 249; i++) { DDRD = stepper_data[i] << 2; // count portD 0 to 31 DDRB = stepper_data[249 - i]; // count portB 31 to 0 delayMicroseconds(MAJOR_DELAY); } // changes needed between steps 999 and 0 if (DIRECTION == 1) { PORTC = 0x3f; PORTB = 0x20; // status LED is turned on } else { PORTC = 0x38; PORTB = 0x3f; // status LED is turned on } } // end main loop } // end program