Timer-based stepper movement is just great. Compared to _delay_1 or _delay_ms it offers following benefits:
- Frees CPU up for other tasks.
- Delay lengths are can be easily specified in milli- or microseconds.
It's not hard. I prepare a list of 'actions' to execute beforehand and set the timer top as follows:
/** Set up timer 1 (16-bit), frequency = F_CPU/(timertop+1). */
#define setup_timer1(timertop) do { \
OCR1A = (timertop); /* set top */ \
/* Mode 4 - CTC with Prescaler 1 */ \
TCCR1B = (1<<WGM12)|(1<<CS10); \
TCNT1 = 0; /* reset counter */ \
TIMSK |= (1<<OCIE1A); /* enable output-compare int */ \
} while (0)
/**
* Calculate timertop for setup_timer1.
*/
static uint16_t
timertop_of( const uint16_t length,
const uint16_t time_ms)
{
const uint16_t timertop = (((uint32_t)time_ms) * (F_CPU/100) / 10) / length - 1;
return timertop;
}
/** Current action index. */
static int8_t action_index = -1;
/** Actions are executed from back to front. */
static ACTION actions[5];
The interrupt service routine chews through the list of actions:
SIGNAL(SIG_OUTPUT_COMPARE1A)
{
if (action_index>=0) {
ACTION* act = &actions[action_index];
move_1_step(act->step_direction);
if (--(act->countdown) == 0) {
--action_index;
}
}
}
The experienced reader can fill out the details...
No comments:
Post a Comment