Intercepting a for loop with an "external" trigger - strange behaviour

Hello,

im currently writing a programm which runs a specific program for a certain amount of time. So far so good.
Attached to the controller is a SHIFT register which can read a switch button state. So far so good.

If position 1 of the switch button is selected -> Programm enabled, If position 0 is selected -> programm disabled.
This all works perfectly. But now it comes to intercept a for loop IF the programm switch is disabled.

for (clock_t t = millis(); (clock_t)(millis() - t) < HOUR && programmRunning == 1; ) {
    
    enableStepper();
    setDir(HIGH);

    [b][color=red]Serial.println(programmRunning); // THIS IS REQUIRED TO WORK? IF OMITTED THE BELOW WHILE NEVER GETS INTERCEPTED! LOL[/color][/b]

    clock_t t0 = millis();
    while (programmRunning == 1 && (clock_t)(millis() - t0) < 1 * MINUTE) {
      step(delayStep);
    }

    delay(1000);
    
    t0 = millis();
    while (programmRunning == 1 && (clock_t)(millis() - t0) < 1 * MINUTE) {
      step(delayStep);
    }
}

I stumbled upon a thing which i really dont know WHY this is happening. If i run the code the Serial.println() which you see there IS required to actually intercept the while loop below. If i remove this line the interception DOES NOT work anymore for the first while loop.

For the second while loop it is perfectly working at any time.

Any ideas WHY i need to make an explicit serial println to get this working?

Full Code:

#include <Arduino.h>
#include <TimerOne.h>
#include "main.h"

// Define Connections to 74HC165

typedef unsigned long clock_t;  
const clock_t SECOND = 1000L;           // 1 secpmd = 1000 ms  
const clock_t MINUTE = 60L * SECOND;    // 1 minute = 60000 ms  
const clock_t HOUR = 60L * MINUTE;      // 1 hour = 3600000 ms

// --- SHIFT REGISTER PIN AND STATE
const int loadPin = 4;
const int clockEnablePin = 5;
const int dataInPin = 7;
const int clockInPin = 6;
uint8_t lastByteFetched;

// --- STEPPER PINS
const int stepPinMot1 = 10;
const int dirPinMot1 = 9;
const int enablePinMot1 = 8;

const int stepPinMot2 = 13;
const int dirPinMot2 = 12;
const int enablePinMot2 = 11;

// -- STEP DELAYS
const int defaultDelay = 3000;
int delayStep = defaultDelay;

int programmRunning = 0;
int selectedProgram = 0;

void setup() {
  Serial.begin(9600);
  // Setup 74HC165 connections
  pinMode(loadPin, OUTPUT);
  pinMode(clockEnablePin, OUTPUT);
  pinMode(clockInPin, OUTPUT);
  pinMode(dataInPin, INPUT);

  pinMode(dirPinMot2, OUTPUT);
  pinMode(enablePinMot2, OUTPUT);
  pinMode(stepPinMot2, OUTPUT);

  pinMode(dirPinMot1, OUTPUT);
  pinMode(enablePinMot1, OUTPUT);
  pinMode(stepPinMot1, OUTPUT);

  digitalWrite(enablePinMot2, HIGH);
  digitalWrite(dirPinMot2, LOW);

  digitalWrite(enablePinMot1, HIGH);
  digitalWrite(dirPinMot2, LOW);

  delay(1000);

  Timer1.initialize(1000000*1);
  Timer1.attachInterrupt(refreshSwitchState);
}

void enableStepper() {
  digitalWrite(enablePinMot1, LOW);
  digitalWrite(enablePinMot2, LOW);
}

void disableStepper() {
  digitalWrite(enablePinMot1, HIGH);
  digitalWrite(enablePinMot2, HIGH);
}

