tun on and off a motor at different times in a loop

Hello everyone,I’ve been working on a project to learn to breathe correctly
(lower your blood pressure, boost your immune system,clear your mind, and
even help you sleep better).I am using an attiny85 (digispark clone)and I got a very ugly code using Delay, just to test it for a few weeks.The scheme is just a state machine with one button to choose between two events, and one more button to reset. One of the events is as follow,

I need a vibrating motor to perform an Off/On pattern.

Off-- during 4 seconds
On – for a brief period of time,just enough to be noticed by the user
Off-- during 7 seconds
On – again briefly
Off – during 8 seconds
On – again briefly
And then start over and over

The problem comes with the big delays, so I need to figure out a way to
ged rid of them so I can change to another event at anytime.I have been
doing my work with google prior to ask but I am kindda new using attiny85,
I tried blink without delay but it is so confused to me,so I have no idea how to modify it for a pattern like above,I did find that not all the timing libraries
available for arduino will work on attiny85, so I would like to present my code
to you guys so you can kindly give me some advice about the best way to go
or point out some timing libraries that actually work on attiny85.

//EasyBreath v1.0 by Tony Morales,2018
//Simple aid to learn breathing: 4 seconds to inhale,7 seconds to 
//keep breath,then 8 seconds to exhale based in TedTalks of Max Strom Breathe to heal.
https://www.youtube.com/watch?v=4Lb5L-VEm34
//I used a clone digispark //so PB5 reset was not disabled so this is cool to start over.
//There is a pushbutton between pb5 and gnd.For mode selection button, there is
//a resistor net among 5v and gnd as follow: 5V--15k--47k--gnd, at the middle point, we attach another
//47k resistor ---push buttom---5v. the middle point is connected to PB4 too.
//the board is set to digispark 1mhz no usb
//There is a led attached to PB2 to display 50 flashes per minute(experimental)
//There is a small vibrating motor attached to PB1.(transistor as driver)
int sensitivity = 0;     // 
int threshold = 6; //
int val = 0;
int old_val = 0;
int led = 12;
int newled = 12;


void setup ()
{
      // Initialize Outputs 
    pinMode(0, OUTPUT);
    pinMode(1, OUTPUT);//small vibration motor
    pinMode(2, OUTPUT);//led 
    pinMode(3, OUTPUT);
    
   sensitivity = analogRead(2); //PB4
  digitalWrite(0, LOW);//save energy
  digitalWrite(1, LOW);//save energy
  digitalWrite(2, LOW);//save energy
  digitalWrite(3, LOW);//save energy
  }


void loop ()
{ 
  val = analogRead(2);//PB4
   if((val > sensitivity + threshold) && (old_val <= sensitivity + threshold ))
   
   {
    newled = led - 1; 
     if (newled == 10) { newled = 12; } 
    led = newled;
    delay(100);
   }
 
  old_val = val;
  
  if (led == 12)// first one
  
  {
digitalWrite(1, HIGH);
delay (100);
digitalWrite(1, LOW);
delay(2000);
val = analogRead(2);//PB4
   if((val > sensitivity + threshold))
   {
    goto label1;
      }
      delay(2000);
digitalWrite(1, HIGH);
delay (100);
digitalWrite(1, LOW);
delay(3500);
val = analogRead(2);//PB4
   if((val > sensitivity + threshold))
   {
    goto label1;
      }
delay(3500);
digitalWrite(1, HIGH);
delay (100);
digitalWrite(1, LOW);
delay(2000);
val = analogRead(2);//PB4
   if((val > sensitivity + threshold))
   {
    goto label1;
      }
delay(2000);
val = analogRead(2);//PB4
   if((val > sensitivity + threshold))
   {
    goto label1;
      }
delay(2000);
val = analogRead(2);//PB4
   if((val > sensitivity + threshold))
   {
   goto label1;
      }
delay(2000);
   
   }
   label1:
 if (led == 11)//second one 50 bpm,T = 1.2 seg
  {
digitalWrite(2, HIGH);
delay (150);
digitalWrite(2, LOW);
delay(1200);
     
        }
 /*if (led == 10)// Third one
  {
    digitalWrite(0, HIGH);
    digitalWrite(1, HIGH);
    digitalWrite(2, HIGH);
    digitalWrite(3, HIGH);   
  } 
   if (led == 9)//Fourth one
  {
    digitalWrite(0, HIGH);
    delay(50);
    digitalWrite(0, LOW);
    delay(50);
    digitalWrite(1, HIGH);
    delay(50);
    digitalWrite(1, LOW);
    delay(50);
    digitalWrite(2, HIGH);
    delay(50);
    digitalWrite(2, LOW);
    delay(50);
    digitalWrite(3, HIGH);
    delay(50);
    digitalWrite(3, LOW);
    delay(50);
       
  } 
   
if (led == 8)
  {
    digitalWrite(0, LOW);
    digitalWrite(1, LOW);
    digitalWrite(2, LOW);
    digitalWrite(3, LOW);
  } 
  */
  }

