#include
<At89x55.h>
//
State Variables
#define
WAIT 0
#define
TRAINING 1
#define
REPLAY 2
//
Constants
#define
MAXINSTRUCTIONS 64
#define
VECTORSIZE 64
//
Global variables
bit
currdir = 1, nextdir = 1, calculateNext = 0;
bit
buttonDown = 0, forward = 1;
unsigned
char num16BitIntr = 0, numMotorIntr = 0;
unsigned
char dirWrite = 0;
char
replayCounter = 0;
unsigned
char trainingCounter = 64;
unsigned
char nextSpeedH = 0, nextSpeedL = 0, currSpeedH = 0, currSpeedL = 0;
unsigned
char currMotorIntrDelay = 4;
char
tickCount = 0;
unsigned
char mode = WAIT;
//
Container to hold instructions. Preloaded with some testing data.
// An
instruction is 1 byte where the bit 8 is unused, bit 7 is the direction bit,
and bits 6 - 1
// contain the number of steps to turn the
motor.
unsigned
char instruction[MAXINSTRUCTIONS] = {
0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,0x0C,0x0D,0x0E,0x0F,
0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1A,0x1B,0x1C,0x1D,0x1E,0x1F,
0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x29,0x2A,0x2B,0x2C,0x2D,0x2E,0x2F,
0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30
};
//
Lookup table to convert a number of ticks read from encoder into a timer
setting
// We
used the following formula to convert number of steps into timer setting:
//
timer_setting = 2^16-(2^16/(num_steps+1))
// this
assumes a 16 bit timer.
code
short unsigned int speed_vector[VECTORSIZE] = {
00000,32768,43691,49152,52429,54613,56174,57344,
58254,58982,59578,60075,60495,60855,61167,61440,61681,
61895,62087,62259,62415,62557,62687,62805,62915,
63015,63109,63195,63276,63351,63422,63488,63550,
63608,63664,63716,63765,63811,63856,63898,63938,
63976,64012,64047,64080,64111,64142,64171,64199,
64225,64251,64276,64299,64322,64344,64366,64386,
64406,64425,64444,64462,64479,64496,64512
};
//
interrupts approx. every 1/32 sec.
void
timer0_isr() interrupt 1 {
// slow it down to ~1/4 second
if(++num16BitIntr >= 8) {
num16BitIntr = 0;
if
(mode == REPLAY) {
//Set motor timer to fire at appropriate interval
if(nextSpeedH == 0) ET1 = 0; //no pulses will be sent
else // start sending pulses to the motor
{
ET1 = 1;
numMotorIntr = 0;
}
// load the precalculated instruction
currSpeedH = nextSpeedH;
currSpeedL = nextSpeedL;
currdir = nextdir;
// set flag to fetch and parse next instruction
calculateNext = 1;
P1_3 = 0;
P1_2 = 1;
}
else if (mode == TRAINING) {
if(tickCount < 0){
dirWrite = 0x00;
tickCount = -tickCount;
}
else dirWrite = 0x40;
// max number of ticks is 63 (6 bits) per 1/4 second
if(tickCount > 63)
tickCount = 63;
instruction[trainingCounter++] =
tickCount | dirWrite;
// OR on the direction bit
tickCount = 0;
P1_3 = 1;
P1_2 = 0;
if (trainingCounter == MAXINSTRUCTIONS)
// filled up the array, quit training mode
mode = WAIT;
}
else{ // mode == WAIT
P1_3 = 1;
P1_2 = 1;
}
}
//reset the timer
TH0 = 0;
TL0 = 0;
}
//
Generated by encoder every time the motor moves.
void
extTimer1_isr() interrupt 2 {
if(INT0){
// If it is moving forward increment count
tickCount++;
}
else{
// else it is moving backward so decrement count
tickCount--;
}
// bounds checking on signed char
if(tickCount >= 127)
tickCount--;
if(tickCount <= -127)
tickCount++;
}
//
Clock pulse generator to stepper motor
void
timer1_isr() interrupt 3 {
if (++numMotorIntr >= currMotorIntrDelay)
{
P1_5 = currdir; // set direction
P1_4 = !P1_4; // toggle motor clock
numMotorIntr = 0;
}
// Set the timer to overflow by using the
speed to preload the timer.
TH1 = currSpeedH;
TL1 = currSpeedL;
}
// used
during replay mode
void
GetNextSpeed() {
unsigned short int temp;
if(forward){
if(trainingCounter > replayCounter){
unsigned char speed, inst =
instruction[replayCounter++];
nextdir = inst & 0x40; // direction is the 7th bit of the
instruction
speed = inst & 0x3F; // speed is the last 6 bits of the
instruction
temp = speed_vector[speed]; //
look up value to preload the motor interrupt timer with
nextSpeedL = (unsigned char)(0x00FF & temp);
nextSpeedH = (unsigned char)(temp>>8);
}
else{
// once the sequence has been played, rewind so you are back where you
started
replayCounter
= trainingCounter;
forward = 0;
nextSpeedH = 0;
}
}
else{
// rewind mode
if(replayCounter > 0){
unsigned char speed, inst =
instruction[--replayCounter];
nextdir = inst & 0x40; // the seventh
bit is direction
nextdir = !nextdir; // flip the
direction since we are rewinding
speed = inst & 0x3F;
temp = speed_vector[speed];
nextSpeedL = (unsigned char)(0x00FF & temp);
nextSpeedH = (unsigned char)(temp>>8);
}
else{
// after rewind is complete stop sending motor pulses until user starts
it up again.
nextSpeedH = 0;
nextSpeedL = 0;
ET1 = 0;
}
}
}
void
main() {
unsigned int x;
bit j;
T2 = 1;
T2_EX = 1;
P1_2 = 1;
P1_3 = 1;
EA = 1; // enable global interrupts
TR0 = 1; //enable timer 0
TR1 = 1; //enable timer 1
TMOD = 0x11; // Set timer 0 to 16 bit, Set timer 1 to 16 bit
EX1 = 1;
// Enable external interrupt 1
ET1 = 1;
// Enable timer 1 interrupt
IT1 = 1;
// External interrupt 1 is edge triggered
ET0 = 1;
// Enable timer 0 interupt
IT0 = 1;
// External interrupt 0 is edge triggered
PT0 = 0; // timer 0 gets low priority
PT0 = 0;
PT1 = 0; // timer 1 gets low priority
PX1 = 1; // external int 1 gets high
priority
while(1) {
// Ready the next instruction so that it
is available when the interrupt occurs
if (calculateNext) {
calculateNext = 0;
GetNextSpeed();
}
// T2 is training button
// T2_EX is replay button
if (buttonDown){
if (T2 && T2_EX)
buttonDown = 0;
}
else if (!T2){
if (mode != TRAINING){
ET1 = 0; // turn off motor pulses
TR1 = 1; // just in case
trainingCounter = 0;
buttonDown = 1;
tickCount = 0;
mode = TRAINING;
}
}
else if (!T2_EX){
if (mode != REPLAY){
if (trainingCounter < 4) // Check
for switch bounce
P1_6 = 1;
else
P1_6 = 0;
replayCounter = 0;
buttonDown = 1;
forward = 1;
mode
= REPLAY;
GetNextSpeed();
ET1 = 1;
numMotorIntr = 0;
}
}
else{
if(mode == TRAINING){ // wait for a bit so we don't get erroneous
readings
for(x =0; x < 20000; x++)
j = 0;
}
P1_5 = 0;
mode = WAIT;
ET1 = 0;
}
}
}