ATtiny85 - Digispark - 2 buttons , 2 outputs

Hello,
I need help in the modification program Arduino Digispark.
The principle of operation of the program:
P1 - button 1
P4 - button 2
P0 - output 1
P2 - output 2

Program at this moment

  • 5 time press the button 1 is switched on output 1 and keeps this state by 40s
  • 5 time press the button 2 is switched on output 2 and keeps this state by 40s
  • If pressing a button 5 times will not happen in the 10s (eg. Pinning 3 times and give up) is a program goes back to the beginning and start counting again

Modifying he wanted me to do:

  • 5 times press the button 1 is switched on output 1 and keeps this state by the 40s, during the 40s at any time I press once the button 2, the program disables the output 1 and goes back to the beginning
  • 5 times press the button 2 is switched on output 2 and keeps this state by the 40s, during the 40s at any time I press once the button 2, the program disables the output 2 and goes back to the beginning
  • If pressing a button 5 times will not happen in the 10s (eg. Pinning 3 times and give up) is a program goes back to the beginning and start counting again
//STALE
const int button1 = 1;
const int button2 = 4;
const int led1 = 0;
const int led2 = 2;

//ZMIENNE
int button1PushCounter = 0;
int button2PushCounter = 0;
int button1State = 0;
int button2State = 0;
int lastButton1State = 0;
int lastButton2State = 0;
int time = millis();
long eventTime = 0;

//SETUP
void setup() 
{
pinMode(button1, INPUT);
pinMode(button2, INPUT);
pinMode(led1, OUTPUT);
pinMode(led2, OUTPUT);
}
//PROGRAM
void loop() 

{
//BUTTON1
button1State = digitalRead(button1);

if(button1State != lastButton1State )
{
   if(button1State != HIGH)
   {
     button1PushCounter++;
     eventTime=millis();
     Time_Check(eventTime);
   }
}
lastButton1State = button1State;

if(button1PushCounter == 3)
{
   digitalWrite(led1, LOW);
   Time_Check(eventTime);
   delay(40000);
   button1PushCounter=0;
}
else
{
   digitalWrite(led1, HIGH);
}
//BUTTON 2
button2State = digitalRead(button2);

if(button2State != lastButton2State )
{
   if(button2State != HIGH)
   {
     button2PushCounter++;
     eventTime=millis();
     Time_Check(eventTime);
   }
}
lastButton2State = button2State;

if(button2PushCounter == 3)
{
   digitalWrite(led2, LOW);
   Time_Check(eventTime);
   delay(40000);
   button2PushCounter=0;
}
else
{
   digitalWrite(led2, HIGH);
}
}

//RESET
void Time_Check(long Time)
{
long Ntime = ((millis() - Time )/ 1000);
  if(Ntime == 5)
{
   button1PushCounter=0;
   button2PushCounter=0;
   digitalWrite(led1, HIGH);
   digitalWrite(led2, HIGH);
}
return;
}

during the 40s at any time I press once the button 2, the program disables the output 1 and goes back to the beginning

The first thing to do is to stop using delay() and switch to millis() timing.

Save the millis() value at the time that the start action happens. Then, each time through loop(), check whether the required wait period has elapsed by subtracting the start time from the millis() value now. If the period has elapsed then act accordingly and maybe save the start time for the next activity. If not, then go round loop() again, perhaps taking other actions and/or reading inputs, but don’t block the free running of loop().

The first step will be to get rid of the delays and replace them by something non-blocking. That way you can keep on checking the buttons.

And next your problem is calling for a small statemachine.

In the first state (state 0) you read buttons to determine if you need to switch led1 (go to state 1) on or led2 (go to state 2) or do nothing (stay in state1). You can keep a global variable to keep track of the current state.

A function to switch led1 on for 40 seconds could look like this.

/*
  switch led1 on for given period
  call this continously from loop (when needed)
*/
void led1_On()
{
  // remember starttime
  unsigned long starttime = 0;

  // if led not on (based on start time)
  if (starttime == 0)
  {
    // switch led on
    digitalWrite(led1, LOW);
    // set starttime
    starttime = millis();
  }

  // if 40 seconds passed
  if (millis() - starttime >= 40000UL)
  {
    // switch led of
    digitalWrite(led1, HIGH);
    // reset start time
    starttime = 0;

    // switch back to state 0
    currentstate = 0;
  }
}