Thanks in advance for any suggestions!

attiny85nightmare:
I tried blink without delay but it is so confused to me,so I have no idea how to modify it for a pattern like above

There's your problem. Take the time to truly understand BlinkWithoutDelay before moving on to applying that technique in your code.

There's surely a reason that books and magazines align the text on the left: it's way easier to read than centred. Please do everyone a favour and modify your post to left aligned and make it more readable.

This may help with blink without delay.

Think about the pattern of off&on as a state machine of its own. For the first 4 seconds you check all the inputs waiting for something to happen. If nothing has happened after 4 seconds, turn the motor on and then go back to checking the inputs again.

At some point the button gets pushed and you go to another state. You didn't say what but I'm guessing there's a "start" or "stop" state? If the button isn't pushed, you keep cycling through those 6 states.

This is my take on the blink without delay technique State Machine

Welcome to the forum !

please take a couple of minutes and read ‘how to use this forum’
and pay attention to item #7 about posting code.

as for your first project, as others have pointed out, there is a programming loop called ‘blink without delay’ aka BWD

there are a lot of variations on that and a lot of ways to do that depending on your needs.

delay() is a blocking command, and the system does nothing until that delay period is over.

BWD is just a simple test,
has the time expired ? NO, doing things, check again…
has the time expired ? YES , then do that thing you need to do…

BWD is a very basic programming loop that should be fundamental in your tool kit.

I modify my post to be more readable,so thank you guys I will be reading Wilfredmedlin and Grumpy_Mike links and will be back with the updated code, now I know that BWOD and state machines is the way to go, the reason of my question was that as a noob ,sometimes I discover myself struggling for days with a piece of code just to find later that there is another easy solution that can do the job.

MorganS, there is no start/stop state yet, the thing start to turn on and off the motor as soon as I apply power,as I said ,it was intended to test the breathing technique and take some measures like blood pressure and oxigen levels in blood.

brb asap!

