This "traditional" code-structure of non-blocking timing has these disadvantages:
- you have to update the timing-variable in its own line of code
- the if-condition is not really self-explaining
- you have to update a second variable
unsigned long msec = millis (); // 1. update timing-variable
if (state && msec - msecLst >= msecPeriod) { // 2. not really self-explaining code
msecLst = msec; // 3. update a second variable
this reduces to a single line of code in my version which uses a self-explaining name
if (state != Idle && TimePeriodIsOver(myTimerVar, msecPeriod ) ) {
So the code looks like this
int btn2 = 3; // increment
int btn1 = 2; // decrement
int in3 = 4;
int in4 = 5;
int enB = 7; // only 3, 5, 6, 9 10 and 11 are PWM outputs
#define Off 0
int incPrev;
int decPrev;
enum { Idle, Run, Pause, Stop };
int state;
unsigned long myTimerVar;
unsigned long msecPeriod;
//unsigned long msecLst;
unsigned long sekunde = 0;
const byte OnBoard_LED = 13;
// -----------------------------------------------------------------------------
void setup () {
Serial.begin (9600);
Serial.println("Setup-Start");
pinMode (btn1, INPUT_PULLUP); //button for increment
pinMode (btn2, INPUT_PULLUP); //button for decrement
pinMode (in3, OUTPUT); // motor 2
pinMode (in4, OUTPUT); // motor 2
pinMode (enB, OUTPUT); // motor 2
digitalWrite (in4, HIGH);
digitalWrite (in3, LOW);
analogWrite (enB, Off);
myTimerVar = millis(); // initialise Timer-variable
}
// -----------------------------------------------------------------------------
void loop () {
if (state != Idle && TimePeriodIsOver(myTimerVar, msecPeriod) ) {
Serial.print (" state ");
Serial.println (state);
if (Run == state) {
state = Pause;
msecPeriod = sekunde * 1000;
analogWrite (enB, 150);
}
else if (Pause == state) {
state = Run;
msecPeriod = 200;
analogWrite(enB, Off);
}
else {
msecPeriod = 0;
analogWrite(enB, Off);
}
}
int inc = digitalRead(btn2);
if (inc != incPrev ) { // if IO-pin-state has changed
incPrev = inc; // update comparing variable
delay (20); // wait unil bouncing is over
if (LOW == inc) { // if button is pressed down
sekunde ++;
if (sekunde != 0)
state = Run;
Serial.println(sekunde);
}
}
int dec = digitalRead(btn1);
if (dec != decPrev) { // if IO-pin-state has changed
decPrev = dec; // update comparing variable
delay (20); // wait unil bouncing is over
if (LOW == dec) { // if button is pressed down
sekunde --;
if (0 >= sekunde) {
sekunde = 0;
state = Stop;
}
Serial.println (sekunde);
}
}
}
// easy to use helper-function for non-blocking timing
boolean TimePeriodIsOver (unsigned long &startOfPeriod, unsigned long TimePeriod) {
unsigned long currentMillis = millis();
if ( currentMillis - startOfPeriod >= TimePeriod ) {
// more time than TimePeriod has elapsed since last time if-condition was true
startOfPeriod = currentMillis; // a new period starts right here so set new starttime
return true;
}
else return false; // actual TimePeriod is NOT yet over
}
C++ offers to declare your own functions. This enables to have better structured code where each function does one thing
- controlling the motor
- reading in the buttons and inc/dec a variable
Here is a version of your code where loop() looks very short because
controlling the motor
and reading in the buttons is in its own functions
void loop () {
controlMotor2();
readButtonsIncDec();
}
here is the complete code. If you look into the functions you will discover that the lines of code have just moved into the functions
int btn2 = 3; // increment
int btn1 = 2; // decrement
int in3 = 4;
int in4 = 5;
int enB = 7; // only 3, 5, 6, 9 10 and 11 are PWM outputs
const byte Off = 0;
const byte pressed = LOW;
// equals to integer-values 0 1 2 3
enum { Idle, Run, Pause, Stop };
int state;
unsigned long msecPeriod;
unsigned long sekunde = 0;
const byte OnBoard_LED = 13;
unsigned long myTimerVar;
// -----------------------------------------------------------------------------
void setup () {
Serial.begin (9600);
Serial.println("Setup-Start");
pinMode (btn1, INPUT_PULLUP); // button for increment
pinMode (btn2, INPUT_PULLUP); // button for decrement
pinMode (in3, OUTPUT); // motor 2
pinMode (in4, OUTPUT); // motor 2
pinMode (enB, OUTPUT); // motor 2
digitalWrite (in4, HIGH);
digitalWrite (in3, LOW);
analogWrite (enB, Off);
myTimerVar = millis ();
}
// -----------------------------------------------------------------------------
void loop () {
controlMotor2();
readButtonsIncDec();
}
void controlMotor2() {
if (state != Idle && TimePeriodIsOver(myTimerVar, msecPeriod) ) {
Serial.print (" state ");
Serial.println (state);
if (Run == state) {
state = Pause;
msecPeriod = sekunde * 1000;
analogWrite (enB, 150);
}
else if (Pause == state) {
state = Run;
msecPeriod = 200;
analogWrite(enB, Off);
}
else {
msecPeriod = 0;
analogWrite(enB, Off);
}
}
}
}
void readButtonsIncDec() {
int inc;
static int incPrev; // must be static to preserve value
int dec;
static int decPrev;
inc = digitalRead(btn2);
if (inc != incPrev ) { // if IO-pin-state has changed
incPrev = inc; // update comparing variable
delay (20); // wait until bouncing is over
if (inc == pressed) { // if button is pressed down
sekunde++;
if (sekunde != 0)
state = Run;
Serial.println(sekunde);
}
}
dec = digitalRead(btn1);
if (dec != decPrev) { // if IO-pin-state has changed
decPrev = dec; // update comparing variable
delay (20); // wait until bouncing is over
if (dec == pressed) { // if button is pressed down
sekunde--;
if (0 >= sekunde) {
sekunde = 0;
state = Stop;
}
Serial.println (sekunde);
}
}
}
// easy to use helper-function for non-blocking timing
boolean TimePeriodIsOver (unsigned long &startOfPeriod, unsigned long TimePeriod) {
unsigned long currentMillis = millis();
if ( currentMillis - startOfPeriod >= TimePeriod ) {
// more time than TimePeriod has elapsed since last time if-condition was true
startOfPeriod = currentMillis; // a new period starts right here so set new starttime
return true;
}
else return false; // actual TimePeriod is NOT yet over
}
best regards Stefan