Button, timing and loops

I am tying to get a 3 second, 350ms pulse set out after I press a button for a heat sealer. I'm not sure what I am missing, or if this is not quite structured right. I was thing this would allow the button to be pressed, start a 3 second timer, and the 350ms loop be activated. What i get is; press the button, the first part of the pulse starts, and it stays there.
Code

#define BUTTON_PIN  17
#define heat 39
int btnState;
int pinState;
int latch = LOW;
int heatState = LOW;
unsigned long interval1 = 350;
unsigned long previousMillis1 = 0;
unsigned long currentTime = 0;
unsigned long interval2 = 3000;
unsigned long previousMillis2 = 0;
void button1() {
  pinState = btnState;
  btnState = digitalRead(17);
  if (pinState == HIGH && btnState == LOW); {
    Serial.print("btn "); Serial.println(btnState);
    Serial.print("pin "); Serial.println(pinState);
    heater();
  }
}

void heater() {
  if (digitalRead(17) == LOW) {
    if (currentTime - previousMillis2 >= interval2) {
      heater2();
      previousMillis2 += currentTime;
    }
    if (digitalRead(17) != LOW) {
      digitalWrite(39, LOW);
    }
  }
}
void heater2() {
  if (millis() - previousMillis1 >= interval1) {
        if (heatState == HIGH) {
          heatState = LOW; Serial.println("on");
        } else {
          heatState = HIGH; Serial.println("off");
        }
        digitalWrite(heat, heatState);
        previousMillis1 += millis();
      }
}
void setup() {
  Serial.begin(115200);
  pinMode(17, INPUT_PULLUP);
  pinMode(39, OUTPUT);
  digitalWrite(39, LOW);
}

void loop() {
  heater();
  currentTime = millis();
}

Ant help would be appriciated.

When in the code is pin 39 ever anything but LOW ?

Your code would be clearer if you used the names that you gave pins 17 and 39 rather than their numbers

You never call button1() so how will you know the button is pressed?

Also, this

has an extra ; at the end of the line which will break your logic. Everything will always get executed.

EDIT: oh, pin 17 must be your button. What @UKHeliBob said.

Start out simple. When the button is pressed, turn on your output, wait 350 msec, turn it off, wait another 2.65 sec and then repeat. No need to start out complicated. Just use delay().

Have a look at the State Change Detection example (File->examples->02.digital->State Change detection) and learn how to detect when your button is pressed, not if the button is pressed.

What comes first, the 3 second delay or the 350ms heat pulse? Which Arduino?

This what i got to work, where the button is pushed and the heater pulses. When the button is released, the heater shuts down.

#define btn  17
#define heat 39
//int btnState;
//int lastBtnState;
int heatState = LOW;
unsigned long interval1 = 750;
unsigned long previousMillis1 = 0;
unsigned long currentTime = 0;


void button1() {
  if (digitalRead(btn) == LOW) {
    if (currentTime - previousMillis1 >= interval1) {
      Serial.print("start "); Serial.println(heatState);
      if (heatState == HIGH) {
        heatState = LOW; Serial.println("on");
      } else {
        heatState = HIGH; Serial.println("off");
      }
      digitalWrite(heat, heatState);
      Serial.print("end "); Serial.println(heatState);
      previousMillis1 = currentTime;
    }
  }
  if (digitalRead(btn) != LOW) {
    digitalWrite(heat, LOW);
  }
}


void setup() {
  Serial.begin(115200);
  pinMode(btn, INPUT_PULLUP);
  pinMode(heat, OUTPUT);
  digitalWrite(39, LOW);
}

void loop() {
  button1();
  currentTime = millis();
}

what does this mean?
a 3 second pulse,
a 350 msec pulse, or
alternately on/off every 350 msec over 3 seconds

if the later, sounds like you need to start pulsing after 8 timer iterations

That does not match your initial post about wanting a 350ms pulse and some sort of 3 sec delay. Are you still working on this or have your needs been met?

My apologies, I should have stated what I have got to work for now. I have a potentiometer inserted to vary the pulse timing last night, and now would like to have a timing variable added. I'm just not sure how to insert a millis function inside another millis function.

please answer?

I wish (and now have) a 350ms on/off pulse for the heat strip, and now would like for that on/off pulse to last 3 (or some other amount) seconds.

