home *** CD-ROM | disk | FTP | other *** search
- #include <time.h>
- #include <sys\timeb.h>
- #include <dos.h>
- #include <values.h>
- #include <iostream.h>
- #include <iomanip.h>
- #include <time.h>
- #include <conio.h>
- #include <alloc.h>
- #include <stdio.h>
- #include <except.h>
-
- #include "common.h"
- #include "badexit.hpp"
- #include "video.hpp"
- #include "atimes.hpp"
- #include "pport.hpp"
- #include "cmosclk.hpp"
- #include "handpad.hpp"
- #include "steppers.hpp"
-
- const int MaxHsIx=7;
- Byte AHsOut[MaxHsIx+1];
- Byte ZHsOut[MaxHsIx+1];
-
- Steppers::Steppers
- (
- const int InvertOutput,
- const int MaxDelay,
- const int MinDelay,
- const int HsDelayX,
- const int InterruptHs,
- const int HoldReps,
- const int MsRepsTick,
- const int MsDelayX,
- const int MsPause,
- const int Ms,
- // ptr to array of size Ms,containing PWM counts
- int* PWM,
- const unsigned PPortAddr
- ):
- Handpad(PPortAddr),
-
- InvertOutput(InvertOutput),
- MaxDelay(MaxDelay),
- MinDelay(MinDelay),
- HsDelayX(HsDelayX),
- InterruptHs(InterruptHs),
- HoldReps(HoldReps),
- MsRepsTick(MsRepsTick),
- MsDelayX(MsDelayX),
- MsPause(MsPause),
- Ms(Ms)
- {
- int Winding;
- int MicroStep;
- int CosWinding;
- int SinWinding;
- int IxA;
- int IxB;
-
- // A motor lower nibble, Z motor upper nibble
- if(InvertOutput)
- {
- AOff=0xF;
- ZOff=0xF0;
- }
- else
- ZOff=AOff=0;
-
- MotorPort=PPortAddrOutByte;
- SteppersOff();
-
- MsPerHs=Ms/2;
-
- ADir=CW;
- ZDir=CW;
-
- ActualMsRepsTick=MsRepsTick;
-
- AHsIx=ZHsIx=0;
- AMsIx=ZMsIx=0;
- ASteps=ZSteps=0;
- AccumAMs=AccumZMs=0;
-
- if(MinDelay>=MaxDelay)
- BadExit E("MinDelay>=MaxDelay in Steppers module");
- if(HsDelayX<1)
- BadExit E("HsDelayX must be at least 1");
- if(MsDelayX<1)
- BadExit E("MsDelayX must be at least 1");
-
- // A motor uses bits 0-3 (1,2,4,8)
- AHsOut[0]=1;
- AHsOut[1]=3;
- AHsOut[2]=2;
- AHsOut[3]=6;
- AHsOut[4]=4;
- AHsOut[5]=12;
- AHsOut[6]=8;
- AHsOut[7]=9;
- // Z motor uses bits 4-7 (16,32,64,128)
- for(IxA=0;IxA<=MaxHsIx;IxA++)
- ZHsOut[IxA]=AHsOut[IxA]*16;
-
- // set MaxHsRepsIx
- MaxHsRepsIx=MaxDelay-MinDelay;
- // build HsReps array
- /* HsReps=(long*)malloc((MaxHsRepsIx+1)*sizeof(long));
- if(HsReps==NULL)
- BadExit E("Problem with malloc of HsReps in steppers module"); */
- try
- {
- HsReps=new long[MaxHsRepsIx+1];
- }
- catch(xalloc)
- {
- BadExit E("Bad call of HsReps=new in steppers module");
- }
- // since MoveHs() rounds up to nearest full step
- MaxHs=MAXLONG-1;
- HsReps[0]=MaxHs;
- for(HsRepsIx=1;HsRepsIx<=MaxHsRepsIx;HsRepsIx++)
- HsReps[HsRepsIx]=(long)MaxDelay/(long)(HsRepsIx+MinDelay);
-
- MaxPWM=PWM[0];
- HsIxToMsIxConvFactor=MaxPWM*MsPerHs;
- // set MaxMsIx;
- // # of microstep waveforms = # of microsteps (Ms) * # of windings (4);
- // # of elements in microstep array = # of microstep waveforms *
- // # of pulse width modulations per microstep voltage (MaxPWM)
- MaxMsIx=4*Ms*MaxPWM-1;
-
- // build microstep arrays
- /* AMs=(Byte*)malloc((MaxMsIx+1)*sizeof(Byte));
- if(AMs==NULL)
- BadExit E("Problem with malloc of AMs in steppers module");
- ZMs=(Byte*)malloc((MaxMsIx+1)*sizeof(Byte));
- if(ZMs==NULL)
- BadExit E("Problem with malloc of ZMs in steppers module"); */
- try
- {
- AMs=new Byte[MaxMsIx+1];
- ZMs=new Byte[MaxMsIx+1];
- }
- catch(xalloc)
- {
- BadExit E("Bad call of AMs=new and ZMs=new in steppers module");
- }
-
- // zero-out arrays
- for(IxA=0;IxA<=MaxMsIx;IxA++)
- ZMs[IxA]=AMs[IxA]=0;
-
- // start cos winding at bit #1 and sin winding at bit #2,
- // cos winding will start at the highest microstep voltage and ramp
- // down to zero volts while sin winding will start at zero volts and
- // ramp up
- CosWinding=1;
- SinWinding=2;
-
- // start base index of microstep array at the beginning,
- // index is incremented by MaxPWM (# of pulse width modulations
- // per microstep voltage)
- IxA=0;
-
- // microstep array has 4 windings to build
- for(Winding=1;Winding<=4;Winding++)
- {
- // each winding has Ms # of microsteps to build
- for(MicroStep=0;MicroStep<Ms;MicroStep++)
- {
- // turn on the cos bit for PWM[MicroStep] # of times
- for(IxB=0;IxB<PWM[MicroStep];IxB++)
- AMs[IxA+IxB]+=CosWinding;
- // Microstep==0 has no contribution from SinWinding
- if(MicroStep>0)
- /* the sin microstep that corresponds to the cos
- microstep of Ms is Ms-MicroStep,
- ie, if the total # of microsteps = 10
- microstep cos sin
- 0 PWM[0] n/a
- 1 PWM[1] PWM[9]
- 2 PWM[2] PWM[8]
- 3 PWM[3] PWM[7]
- 4 PWM[4] PWM[6]
- 5 PWM[5] PWM[5]
- 6 PWM[6] PWM[4]
- 7 PWM[7] PWM[3]
- 8 PWM[8] PWM[2]
- 9 PWM[9] PWM[1] */
- for(IxB=0;IxB<PWM[Ms-MicroStep];IxB++)
- AMs[IxA+IxB]+=SinWinding;
- // increment to start of next microstep voltage
- IxA+=MaxPWM;
- }
- // goto next windings
- CosWinding*=2;
- SinWinding*=2;
- if(SinWinding>8)
- SinWinding=1;
- }
- // Z motor bits occupy upper nibble
- for(IxA=0;IxA<=MaxMsIx;IxA++)
- ZMs[IxA]=AMs[IxA]*16;
-
- if(InvertOutput)
- {
- for(IxA=0;IxA<=MaxHsIx;IxA++)
- {
- AHsOut[IxA]=AOff-AHsOut[IxA];
- ZHsOut[IxA]=ZOff-ZHsOut[IxA];
- }
- for(IxA=0;IxA<=MaxMsIx;IxA++)
- {
- AMs[IxA]=AOff-AMs[IxA];
- ZMs[IxA]=ZOff-ZMs[IxA];
- }
- }
- }
-
- Steppers::~Steppers(void)
- {
- delete(HsReps);
- delete(AMs);
- delete(ZMs);
- }
-
- void Steppers::SteppersOff(void)
- {
- outportb(MotorPort,AOff+ZOff);
- }
-
- void Steppers::Hold(void)
- {
- Byte AOut,ZOut;
- int RepCount,HsDelayXCount,DelayCount;
-
- if(AHoldFlag)
- AOut=AHsOut[AHsIx];
- else
- AOut=AOff;
- if(ZHoldFlag)
- ZOut=ZHsOut[ZHsIx];
- else
- ZOut=ZOff;
- outportb(MotorPort,AOut+ZOut);
- for(RepCount=0;RepCount<HoldReps;RepCount++)
- for(HsDelayXCount=0;HsDelayXCount<HsDelayX;HsDelayXCount++)
- for(DelayCount=0;DelayCount<HsRepsIx+MinDelay;DelayCount++)
- ;
- }
-
- int Steppers::ClockTick(void)
- {
- static long HoldClock;
-
- long Clock=clock();
- if(Clock==HoldClock)
- return No;
- else
- {
- HoldClock=Clock;
- return Yes;
- }
- }
-
- void Steppers::PauseUntilClockTick(void)
- {
- ClockTick();
- while(!ClockTick())
- ;
- }
-
- void Steppers::DoOneHs(void)
- {
- Byte AOut;
- Byte ZOut;
- int HsDelayXCount,DelayCount;
-
- if(ASteps)
- {
- if(ADir==CW)
- {
- AHsIx++;
- if(AHsIx>MaxHsIx)
- AHsIx=0;
- AccumAMs+=MsPerHs;
- }
- else
- {
- AHsIx--;
- if(AHsIx<0)
- AHsIx=MaxHsIx;
- AccumAMs-=MsPerHs;
- }
- ASteps--;
- AOut=AHsOut[AHsIx];
- }
- else
- AOut=AOff;
- AMsIx=AHsIx*HsIxToMsIxConvFactor;
-
- if(ZSteps)
- {
- if(ZDir==CW)
- {
- ZHsIx++;
- if(ZHsIx>MaxHsIx)
- ZHsIx=0;
- AccumZMs+=MsPerHs;
- }
- else
- {
- ZHsIx--;
- if(ZHsIx<0)
- ZHsIx=MaxHsIx;
- AccumZMs-=MsPerHs;
- }
- ZSteps--;
- ZOut=ZHsOut[ZHsIx];
- }
- else
- ZOut=ZOff;
- ZMsIx=ZHsIx*HsIxToMsIxConvFactor;
-
- outportb(MotorPort,AOut+ZOut);
- // repetitions of delay counts
- for(HsDelayXCount=0;HsDelayXCount<HsDelayX;HsDelayXCount++)
- for(DelayCount=0;DelayCount<HsRepsIx+MinDelay;DelayCount++)
- ;
- SetHandPadOKFlag();
- }
-
- void Steppers::MoveHs(void)
- {
- Flag InterruptFlag=No;
- long MvmtHs;
- long RampHs;
- long SameSpeedHs;
-
- InitHandPad=HandPad;
- HandPadOKFlag=Yes;
- // end on next fullstep
- if(ASteps%2)
- ASteps++;
- if(ZSteps%2)
- ZSteps++;
- while(HandPadOKFlag && (ASteps || ZSteps))
- {
- // do smaller # of steps 1st unless a motor has 0 steps to do:
- // flags set for Hold() depend on this mvmt algorithm
- if(ASteps==0)
- MvmtHs=ZSteps;
- else if(ZSteps==0)
- MvmtHs=ASteps;
- else if(ASteps<ZSteps)
- MvmtHs=ASteps;
- else
- MvmtHs=ZSteps;
- RampHs=MvmtHs/2;
- /* set for max delay giving slowest speed (index is decremented
- in while loop before being used for 1st time) */
- HsRepsIx=MaxHsRepsIx+1;
- /* if steps to move exceed InterruptHs, then disable interrupts for
- smoothest timing pulses to allow faster speeds */
- if(RampHs>InterruptHs)
- {
- InterruptFlag=Yes;
- disable();
- }
- // hold motor(s) position for brief time to align
- if(ASteps)
- AHoldFlag=On;
- else
- AHoldFlag=Off;
- if(ZSteps)
- ZHoldFlag=On;
- else
- ZHoldFlag=Off;
- Hold();
- // ramp up
- while(HandPadOKFlag && RampHs)
- {
- HsRepsIx--;
- SameSpeedHs=HsReps[HsRepsIx];
- while(HandPadOKFlag && RampHs && SameSpeedHs)
- {
- DoOneHs();
- RampHs--;
- SameSpeedHs--;
- }
- }
- // ramp down
- while(HsRepsIx<=MaxHsRepsIx)
- {
- while(SameSpeedHs<HsReps[HsRepsIx])
- {
- /* if move cancelled while moving at max speed, then immediate
- ramp down */
- if(!HandPadOKFlag && HsRepsIx==0)
- SameSpeedHs=HsReps[HsRepsIx]-1;
- DoOneHs();
- RampHs--;
- SameSpeedHs++;
- }
- SameSpeedHs=0;
- HsRepsIx++;
- }
- // hold motor(s) position for brief time to brake
- Hold();
- AHoldFlag=ZHoldFlag=Off;
- }
- SteppersOff();
- if(InterruptFlag)
- {
- SetDOSToCMOS();
- enable();
- }
- PauseUntilClockTick();
- }
-
- void Steppers::MoveMs(void)
- {
- int IxA,IxB,IxC;
- int AMsToDo;
- int ZMsToDo;
- double AMsRunningTotal=0;
- double ZMsRunningTotal=0;
-
- MsAlignFlag=No;
- ActualMsRepsTick=0;
-
- // allow skipping of microsteps up to halfstepping
- double IncrAMs=(double)ASteps/(double)(MsRepsTick);
- if(IncrAMs>MsPerHs)
- IncrAMs=MsPerHs;
- double IncrZMs=(double)ZSteps/(double)(MsRepsTick);
- if(IncrZMs>MsPerHs)
- IncrZMs=MsPerHs;
-
- do
- {
- if(ASteps)
- {
- AMsRunningTotal+=IncrAMs;
- AMsToDo=AMsRunningTotal;
- AMsRunningTotal-=AMsToDo;
- ASteps-=AMsToDo;
- if(ADir==CW)
- {
- AMsIx+=MaxPWM*AMsToDo;
- if(AMsIx>MaxMsIx)
- AMsIx-=MaxMsIx+1;
- AccumAMs+=AMsToDo;
- }
- else
- {
- AMsIx-=MaxPWM*AMsToDo;
- if(AMsIx<0)
- AMsIx+=MaxMsIx+1;
- AccumAMs-=AMsToDo;
- }
- }
- if(ZSteps)
- {
- ZMsRunningTotal+=IncrZMs;
- ZMsToDo=ZMsRunningTotal;
- ZMsRunningTotal-=ZMsToDo;
- ZSteps-=ZMsToDo;
- if(ZDir==CW)
- {
- ZMsIx+=MaxPWM*ZMsToDo;
- if(ZMsIx>MaxMsIx)
- ZMsIx-=MaxMsIx+1;
- AccumZMs+=ZMsToDo;
- }
- else
- {
- ZMsIx-=MaxPWM*ZMsToDo;
- if(ZMsIx<0)
- ZMsIx+=MaxMsIx+1;
- AccumZMs-=ZMsToDo;
- }
- }
- // send voltages to motors
- for(IxA=0;IxA<MaxPWM;IxA++)
- // repeat outportb() MsDelayX times
- for(IxB=0;IxB<MsDelayX;IxB++)
- outportb(MotorPort,AMs[AMsIx+IxA]+ZMs[ZMsIx+IxA]);
- SteppersOff();
- // pause for MsPause counts
- for(IxC=0;IxC<MsPause;IxC++)
- SteppersOff();
- // one microstepping voltage waveform finished
- ActualMsRepsTick++;
- } while(!ClockTick());
-
- AHsIx=AMsIx/HsIxToMsIxConvFactor;
- ZHsIx=ZMsIx/HsIxToMsIxConvFactor;
- }
-
- void Steppers::AlignMs(void)
- {
- if(MsAlignFlag)
- PauseUntilClockTick();
- else
- {
- // find microsteps to nearest fullstep
- ASteps=(AMsIx/MaxPWM)%Ms;
- if(ASteps && ADir==CW)
- ASteps=Ms-ASteps;
- ZSteps=(ZMsIx/MaxPWM)%Ms;
- if(ZSteps && ZDir==CW)
- ZSteps=Ms-ZSteps;
- Steppers::MoveMs();
- MsAlignFlag=Yes;
- }
- }
-
- void Steppers::Test(int TestMs,long TestHs)
- {
- int Input=0;
- int IxA,IxB;
-
- clrscr();
- cout<<endl<<endl<<endl<<"Starting steppers module test:"<<endl;
- if(TestMs>MsRepsTick*MsPerHs)
- TestMs=MsRepsTick*MsPerHs;
- cout<<endl<<"microstepping at "<<TestMs*18.2<<" microsteps/sec";
- cout<<endl<<ContMsg<<endl;
- ASteps=TestMs;
- PauseUntilClockTick();
- while(!kbhit())
- {
- Steppers::MoveMs();
- ASteps+=TestMs;
- }
- Steppers::AlignMs();
- cout<<endl<<"MsRepsTick="<<MsRepsTick<<endl;
- getch();
- cout<<endl<<"halfstepping test:";
- Input=' ';
- while(Input!='q')
- {
- cout<<endl<<"press 'm' to move, 'q' to quit";
- Input=getch();
- if(Input=='m')
- {
- ASteps=ZSteps=TestHs;
- Steppers::MoveHs();
- }
- }
- cout<<endl<<endl<<"individual microstep test:";
- Input=' ';
- while(Input!='q')
- {
- cout<<endl<<"press 'l' for left, 'r' for right, 'q' to quit"<<endl;
- Input=getch();
- if(Input=='l')
- ADir=CW;
- else if(Input=='r')
- ADir=CCW;
- else
- continue;
- PauseUntilClockTick();
- for(IxA=0;IxA<Ms;IxA++)
- {
- cout<<" "<<IxA;
- ASteps=ZSteps=1;
- Steppers::MoveMs();
- for(IxB=0;IxB<(int)ClockTicksSec;IxB++)
- Steppers::MoveMs();
- }
- }
- cout<<endl<<endl<<ContMsg;
- getch();
- }
-
- void Steppers::Test1(void)
- {
- int Input=0;
- int Ix=0;
- long Fs=2;
-
- clrscr();
- cout<<endl<<endl<<endl<<"Starting steppers module1 test:"<<endl;
- ASteps=ZSteps=Fs;
- Steppers::MoveHs();
- while(Input!='q')
- {
- cout<<"press 'm' to move one full step, 'q' to quit"<<endl;
- Input=getch();
- if(Input=='m')
- {
- ASteps=ZSteps=Fs;
- Steppers::MoveHs();
- cout<<"full step = "<<++Ix<<" ";
- }
- }
- cout<<endl<<endl<<ContMsg;
- getch();
- }
-
-