/* TurnTableV1 06/12/2021 Final Programming against board micros() rollover code on turntable move...WORKING :-) Turntable adjuster with cap switches...WORKING Station DCC Controller Turntable EEPROM 2 x touch screen turntable adjusters 2 x photointerrupter Turntable has 4 exits Pins 2 - interrupt pin for DCC 7 = enablePin...stepper 8 = stepPin...stepper 9 = dirPin...stepper 23 = cap switch 25 = cap switch A0 = photointerrupter....far corner A1 = photointerrupter...station end */ #include "NmraDcc.h" NmraDcc Dcc ; DCC_MSG Packet ; //EEPROM //system will use built in eeprom as it should not be written to very much...limited lifecycle. #include "EEPROM.h" long eepromUpdatePeriod = 60000;//60 secs between updates...also used to turn the power off unsigned long eepromUpdateTimer; const int eepromOffset = 200;//position of 1st bit of data...prevents eeprom wear in same place from previous use place //stores the positions of the exits int trackPositions[4] = {247, 10747, 13047, 23547}; //default positions in steps of track exits from end 1 //stepper motor const int maxSteps = 25600;//number of steps in rotation...1/8 stepping plus pulley reduction const int enablePin = 7;//taken high to disable stepper const int stepPin = 8; const int dirPin = 9; const int poweron = 0; const int poweroff = 1; const int clockwise = 0; const int anticlockwise = 1; const int capClockPin = 23; const int capantiClockPin = 25; int moveToTrackPos = 100; //default when not looking for a track int currentTrackPos; byte turntableIndexState = 0; //1 means it has indexed byte turntableDirection; byte stepInState = 0;//high or low state for next step unsigned long stepperTimer;//timer until next step in micros(); int stepperSpeedDelay = 1000;//delay in micros() between steps...controls speed, Good max speed int stepperStartSpeedDelay = 30000;//nice and slow for start speed...adjustment speed int stepCounter;//current step position of the turntable byte photointerruptReadState = 0;//photointyerrupter state...triggers if hit int currentStepperSpeedDelay; //counters to deal with acceleration timings int findDirection; int stepsTaken;//count up from start //gets eeprom data and puts in trackpositions[4] array void geteepromdata() { int q; byte getbytes[8];//2 bytes per position Serial.println("getbytes[]: "); //get the data from eeprom and store in array for (q = 0; q < 8; q++) { getbytes[q] = EEPROM.read(q + eepromOffset); Serial.println( getbytes[q]); } Serial.println("trackPositions[]: "); //now assemble the data and put into trackpositions[4] for (q = 0; q < 4; q++) { trackPositions[q] = (getbytes[q * 2] * 256) + (getbytes[(q * 2) + 1]); Serial.println(trackPositions[q]); } } //update the eeprom with current trackpositions void updateeeprom() { int q; for (q = 0; q < 4; q++) { EEPROM.update((q * 2) + eepromOffset, highByte(trackPositions[q])); EEPROM.update((q * 2) + eepromOffset + 1, lowByte(trackPositions[q])); } geteepromdata(); } void moveTurntable() { unsigned long currentMicros; currentMicros = micros(); //only do something of a movement has been commanded if (moveToTrackPos < 5) { //changes here to how timing works, this avoids the micros tollover issue at 70 minutes if ((currentMicros - stepperTimer) >= currentStepperSpeedDelay) { stepperTimer = currentMicros; if (stepInState > 0) { stepInState = 0; } else { stepInState = 1; } digitalWrite(stepPin, stepInState); stepsTaken++; if (turntableIndexState > 0) { //don't adjust speed if not indexed //acceleration if (stepsTaken < 500) { currentStepperSpeedDelay = stepperSpeedDelay + 2000 - (stepsTaken * 4); } if ((findDirection - stepsTaken) < 500) { currentStepperSpeedDelay = stepperSpeedDelay + 2000 - ((findDirection - stepsTaken) * 4); } } else { stepsTaken = 0; } //stepperTimer = micros() + currentStepperSpeedDelay;//this is the adjustable version if (turntableDirection == clockwise ) { stepCounter++; if (stepCounter > maxSteps) { stepCounter = 0; } } else { stepCounter--; if (stepCounter < 0) { stepCounter = maxSteps; } } //this resets the index everytime the indexing point is crossed in a clockwise direction int photointerruptRead = analogRead(A0); if (photointerruptRead < 250 && turntableDirection == clockwise && photointerruptReadState < 1) { //only do this check in clockwise direction photointerruptReadState = 1; Serial.println(stepCounter); stepCounter = 0; } if (photointerruptRead > 250 && photointerruptReadState > 0) { photointerruptReadState = 0; } } //stop the table at preset points if (stepCounter == trackPositions[moveToTrackPos]) { Serial.print("Target: "); Serial.print(trackPositions[moveToTrackPos]); Serial.print(" : "); Serial.print(stepCounter); Serial.println(" "); currentTrackPos = moveToTrackPos; moveToTrackPos = 100; turntableIndexState = 1; } } } //finds out what direction to spin the turntable...shortest route //turns power on if there is a change of position void getTurntableDirection() { findDirection = trackPositions[moveToTrackPos] - stepCounter; if (findDirection < 0) { findDirection = findDirection + maxSteps; } if (findDirection > (maxSteps / 2)) { Serial.println("anticlock: "); digitalWrite(dirPin, anticlockwise); // LOW for anticlockwise turntableDirection = anticlockwise; } else { Serial.println("clock: "); digitalWrite(dirPin, clockwise); // LOW for anticlockwise turntableDirection = clockwise; } Serial.println("findDirection: " + String(findDirection)); //turn the power on if the stepper needs to move if (trackPositions[moveToTrackPos] != stepCounter) { stepsTaken = 0;//reset currentStepperSpeedDelay = stepperStartSpeedDelay; digitalWrite(enablePin, poweron);//turn motor driver on } else {//is the track already at the position selected...if so do nothing moveToTrackPos = 100; } } // This function is called whenever a normal DCC Turnout Packet is received and we're in Output Addressing Mode void notifyDccAccTurnoutOutput( uint16_t Addr, uint8_t Direction, uint8_t OutputPower) { switch (Addr) { //Using old track panel codes for testing so 61 & 64 case 61: // Track to station if (moveToTrackPos == 100) { //make sure last movement has stopped before strting a new one if (Direction == 0) { moveToTrackPos = 0;//left } else { moveToTrackPos = 2;//right } getTurntableDirection(); } break; case 64: //loop at front of station if (moveToTrackPos == 100) { //make sure last movement has stopped before strting a new one if (Direction == 0) { moveToTrackPos = 1;//left } else { moveToTrackPos = 3;//right } getTurntableDirection(); } break; default: break; } Serial.print("notifyDccAccTurnoutOutput: ") ; Serial.print(Addr, DEC) ; Serial.print(','); Serial.println(Direction, DEC) ; } void adjustTurntablePostionSettings() { //can only manually move when not in a movement if (digitalRead(capClockPin) > 0 && moveToTrackPos == 100) { //Serial.println("capClockPin"); digitalWrite(enablePin, poweron); digitalWrite(dirPin, clockwise); //direction delayMicroseconds(stepperStartSpeedDelay); digitalWrite(stepPin, HIGH); trackPositions[currentTrackPos]++; stepCounter++;//update the turntable position delayMicroseconds(stepperStartSpeedDelay); digitalWrite(stepPin, LOW); trackPositions[currentTrackPos]++; stepCounter++;//update the turntable position } if (digitalRead(capantiClockPin) > 0) { digitalWrite(enablePin, poweron); digitalWrite(dirPin, anticlockwise); //direction delayMicroseconds(stepperStartSpeedDelay); digitalWrite(stepPin, HIGH); trackPositions[currentTrackPos]--; stepCounter--;//update the turntable position delayMicroseconds(stepperStartSpeedDelay); digitalWrite(stepPin, LOW); trackPositions[currentTrackPos]--; stepCounter--;//update the turntable position } } void setup() { Serial.begin(9600); Serial.println("TurnTableV1"); //stepper set up pins as outputs pinMode(stepPin, OUTPUT); pinMode(dirPin, OUTPUT); pinMode(enablePin, OUTPUT); //turndriver on and off to get rid of the noise digitalWrite(enablePin, poweroff); digitalWrite(dirPin, clockwise); // LOW for anticlockwise turntableDirection = clockwise; //cap touch switches for adjustment pinMode(capClockPin, INPUT); pinMode(capantiClockPin, INPUT); //get trackposition data from eeprom geteepromdata(); // Setup which External Interrupt, the Pin it's associated with that we're using and enable the Pull-Up Dcc.pin(0, 2, 1); // Call the main DCC Init function to enable the DCC Receiver Dcc.init( MAN_ID_DIY, 10, CV29_ACCESSORY_DECODER | CV29_OUTPUT_ADDRESS_MODE, 0 ); //index the unit digitalWrite(dirPin, clockwise); // LOW for anticlockwise turntableDirection = clockwise; moveToTrackPos = 3;//always index clockwise to position 0 digitalWrite(enablePin, poweron);//turn motor driver on } void loop() { Dcc.process();//process incoming DCC Commands moveTurntable();//deals with turntable control adjustTurntablePostionSettings();//touch switches to make adjustments //do the eeprom updates if (millis() > eepromUpdateTimer && moveToTrackPos == 100) { // not moving so can be updated digitalWrite(enablePin, poweroff);//turn the power off as it's not moving eepromUpdateTimer = millis() + eepromUpdatePeriod; updateeeprom(); } }