/************************************************************************************************* * * * filename: host_controlling_Stepper.ino * * * * function: host for the stepper motor controller * * * * project: * * * * Ed. When Who What * *----------------------------------------------------------------------------------------------- * * 01 25.02.20 liebers created * * 02 07.03.20 liebers ended * **************************************************************************************************/ #include /* only if needed */ #include /* library for I2C devices (display) */ #include /* Arduino´s software interrupt library */ #define TRUE 1 #define FALSE 0 #define CHAR_TIMEOUT 5 // was 20, 5 /* max. delay of received serial data (chars) */ #define DEBOUNCEDELAY 100l // was 50l /* estimated debounce period in milli secs */ #define POLLINGDELAY 300 /* to avoid serial polling overload [milli sec] */ #define EXECUTIONDELAY 4 /* the assciated function is invoked every 4 [ms] */ /* artificial prolonging of a key press end in millis. */ /* "Key press" events shorter than the debounce period will */ /* get lost. There is a small uncertainty in this period */ #define PROLONGE_TRUESTATE 50l // was 100 300 400l /* the normalized length of a key press */ #define LENGTHOFTRAVEL 50l; /* defined in steps (of type full, halph, quarter) */ #define BUSY 2 /* stepper controller is busy with previous travel */ #define READY 3 /* stepper controller is ready for a travel order */ #define COMM_ERROR 4 /* faulty or no communication */ #define ON_ENTRY 5 /* enables the elcome mask */ #define FINISH_1 '\253' #define FINISH_0 '\254' #define DE_FAULT '\255' const int key_0 = 2; /* the first key, input pin 2 */ const int key_1 = 3; /* the second key, " pin 3 */ const int key_2 = 4; /* the third key, " pin 4 */ bool monitored_key_0 = FALSE; /* represents the logic state of a key press */ bool monitored_key_1 = FALSE; /* HIGH means: Key has been pressed */ bool monitored_key_2 = FALSE; /* LOW means: No key press detected */ /* the TRUE time is DEBOUNCEDELAY plus */ /* PROLONGE_TRUESTATE */ LiquidCrystal_I2C lcd(0x27, 2, 1, 0, 4, 5, 6, 7, 3, POSITIVE ); //LiquidCrystal_I2C lcd(0x27, 20, 4); /* set the LCD address to 0x27 for a 16 chars */ void setup() { pinMode(key_0, INPUT); /* 3 keys are in use */ pinMode(key_1, INPUT); pinMode(key_2, INPUT); digitalWrite( key_0, HIGH ); /* activate the internal pull-up resistor */ digitalWrite( key_1, HIGH ); digitalWrite( key_2, HIGH ); pinMode(LED_BUILTIN, OUTPUT); /* make use of the onboard LED */ Serial.begin( 9600 ); //was 38400 /* enable serial port which is in use by the */ /* binary code program loader */ lcd.begin( 20, 04 ); /* enable LCD-display of 20 chars, 4 lines */ lcd.clear(); lcd.backlight(); /* switch on backlight illumination */ //lcd.noBacklight(); /* the ISR gets invoked every 2500us or 2.5 milli sec, */ // Timer1.initialize( 2500 ); /* corresponding to 400Hz */ // Timer1.attachInterrupt( monitoring_keys ); /* assign this software int. to the subroutine */ // interrupts(); } /* end of function setup() */ /* ----------------------------------- monitoring_keys() --------------------------------------- */ /* the funvtion monitors the state of key_0, key_1 and key_2 input used to send certain orders */ /* to the stepper controller. */ /* Functionality: */ /* - very short "key presses" within the leading debounce period are ignored */ /* - the trailing "key release" is detected as "key active" and triggers a minimum TRUE period */ /* to elapse called PROLONGE_TRUESTATE */ /* - after this has happened a second polling for "key released" is done and the routine */ /* returns to its original state which is polling for another "key pressed" */ /* The advantage of this procedure is that a "key press", regardless of its length, leads to a */ /* unified and debounced pulse length right after a "key press" has been triggered. This length */ /* can be adapted to requirements of loop() which is evaluating the "key press" varables. */ /* "Key presses"" are imaged on 3 module-global variables: monitored_key_0, monitored_key_1 */ /* monitored_key_2 */ /* Each input is monitored 100 times per second. */ /* The run time for monitoring each of the three inputs is around 20us */ void monitoring_keys() { static int flow_0 = 0; /* used in the inner switch() statements below */ static int flow_1 = 0; /* each flow is related to a key press input pin */ static int flow_2 = 0; static char key_index = 0; /* controls the inner, pin related switch statements */ static unsigned long time_stamp_0; /* freezes the moment a certain event takes place */ static unsigned long time_stamp_1; /* each time_stamp is related to a key press input pin*/ static unsigned long time_stamp_2; /* 400Hz repetition rate in here */ switch( key_index ) /* the outer switch statement processes the inner */ { /* switch statements in a fixed order 0, 1, 2, default*/ case 0: /* monotoring key press of the pin_0 */ /* 400 / 4 == 100Hz repetition rate in here */ key_index++; /* exclude for 3 times */ switch( flow_0 ) /* unpressed keys mean HIGH state due to the activated pull-up-resistor. */ { /* This is called electrically "active low state". */ case 0: /* this is the starting point for the monitoring. */ if( digitalRead(key_0) == LOW ) /* Check for key pressed, meaning electric LOW state */ { time_stamp_0 = millis(); /* freeze this moment in time */ flow_0 = 1; /* activate the code portion for key release */ } break; /* if not keep on polling */ case 1: /* key press event has happened, let pass debounce period */ if( (millis()-time_stamp_0) > DEBOUNCEDELAY ) { time_stamp_0 = millis(); /* get one more time stamp of another meaning */ flow_0 = 2; } else flow_0 = 1; /* contact still in bouncing period, let more time pass by */ break; case 2: /* key still pressed? */ if( (digitalRead(key_0) == LOW) ) flow_0 = 3; else flow_0 = 0; /* a very short key press will be ignored */ break; case 3: if( (digitalRead(key_0) == HIGH) ) /* key press has ended ? */ { time_stamp_0 = millis(); /* freeze this moment in time */ monitored_key_0 = TRUE; /* reaktion on the trailing edge of a key press */ digitalWrite(LED_BUILTIN, HIGH); flow_0 = 4; } break; /* if not keep on polling */ case 4: /* prolong TRUE time of key press */ if( (millis()-time_stamp_0) > PROLONGE_TRUESTATE ) /*and skip second bounce period */ flow_0 = 5; break; case 5: if( (digitalRead(key_0) == HIGH) ) /* check key release for a second time */ { monitored_key_0 = FALSE; /* end of TRUE period */ flow_0 = 0; digitalWrite(LED_BUILTIN, LOW); } break; /* if not keep on polling */ } /* end of inner switch 0 */ break; case 1: /* monotoring key press on pin_1 */ key_index++; switch( flow_1 ) /* unpressed keys mean HIGH state due to the activated pull-up-resistor. */ { /* This is called electrically "active low state". */ case 0: /* this is the starting point for the monitoring. */ if( digitalRead(key_1) == LOW ) /* Check for key pressed, meaning electric LOW state */ { time_stamp_1 = millis(); /* freeze this moment in time */ flow_1 = 1; /* activate the code portion for key release */ } break; /* if not keep on polling */ case 1: /* key press event has happened, let pass debounce period */ if( (millis()-time_stamp_1) > DEBOUNCEDELAY ) { time_stamp_1 = millis(); /* get one more time stamp of another meaning */ flow_1 = 2; } else flow_1 = 1; /* contact still in bouncing period, let more time pass by */ break; case 2: /* key still pressed? */ if( (digitalRead(key_1) == LOW) ) flow_1 = 3; else flow_1 = 0; /* a very short key press will be ignored */ break; case 3: if( (digitalRead(key_1) == HIGH) ) /* key press has ended ? */ { time_stamp_1 = millis(); /* freeze this moment in time */ monitored_key_1 = TRUE; /* reaktion on the trailing edge of a key press */ flow_1 = 4; } break; /* if not keep on polling */ case 4: /* prolong TRUE time of key press */ if( (millis()-time_stamp_1) > PROLONGE_TRUESTATE ) /*and skip second bounce period */ flow_1 = 5; break; case 5: if( (digitalRead(key_1) == HIGH) ) /* check key release for a second time */ { monitored_key_1 = FALSE; /* end of TRUE period */ flow_1 = 0; } break; /* if not keep on polling */ } /* end of inner switch 1 */ break; case 2: /* monotoring key press on pin_2 */ key_index++; switch( flow_2 ) /* unpressed keys mean HIGH state due to the activated pull-up-resistor. */ { /* This is called electrically "active low state". */ case 0: /* this is the starting point for the monitoring. */ if( digitalRead(key_2) == LOW ) /* Check for key pressed, meaning electric LOW state */ { time_stamp_2 = millis(); /* freeze this moment in time */ flow_2 = 1; /* activate the code portion for key release */ } break; /* if not keep on polling */ case 1: /* key press event has happened, let pass debounce period */ if( (millis()-time_stamp_2) > DEBOUNCEDELAY ) { time_stamp_2 = millis(); /* get one more time stamp of another meaning */ flow_2 = 2; } else flow_2 = 1; /* contact still in bouncing period, let more time pass by */ break; case 2: /* key still pressed? */ if( (digitalRead(key_2) == LOW) ) flow_2 = 3; else flow_2 = 0; /* a very short key press will be ignored */ break; case 3: if( (digitalRead(key_2) == HIGH) ) /* key press has ended ? */ { time_stamp_2 = millis(); /* freeze this moment in time */ monitored_key_2 = TRUE; /* reaction on the trailing edge of a key press */ flow_2 = 4; } break; /* if not keep on polling */ case 4: /* prolong TRUE time of key press */ if( (millis()-time_stamp_2) > PROLONGE_TRUESTATE ) /* and skip second bounce period */ flow_2 = 5; break; case 5: if( (digitalRead(key_2) == HIGH) ) /* check key release for a second time */ { monitored_key_2 = FALSE; /* end of TRUE period */ flow_2 = 0; } break; /* if not keep on polling */ } /* end of inner switch 2 */ break; default: /* if key_index is not 0, 1, 2 than default is valid */ key_index = 0; /* after having monitored three pins, same procedure again */ break; } /* end of outer switch */ } /* end of function ISR... */ /* --------------------------------- error_message_stop() -------------------------------------- */ /* */ /* --------------------------------------------------------------------------------------------- */ int error_message_and_stop() { lcd.setCursor( 0, 0 ); lcd.print("Communication "); lcd.setCursor( 0, 1 ); lcd.print("Error, full stop"); while( 1 ) /* only a hardware reset will bring it back to life */ { digitalWrite(LED_BUILTIN, HIGH); /* we don´t want to see this ever happen */ delay( 200 ); digitalWrite(LED_BUILTIN, LOW); delay( 200 ); } } /* end of function, no need for a return value */ /* ------------------------------------ basic_message() ---------------------------------------- */ /* */ /* --------------------------------------------------------------------------------------------- */ int basic_message() { lcd.setCursor( 0, 0 ); lcd.print("Stepper Controller Ver 1.0"); lcd.setCursor( 0, 1 ); lcd.print("Press a key "); return( DE_FAULT ); } /* end of function */ /* ------------------------------------ start_message() ---------------------------------------- */ /* */ /* --------------------------------------------------------------------------------------------- */ int start_message() { lcd.setCursor( 0, 0 ); lcd.print("T0toggles On-Off"); //lcd.print("T0= On, T1= Off "); lcd.setCursor( 0, 1 ); lcd.print(" "); } /* end of function */ /* ------------------------------------ finish_message() --------------------------------------- */ /* */ /* --------------------------------------------------------------------------------------------- */ int finish_message() { // lcd.setCursor( 0, 0 ); // lcd.print("All done "); lcd.setCursor( 0, 1 ); lcd.print("Press a key "); } /* end of function */ /* ------------------------------------- display_cycles() -------------------------------------- */ /* */ /* --------------------------------------------------------------------------------------------- */ int display_cycles( unsigned long int *cycle_cnt ) { char stringbuf[10]; /* must be Auto */ sprintf( stringbuf, "Cycles: %ld", *cycle_cnt ); /* convert the number to ASCII string */ lcd.setCursor( 0, 0 ); /* erase the first line completely */ lcd.print(" "); lcd.setCursor( 0, 0 ); lcd.print( stringbuf ); /* display the number of forward/backward cycles */ lcd.setCursor( 0, 1 ); lcd.print(" "); /* erase the second line completely */ } /* end of function */ /* ------------------------------------- myreadln() -------------------------------------------- */ /* read a '\r' terminated string from input path. This function returns the following results: */ /* TRUE, means: The properly received string is written into the buffer of the caller */ /* COMM_ERROR, means: No reveival of characters in good time, so violating time out */ /* The calling functions are: report_stepper_state(), cyclic_travel() */ static bool myreadln( char *strbuf, int timeout ) { /* char *strbuf: pointer on character string for recieved chars defined by the caller */ /* int timeout; max. time in milli secs to wait for next character */ int count; do { count = timeout; while ( (Serial.available() == 0) ) /* while no characters are available */ { if (--count <= 0) /* if negative, time out has occurred */ { *strbuf = '\0'; /* put string termination */ return ( COMM_ERROR ); /* no receival of characters in good time */ } delay(5); // was 1 /* waiting time in milli secs */ } *strbuf = (char) Serial.read(); /* get the character having been cast into char */ *strbuf = *strbuf & 0x7f; /* put a mask on the 7 bit ASCII data */ } while (*strbuf++ != '\r'); /* get all characters except the last one */ *strbuf = '\0'; /* insert the string terminator into the buffer */ return ( TRUE ); /* containing the completely received string now */ } /* end of myreadln() */ /* --------------------------------- report_stepper_state()------------------------------------- */ /* report the current state to the caller. This function returns the following results: */ /* - COMM_ERROR in case the serial communication was faulty */ /* - BUSY */ /* - READY */ /* The calling functions are: forward_travel(), backward_travel() */ /* */ int report_stepper_state() { static char stringbuf[10]; /* buffer for characters to be received */ static int requested_state; /* result of the enquiry about the stepper controller */ /* flush the input buffer once on entry */ while( Serial.available() > 0 ) /* no specific flush function found in the libraries */ Serial.read(); Serial.print("F\r"); /* send an inquiry about the state of the stepper controller */ delay( 5 ); myreadln( &stringbuf[0], CHAR_TIMEOUT); stringbuf[0] &= 0x7f; /* put a mask on the 7 bit information residing in stringbuf[0] */ switch( stringbuf[0] ) { case 'R': /* stepper controller ready for next travel order */ requested_state = READY; break; case 'B': /* stepper busy with current travel order in progress */ requested_state = BUSY; break; default: /* if anything else like communication error */ requested_state = COMM_ERROR; break; } /* end of switch statement */ return( requested_state ); } /* end of function */ /* ------------------------------ terminate_current_travel() ----------------------------------- */ /* If a travel order is currently pending, terminate it before starting a new one. */ /* This is done by sending two ASCII chars to the stepper controller: "Z\r" */ /* For a reaction of the controller, a string "Y\r" is expected. */ /* */ /* return value: TRUE means: string "Y\r" as acknowledge has been received */ /* return value: FALSE means: something else than "Y\r" or anying in time has been received */ /* The caller of this function is: forth_and_back() */ int terminate_current_travel() { static char stringbuf[10]; Serial.print("Z\r"); /* send an order for a soft stop to the stepper controller */ if( myreadln( &stringbuf[0], CHAR_TIMEOUT ) == COMM_ERROR ) return FALSE; /* if the controller does not answer in time */ if( ( stringbuf[0] & 0x7f ) == 'Y') /* if the answer is valid */ return TRUE; return FALSE; } /* end of function */ /* ------------------------------------- travel_order() ---------------------------------------- */ /* issues a travel order with the parameters given */ /* */ /* return value: TRUE means: a proper "Y\r" acknowledge has been given back by the controller */ /* return value: FALSE means: something else than "Y\r" or nothing in time has been received, */ /* so a communication error has happened */ /* The calling function is single_travel(). */ /* The time consumption of this routine is some tenth of millisecs, not more */ int travel_order( int st_speed, int top_speed, int ramp, long my_position ) { static char flow = 0; /* used in the switch() statement below */ static char stringbuf[10]; /* flush the input buffer once on entry */ while( Serial.available() > 0 ) /* no specific flush function found in the libraries */ Serial.read(); do { switch( flow ) { case 0: Serial.print("PO\r"); /* send the header for a travel order to the stepper controller */ flow = 1; delay( 5 ); break; case 1: if( myreadln( &stringbuf[0], CHAR_TIMEOUT ) == COMM_ERROR ) { flow = 0; /* restore initial state */ return( FALSE ); /* if the controller does not answer proper and in time */ } /* communication ok, so far */ flow = 2; break; case 2: if( ( stringbuf[0] & 0x7f ) != 'Y' ) /* proper communication? */ { flow = 0; /* restore initial state */ return( FALSE ); /* if the controller does not answer proper and in time */ } /* communication ok, so far */ flow = 3; break; case 3: sprintf( stringbuf, "S%d\r", st_speed/10 ); /* send the parameter for start/stop speed */ Serial.print( stringbuf ); /* send the header for a travel to the stepper controller */ delay( 5 ); flow = 4; break; case 4: if( myreadln( &stringbuf[0], CHAR_TIMEOUT ) == COMM_ERROR ) { flow = 0; /* restore initial state */ return( FALSE ); /* if the controller does not answer proper and in time */ } /* communication ok, so far */ flow = 5; break; case 5: if( ( stringbuf[0] & 0x7f ) != 'Y' ) /* proper communication? */ { flow = 0; /* restore initial state */ return( FALSE ); /* if the controller does not answer proper and in time */ } /* communication ok, so far */ flow = 6; break; case 6: sprintf( stringbuf, "T%d\r", top_speed/10 ); /* send the parameter for top speed */ Serial.print( stringbuf ); delay( 5 ); flow = 7; break; case 7: if( myreadln( &stringbuf[0], CHAR_TIMEOUT ) == COMM_ERROR ) { flow = 0; /* restore initial state */ return( FALSE ); /* if the controller does not answer proper and in time */ } /* communication ok, so far */ flow = 8; break; case 8: if( ( stringbuf[0] & 0x7f ) != 'Y' ) /* proper communication? */ { flow = 0; /* restore initial state */ return( FALSE ); /* if the controller does not answer proper and in time */ } /* communication ok, so far */ flow = 9; break; case 9: sprintf( stringbuf, "R%d\r", ramp ); /* send the parameter for ramp length */ Serial.print( stringbuf ); delay( 5 ); flow = 10; break; case 10: if( myreadln( &stringbuf[0], CHAR_TIMEOUT ) == COMM_ERROR ) { flow = 0; /* restore initial state */ return( FALSE ); /* if the controller does not answer proper and in time */ } /* communication ok, so far */ flow = 11; break; case 11: if( ( stringbuf[0] & 0x7f ) != 'Y' ) /* proper communication? */ { flow = 0; /* restore initial state */ return( FALSE ); /* if the controller does not answer proper and in time */ } /* communication ok, so far */ flow = 12; break; case 12: if( my_position < 0l ) /* negative? */ sprintf( stringbuf, "G-%ld\r", my_position ); /* send the minus distance parameter */ else sprintf( stringbuf, "G+%ld\r", my_position ); /* send the plus distance parameter */ Serial.print( stringbuf ); delay( 5 ); flow = 13; break; case 13: if( myreadln( &stringbuf[0], CHAR_TIMEOUT ) == COMM_ERROR ) { flow = 0; /* restore initial state */ return( FALSE ); /* if the controller does not answer proper and in time */ } /* communication ok, so far */ flow = 14; break; case 14: if( ( stringbuf[0] & 0x7f ) != 'Y' ) /* proper communication? */ { flow = 0; /* restore initial state */ return( FALSE ); /* if the controller does not answer proper and in time */ } /* communication ok, so far */ flow = 15; break; case 15: Serial.print("E\r"); /* send the trailer for a travel order to the stepper controller */ delay( 5 ); flow = 16; break; case 16: if( myreadln( &stringbuf[0], CHAR_TIMEOUT ) == COMM_ERROR ) { flow = 0; /* restore initial state */ return( FALSE ); /* if the controller does not answer in good time */ } flow = 17; break; case 17: flow = 0; /* restore initial state */ if( ( stringbuf[0] & 0x7f ) == 'Y' ) /* proper communication? */ return( TRUE ); /* travel order completed successfully communication ok */ return( FALSE ); } }while( 1 ); /* end of while() */ } /* end of function */ /* --------------------------- simplyfied_travel_order() --------------------------------------- */ /* this function instructs the controller in a higher organized order to do a single travel. */ /* Attention: It is assumed that the caller has assured to start this travel only at a moment */ /* the controller is IDLING ("R\r" answer). */ /* If however the cotroller is busy, the result of starting this function at such moment is */ /* unpredictable. */ /* There is no waiting for anything except for some evtl. time-outs in the milli second range, */ /* mostly invisible to the user. */ /* The following return values are given out on exit of the function: */ /* TRUE, meaning: The requested travel order has been issued and its execution is just in */ /* progress, but not finished yet */ /* FALSE, meaning: a communication error occurred, no measures are taken to correct anything */ /* */ /* The calling function is single_travel() */ /* Note: This function does nothing else but polling, it has to be invoked multiple times! */ /* --------------------------------------------------------------------------------------------- */ int simplyfied_travel_order( long int abs_position ) { static int answer; /* result of the request for stepper controller state */ static char stringbuf[10]; /* travel parameters: */ const int st_speed = 50; /* start / stop speed in steps per second */ const int top_speed = 2000; /* top speed in steps per second */ const int ramp = 50; /* length of the ramp in steps */ /* Assumption: controller is idling, motor standing still */ answer = travel_order( st_speed, top_speed, ramp, abs_position ); /* apply a travel order */ if( answer == TRUE ) /* travel order successfully given out? */ return TRUE; else return FALSE; /* must be the FALSE state, something has gone wrong */ } /* end of function */ /* ------------------------------------ forward_travel() --------------------------------------- */ /* this routine makes the controller perform a single travel an absolute position */ /* Important: Before a travel order is issued, a check is made to see whether the controller is */ /* In other words: The routine checks the controller for being READY for a travel order and if */ /* positive, it sends a travel command to the controller. */ /* */ /* The return values of this function are: */ /* 'b', meaning: stay in the mode of being invoked repeatedly */ /* FINISHED, meaning: order given out properly */ /* COMM_ERROR, meaning: communication error, will trigger a dynamic stop in loop() */ /* The calling function is loop(); */ /* --------------------------------------------------------------------------------------------- */ int forward_travel( long int abs_position ) { static int result; /* reaction of the called function */ static char flow = 0; /* used in the switch() statement below */ static unsigned long int my_time_stamp; /* needed in order to delay the polling rate */ switch( flow ) { case 0: my_time_stamp = millis(); /* freeze this moment in time */ result = report_stepper_state(); /* check the state of the stepper controller */ flow = 1; /* we leave the function with return value 'b' */ break; /* meaning to come back very soon */ case 1: if( result == READY ) /* a travel order can be issued */ { flow = 2; /* at stand still a travel order can be issued */ break; /* leave the function with return value 'b' */ } if( result == COMM_ERROR ) flow = 4; /* leave the function with return value COMM_ERROR */ else /* if !READY, !COMM_ERROR, controller must be BUSY */ if( (millis()-my_time_stamp) > POLLINGDELAY ) flow = 0; /* keep on polling the state of the stepper controller*/ break; /* leave the function with return value 'b' */ case 2: result = simplyfied_travel_order( abs_position ); /* issue the simple travel order by */ flow = 3; /* sending the defined ASCII strings to the controller*/ break; /* result can be: TRUE, FALSE */ case 3: if( result == TRUE ) /* if travel order has reached ready state */ { flow = 0; /* restore initial state */ return FINISH_0; /* order given out properly */ } flow = 4; /* do a second check */ break; case 4: /* if result !TRUE, it must be FALSE, so a comm. error has happened */ flow = 0; /* restore initial state */ return COMM_ERROR; } /* end of switch statement */ return 'b'; /* travel order yet in progress, come back */ } /* end of function */ /* ------------------------------------ backward_travel() -------------------------------------- */ /* this routine makes the controller perform a counter travel from an absolute position to zero */ /* Important: Before a travel order is issued, a check is made to see whether the controller is */ /* In other words: The routine checks the controller for being READY for a travel order and if */ /* positive, it sends a travel command to the controller. */ /* */ /* The return values of this function are: */ /* 'b', meaning: stay in the mode of being invoked repeatedly */ /* FINISHED, meaning: order given out properly */ /* COMM_ERROR, meaning: communication error, will trigger a dynamic stop in loop() */ /* The calling function is loop(); */ /* --------------------------------------------------------------------------------------------- */ int backward_travel( long int abs_position ) { static int result; /* reaction of the called function */ static char flow = 0; /* used in the switch() statement below */ static unsigned long int my_time_stamp; /* needed in order to delay the polling rate */ switch( flow ) { case 0: my_time_stamp = millis(); /* freeze this moment in time */ result = report_stepper_state(); /* check the state of the stepper controller */ flow = 1; /* we leave the function with return value 'b' */ break; /* meaning to come back very soon */ case 1: if( result == READY ) /* a travel order can be issued */ { flow = 2; /* at stand still a travel order can be issued */ break; /* leave the function with return value 'b' */ } if( result == COMM_ERROR ) flow = 4; /* leave the function with return value COMM_ERROR */ else /* if !READY, !COMM_ERROR, controller must be BUSY */ if( (millis()-my_time_stamp) > POLLINGDELAY ) flow = 0; /* keep on polling the state of the stepper controller*/ break; /* leave the function with return value 'b' */ case 2: result = simplyfied_travel_order( abs_position ); /* issue the simple travel order by */ flow = 3; /* sending the defined ASCII strings to the controller*/ break; /* result can be: TRUE, FALSE */ case 3: if( result == TRUE ) /* if travel order has reached ready state */ { flow = 0; /* restore initial state */ return FINISH_1; /* order given out properly */ } flow = 4; /* do a second check */ break; case 4: /* if result !TRUE, it must be FALSE, so a comm. error has happened */ flow = 0; /* restore initial state */ return COMM_ERROR; } /* end of switch statement */ return 'c'; /* travel order yet in progress, come back */ } /* end of function */ /* ----------------------------------------- loop() -------------------------------------------- */ /* this is the cyclic part of the Arduino code, by default called "main()" in other IDEs */ /* --------------------------------------------------------------------------------------------- */ void loop() { static long test_counter = 0l; static int i_counter; static long int reducer = 0l; static int choice = ON_ENTRY; /* start with the welcome message */ static long int abs_travel = LENGTHOFTRAVEL /* the end of the travel as absolute positio */ static unsigned long int cyclecounter = 0l; /* counting the forward/backward travels */ static unsigned long int old_cyclecounter = 0l; /* gets dragged behind its leader */ static bool toggle = FALSE; /* for run time management in loop() */ /* has an auxiliary purpose: prolongs the unified and */ static bool run_infinitively = FALSE; /* organising tool */ monitoring_keys(); /* scan key presses without waiting for them */ switch( choice ) /* this portion of code deals with the execution of unified key presses */ { /*on key_0. It perfoms the function of ON, OFF, ON, OFF... */ case ON_ENTRY: /* the predefined state on entry into loop(). */ basic_message(); /* The welcome message. Function returns nothing. */ choice = DE_FAULT; /* check for another travel order */ break; default: /* poll for a unified key_0 entry, meaning start of */ if( monitored_key_0 == TRUE ) /* the cyclic forward/backward traveling */ choice = 'a'; /* define the entry point into the first function. */ break; /* Monitored_key_1 is the unified key press for ending the cyclic traveling */ case 'a': run_infinitively = TRUE; /* means: cyclic traveling is in progress, from now */ start_message(); /* on a check for cyclic travel == OFF can be done */ monitored_key_0 = FALSE; /* prepare for next key check */ choice = 'b'; break; case 'b': if( ( monitored_key_0 == TRUE ) && ( run_infinitively == TRUE ) ) /*new key press? */ run_infinitively = FALSE; /* prepare for ending the cycles in case of key_0 press */ choice = forward_travel( abs_travel ); /* single forward travel. Returns 'b', COMM_ERROR */ break; /* or FINISH_0. Comes back very soon (within microseconds) */ case FINISH_0: case 'c': if( ( monitored_key_0 == TRUE ) && ( run_infinitively == TRUE ) ) run_infinitively = FALSE; choice = backward_travel( 0l ); /* single backward travel to initial position. */ break; /* Returns 'c', COMM_ERROR, or FINISH_1. */ /* Is very similar to the above forward travel. */ case FINISH_1: if( run_infinitively == TRUE ) /* continue the cyclic traveling */ { /* delayed display in order to keep the previous message for some travels */ if( (cyclecounter++ - old_cyclecounter) > 3 ) display_cycles( &cyclecounter ); /* displays the counter, nothing is returned */ choice = 'b'; /* continue the forward/backward traveling */ } else /* FALSE: stop the process in an orderly fashion */ { finish_message(); /* print "All done". Function returns nothing */ old_cyclecounter = cyclecounter; choice = DE_FAULT; /* go for getting a new order */ } break; case COMM_ERROR: error_message_and_stop(); /* print the error menu and do a dynamic stop */ /* break; "never come back" function, so break is not needed */ } /* end of switch */ } /* end of loop() */ // digitalWrite(LED_BUILTIN, HIGH); delay( 200 ); digitalWrite(LED_BUILTIN, LOW); delay( 200 ); digitalWrite(LED_BUILTIN, HIGH); delay( 200 ); digitalWrite(LED_BUILTIN, LOW); delay( 200 ); /* ***************************** static long test_counter = 0; static int i_counter; goto lab; if( test_counter++ == 100000l ) { test_counter = 0l; i_counter++; lcd.backlight(); lcd.setCursor( 0, 0); lcd.print(F("i_cnt: ")); lcd.setCursor( 8, 0); lcd.print( i_counter ); } lab:while(0); ***************************** */ /* if( (monitored_key_0 == TRUE ) || ( monitored_key_1 == TRUE ) || ( monitored_key_2 == TRUE ) ) digitalWrite(LED_BUILTIN, HIGH); else digitalWrite(LED_BUILTIN, LOW); */ /* if( reducer++ > 200l ) reducer = 0l; else goto lab1; */ /* hier kommt er nur jedes 200.ste mal durch if( test_counter++ == 500l ) { test_counter = 0l; if( i_counter++ %2 ) digitalWrite(LED_BUILTIN, LOW); else digitalWrite(LED_BUILTIN, HIGH); } */ /* end of file */