/***************************************************************************
StepperMotor.c
****************************************************************************/
#include "StepperMotor.h"
/*--------------------------
Module Constants -----------------------------*/
const static char hardGrapple = 1; //Boolean used to invert the grapple
control dial to make
//the game more difficult
const static unsigned int dialLO = 15; //Zero
position on raw analog input from dial
const static unsigned int dialHI = 1005; //Max position on raw analog input from
dial
const static unsigned int minWait = 2; //max motor speed
const static unsigned int maxWait = 10; //min motor speed
const static unsigned int resetWait = 5; //reset motor speed
const static unsigned int deadZone_pct10 = 30; //Portion of analog dial that reads neutral
(commands
//no motor speed); this must be greater than 25
const static unsigned int victorySpeed = 15; //victory
motor speed
const static int startPosOffset = 23; //Start
position for Tom Cruise
const static int topRangePos = 593; //Highest
position that Tom can begin download
const static int bottomRangePos = 643; //Lowest
position that Tom can begin download
const static int hitFloorPos = 667; //Hit
floor position
/*-------------------------
Module Definitions ----------------------------*/
#define LOWER_DIR
0 //Dir command to stepper motor that
results in motor rotation that lowers Tom
#define RAISE_DIR
1
//Dir command to stepper motor that results in motor rotation that
raises Tom
/*--------------------------
Module Variables -----------------------------*/
static int lastCalPt;
//used only for test function
static int motorPos; //Motor position (always positive
with 0 being top)
static char motorDir; //Indicates which direction the
motor is current set at
static int motorSpd; //Indicates current speed of the
motor
static char waitingForDialNeutral; //Indicates if dial started in non neutral
position
static unsigned int lastClockTime; //Timing variable for motor speed control
static unsigned int lastMotorPrint; //Timing
variable for test function
/*--------------------------
Module Functions -----------------------------*/
static void pulseClock(void); //Pulses the clock line to the stepper
motor driver
static int readDial(void); //Reads analog dial as a number between
0 and 1000
static void setDir(char); //Sets the direction line to the
stepper motor driver
static void runMotor(int); //Runs
the motor at the given speed (input int is actually
the
//wait time,
so speed = 1/(wait time) )
/*----------------------------
Module Code ------------------------------*/
void initStepMotor(int howManySteps) {
int
dialPos;
lastClockTime
= TMRS12_GetTime(); //Upate timing variables
lastMotorPrint
= TMRS12_GetTime();
//Zero out position
motorSpd
= 0;
motorPos
= 0;
setDir(RAISE_DIR); //Set motor direction to raise Tom
Cruise
while (motorPos > (-1)*(howManySteps))
{ //Run motor into stop for a
specified # of steps
runMotor(resetWait); //Run motor at a
calibrated reset speed
}
motorPos
= 0; //Reset
zero position
//Move to calibrated start position
setDir(LOWER_DIR); //Set motor direction to lower Tom
Cruise
while (motorPos != startPosOffset) { //Continue lowering him until he is at
the start
runMotor(resetWait); //position
}
motorPos
= 0; //Reset
zero position
//Check if dial is not in neutral
dialPos
= readDial();
if ((dialPos > (500 + deadZone_pct10 - 5)) || (dialPos < (500 - deadZone_pct10 + 5))) {
waitingForDialNeutral = 1; //Dial not in neutral position, make note to
ignore dial input
//until it passes through neutral position
}
else {
waitingForDialNeutral
= 0; //Dial is ready to go
}
//testing only
lastCalPt
= -1;
}
MOTOR_STATUS_t resetStepMotorStatus(void) {
if (motorPos <= 0) {
return MOTOR_NOT_IN_RANGE_STATUS;
}
else {
setDir(RAISE_DIR);
runMotor(resetWait);
return
MOTOR_RESETTING_STATUS;
}
}
MOTOR_STATUS_t slowVictoryReset(void) {
if (motorPos <= 0) {
return
MOTOR_NOT_IN_RANGE_STATUS ;
}
else {
setDir(RAISE_DIR);
runMotor(victorySpeed);
return
MOTOR_RESETTING_STATUS;
}
}
MOTOR_STATUS_t checkStepMotorStatus(void) {
int
dialPos = 0;
int
relativeDialPos = 0;
int
cmdWaitTime = 0;
unsigned long myTemp = 0; //Use to avoid floating-point math
//Read in analog dial
dialPos
= readDial(); //Will return a number between 0 and 1000
// Determine
commanded direction and speed
if (dialPos < (500 - deadZone_pct10)){ //Check if dial is above the neutral (aka dead) zone
//Raise grapple
setDir(LOWER_DIR);
if (hardGrapple) //Interpret dial commands
“backwards” if hard grapple is activated
relativeDialPos
= dialPos + 1;
else
relativeDialPos
= (500 - deadZone_pct10) - dialPos;
}
else {
if (dialPos > (500 + deadZone_pct10)){ //Check if dial is below the neutral (aka dead) zone
//Lower grapple
setDir(RAISE_DIR);
if (hardGrapple) //Interpret dial commands
“backwards” if hard grapple is activated
relativeDialPos
= 1001 - dialPos;
else
relativeDialPos
= dialPos - (500 + deadZone_pct10);
}
else {
relativeDialPos
= 0; //If dial is in neutral (aka dead) zone, don’t command any speed
}
}
//Need to get a neutral reading before
allowing dial to control grapple (this prevents the
//grapple from running before the user has
ever touched the dial)
if (waitingForDialNeutral) {
//Check if dial is in neutral (aka dead) zone plus some hysteresis
if ((dialPos > (500 + deadZone_pct10 - 25)) || (dialPos < (500 - deadZone_pct10 + 25)))
relativeDialPos
= 0; //cancel dial command until neutral is found
else
waitingForDialNeutral
= 0;
}
//Calculate speed (which is actually
commanded by wait time); commanded wait time will be
//something between the calibrated max and
min wait times (corresponding to the min and max
//speeds of the motor)
myTemp
= ((long)maxWait-minWait)*(relativeDialPos);
cmdWaitTime
= maxWait - (int)(myTemp/(500 - deadZone_pct10));
//Before commanding motor, check limits;
don’t allow motor to go up passed zero position, or
//lower than the floor
if (((motorDir
== RAISE_DIR) && (motorPos > 0)) ||
((motorDir ==
LOWER_DIR) && (motorPos < hitFloorPos))) {
if (relativeDialPos != 0) {
runMotor(cmdWaitTime); //Command motor to be run at specified
speed = 1/cmdWaitTime
}
}
//Check current motor position to determine
if an event has occured
if (motorPos >= hitFloorPos) {
return
MOTOR_HIT_FLOOR_STATUS;
}
else {
if ((motorPos >= topRangePos)
&& (motorPos <= bottomRangePos))
return
MOTOR_IN_RANGE_STATUS;
}
else {
return MOTOR_NOT_IN_RANGE_STATUS;
}
}
}
static void runMotor(int cmdWaitTime) {
unsigned int myTime = 0;
int
filteredWaitTime = 0;
//Filter input speed to prevent instananous accelerations of the stepper motor
filteredWaitTime
= motorSpd;
if (cmdWaitTime < motorSpd)
filteredWaitTime
= motorSpd - 1;
if (cmdWaitTime > motorSpd)
filteredWaitTime
= motorSpd + 1;
myTime
= TMRS12_GetTime();
if ((myTime-lastClockTime) >= filteredWaitTime)
{ //If enough time has passed, command a
step
pulseClock();
motorSpd
= filteredWaitTime; //Save current speed for future
filtering
lastClockTime
= myTime; //Update
timing variables
if (motorDir == LOWER_DIR) //Update
motor position
motorPos++;
else
motorPos--;
}
}
static int readDial(void)
{
int
myPos = 0;
unsigned long myTemp
= 0; //Used to avoid floating point
math
int
myCalc = 0;
myPos
= ADS12_ReadADPin(0); //Read in analog dial as number between 0 and
1023
if (myPos <= dialLO) //Check against calibrated zero
position on dial
return 0;
else {
if (myPos >= dialHI) //Check against calibrated fully on
position on dial
return 1000;
else { //Linearize
between the two extreme calibrations
myTemp
= (1000*((long)myPos-dialLO));
myCalc
= (int)((myTemp)/((dialHI-dialLO)));
return myCalc;
}
}
}
static void setDir(char dir) {
motorDir
= dir;
if (dir)
PTAD = PTAD | BIT2HI; //Set stepper motor driver direction line to
HI
else
PTAD = PTAD & BIT2LO; //Set stepper motor driver direction line to
LO
}
static void pulseClock(void) {
int
j = 0;
PTAD = PTAD | BIT1HI; //Set step command line to HI
//delay slightly to ensure CLOCK output stays
HI for > 10[us]
for (j=1; j<200;
j++) {
}
PTAD = PTAD & BIT1LO; //Set step command line to LO
}
//test function
void calibrateDial(void) {
int
myPos = 0;
myPos
= readDial();
if (myPos != lastCalPt) {
lastCalPt
= myPos;
printf("Dial: %d\r\n", myPos);
}
}
//test function
void showMotorPos(void) {
unsigned int curTime;
curTime
= TMRS12_GetTime();
if (curTime > (lastMotorPrint +
500)){
lastMotorPrint
= curTime;
printf("MotorPos: %d\r\n", motorPos);
}
}