I have been working with my code,this is what I have done so far:
2 buttons to control a FSM with 3 states, state 0 for monitoring the buttons and select the next state. state 1 simple turn a led ON and state 2 start the the ON/OFF patterns in another led ( 4 seg OFF,100 ms ON,7 seg OFF,100 ms ON,8 seg OFF and start over.
As MorganS said, I managed to put another state machine inside state2 and
buttons monitoring so if button2 is pressed being in State2 we go back to state 0, same for state1, so far so good, the problem comes when I go from state 0 to state2 again, the second inner state machine starts at any state, but I need that every time state2 is reached, the sequence starts with the first 4 seg OFF.
So I think is all about the reseting some variable, I tried to do previousMillis = 0 when the secuence starts(at the very begining of state2) but nothing seems to work. Maybe my whole code is a wrong approach or is just a matter of deleting/adding a little piece.

If I am able to reset the sequence,I still need to add some code so I can jump from state 1 to state 2 and vice versa.

I wanted to show my code but it says I only have 9000 characters and I can post again only after 5 minutes passed!

Here my code

unsigned long previousMillis = 0;
unsigned long currentMillis;
const long interval = 4000;
const long interval2 = 100;
const long interval3 = 7000;
const long interval4 = 8000;
const int button = 4;
const int button2 = 5;
int state = 0;
int state2 = 0;
int ledstatus = LOW;
int ledstatus2 = LOW;

int buttonState;//variable to hold the state of the button
int lastButtonState = HIGH;

int buttonState2;//variable to hold the state of the button
int lastButtonState2 = HIGH;

long lastDebounceTime = 0;  // the last time the output pin was toggled
long lastDebounceTime2 = 0;  // the last time the output pin was toggled

long debounceDelay = 50;

void setup() {
  Serial.begin(9600);
  pinMode(button, INPUT_PULLUP); 
  pinMode(button2, INPUT_PULLUP); 
  pinMode(13, OUTPUT);
  pinMode(12, OUTPUT);
  digitalWrite(13, ledstatus);
  digitalWrite(12, ledstatus2);
}
void loop() {
  int reading = digitalRead(button);
  int reading2 = digitalRead(button2);
  switch (state) {
    case 0:
            
      //step 1
      if (reading != lastButtonState) { //HIGH ,reading is LOW! something is going on,we do not what yet

        // reset the debouncing timer
        lastDebounceTime = millis();
      }
      //step 2
      if ((millis() - lastDebounceTime) > debounceDelay) {
       
      
        if (reading != buttonState) {
          buttonState = reading; //it is OFFICIALLY LOW now
          // Serial.println( reading);//print the number //HIGH

          //step 3 do your stuff finally yay!

          // my stuff inside-state 0-button
          if (buttonState == LOW) {
            ledstatus = !ledstatus;
            state = 1;

          }

        }

      }
      lastButtonState = reading;
      //for button2 state 0
      //step 1
      if (reading2 != lastButtonState2) { //HIGH ,reading is LOW! something is going on,we do not what yet

        lastDebounceTime2 = millis();
      }
      //step 2
      if ((millis() - lastDebounceTime2) > debounceDelay) {
       
       
        if (reading2 != buttonState2) {
          buttonState2 = reading2; //it is OFFICIALLY LOW now
          //step 3 do your stuff finally yay!

          // my stuff inside-state 0
          if (buttonState2 == LOW) {

            state = 2;

          }

        }

      }

           lastButtonState2 = reading2;
         break;

    case 1: //-state 1
     
      reading = digitalRead(button);
      reading2 = digitalRead(button2);
      //step 1
      if (reading != lastButtonState) { //HIGH ,reading is LOW! something is going on,we do not what yet
      
        lastDebounceTime = millis();
      }
      //step 2
      if ((millis() - lastDebounceTime) > debounceDelay) {
        // whatever the reading is at, it's been there for longer
        // than the debounce delay, so take it as the actual current state:

        // if the button state has changed:
        if (reading != buttonState) {
          buttonState = reading; //it is OFFICIALLY LOW now
       

          //---------------step 3 do your stuff finally yay!

          // my stuff inside-----------------
          if (buttonState == LOW) {
            ledstatus = !ledstatus;
            state = 0;

          }

        }

      }

      //Serial.println("lastButtonState after the button show");
      lastButtonState = reading;
      //  Serial.println(lastButtonState);

      //go to state 2 by pressing button2--------------------
      // --------------------for button2 state 1--------------
      //----------------step 1-------------------
      if (reading2 != lastButtonState2) { //HIGH ,reading is LOW! something is going on,we do not what yet

        // reset the debouncing timer
        lastDebounceTime2 = millis();
      }
      //-------------------step 2------------------------------------------------
      if ((millis() - lastDebounceTime2) > debounceDelay) {
        // whatever the reading is at, it's been there for longer
        // than the debounce delay, so take it as the actual current state:

        // if the button state has changed:
        if (reading2 != buttonState2) {
          buttonState2 = reading2; //it is OFFICIALLY LOW now
          // Serial.println( reading);//print the number //HIGH

          //---------------step 3 do your stuff finally yay!----------

          // my stuff inside-------state 1----------
          if (buttonState2 == LOW) {
            ledstatus = !ledstatus;
            state = 2;


          }

        }

      }

      //Serial.println("lastButtonState after the button show");
      lastButtonState2 = reading2;
      
      break;
    case 2:

      //Serial.println("This is state 2");
      reading2 = digitalRead(button2);
      //step 1
      if (reading2 != lastButtonState2) { //HIGH ,reading is LOW! something is going on,we do not what yet

        // reset the debouncing timer
        lastDebounceTime2 = millis();
      }
      //step 2
      if ((millis() - lastDebounceTime2) > debounceDelay) {
        
        // if the button state has changed:
        if (reading2 != buttonState2) {
          buttonState2 = reading2; //it is OFFICIALLY LOW now
          // Serial.println( reading);//print the number //HIGH

          //-step 3 do your stuff finally yay!
          // my stuff inside-state 2-button2
          if (buttonState2 == LOW) {

            ///maybe we must reset something here,before leaving state 2
             state2 = 0;
             state = 0;

          }

        }

      }

      lastButtonState2 = reading2;

      //my sequential stuff here
      switch (state2) { //start switch
        case 0:
          currentMillis = millis(); 
          if ((currentMillis - previousMillis) >= interval) { //4000
             previousMillis = currentMillis;
             Serial.println(previousMillis);
            ledstatus2 = !ledstatus2;
            state2 = 1;
          }
          break;
        
        case 1:// actions here and change to next state
               currentMillis = millis();     
          if ((currentMillis - previousMillis) >= interval2) { //100
              previousMillis = currentMillis;//
            ledstatus2 = !ledstatus2;
            state2 = 2;
          }
          break;
        
        case 2:// actions here and change to next state
          currentMillis = millis();
          if ((currentMillis - previousMillis) >= interval3) {//7000
            previousMillis = currentMillis;//
            Serial.println(previousMillis); //1
            ledstatus2 = !ledstatus2;
            state2 = 3;
          }
          break;
        
        case 3:// actions here and change to next state
         currentMillis = millis();
          if ((currentMillis - previousMillis) >= interval2) {//100
             previousMillis = currentMillis;//
            ledstatus2 = !ledstatus2;
            state2 = 4;
          }
          break;
        
        case 4:// actions here and change to next state
         currentMillis = millis();
          if ((currentMillis - previousMillis) >= interval4) {//8000
            previousMillis = currentMillis;//
             Serial.println(previousMillis); //1
            ledstatus2 = !ledstatus2;
            state2 = 5;
          }
          break;
        
        case 5:// actions here and change to next state
         currentMillis = millis();
          if ((currentMillis - previousMillis) >= interval2) {//100
            previousMillis = currentMillis;//
            ledstatus2 = !ledstatus2;
            state2 = 0;
          }
          break;
      }//finish inner switch}

      break;

  }//end switch(state)

  digitalWrite(13, ledstatus);
  digitalWrite(12, ledstatus2);

}//end loop

Any help in resetting the blinking pattern each time we enter in it is always welcome!

The 5-minute thing goes away quickly. It just depends on how many posts you've made.

You can attach the code but that makes it ten times less likely that most forum members will look at it. If you can, try to trim the code down to the simplest example which compiles and shows the problem. (Often this will solve your problem for you.) Strip out the LCD display or whatever bulky stuff is not relevant to the problem.

The outer state machine is allowed to mess with the values of the inner one. Every time you set the outer state to 2, you should set the inner one to zero (or whatever.) Often that will set previousInnerMillis=millis(); so that the inner one knows what time it started. You do have separate "previous" measurements for each different state machine, don't you?

The state transitions are where most of the work is done. You turn the motor on or off in the transition event, then the state waits for X seconds while checking all the inputs. When it gets an input, it does that next transition's work.

(Note the previous post was written just before the code was posted.)

Button? Button2? Give them names please! Like "start" or "menu" or whatever they actually do. Same with the LEDs. Don't even give them colours. redLED is informative now, but in a few weeks you will forget if the red one is the one that means it's on or means it's off.

The debounce stuff is copied several times. That's just screaming out for a function. Or just read the buttons once before the switches.

In the second switch, every single choice first does currentMillis=millis(); Just do it once before the switch. It takes out that repetitive code from the actual interesting section and makes that section easier to read.

            ledstatus = !ledstatus;

This is kind of a trick that C programmers like to do. But in your states, I can't tell if you're turning the LED on or off. Which is it? Just explicitly turn it on or off.

As far as I can see, the state2 sequence always runs. It just repeats forever without any interaction with the state1 state. I was expecting it to have a state 0 which does nothing. The other state machine either starts it into the endless loop or interrupts that loop and kicks it back to state 0. (Also reset its outputs when you do both of those.)

will be back with all the mods! thank you!

As noobie, I feel most of the time like: OMG!! I want to throw this blue board through the window! but right now I feel like Neo, I can see the matrix!

I can navigate through each state now. state 0 does nothing, state 1 one led ON, state 2 a series of blinks for the other led (the vibrating motor will go here) I followed every single suggestion MorganS did :slight_smile:

unsigned long previousMillis = 0;
unsigned long currentMillis;

const long interval = 4000;
const long interval2 = 100;
const long interval3 = 7000;
const long interval4 = 8000;

const int Onbttn = 4;
const int blinkbttn = 5;
int state = 0;
int innerstate = 1;

int flagOnbttn;
int flagblinkbttn;

int Onbttnstate;//variable to hold the state of the button
int lastOnbttnstate = HIGH;

int blinkbttnstate;//variable to hold the state of the button
int lastblinkbttnstate = HIGH;

long lastDebounceTime = 0;  // the last time the output pin was toggled
long lastDebounceTime2 = 0;

long debounceDelay = 50;



void setup() {
  // Serial.begin(9600);// initialize serial communication:

  pinMode(Onbttn, INPUT_PULLUP);
  pinMode(blinkbttn, INPUT_PULLUP);
  pinMode(13, OUTPUT);
  pinMode(12, OUTPUT);
  digitalWrite(13, LOW);
  digitalWrite(12, LOW);
}//end setup

void loop() {

  debounce();
  switch (state) {
    case 0://wait for buttons
      //Serial.println("do nothing");
      if (flagOnbttn == HIGH) {
        flagOnbttn = LOW;
        state = 1;
      }
      if (flagblinkbttn == HIGH) {
        flagblinkbttn = LOW;
        innerstate = 1;
        state = 2;
        previousMillis = millis();
      }
      digitalWrite(13, LOW);
      digitalWrite(12, LOW);
      break;

    case 1:
      //Serial.println("this is state 1");
      if (flagOnbttn == HIGH) {
        flagOnbttn = LOW;
        state = 0;
      }
      if (flagblinkbttn == HIGH) {
        flagblinkbttn = LOW;
        innerstate = 1;
        state = 2;
        previousMillis = millis();
      }
      digitalWrite(13, HIGH);
      digitalWrite(12, LOW);
      break;
    case 2:
      // Serial.println("this is state 2");
      digitalWrite(13, LOW);
      //Serial.println(previousMillis);
      if (flagOnbttn == HIGH) {
        flagOnbttn = LOW;
        state = 1;
      }
      if (flagblinkbttn == HIGH) {
        flagblinkbttn = LOW;
        state = 0;
      }
      blinks();
      break;//ends case 2
  }//end switch(state)
}//end loop



void debounce() {
  int reading = digitalRead(Onbttn);
  int reading2 = digitalRead(blinkbttn);
  if (reading != lastOnbttnstate) {
    lastDebounceTime = millis();
  }
  if ((millis() - lastDebounceTime) > debounceDelay) {
    if (reading != Onbttnstate) {
      Onbttnstate = reading; //it is OFFICIALLY LOW now
      if (Onbttnstate == LOW) {
        flagOnbttn = HIGH;
      }
    }
  }
  if (reading2 != lastblinkbttnstate) {
    lastDebounceTime2 = millis();
  }
  if ((millis() - lastDebounceTime2) > debounceDelay) {
    if (reading2 != blinkbttnstate) {
      blinkbttnstate = reading2; //it is OFFICIALLY LOW now
      if (blinkbttnstate == LOW) {
        flagblinkbttn = HIGH;
      }
    }
  }
  lastOnbttnstate = reading;
  lastblinkbttnstate = reading2;
}

void blinks() {
  currentMillis = millis();
  switch (innerstate)
  { //start switch
    case 1:
      if (currentMillis - previousMillis >= interval) { //4000
        previousMillis = currentMillis;
        //Serial.println(previousMillis); //1
        digitalWrite(12, HIGH);
        innerstate = 2;
      }
      break;
    case 2:
      if (currentMillis - previousMillis >= interval2) { //100
        previousMillis = currentMillis;
        digitalWrite(12, LOW);
        innerstate = 3;
      }
      break;
    case 3:
      if (currentMillis - previousMillis >= interval3) {//7000
        previousMillis = currentMillis;
        //Serial.println(previousMillis); //2
        digitalWrite(12, HIGH);
        innerstate = 4;
      }
      break;
    case 4:
      if (currentMillis - previousMillis >= interval2) {//100
        previousMillis = currentMillis;
        digitalWrite(12, LOW);
        innerstate = 5;
      }
      break;
    case 5:
      if (currentMillis - previousMillis >= interval4) {//8000
        previousMillis = currentMillis;
        //Serial.println(previousMillis); //3
        digitalWrite(12, HIGH);
        innerstate = 6;
      }
      break;
    case 6:
      if (currentMillis - previousMillis >= interval2) {//100
        // save the last time you blinked the LED
        previousMillis = currentMillis;
        digitalWrite(12, LOW);;
        innerstate = 1;
      }
      break;
  }//ends switch(innerstate)
}