void refreshSwitchState() {
  // Write pulse to load pin
  digitalWrite(loadPin, LOW);
  delayMicroseconds(5);
  digitalWrite(loadPin, HIGH);
  delayMicroseconds(5);
 
  // Get data from 74HC165
  digitalWrite(clockInPin, HIGH);
  digitalWrite(clockEnablePin, LOW);
  uint8_t incoming = shiftIn(dataInPin, clockInPin, LSBFIRST);
  digitalWrite(clockEnablePin, HIGH);

  if (lastByteFetched == incoming) {
    return;
  }

  lastByteFetched = incoming;

  int enableProgramm4 = bitRead(incoming, 0);
  int enableProgramm3 = bitRead(incoming, 1);
  int enableProgramm2 = bitRead(incoming, 2);
  int enableProgramm1 = bitRead(incoming, 3);
  int speed4 = bitRead(incoming, 4);
  int speed3 = bitRead(incoming, 5);
  int speed2 = bitRead(incoming, 6);
  int speed1 = bitRead(incoming, 7);

  if (enableProgramm1 == 0 || enableProgramm2 == 0 || enableProgramm3 == 0 || enableProgramm4 == 0) {
      enableStepper();
      programmRunning = 1;
      Serial.println(programmRunning);
  } else {
      disableStepper();
      programmRunning = 0;
      Serial.println(programmRunning);
  }
  
  delayStep = defaultDelay;
  if (speed1 == 0) {
    delayStep = 2600;
  }

  if (speed2 == 0) {
    delayStep = 2200;
  }

    if (speed3 == 0) {
    delayStep = 1800;
  }

  if (speed4 == 0) {
    delayStep = 1400;
  }
}

void step(unsigned int us) {
  digitalWrite(stepPinMot1, HIGH);
  digitalWrite(stepPinMot2, HIGH);
  digitalWrite(stepPinMot1, LOW);
  digitalWrite(stepPinMot2, LOW);
  delayMicroseconds(us);
}

void setDir(uint8_t direction) {
  digitalWrite(dirPinMot1, direction);
  digitalWrite(dirPinMot2, direction);
}

void loop() {
  if (!programmRunning) {
    return;
  }

  Serial.println("Starting Program 1");
  Serial.println(programmRunning);

  for (clock_t t = millis(); (clock_t)(millis() - t) < HOUR && programmRunning == 1;) {
    enableStepper();
    setDir(HIGH);

    clock_t t0 = millis();
    while ((clock_t)(millis() - t0) < 1 * MINUTE && programmRunning == 1) {
      step(delayStep);
    }

    setDir(LOW);

    t0 = millis();
    while ((clock_t)(millis() - t0) < 1 * MINUTE && programmRunning == 1) {
      step(delayStep);
    }

    disableStepper();

    t0 = millis();
    while ((clock_t)(millis() - t0) < 5 * MINUTE && programmRunning == 1) { }
  }

  for (clock_t t0 = millis(); (clock_t)(millis() - t0) < 3 * HOUR && programmRunning == 1; ) { }

  Serial.println("Finishing Program 1");
}

main.cpp (3.96 KB)

Welcome to the forum

Please follow the advice on posting code given in Read this before posting a programming question

In particular note the advice to Auto format code in the IDE and to use code tags when posting code here as it prevents some combinations of characters in code being interpreted as HTML commands such as italics, bold or a smiley character, all of which render the code useless

If the code exceeds the 9000 character inline limit then attach it to a post

programRunning is being changed asynchronously by your timer interupt. The compiler optimisation is probably just using a register with the routine you highlight unless it is calling an external routine when it will update the in memory location. You have to stop the compiler optimising that variable so that the interupt updating it is then read by the routine interupted. Depending on the machine architecture it may be that you also need to disable interupts whenever you change that variable outside of the timer interupt if the variable is multibyte. Change the variable to a single byte and use the volatile declaration.

Change your programRunning variable to bool so it will only be 1 byte. Declare it as

volatile bool programRunning;

Since your delayStep variable is used inside the ISR as well as the main loop, it needs to be volatile as well

volatile int delayStep;

and since it is more than 1 byte, you have to make a copy to use inside of loop

  int delayStepLocal;

  noInterrupts();
  delayStepLocal = delayStep;
  Interrupts();

And then use delayStepLocal wherever you were using delayStep in loop()

Hey!

Thank to you two!!!

This did the trick :slight_smile:

KUDOS!

This topic was automatically closed 120 days after the last reply. New replies are no longer allowed.