In this function you can also check if button 2 was pressed; e.g.

  // if 40 seconds passed or button 2 pressed
  if (millis() - starttime >= 40000UL || digitalRead(button2 == LOW)
  {
    ...
    ...
    currentstate = 0;
  }

The loop() can be a simple switch/case

int currentstate = 0;
void loop()
{
  switch (currentstate)
  {
    case 0:
      // read buttons till we know what to do
      ...
      ...

      if (button1PushCounter == 5)
      {
        button1PushCounter = 0;
        currentstate = 1;
      }
      if (button2PushCounter == 5)
      {
        button2PushCounter = 0;
        currentstate = 2;
      }
      break;
    case 1:
      led1_On();
      break;
    case 2:
      led2_On();
      break;
  }
}

You need to implement led2_On yourself and implement the reading of the buttons (including timeout).

Your Time_Check will never work. You're passing millis() as an argument (Time) and next subtract that from millis() in the function. That will never reach 5000.
You also increment the push counter for button when when pressing button 2.

I missed a bracket when I added the button to check if it's pressed during the 'delay'; you added it at the wrong place :wink:

And I made a mistake; the starttime should be static :frowning:

/*
  switch led1 on for given period
  call this continously from loop (when needed)
*/
void led1_On()
{
  // remember starttime
  static unsigned long starttime = 0;

  // if led not on (based on start time)
  if (starttime == 0)
  {
    // switch led on
    digitalWrite(led1, HIGH);
    // set starttime
    starttime = millis();
  }

  // if 10 seconds passed
  if (millis() - starttime >= 10000UL || digitalRead(button2) == LOW)
  {
    // switch led of
    digitalWrite(led1, LOW);
    // reset start time
    starttime = 0;

    // switch back to state 0
    currentstate = 0;
  }
}

You need to check if your button is low when it's pressed or not; the above assumes it is but from your other parts of the code I think it is HIGH.

By the way, who wants you to modify the code?

I only have an Uno; I hope things work the same on an ATtiny.

I suggest that you move what you wrote in ‘case 0’ to a function. It keeps the code a bit more tidy. Below a complete implementation. It has a few more states. If ‘the other button’ is pressed while a LED is on, we don’‘t want to count that as the first press when checking the buttons’; the new states check (and wait) till the button is released. A simple debouncing of buttons is added as well.

The code assumes that you have buttons going from the pin to ground; this seems OK based on your original code. The LEDs probably work the other way around; check it. You can modify the first two #define lines to turn it around.

const int button1 = 1;
const int button2 = 4;
const int led1 = 0;
const int led2 = 2;

int button1PushCounter = 0;
int button2PushCounter = 0;
int button1State = 0;
int button2State = 0;
int lastButton1State = 0;
int lastButton2State = 0;

// sensible names for on and off for leds
#define ON HIGH   // if led from pin to ground: HIGH; if led from Vcc to pin: LOW
#define OFF LOW   // if led from pin to ground: LOW; if led from Vcc to pin: HIGH

// define sensible names for the states
#define STATE_CHECKBUTTONS 0
#define STATE_LEDONE 1
#define STATE_LEDTWO 2
#define STATE_CHECKBUTTON2RELEASED 3
#define STATE_CHECKBUTTON1RELEASED 4


void setup()
{
  pinMode(button1, INPUT_PULLUP);
  pinMode(button2, INPUT_PULLUP);
  pinMode(led1, OUTPUT);
  pinMode(led2, OUTPUT);
  digitalWrite(led1, OFF);
  digitalWrite(led2, OFF);
}

void loop()
{
  switch (currentstate)
  {
    case STATE_CHECKBUTTONS:
      checkButtons();
      break;
    case STATE_LEDONE:
      led1_On();
      break;
    case STATE_LEDTWO:
      led2_On();
      break;
    case STATE_CHECKBUTTON2RELEASED:
      checkButton2Released();
      break;
    case STATE_CHECKBUTTON1RELEASED:
      checkButton1Released();
      break;

  }
}
/*
  switch led1 on for given period
  call this continously from loop (when needed)
*/
void led1_On()
{
  // remember starttime
  static unsigned long starttime = 0;

  // if led not on (based on start time)
  if (starttime == 0)
  {
    // switch led on
    digitalWrite(led1, ON);
    // set starttime
    starttime = millis();
  }

  // check button2
  int b2 = digitalRead(button2);

  // if 40 seconds passed
  if (millis() - starttime >= 10000UL || b2 == LOW)
  {
    // switch led off
    digitalWrite(led1, OFF);
    // reset start time
    starttime = 0;
    // if the button was pressed
    if (b2 == LOW)
    {
      // go to state 3 (check if button2 relesed)
      currentstate = STATE_CHECKBUTTON2RELEASED;
    }
    // else it was a timeout (no need to check if button was released)
    else
    {
      // go to 'next' state
      currentstate = STATE_CHECKBUTTONS;
    }
  }
}
/*
  switch led2 on for given period
  call this continously from loop (when needed)
*/
void led2_On()
{
  // remember starttime
  static unsigned long starttime = 0;

  // if led not on (based on start time)
  if (starttime == 0)
  {
    // switch led on
    digitalWrite(led2, ON);
    // set starttime
    starttime = millis();
  }

  // check button1
  int b1 = digitalRead(button1);
  // if 40 seconds passed
  if (millis() - starttime >= 10000UL || b1 == LOW)
  {
    // switch led off
    digitalWrite(led2, OFF);
    // reset start time
    starttime = 0;
    // if the button was pressed
    if (b1 == LOW)
    {
      // go to state 4 (check if button1 relesed)
      currentstate = STATE_CHECKBUTTON1RELEASED;
    }
    // else it was a timeout (no need to check if button was released)
    else
    {
      // go to 'next' state
      currentstate = STATE_CHECKBUTTONS;
    }
  }
}

/*
  check buttons
*/
void checkButtons()
{
  static unsigned long starttime = 0;
  static unsigned long debouncestarttime = 0;

  // check if a button was pressed (starttime will not be 0) and if timeout
  if (starttime != 0 && millis() - starttime >= 10000UL)
  {
    // reset start time
    starttime = 0;
    // reset push counters
    button1PushCounter = 0;
    button2PushCounter = 0;
  }

  // a slight delay for debouncing the switches
  // if debounce delay not started
  if (debouncestarttime == 0)
  {
    // remember debounce start time
    debouncestarttime = millis();
  }
  // if debounce time not lapsed
  if (millis() - debouncestarttime < 10UL)
  {
    // do nothing
    return;
  }
  // reset debounce start time
  debouncestarttime = 0;

  // read first button
  button1State = digitalRead(button1);
  // if status of button changed
  if (button1State != lastButton1State )
  {
    // set the start time for the timeout
    starttime = millis();
    // if button1 pressed
    if (button1State != HIGH)
    {
      // reset button2 counter
      button2PushCounter = 0;
      // increment button1 counter
      button1PushCounter++;
    }
  }
  // remember last state
  lastButton1State = button1State;

  // if 5 pushes
  if (button1PushCounter == 5)
  {
    // reset start time
    starttime = 0;
    // reset pusg counter
    button1PushCounter = 0;
    // goto net state
    currentstate = STATE_LEDONE;
  }

  // read second button
  button2State = digitalRead(button2);
  // if status of button changed
  if (button2State != lastButton2State )
  {
    // set the start time for the timeout
    starttime = millis();
    // if button2 pressed
    if (button2State != HIGH)
    {
      // reset button1 counter
      button1PushCounter = 0;
      // increment button2 counter
      button2PushCounter++;
    }
  }
  // remember last state
  lastButton2State = button2State;
  // if 5 pushes
  if (button2PushCounter == 5)
  {
    // reset start time
    starttime = 0;
    // reset push counter
    button2PushCounter = 0;
    // goto net state
    currentstate = STATE_LEDTWO;
  }
}

/*
  check if button 1 is released
*/
void checkButton1Released()
{
  static unsigned long debouncestarttime = 0;
  // a slight delay for debouncing the switches
  // if debounce delay not started
  if (debouncestarttime == 0)
  {
    // remember debounce start time
    debouncestarttime = millis();
  }
  // if debounce time not lapsed
  if (millis() - debouncestarttime < 10UL)
  {
    // do nothing
    return;
  }
  // reset debounce start time
  debouncestarttime = 0;
  // check if button released
  if (digitalRead(button1) == HIGH)
  {
    currentstate = STATE_CHECKBUTTONS;
  }
}

/*
  check if button 2 is released
*/
void checkButton2Released()
{
  static unsigned long debouncestarttime = 0;

  // a slight delay for debouncing the switches
  // if debounce delay not started
  if (debouncestarttime == 0)
  {
    // remember debounce start time
    debouncestarttime = millis();
  }
  // if debounce time not lapsed
  if (millis() - debouncestarttime < 10UL)
  {
    // do nothing
    return;
  }
  // reset debounce start time
  debouncestarttime = 0;
  // check if button released
  if (digitalRead(button2) == HIGH)
  {
    currentstate = STATE_CHECKBUTTONS;
  }
}

You need to test it and you need to understand it as you’re the one that will have to maintain the code. Ask questions if you don’t understand something, else good luck.

The version in reply #7 does that. Check the checkButtons() function.

Will try to have a look at it later today.

Except for the fact that I left out the declaration of currentstate (and hence it did not compile), the code works after that fix.

How are your switches wired? How are your LEDs wired?

WORKS OK :slight_smile:

As You said:
“If you understand an example, use it.
If you don’t understand an example, don’t use it.” :wink:

const int button1 = 1;
const int button2 = 4;
const int led1 = 0;
const int led2 = 2;

int button1PushCounter = 0;
int button2PushCounter = 0;
int button1State = 0;
int button2State = 0;
int lastButton1State = 0;
int lastButton2State = 0;
int currentstate = 0;


// sensible names for on and off for leds
#define ON LOW   // if led from pin to ground: HIGH; if led from Vcc to pin: LOW
#define OFF HIGH   // if led from pin to ground: LOW; if led from Vcc to pin: HIGH

// define sensible names for the states
#define STATE_CHECKBUTTONS 0
#define STATE_LEDONE 1
#define STATE_LEDTWO 2
#define STATE_CHECKBUTTON2RELEASED 3
#define STATE_CHECKBUTTON1RELEASED 4


void setup()
{
  pinMode(button1, INPUT);
  pinMode(button2, INPUT);
  pinMode(led1, OUTPUT);
  pinMode(led2, OUTPUT);
  digitalWrite(led1, OFF);
  digitalWrite(led2, OFF);
}

void loop()
{
  switch (currentstate)
  {
    case STATE_CHECKBUTTONS:
      checkButtons();
      break;
    case STATE_LEDONE:
      led1_On();
      break;
    case STATE_LEDTWO:
      led2_On();
      break;
    case STATE_CHECKBUTTON2RELEASED:
      checkButton2Released();
      break;
    case STATE_CHECKBUTTON1RELEASED:
      checkButton1Released();
      break;

  }
}
/*
  switch led1 on for given period
  call this continously from loop (when needed)
*/
void led1_On()
{
  // remember starttime
  static unsigned long starttime = 0;

  // if led not on (based on start time)
  if (starttime == 0)
  {
    // switch led on
    digitalWrite(led1, ON);
    // set starttime
    starttime = millis();
  }

  // check button2
  int b2 = digitalRead(button2);

  // if 40 seconds passed
  if (millis() - starttime >= 10000UL || b2 == HIGH)
  {
    // switch led off
    digitalWrite(led1, OFF);
    // reset start time
    starttime = 0;
    // if the button was pressed
    if (b2 == HIGH)
    {
      // go to state 3 (check if button2 relesed)
      currentstate = STATE_CHECKBUTTON2RELEASED;
    }
    // else it was a timeout (no need to check if button was released)
    else
    {
      // go to 'next' state
      currentstate = STATE_CHECKBUTTONS;
    }
  }
}
/*
  switch led2 on for given period
  call this continously from loop (when needed)
*/
void led2_On()
{
  // remember starttime
  static unsigned long starttime = 0;

  // if led not on (based on start time)
  if (starttime == 0)
  {
    // switch led on
    digitalWrite(led2, ON);
    // set starttime
    starttime = millis();
  }

  // check button1
  int b1 = digitalRead(button1);
  // if 40 seconds passed
  if (millis() - starttime >= 10000UL || b1 == HIGH)
  {
    // switch led off
    digitalWrite(led2, OFF);
    // reset start time
    starttime = 0;
    // if the button was pressed
    if (b1 == HIGH)
    {
      // go to state 4 (check if button1 relesed)
      currentstate = STATE_CHECKBUTTON1RELEASED;
    }
    // else it was a timeout (no need to check if button was released)
    else
    {
      // go to 'next' state
      currentstate = STATE_CHECKBUTTONS;
    }
  }
}

/*
  check buttons
*/
void checkButtons()
{
  static unsigned long starttime = 0;
  static unsigned long debouncestarttime = 0;

  // check if a button was pressed (starttime will not be 0) and if timeout
  if (starttime != 0 && millis() - starttime >= 10000UL)
  {
    // reset start time
    starttime = 0;
    // reset push counters
    button1PushCounter = 0;
    button2PushCounter = 0;
  }

  // a slight delay for debouncing the switches
  // if debounce delay not started
  if (debouncestarttime == 0)
  {
    // remember debounce start time
    debouncestarttime = millis();
  }
  // if debounce time not lapsed
  if (millis() - debouncestarttime < 10UL)
  {
    // do nothing
    return;
  }
  // reset debounce start time
  debouncestarttime = 0;

  // read first button
  button1State = digitalRead(button1);
  // if status of button changed
  if (button1State != lastButton1State )
  {
    // set the start time for the timeout
    starttime = millis();
    // if button1 pressed
    if (button1State != LOW)
    {
      // reset button2 counter
      button2PushCounter = 0;
      // increment button1 counter
      button1PushCounter++;
    }
  }
  // remember last state
  lastButton1State = button1State;

  // if 5 pushes
  if (button1PushCounter == 5)
  {
    // reset start time
    starttime = 0;
    // reset pusg counter
    button1PushCounter = 0;
    // goto net state
    currentstate = STATE_LEDONE;
  }

  // read second button
  button2State = digitalRead(button2);
  // if status of button changed
  if (button2State != lastButton2State )
  {
    // set the start time for the timeout
    starttime = millis();
    // if button2 pressed
    if (button2State != LOW)
    {
      // reset button1 counter
      button1PushCounter = 0;
      // increment button2 counter
      button2PushCounter++;
    }
  }
  // remember last state
  lastButton2State = button2State;
  // if 5 pushes
  if (button2PushCounter == 5)
  {
    // reset start time
    starttime = 0;
    // reset push counter
    button2PushCounter = 0;
    // goto net state
    currentstate = STATE_LEDTWO;
  }
}

/*
  check if button 1 is released
*/
void checkButton1Released()
{
  static unsigned long debouncestarttime = 0;
  // a slight delay for debouncing the switches
  // if debounce delay not started
  if (debouncestarttime == 0)
  {
    // remember debounce start time
    debouncestarttime = millis();
  }
  // if debounce time not lapsed
  if (millis() - debouncestarttime < 10UL)
  {
    // do nothing
    return;
  }
  // reset debounce start time
  debouncestarttime = 0;
  // check if button released
  if (digitalRead(button1) == LOW)
  {
    currentstate = STATE_CHECKBUTTONS;
  }
}

/*
  check if button 2 is released
*/
void checkButton2Released()
{
  static unsigned long debouncestarttime = 0;

  // a slight delay for debouncing the switches
  // if debounce delay not started
  if (debouncestarttime == 0)
  {
    // remember debounce start time
    debouncestarttime = millis();
  }
  // if debounce time not lapsed
  if (millis() - debouncestarttime < 10UL)
  {
    // do nothing
    return;
  }
  // reset debounce start time
  debouncestarttime = 0;
  // check if button released
  if (digitalRead(button2) == LOW)
  {
    currentstate = STATE_CHECKBUTTONS;
  }
}

WORKS OK - now improve it

const int button1 = 1;
const int button2 = 4;
const int led1 = 0;
const int led2 = 2;

int button1PushCounter = 0;
int button2PushCounter = 0;
int button1State = 0;
int button2State = 0;
int lastButton1State = 0;
int lastButton2State = 0;
int currentstate = 0;

Do all/any of these variables need to be ints or would bytes do ?
It will not make any difference to the running of the program but it is good practice to use variables of an appropriate size in order to save memory.