so you mean 350 - 3000 msec?

Right now, I press the button, and the strip loop continues until I release the button.
I would like to press and release the button and the strip loop continues (350ms on/off) for 3 seconds

Something like this?

... you set a timer for 3 seconds, and while it is active, you do the 350ms heater toggling.

i think you want something like following
pressing the button sets a count and enables a timer

enum { Off = LOW, On = HIGH };

int heatState = Off;

unsigned long previousMillis1 = 0;
unsigned long currentTime     = 0;
unsigned long Interval1       = 350;
int           pulseCnt;

char s [90];

// -----------------------------------------------------------------------------
void button1 ()
{
    if (0 < pulseCnt && currentTime - previousMillis1 >= Interval1) {
        previousMillis1 = currentTime;
        pulseCnt--;

        if (heatState == On) {
            heatState = Off;
        } else {
            heatState = On;
        }
        digitalWrite (heat, heatState);

        sprintf (s, " heatState %d, %8lu msec", heatState, currentTime);
        Serial.println (s);
    }

    byte but = digitalRead (btn);
    if (butState != but)  {
        butState = but;
        delay (20);                         // debounce

        if (LOW == but)  {                  // pressed
            pulseCnt  = 7;                  // enable timer
            heatState = On;
            digitalWrite (heat, heatState); // turn heater on
            previousMillis1 = currentTime;

            sprintf (s, " heatState %d, %8lu msec", heatState, currentTime);
            Serial.println (s);
        }
    }
}

Thank you. I now have to research and learn how this works.

There are many ways to achieve your functionality.

They differ in style and the grade if they are easier or harder to understand.
One way to increase understandability is to add explaining comments and using of self-explaining variable-names

So this is my attempt to do so.

source-code as in WOKWI

// https://forum.arduino.cc/t/button-timing-and-loops/1223168
// https://wokwi.com/projects/390016797849980929  
unsigned long my3SecondTimer  = 0;  // Timer-variables MUST be of type unsigned long
unsigned long my350mSecsTimer = 0;  // Timer-variables MUST be of type unsigned long

const byte buttonPin = 17;
const byte heaterPin = 39;

byte buttonState;

boolean heatingStarted = false;

const byte released = HIGH;
const byte pressed  = LOW;


void setup() {
  Serial.begin(115200);
  Serial.println("Setup-Start");
  pinMode(buttonPin, INPUT_PULLUP);
  digitalWrite (heaterPin, LOW);
  pinMode(heaterPin, OUTPUT);  
  Serial.println("press button to start heater-cycle");
}

void loop() {

  // if heating has not yet started read in the button
  if (heatingStarted == false) {     
    buttonState = digitalRead(buttonPin);
    if ( buttonState == pressed ) {
      Serial.println("Start-Button pressed start heater cycle heater-pulsing");
      heatingStarted = true;      // indicate heating HAS started
      my3SecondTimer  = millis(); // store actual time
      my350mSecsTimer = millis(); // store actual time
      digitalWrite(heaterPin,HIGH);
    }
  }
  else { // heating HAS started and is running

    // check if 350 milliseconds have pased by since heating started
    if (  TimePeriodIsOver(my350mSecsTimer,  350)  ) {
      // when 350 milliseconds REALLY HAVE passed by
      // update timervariable with name "my350mSecsTimer" automatically
      // for next interval
      invertHeaterStateOnOff(); // say what it does
    }
    

    // check if 3000 milliseconds have passed by since heating started
    if (  TimePeriodIsOver(my3SecondTimer, 3000)  ) {
      // when 3000 milliseconds REALLY HAVE passed by
      // not reevant here: update timervariable with name "my3SecondTimer" automatically
      Serial.println("3 seconds over heater switched OFF");
      digitalWrite(heaterPin, LOW);   
      Serial.println("heating cycle finished press button for new heater-cycle");
      Serial.println();
      heatingStarted = false;
    }
  }
}


void invertHeaterStateOnOff() {
  if ( digitalRead(heaterPin) == HIGH) {
    digitalWrite(heaterPin, LOW); 
    Serial.println("Heater  switched OFF");
  }
  else {
    digitalWrite(heaterPin, HIGH);     
    Serial.println("Heater  switched ON");
  }
}

// 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
}

Thank you. This give me a better understanding of how to properly code. And how to test

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