The capeMirror Wiring
On the right can be seen the pin mapping.
The capeMirror Library
Now it’s just a question of combining the following libraries into one: Stepper_Aclr8_2, Stepper_Aclr8_i, Matrix_Steppers, and SerialParse.
/* * capeMirror v2a * * created by Ben @ Cape Ealing * 24 January 2010 * */ //******************************************************************** // Initial Definitions //******************************************************************** // include the libraries // ------------------------------------------------------------------- #include "NewSoftSerial.h" #include "CapeMirror.h" // map all the pins // ------------------------------------------------------------------- #define pReceiveBT 2 #define pTransmitBT 3 #define pAzStep1 4 #define pAzStep2 5 #define pAzStep3 6 #define pAzStep4 7 #define pAltStep1 8 #define pAltStep2 9 #define pAltStep3 10 #define pAltStep4 11 #define pKeypadCol1 12 #define pKeypadCol2 13 #define pKeypadCol3 14 #define pTransmitLCD 15 #define pKeypadRow1 16 #define pKeypadRow2 17 #define pKeypadRow3 18 #define pKeypadRow4 19 // the LCD constants and variables // ------------------------------------------------------------------- #define lcdDataRate 9600 #define pLCDNoReceivePin 255 #define lcdLine1 1 #define lcdLine2 2 int lcdBright = 100; // the bluetooth constants and variables // ------------------------------------------------------------------- #define btDataRate 9600 #define btHandshake1 1234567 #define btHandshake2 7654321 #define btNewCoords 1111112 #define btPark 2222222 #define btUnpark 333333 #define btSlew 4444444 // the keypad constants and variables // ------------------------------------------------------------------- int keypadResult = 13; // the stepper motors constants and variables // ------------------------------------------------------------------- // Azimuth stepper #define azSteps 200 #define azMinSpeed 1 #define azMaxSpeed 30 #define azAccSteps 400 #define azMoveSpeed 10 // Altitude stepper #define altSteps 200 #define altMinSpeed 1 #define altMaxSpeed 30 #define altAccSteps 100 #define altMoveSpeed 10 // ancillary set-up // ------------------------------------------------------------------- boolean pcControl = false; int azStepsToDo = 0; // variable to hold the 'az steps to take' data int altStepsToDo = 0; // variable to hold the 'alt steps to take' data // variables for the data long azVal = 0; long altVal = 0; long cmdVal = 0; // global variables for mount's azimuth and altitude (in arcseconds) long azGlobal = 0; long altGlobal = 187826; boolean initialised = false; // initialise the classes // ------------------------------------------------------------------- NewSoftSerial cmBlueTooth(pReceiveBT, pTransmitBT); NewSoftSerial cmLCD(pLCDNoReceivePin, pTransmitLCD); CapeMirror cmMount = CapeMirror(&azGlobal, &altGlobal); // DB change name //******************************************************************** // Setup Procedure //******************************************************************** void setup() { // define the (lcd) serial communication cmMount.setLCDaddress(&cmLCD); cmMount.beginLCD(lcdDataRate); cmMount.lcdOn(); cmMount.lcdClear(); cmMount.lcdBacklight(100); cmMount.lcdDisplay(lcdLine1, 1, " capeMirror"); cmMount.lcdDisplay(lcdLine2, 1, " created by Ben"); delay(3000); // define the (bluetooth) serial communication with the laptop cmMount.setBTaddress(&cmBlueTooth); cmMount.beginBT(btDataRate); // define the keypad (fires columns, and reads rows) cmMount.setKeypadCols(pKeypadCol1, pKeypadCol2, pKeypadCol3); cmMount.setKeypadRows(pKeypadRow1, pKeypadRow2, pKeypadRow3, pKeypadRow4); cmMount.setInterruptPins(pKeypadCol2, pKeypadRow2); // define each stepper motor // (no of steps per rev, pin1, pin2, pin3, pin4) cmMount.azStepper(azSteps, pAzStep1, pAzStep3, pAzStep2, pAzStep4); cmMount.altStepper(altSteps, pAltStep1, pAltStep3, pAltStep2, pAltStep4); // define the rates of each motor: // min, max, steps take to accelerate, and 'move speed' (when keypad pressed) cmMount.azStepperSpeeds(azMinSpeed, azMaxSpeed, azAccSteps, azMoveSpeed); cmMount.altStepperSpeeds(altMinSpeed, altMaxSpeed, altAccSteps, altMoveSpeed); // pass the address of the 'steps to take variables' cmMount.setStepsAddress(&azStepsToDo, &azStepsToDo); // run the startup routine do { userStart(); } while (initialised == false); cmMount.lcdDisplayCoords(); cmMount.lcdDisplayDegsMins(); cmMount.lcdDisplaySecs(); if (pcControl == true) {cmMount.lcdDisplayControlPC();} else {cmMount.lcdDisplayControlMT();} delay(2000); } // End: setup //******************************************************************** // Loop procedure (the main procedure) //******************************************************************** void loop() { // read the keypad keypadResult = cmMount.readKeypad(); if (keypadResult != 13){cmMount.move(keypadResult);} if (keypadResult == 0){ // wait until key no longer pressed do {keypadResult = cmMount.readKeypad();} while (keypadResult == 0); // vary the backlight cmMount.lcdBacklightShift(); } //SCENARIO A // read the serialcomm // if available...parse the data // if under pcControl = true {} // then 'switch case' the cmd value // do as required: ie slew, or acceptnewcoords, or park // need to be able to handle a 'move' command (ie slew can be interrupted by serial data) // else (not under pcControl // then check pc wants to take control // if not, error // if does want to take control, then // toggle pcControl // read the keypad // if pressed then: // if pcControl = true, see if mount wants to take over. if so, then park (same as park above?) otherwise ignore // if pcControl = false, then move as required, but if '#' pressed, then part (same as park above?) // always check for 0. If 0 pressed then increase brightness by 20% (set to zero if result > 100). // NOTE: Whenever stepping on whatever instruction, need to // 1. read the mount interrupt pin (*), to check user hasn't cancelled at that end // if cancelled by keypad, then // if under MT control just stop (coords will have been saved anyway) // if under PC control then need to report to PC the interruption and the new coords // and turn to MT control // 2. read the serial data, to check not cancelled by PC (eg a 'move') // if cancelled by bluetooth, then // if under PC control then report to PC the interruption and the new coords // if under MT control then report to PC the interruption and the new coords // and turn to PC control //SCENARIO B // if pcControl = true { // } // Either PC control: waiting for BlueTooth Data and reading '#' pin // hash says 'i want control': if hash pressed then the scope is 'parked' // if it's in the middle of a move routine, then can only interrupt by // pressing the 'abandon' key (*) // That just means that the mount is interrupted, it sends its new position // to the PC. Waits for the PC to confirm that OK to proceed. // if pcControl = false { // } // Or Mount control: waiting for BlueTooth and reading keypad (possible) // scope is 'parked' as far as PC is concerned // read the keypad, move as necesssary, store alt and az position // if user presses '#' then unparks and goes over to pc control // also PC can regain control, so needs to read bluetooth too if (cmBlueTooth.available() > 0) { // the call parseData method cmMount.btParseData(&azVal, &altVal, &cmdVal); // the integers xVal, yVal, zVal now hold the values received cmBlueTooth.print("["); cmBlueTooth.print(azVal); cmBlueTooth.print(";"); cmBlueTooth.print(altVal); cmBlueTooth.print(";"); cmBlueTooth.print(cmdVal); cmBlueTooth.print("]"); } // end if } //******************************************************************** // All subsidiary procedures //******************************************************************** // start up routine // ------------------------------------------------------------------- void userStart() { // 1. Ask if making a PC connection cmMount.lcdClear(); cmMount.lcdDisplay(lcdLine1, 1, "Control by PC?"); cmMount.lcdDisplay(lcdLine2, 1, "1 = Yes, 2 = No"); // loop through until a result is obtained do { keypadResult = cmMount.readKeypad(); } while (keypadResult != 1 && keypadResult != 2); if (keypadResult ==1) { cmMount.lcdDisplay(lcdLine2, 1, " Yes "); do {keypadResult = cmMount.readKeypad();} while (keypadResult != 13); keypadResult = 1; } else { cmMount.lcdDisplay(lcdLine2, 1, " No"); do {keypadResult = cmMount.readKeypad();} while (keypadResult != 13); keypadResult = 2; } delay(1000); if (keypadResult ==1){ // PC control cmMount.lcdClear(); cmMount.lcdDisplay(lcdLine1, 1, "Run PC software,"); cmMount.lcdDisplay(lcdLine2, 1, "waiting... s"); // wait for bluetooth commands (or max 5 mins) int waiting=90; while ((cmMount.btAvailable() == 0) && waiting > 0) { if (waiting > 9) { cmMount.lcdDisplay(lcdLine2, 13, waiting); } else { cmMount.lcdDisplay(lcdLine2, 13, " "); cmMount.lcdDisplay(lcdLine2, 14, waiting); } waiting--; cmMount.btAvailable(); // needed with NewSoftSerial library delay(1000); } // if timed out, start the loop within setup again if (waiting==0) { cmMount.lcdClear(); cmMount.lcdDisplay(lcdLine1, 1, "Error: timed out"); delay(5000); keypadResult = 3; } // or got serial data, so handshake else { pcHandShaking(); } } // Mount control if (keypadResult ==2){ mtCoordObtaining(); } } // end userStart // pcHandshaking procedure // ------------------------------------------------------------------- void pcHandShaking() { // parse the data received cmMount.btParseData(&azVal, &altVal, &cmdVal); if (azVal == btHandshake1 && altVal == btHandshake1 && cmdVal == btHandshake1) { // report that 'good data' has been recieved cmMount.lcdClear(); cmMount.lcdDisplay(lcdLine1, 1, "Data received,"); cmMount.lcdDisplay(lcdLine2, 1, "handshaking..."); cmMount.btAvailable(); // needed with NewSoftSerial library delay(2000); // write data back to the laptop cmMount.btWrite("["); cmMount.btWrite(btHandshake2); cmMount.btWrite(";"); cmMount.btWrite(btHandshake2); cmMount.btWrite(";"); cmMount.btWrite(btHandshake2); cmMount.btWrite("]"); } else { cmMount.lcdClear(); cmMount.lcdDisplay(lcdLine1, 1, "Error:"); cmMount.lcdDisplay(lcdLine2, 1, "Bad data recd"); keypadResult = 3; // loop round startup procedures again delay(2000); } // if PC control proceeding successully if (keypadResult == 1) { cmMount.lcdDisplay(lcdLine1, 1, "Now, polar align"); cmMount.lcdDisplay(lcdLine2, 1, "#=Done; *=Cancel"); do { keypadResult = cmMount.readKeypad(); //move using keypad until press # or cancel } while (keypadResult != 10 && keypadResult != 11); // HERE NEED TO PUT IN POLAR ALIGN ROUTINE // HAVING SENT THE DATA OUT // JUST GO INTO KEYPAD READING / MOVING ROUTINE // CARRY ON UNTIL PRESSSES # AT THIS END. // THEN MOUNT WAITS FOR PC RESPONSE // PC ONLY RESPONDS WHEN USER PRESSES 'OK' ON PC // (AMEND PC INSTRUCTIONS SO IT SAYS, POLAR ALIGN MOUNT, // THEN PRESS '#' ON MOUNT. // AFTER PRESSSING '#', CLICK OK HERE. // ON PC: // IF PC RECEIVES GOOD DATA, THEN WILL POP UP QUESTION (ABOVE) // IF PC RECEIVES BAD DATA, THEN WILL NOT POP UP. // SO NEED TO BE ABLE CANCEL POLAR ALIGN ON THE MOUNT // WOULD SUGGEST THAT * ON THE KEYPAD ABANDONS POLAR ALIGN // THEN STARTS AT BEGINNING OF START UP ROUTINE AGAIN // on 'OK' on PC, the PC sends through the mounts coords // assuming that the cmdVal is correct (ie new coords // - which will be used as 'synch' later too. // then store the new coords. // Display the new coords as (need routine for this): // cmMount.lcdDisplay(lcdLine1, 1, "Az: 359.59'59" P"); // cmMount.lcdDisplay(lcdLine2, 1, "Alt: 89.59'59" C"); // display routines: // 1. Initialise for coords (ie put in Az:, Alt: etc) // 2. just display coords // 3. PC control // 4. MT control // if good data received then wait for more data back // this contains the az and alt coords // if good data received back then store it and // successfully connected pcControl = true; initialised = true; } } // end pcHandShaking void mtCoordObtaining() { // Get the Coords boolean azCoordsOK = false; boolean altCoordsOK = false; char azCoordsInput[10] = {0,0,0,0,0,0,0,0,0,0}; char altCoordsInput[10] = {0,0,5,2,0,1,0,0,2,6}; do { cmMount.lcdClear(); cmMount.lcdDisplay(lcdLine1, 1, "Enter Az: #=OK"); cmMount.lcdDisplay(2, 1, "000"); cmMount.lcdDisplay(2, 4, (char)223); cmMount.lcdDisplay(2, 5, "00"); cmMount.lcdDisplay(2, 7, (char)39); cmMount.lcdDisplay(2, 8, "00"); cmMount.lcdDisplay(2, 10, (char)34); cmMount.lcdDisplay(2, 11, " *=Del"); cmMount.lcdPosition(2,1); cmMount.lcdBlockCursor(); // Az input loop int entrypos = 1; do { // wait until get a response do {keypadResult = cmMount.readKeypad();} while (keypadResult == 13); // check the result switch (keypadResult){ case 10: // * entrypos -=1; if (entrypos==0){entrypos=1;} if (entrypos==4 || entrypos==7) {entrypos -=1;} cmMount.lcdPosition(2,entrypos); break; case 11: // # entrypos = 13; break; default: azCoordsInput[entrypos] = char(keypadResult); cmMount.lcdDisplay(2,entrypos, keypadResult); entrypos +=1; if (entrypos==4 || entrypos==7) {entrypos +=1;} if (entrypos==10){entrypos=9;} cmMount.lcdPosition(2,entrypos); } // end: switxh do {keypadResult = cmMount.readKeypad();} while (keypadResult != 13); } while (entrypos != 13); // end: do Az input loop // Az coords have been entered long azDegs = (int(azCoordsInput[1]) * 100) + (int(azCoordsInput[2]) * 10) + (int(azCoordsInput[3])); azDegs = azDegs * 3600; long azMins = (int(azCoordsInput[5]) * 10) + (int(azCoordsInput[6])); if (azMins>59) {azDegs=400;} // throw an error if over 59 mins azMins = azMins * 60; long azSecs = (int(azCoordsInput[8]) * 10) + (int(azCoordsInput[9])); if (azSecs>59) {azDegs=400;} // throw an error if over 59 secs azSecs = azSecs + azMins + azDegs; // Az coords: check within 2 degrees of zero degrees if (azSecs == 1296000){azSecs = 0;} // change to zero if 360 degrees entered if ((azSecs <= 7200) || ((azSecs >= 1288800) && (azSecs < 1296000))) { azCoordsOK = true; cmMount.lcdNoCursor(); cmMount.lcdClear(); azGlobal = azSecs; } else { cmMount.lcdNoCursor(); cmMount.lcdClear(); cmMount.lcdDisplay(lcdLine1, 1, "Error"); cmMount.lcdDisplay(lcdLine2, 1, "Bad Az data"); delay(2000); } } while (azCoordsOK == false); // End: Get the Az Coords // Get the Az Coords do { // clear the screen cmMount.lcdDisplay(lcdLine1, 1, "Enter Alt: #=OK"); cmMount.lcdDisplay(2, 1, " 52"); cmMount.lcdDisplay(2, 4, (char)223); cmMount.lcdDisplay(2, 5, "10"); cmMount.lcdDisplay(2, 7, (char)39); cmMount.lcdDisplay(2, 8, "26"); cmMount.lcdDisplay(2, 10, (char)34); cmMount.lcdDisplay(2, 11, " *=Del"); cmMount.lcdPosition(2,2); cmMount.lcdBlockCursor(); // Alt input loop int entrypos = 2; do { // wait until get a response do {keypadResult = cmMount.readKeypad();} while (keypadResult == 13); // check the result switch (keypadResult){ case 10: // * entrypos -=1; if (entrypos==1){entrypos=2;} if (entrypos==4 || entrypos==7) {entrypos -=1;} cmMount.lcdPosition(2,entrypos); break; case 11: // # entrypos = 13; break; default: altCoordsInput[entrypos] = char(keypadResult); cmMount.lcdDisplay(2,entrypos, keypadResult); entrypos +=1; if (entrypos==4 || entrypos==7) {entrypos +=1;} if (entrypos==10){entrypos=9;} cmMount.lcdPosition(2,entrypos); } // end: switch do {keypadResult = cmMount.readKeypad();} while (keypadResult != 13); } while (entrypos != 13); // end: do Az input loop // Alt coords have been entered long altDegs = (int(altCoordsInput[2]) * 10) + (int(altCoordsInput[3])); altDegs = altDegs * 3600; long altMins = (int(altCoordsInput[5]) * 10) + (int(altCoordsInput[6])); if (altMins>59) {altDegs=400;} // throw an error if over 59 mins altMins = altMins * 60; long altSecs = (int(altCoordsInput[8]) * 10) + (int(altCoordsInput[9])); if (altSecs>60) {altDegs=400;} // throw an error if over 59 secs altSecs = altSecs + altMins + altDegs; // Alt coords: check over 20 degrees and less then 90 degrees if ((altSecs >= 72000) && (altSecs < 324000)) { altCoordsOK = true; cmMount.lcdNoCursor(); cmMount.lcdClear(); altGlobal = altSecs; } else { cmMount.lcdNoCursor(); cmMount.lcdClear(); cmMount.lcdDisplay(lcdLine1, 1, "Error"); cmMount.lcdDisplay(lcdLine2, 1, "Bad Alt data"); delay(2000); } } while (altCoordsOK == false); // End: Get the Alt Coords // report successful cmMount.lcdDisplay(lcdLine1, 1, "Startup complete"); cmMount.lcdDisplay(lcdLine2, 1, "Mount control"); delay(2000); initialised = true; }
this is the test
/* CapeMirror.h v. 2a by Ben @ Cape Ealing */ // ensure this library description is only included once #ifndef CapeMirror_h #define CapeMirror_h #define moveStep 1 #define slewStep 2 // create shorthand refs for "[" and "]" and ";" #define leftbracket 0x5b #define rightbracket 0x5d #define semicolon 0x3b #define dataLength 8 // LCD definitions #define _line1 127 #define _line2 191 #define _cmd 254 #define _cmdSp 124 #define _clear 1 #define _on 12 #define _off 8 #define _nocursor 12 #define _block 13 #define _line 14 #define _lcddelay 50 //#define _blightshiftdelay 500 // stepper motor definitions // azimuth resolution: 0.045 degrees (162 arcsecs) // altitude resolution: 0.09 degrees (324 arcsecs) #define _azRes 162 #define _altRes 324 #define _azMax 1296000 #define _altMax 324000 #define _altMin 72000 /* CapeMirror library */ class CapeMirror { // public methods and variables // ---------------------------- public: // Initialise the class CapeMirror(long* gAz, long* gAlt); // define the 'address' for the bluetooth serial connection void setBTaddress(NewSoftSerial *btAddress); // define the 'address' for the LCD serial connection void setLCDaddress(NewSoftSerial *lcdAddress); // wrappers for the NewSoftSerial begin method void beginBT(int btBaudRate); void beginLCD(int lcdBaudRate); // Create the parse method void btParseData(long *azVal, long *altVal, long *cmdVal); // bluetooth write methods void btWrite (char msg); void btWrite (const char msg[]); void btWrite (uint8_t msg); void btWrite (int msg); void btWrite (unsigned int msg); void btWrite (long msg); void btWrite (unsigned long msg); // wrapper for NewSoftSerial available method uint8_t btAvailable(void); // serLCD // ---------------- // selection of methods from the serLCD library void lcdOn(); void lcdOff(); void lcdClear(); void lcdBlockCursor(); void lcdLineCursor(); void lcdNoCursor(); void lcdBacklight(int blight); void lcdBacklightShift(); void lcdPosition (int line, int character); void lcdDisplay ( int line, int character, char ); void lcdDisplay ( int line, int character, const char[] ); void lcdDisplay ( int line, int character, uint8_t ); void lcdDisplay ( int line, int character, int ); void lcdDisplay ( int line, int character, unsigned int ); void lcdDisplay ( int line, int character, long ); void lcdDisplay ( int line, int character, unsigned long ); void lcdDisplay ( int line, int character, long, int ); void lcdDisplayCoords(); void lcdDisplayDegsMins(); void lcdDisplaySecs(); void lcdDisplayAzSecs(); void lcdDisplayAltSecs(); void lcdDisplayControlMT(); void lcdDisplayControlPC(); // ---------------- // Matrix_Steppers // ---------------- // define the rows and columns void setKeypadRows(int row1, int row2, int row3, int row4); void setKeypadCols(int col1, int col2, int col3); // read the keypad int readKeypad(void); // ---------------- // The movement methods (slew and move) // ---------------- void slew (int steps_to_move1, int steps_to_move2); void move (int keyResult); // ---------------- // Stepper_Aclr8_2 // ---------------- // Stepper constructors: 4 wire stepper motors only void azStepper(int number_of_steps1, int motor1_pin_1, \ int motor1_pin_2, int motor1_pin_3, int motor1_pin_4); void altStepper(int number_of_steps2, int motor2_pin_1, \ int motor2_pin_2, int motor2_pin_3, int motor2_pin_4); // Define each stepper's rates (min speed, max speed, acceleration) void azStepperSpeeds(long minSpeed1, long maxSpeed1, double Accel1, long moveSpeed1); void altStepperSpeeds(long minSpeed2, long maxSpeed2, double Accel2, long moveSpeed2); // ---------------- // Stepper_Aclr8_i // ---------------- // define interupt pins method: void setInterruptPins(int firePin, int readPin); void setStepsAddress(int* azStepsAddress, int* altStepsAddress); // return the version if asked int version(void); // ******************************************************** // private methods and variables // ******************************************************** private: // variable to hold a references to the serial connections NewSoftSerial* cmBlueToothRef; NewSoftSerial* cmLCDRef; long* gAzimuth; long* gAltitude; // ---------------- // The keypad // ---------------- int col1; int col2; int col3; int row1; int row2; int row3; int row4; int keyResult; // ---------------- // Stepper_Aclr8_2 // ---------------- // setup the motors void takeSteps(int steps_to_move1, int steps_to_move2, int step_type); void stepMotor1(int thisStep1); void stepMotor2(int thisStep2); // Direction of rotation int direction1; int direction2; // Speed in RPMs int speed1; int speed2; // delay between steps, in ms, based on speed1 double step_delay1; double step_delay2; double move_step_delay1; double move_step_delay2; // total number of steps this motor can take int number_of_steps1; int number_of_steps2; // delay at 1 rev per minute double delay_1revpermin1; double delay_1revpermin2; // which step the motor is on int step_number1; int step_number2; //steps left int steps_left1; int steps_left2; // motor pin numbers: int motor1_pin_1; int motor2_pin_1; int motor1_pin_2; int motor2_pin_2; int motor1_pin_3; int motor2_pin_3; int motor1_pin_4; int motor2_pin_4; // time stamp in ms of when the last step was taken long last_step_time1; long last_step_time2; //motor speeds long motorMinSpeed1; long motorMinSpeed2; long motorMaxSpeed1; long motorMaxSpeed2; long motorAccSteps1; long motorAccSteps2; double motorAccelVal1; double motorAccelVal2; long minSpeed1; long minSpeed2; // which step number of steps to take int steps_no1; int steps_no2; // total steps for both motors int total_steps_left; // interupt pins int firePin; int readPin; // references to variables in sketch //NewSoftSerial* theSerial; int* azStepsToDoAddress; int* altStepsToDoAddress; // counter for number of bytes read int btByteIndex; // whether all data has been read int btAllComplete; // arrays for each of the three values received char azData[dataLength], altData[dataLength], cmdData[dataLength]; // the character being read char thisChar; // variable to hold whether any partic value is complete int azComplete, altComplete, cmdComplete; long azDegLCD; long azMinLCD; long azSecLCD; long altDegLCD; long altMinLCD; long altSecLCD; int blightShift; bool moveSingleStep; void moveSingleStepToggle(); int t; }; #endif
/* CapeMirror.cpp v. 2a by Ben @ Cape Ealing */ #include "WProgram.h" #include "NewSoftSerial.h" #include "CapeMirror.h" /* * Initialise the class */ CapeMirror::CapeMirror(long* gAz, long* gAlt) { gAzimuth = gAz; gAltitude = gAlt; } // define the 'address' for the bluetooth serial connection void CapeMirror::setBTaddress(NewSoftSerial* btAddress) { cmBlueToothRef = btAddress; } // start the bluetooth connection void CapeMirror::beginBT(int btBaudRate) { cmBlueToothRef->begin(btBaudRate); } uint8_t CapeMirror::btAvailable(void) { return cmBlueToothRef->available(); } // define the 'address' for the LCD serial connection void CapeMirror::setLCDaddress(NewSoftSerial* lcdAddress) { cmLCDRef = lcdAddress; } // start the lcd connection void CapeMirror::beginLCD(int lcdBaudRate) { blightShift = 5; cmLCDRef->begin(lcdBaudRate); } void CapeMirror::lcdOn() { cmLCDRef->print(_cmd, BYTE); // instruction cmLCDRef->print(_on, BYTE); // turn on delay(_lcddelay); } void CapeMirror::lcdOff() { cmLCDRef->print(_cmd, BYTE); // instruction cmLCDRef->print(_off, BYTE); // turn off delay(_lcddelay); } void CapeMirror::lcdClear() { cmLCDRef->print(_cmd, BYTE); // instruction cmLCDRef->print(_clear, BYTE); // clear the LCD 0x01 or 1 delay(_lcddelay); } void CapeMirror::lcdBlockCursor() { cmLCDRef->print(_cmd, BYTE); // instruction cmLCDRef->print(_block, BYTE); // block cursor: 0X0D or 13 delay(_lcddelay); } void CapeMirror::lcdLineCursor() { cmLCDRef->print(_cmd, BYTE); // instruction cmLCDRef->print(_line, BYTE); // block cursor: 0X0D or 13 delay(_lcddelay); } void CapeMirror::lcdNoCursor() { cmLCDRef->print(_cmd, BYTE); // instruction cmLCDRef->print(_nocursor, BYTE); // block cursor: 0X0D or 13 delay(_lcddelay); } void CapeMirror::lcdBacklight(int blight) { blight = int((blight*30)/100); blight = (blight<3)?3:blight; blight = (blight>30)?30:blight; blight += 127; cmLCDRef->print(_cmdSp, BYTE); // instruction coming cmLCDRef->print(blight, BYTE); // backlight instruction delay(_lcddelay); } void CapeMirror::lcdBacklightShift() { blightShift -= 1; if (blightShift == -1){blightShift = 5;} lcdBacklight ((blightShift*20)); // delay(_blightshiftdelay); } void CapeMirror::lcdPosition (int line, int character) { int pos = 0; if(line==2) { pos = _line2; } else { pos = _line1; } pos = pos + character; cmLCDRef->print(_cmd, BYTE); // command cmLCDRef->print(pos, BYTE); // set the position } void CapeMirror::lcdDisplay ( int line, int character, char v ) { lcdPosition (line,character); cmLCDRef->print(v); } void CapeMirror::lcdDisplay ( int line, int character, const char v[] ) { lcdPosition (line,character); cmLCDRef->print(v); } void CapeMirror::lcdDisplay ( int line, int character, uint8_t v ) { lcdPosition (line,character); cmLCDRef->print(v); } void CapeMirror::lcdDisplay ( int line, int character, int v ) { lcdPosition (line,character); cmLCDRef->print(v); } void CapeMirror::lcdDisplay ( int line, int character, unsigned int v ) { lcdPosition (line,character); cmLCDRef->print(v); } void CapeMirror::lcdDisplay ( int line, int character, long v ) { lcdPosition (line,character); cmLCDRef->print(v); } void CapeMirror::lcdDisplay ( int line, int character, unsigned long v ) { lcdPosition (line,character); cmLCDRef->print(v); } void CapeMirror::lcdDisplay ( int line, int character, long v, int t ) { lcdPosition (line,character); cmLCDRef->print(v,t); } void CapeMirror::btWrite (char msg) {cmBlueToothRef->print(msg);} void CapeMirror::btWrite (const char msg[]) {cmBlueToothRef->print(msg);} void CapeMirror::btWrite (uint8_t msg) {cmBlueToothRef->print(msg);} void CapeMirror::btWrite (int msg) {cmBlueToothRef->print(msg);} void CapeMirror::btWrite (unsigned int msg) {cmBlueToothRef->print(msg);} void CapeMirror::btWrite (long msg) {cmBlueToothRef->print(msg);} void CapeMirror::btWrite (unsigned long msg) {cmBlueToothRef->print(msg);} void CapeMirror::lcdDisplayControlMT() {lcdDisplay(1,16,"M"); lcdDisplay(2,16,"T");} void CapeMirror::lcdDisplayControlPC() { lcdDisplay(1,16,"P"); lcdDisplay(2,16,"C"); } void CapeMirror::btParseData(long* azVal, long* altVal, long* cmdVal) { // reset the variables *azVal = 0; *altVal = 0; *cmdVal = 0; azComplete = false; altComplete = false; cmdComplete = false; for (int i=0;iread(); if (thisChar == leftbracket) { // read all first data section while (azComplete == false && cmBlueToothRef->available() > 0) { char thisChar = cmBlueToothRef->read(); if (thisChar == semicolon) { azComplete = true; break; } else { azData[btByteIndex] = thisChar; btByteIndex++; } } btByteIndex = 0; // read the second data section while (altComplete == false && cmBlueToothRef->available() > 0) { char thisChar = cmBlueToothRef->read(); if (thisChar == semicolon) { altComplete = true; break; } else { altData[btByteIndex] = thisChar; btByteIndex++; } } btByteIndex= 0; // read the third data section while (cmdComplete == false && cmBlueToothRef->available() > 0) { char thisChar = cmBlueToothRef->read(); if (thisChar == rightbracket) { cmdComplete = true; break; } else { cmdData[btByteIndex] = thisChar; btByteIndex++; } } btByteIndex= 0; // report back the values *azVal = atol(azData); *altVal = atol(altData); *cmdVal = atol(cmdData); } } /* * Set up the keypad */ // define the rows void CapeMirror::setKeypadRows(int row1, int row2, int row3, int row4) { this->row1 = row1; this->row2 = row2; this->row3 = row3; this->row4 = row4; moveSingleStep = false; } // define the columns void CapeMirror::setKeypadCols(int col1, int col2, int col3) { this->col1 = col1; this->col2 = col2; this->col3 = col3; // set them as outputs pinMode(this->col1, OUTPUT); pinMode(this->col2, OUTPUT); pinMode(this->col3, OUTPUT); } /* * Read the keypad */ int CapeMirror::readKeypad(void) { keyResult = 13; // Read the 1st column digitalWrite(col1, HIGH); if (digitalRead(row1) == HIGH){keyResult = 1;} if (digitalRead(row2) == HIGH){keyResult = 4;} if (digitalRead(row3) == HIGH){keyResult = 7;} if (digitalRead(row4) == HIGH){keyResult = 10;} digitalWrite(col1, LOW); if (keyResult<12){return keyResult;} // Read the 2nd column digitalWrite(col2, HIGH); if (digitalRead(row1) == HIGH){keyResult = 2;} if (digitalRead(row2) == HIGH){keyResult = 5;} if (digitalRead(row3) == HIGH){keyResult = 8;} if (digitalRead(row4) == HIGH){keyResult = 0;} digitalWrite(col2, LOW); if (keyResult<12){return keyResult;} // Read the 3rd column digitalWrite(col3, HIGH); if (digitalRead(row1) == HIGH){keyResult = 3;} if (digitalRead(row2) == HIGH){keyResult = 6;} if (digitalRead(row3) == HIGH){keyResult = 9;} if (digitalRead(row4) == HIGH){keyResult = 11;} digitalWrite(col3, LOW); return keyResult; } /* First motor * Constructor for four-pin stepper motor * Sets which wires should control the motor and * primary variables used by motor. */ void CapeMirror::azStepper(int number_of_steps1, \ int motor1_pin_1, int motor1_pin_2, \ int motor1_pin_3, int motor1_pin_4) { // which step the motor is on this->step_number1 = 0; // the motor speed1, in revolutions per minute this->speed1 = 0; // motor direction1 this->direction1 = 0; // time stamp in ms of the last step taken this->last_step_time1 = 0; // total number of steps for this motor this->number_of_steps1 = number_of_steps1; // find the delay nec at 1 rev per min this->delay_1revpermin1 = 60L * 1000L / number_of_steps1; // Arduino pins for the motor control connection this->motor1_pin_1 = motor1_pin_1; this->motor1_pin_2 = motor1_pin_2; this->motor1_pin_3 = motor1_pin_3; this->motor1_pin_4 = motor1_pin_4; // setup the pins on the microcontroller pinMode(this->motor1_pin_1, OUTPUT); pinMode(this->motor1_pin_2, OUTPUT); pinMode(this->motor1_pin_3, OUTPUT); pinMode(this->motor1_pin_4, OUTPUT); } /* Second motor * Constructor for four-pin stepper motor * Sets which wires should control the motor and * primary variables used by motor. */ void CapeMirror::altStepper(int number_of_steps2, \ int motor2_pin_1, int motor2_pin_2, \ int motor2_pin_3, int motor2_pin_4) { // which step the motor is on this->step_number2 = 0; // the motor speed, in revolutions per minute this->speed2 = 0; // motor direction this->direction2 = 0; // time stamp in ms of the last step taken this->last_step_time2 = 0; // total number of steps for this motor this->number_of_steps2 = number_of_steps2; // find the delay nec at 1 rev per min this->delay_1revpermin2 = 60L * 1000L / number_of_steps2; // Arduino pins for the motor control connection this->motor2_pin_1 = motor2_pin_1; this->motor2_pin_2 = motor2_pin_2; this->motor2_pin_3 = motor2_pin_3; this->motor2_pin_4 = motor2_pin_4; // setup the pins on the microcontroller pinMode(this->motor2_pin_1, OUTPUT); pinMode(this->motor2_pin_2, OUTPUT); pinMode(this->motor2_pin_3, OUTPUT); pinMode(this->motor2_pin_4, OUTPUT); } /* First motor Set the min speed, max speed, and steps taken to accelerate */ void CapeMirror::azStepperSpeeds(long minSpeed1, long maxSpeed1, double Accel1, long moveSpeed1) { this->motorMinSpeed1 = minSpeed1; this->motorMaxSpeed1 = maxSpeed1; // Number of steps to accelerate over this->motorAccSteps1 = Accel1; // Change in speed1 needed per step this->motorAccelVal1 = (this->motorMaxSpeed1 -this->motorMinSpeed1) / (Accel1-1); // Set the move speed (ie the speed when 'moving' in response to keypad press this->move_step_delay1 = 60L * 1000L / this->number_of_steps1 / moveSpeed1; } /* Second motor Set the min speed, max speed, and steps taken to accelerate */ void CapeMirror::altStepperSpeeds(long minSpeed2, long maxSpeed2, double Accel2, long moveSpeed2) { this->motorMinSpeed2 = minSpeed2; this->motorMaxSpeed2 = maxSpeed2; // Number of steps to accelerate over this->motorAccSteps2 = Accel2; // Change in speed1 needed per step this->motorAccelVal2 = (this->motorMaxSpeed2 -this->motorMinSpeed2) / (Accel2-1); // Set the move speed (ie the speed when 'moving' in response to keypad press this->move_step_delay2 = 60L * 1000L / this->number_of_steps2 / moveSpeed2; } /* Set the interrupt pins */ void CapeMirror::setInterruptPins(int firePin, int readPin) { // Pin to fire as an output pin (here a keypad column) this->firePin = firePin; // Pin to read (here a keypad row) this->readPin = readPin; } /* Get the address of the 'steps to do' variables */ void CapeMirror::setStepsAddress(int* azStepsAddress, int* altStepsAddress) { azStepsToDoAddress = azStepsAddress; altStepsToDoAddress = altStepsAddress; } void CapeMirror::slew (int steps_to_move1, int steps_to_move2) { takeSteps(steps_to_move1, steps_to_move2, slewStep); } void CapeMirror::move(int keyResult) { switch (keyResult) { case 0: break; case 1: // up and left takeSteps(-1,1, moveStep); break; case 2: // up takeSteps(0, 1, moveStep); break; case 3: // up and right takeSteps(1, 1, moveStep); break; case 4: // left takeSteps(-1, 0, moveStep); break; case 5: // toggle whether only moving in single steps do {t = readKeypad();} while (t != 13); moveSingleStepToggle(); break; case 6: // right takeSteps(1, 0, moveStep); break; case 7: // left and down takeSteps(-1, -1, moveStep); break; case 8: // down takeSteps(0, -1, moveStep); break; case 9: // right and down takeSteps(1, -1, moveStep); break; } delay(move_step_delay1); if (moveSingleStep == true) { do {t = readKeypad();} while (t != 13); } } void CapeMirror::moveSingleStepToggle() { moveSingleStep = (moveSingleStep==false)?true:false; } /* Step method for both motors */ void CapeMirror::takeSteps(int steps_to_move1, int steps_to_move2, int step_type) { if (step_type == slewStep){ // if slewing, set the interrupt 'fire' pin high digitalWrite(this->firePin, HIGH); } // steps taken int steps_no1= 1; int steps_no2= 1; // Steps for each motor to complete, and the total // how many steps to take for the motor int steps_left1 = abs(steps_to_move1); int steps_left2 = abs(steps_to_move2); int total_steps_left = steps_left1 + steps_left2; // determine direction1 based on whether steps_to_mode is + or -: if (steps_to_move1 > 0) {this->direction1 = 1;} else {this->direction1 = 0;} if (steps_to_move2 > 0) {this->direction2 = 1;} else {this->direction2 = 0;} // if a slew, reset the motor speed if (step_type == slewStep) { this->speed1 = this->motorMinSpeed1; this->speed2 = this->motorMinSpeed2; } // this is the loop for both motor while(total_steps_left > 0) { // set new values for the StepsToTake address (ie StepsToTake variable) *azStepsToDoAddress = steps_left1; *altStepsToDoAddress = steps_left2; // if a slew, read the interrupt pin if (step_type == slewStep) { int readVal = digitalRead(this->readPin); // if high then exit if (readVal==HIGH){ break; } } //First motor //If the motor steps not completed it's steps then if (steps_left1 > 0) { //if a slew, work out the speed if (step_type == slewStep) { //1.a. if in the first third of total steps AND if ((steps_left1 > abs(steps_to_move1/3)) && \ (steps_left1 > (abs(steps_to_move1/3)*2))) { // 1.b if not yet at max speed1 if (this->speed1 < this->motorMaxSpeed1){ // get the new speed1 this->speed1 = ((steps_no1 -1) * this->motorAccelVal1) + this->motorMinSpeed1; // get the new delay step_delay1 = (this->delay_1revpermin1 / this->speed1); } // i.b. end if: not yet max speed1 } //1.a. end if: first third of total steps //2. if in middle third of steps do nothing //3.a. if in the last third of total steps AND if (steps_left1 <= (abs(steps_to_move1)/3)) { //3.b. if within deceleration zone if (steps_left1 <= this->motorAccSteps1) { // get the new speed1 this->speed1 = ((steps_left1-1) * this->motorAccelVal1) + this->motorMinSpeed1; // get the new delay step_delay1 = (this->delay_1revpermin1 / this->speed1); } //3.b. end if: within deceleration zone } //3.a. end if: last third of total steps } // end: if this is a 'slew' else // if this is a 'move' not a 'slew' { step_delay1 = move_step_delay1; } // move only if the appropriate delay has passed: if (millis() - this->last_step_time1 >= this->step_delay1) { // get the timeStamp of when you stepped: this->last_step_time1 = millis(); // increment or decrement the step number, // depending on direction1: if (this->direction1 == 1) { this->step_number1++; if (this->step_number1 == this->number_of_steps1) { this->step_number1 = 0; } } else { if (this->step_number1 == 0) { this->step_number1 = this->number_of_steps1; } this->step_number1--; } // in/decrement the steps left: steps_no1++; steps_left1--; total_steps_left--; // Adjust the Azimuth variable if (this->direction1 >0) { *gAzimuth += _azRes;} else {*gAzimuth -= _azRes;} if (*gAzimuth >= _azMax) { *gAzimuth -= _azMax; } if (*gAzimuth < 0) { *gAzimuth += _azMax; } // only report the arcseconds at the end of the slew if (steps_left1 == 0) {lcdDisplayAzSecs();} // step the motor to step number 0, 1, 2, or 3: stepMotor1(this->step_number1 % 4); } // End: if suitable delay passed } //End: if (steps_left1 > 0) //Second motor //If the motor steps not completed it's steps then if (steps_left2 > 0) { //if a slew, work out the speed if (step_type == slewStep) { //1.a. if in the first third of total steps AND if ((steps_left2 > abs(steps_to_move2/3)) && \ (steps_left2 > (abs(steps_to_move2/3)*2))) { // 1.b if not yet at max speed1 if (this->speed2 < this->motorMaxSpeed2){ // get the new speed1 this->speed2 = ((steps_no2 -1) * this->motorAccelVal2) + this->motorMinSpeed2; // get the new delay step_delay2 = (this->delay_1revpermin2 / this->speed2); } // i.b. end if: not yet max speed1 } //1.a. end if: first third of total steps //2. if in middle third of steps do nothing //3.a. if in the last third of total steps AND if (steps_left2 <= (abs(steps_to_move2)/3)) { //3.b. if within deceleration zone if (steps_left2 <= this->motorAccSteps2) { // get the new speed1 this->speed2 = ((steps_left2-1) * this->motorAccelVal2) + this->motorMinSpeed2; // get the new delay step_delay2 = (this->delay_1revpermin2 / this->speed2); } //end if: within deceleration zone } //3.a. end if: last third of total steps } // end: if this is a 'slew' else // if this is a 'move' not a 'slew' { step_delay2 = move_step_delay2; } // move only if the appropriate delay has passed: if (millis() - this->last_step_time2 >= this->step_delay2) { // get the timeStamp of when you stepped: this->last_step_time2 = millis(); // increment or decrement the step number, // depending on direction1: if (this->direction2 == 1) { this->step_number2++; if (this->step_number2 == this->number_of_steps2) { this->step_number2 = 0; } } else { if (this->step_number2 == 0) { this->step_number2 = this->number_of_steps2; } this->step_number2--; } // in/decrement the steps left: steps_no2++; steps_left2--; total_steps_left--; // Adjust the Altitude variable if (this->direction2 >0) { *gAltitude += _altRes;} else {*gAltitude -= _altRes;} if (*gAltitude >= _altMax) { // gone too high, end stepping *gAltitude -= _altRes; steps_left2=0; if (step_type == slewStep) {digitalWrite(this->firePin, LOW);} lcdDisplayDegsMins(); lcdDisplaySecs(); break; } if (*gAltitude < _altMin) { // gone too low, end stepping *gAltitude += _altRes; steps_left2=0; if (step_type == slewStep) {digitalWrite(this->firePin, LOW);} lcdDisplayDegsMins(); lcdDisplaySecs(); break; } // only report the arcseconds at the end of the slew if (steps_left2 == 0) { lcdDisplayAltSecs(); } // step the motor to step number 0, 1, 2, or 3: stepMotor2(this->step_number2 % 4); } // end: if suitable delay passed } //End: if (steps_left1 > 0) // Display the results lcdDisplayDegsMins(); } //End: WHILE statement // if a 'slew', set the interrupt 'fire' pin low if (step_type == slewStep) {digitalWrite(this->firePin, LOW);} } //End: void step() /* First motor * Moves the motor forward or backwards */ void CapeMirror::stepMotor1(int thisStep1) { switch (thisStep1) { case 0: // 1010 digitalWrite(motor1_pin_1, HIGH); digitalWrite(motor1_pin_2, LOW); digitalWrite(motor1_pin_3, HIGH); digitalWrite(motor1_pin_4, LOW); break; case 1: // 0110 digitalWrite(motor1_pin_1, LOW); digitalWrite(motor1_pin_2, HIGH); digitalWrite(motor1_pin_3, HIGH); digitalWrite(motor1_pin_4, LOW); break; case 2: //0101 digitalWrite(motor1_pin_1, LOW); digitalWrite(motor1_pin_2, HIGH); digitalWrite(motor1_pin_3, LOW); digitalWrite(motor1_pin_4, HIGH); break; case 3: //1001 digitalWrite(motor1_pin_1, HIGH); digitalWrite(motor1_pin_2, LOW); digitalWrite(motor1_pin_3, LOW); digitalWrite(motor1_pin_4, HIGH); break; } } /* Second motor * Moves the motor forward or backwards */ void CapeMirror::stepMotor2(int thisStep2) { switch (thisStep2) { case 0: // 1010 digitalWrite(motor2_pin_1, HIGH); digitalWrite(motor2_pin_2, LOW); digitalWrite(motor2_pin_3, HIGH); digitalWrite(motor2_pin_4, LOW); break; case 1: // 0110 digitalWrite(motor2_pin_1, LOW); digitalWrite(motor2_pin_2, HIGH); digitalWrite(motor2_pin_3, HIGH); digitalWrite(motor2_pin_4, LOW); break; case 2: //0101 digitalWrite(motor2_pin_1, LOW); digitalWrite(motor2_pin_2, HIGH); digitalWrite(motor2_pin_3, LOW); digitalWrite(motor2_pin_4, HIGH); break; case 3: //1001 digitalWrite(motor2_pin_1, HIGH); digitalWrite(motor2_pin_2, LOW); digitalWrite(motor2_pin_3, LOW); digitalWrite(motor2_pin_4, HIGH); break; } } void CapeMirror::lcdDisplayCoords() { lcdClear(); lcdDisplay(1, 1, "Az: "); lcdDisplay(1, 8, (char)223); lcdDisplay(1, 9, " "); lcdDisplay(1, 11, (char)39); lcdDisplay(1, 12, " "); lcdDisplay(1, 14, (char)34); lcdDisplay(1, 15, " "); lcdDisplay(2, 1, "Alt: "); lcdDisplay(2, 8, (char)223); lcdDisplay(2, 9, " "); lcdDisplay(2, 11, (char)39); lcdDisplay(2, 12, " "); lcdDisplay(2, 14, (char)34); lcdDisplay(2, 15, " "); } void CapeMirror::lcdDisplayDegsMins() { //Azimuth azDegLCD = int(*gAzimuth/3600); azMinLCD = int((*gAzimuth-(azDegLCD*3600))/60); if (azDegLCD > 99){lcdDisplay(1, 5, azDegLCD);} else if (azDegLCD < 10) {lcdDisplay(1, 5, " "); lcdDisplay(1, 7, azDegLCD);} else {lcdDisplay(1, 5, " "); lcdDisplay(1, 6, azDegLCD);} if (azMinLCD < 10) {lcdDisplay(1, 9, " "); lcdDisplay(1, 10, azMinLCD);} else {lcdDisplay(1, 9, azMinLCD);} //Altitude altDegLCD = int(*gAltitude/3600); altMinLCD = int((*gAltitude-(altDegLCD*3600))/60); if (altDegLCD < 10) {lcdDisplay(2, 6, " "); lcdDisplay(2, 7, altDegLCD);} else {lcdDisplay(2, 6, altDegLCD);} if (altMinLCD < 10) {lcdDisplay(2, 9, " "); lcdDisplay(2, 10, altMinLCD);} else {lcdDisplay(2, 9, altMinLCD);} } void CapeMirror::lcdDisplaySecs() { lcdDisplayAzSecs(); lcdDisplayAltSecs(); } void CapeMirror::lcdDisplayAzSecs() { //Azimuth azDegLCD = int(*gAzimuth/3600); azMinLCD = int((*gAzimuth-(azDegLCD*3600))/60); azSecLCD = int(*gAzimuth-((azDegLCD*3600)+(azMinLCD*60))); if (azSecLCD < 10) {lcdDisplay(1, 12, " "); lcdDisplay(1, 13, azSecLCD);} else {lcdDisplay(1, 12, azSecLCD);} } void CapeMirror::lcdDisplayAltSecs() { //Altitude altDegLCD = int(*gAltitude/3600); altMinLCD = int((*gAltitude-(altDegLCD*3600))/60); altSecLCD = int(*gAltitude-((altDegLCD*3600)+(altMinLCD*60))); if (altSecLCD < 10) {lcdDisplay(2, 12, " "); lcdDisplay(2, 13, altSecLCD);} else {lcdDisplay(2, 12, altSecLCD);} } /* version() returns the version of the library: */ int CapeMirror::version(void) { return 2; }
post a comment...
you must be logged in to post a comment.