1

I have used this program to control relays based on commands from a serial input or control the relays with a button. Single click for a particular pin toggle and double click is like a master switch.

The code works well normally but sometimes the button just does not respond. the button works without flaw if I remove serial communication and EEPROM part of the code.

Here is the Arduino code

#include <EEPROM.h>
#include <Arduino.h>
#include <avr/wdt.h>

int pins[]={14,16,17,18,19};    //TODO: Set Switch Configuration
int no_of_switches=5;

String names, req, s;

void setup() {

  //Setting up for switches

  // initialize the pushbutton pin as an input:
  for(int i=0;i<6;i++)
  pinMode(i+3, INPUT);

  //Common pin pull up resistor
  pinMode(2,OUTPUT);
  digitalWrite(2,HIGH);

  //Setting up for relays
  Serial.begin(115200);

  for(int i=0;i<6;i++)
  {
    pinMode(i+14, OUTPUT);
    digitalWrite(14, 0);
  }

  Serial.setTimeout(4);

  names="";
  int i=0;
  char data;
  EEPROM.get(i, data);

  while(data!='^')
  {
    names+=data;
    i++;
    EEPROM.get(i, data);
  }
  names+='^';

   wdt_enable(WDTO_4S);
}

void loop() {
  wdt_reset();
  for(int i=0;i<=no_of_switches;i++){
    int b = checkButton(i);
    if (b == 1) clickEvent(i);
    if (b == 2) doubleClickEvent(i);
    if (b == 3) holdEvent(i);
    if (b == 4) longHoldEvent(i);
 }

  if (Serial.available()) {
    req = Serial.readString();
    s = "";

  if (req.indexOf("gpio") != -1)
  {
    String val = req.substring(req.lastIndexOf("gpio")+4);
    int index = val.toInt()-1;

    digitalWrite(pins[index], !digitalRead(pins[index]));

    s += pins[index];
    s += " is ";
    s += (digitalRead(pins[index]) == HIGH) ? "ON  " : "OFF  ";
  }
  else if (req.indexOf("status") != -1){
    String response_code="";
    for(int i=0;i<no_of_switches;i++){
      response_code=response_code+(digitalRead(pins[i])==HIGH?1:0);
      }
    s += response_code;
  }
  else if (req.indexOf("setstate") != -1){
    String val = req.substring(req.lastIndexOf("setstate")+8);
    for(int i=0;i<no_of_switches;i++){
      if(val.charAt(i)=='1')
      digitalWrite(pins[i],HIGH);
      else
      digitalWrite(pins[i],LOW);
      }
    s += "saved";
  }
  else if (req.indexOf("setname") != -1)
  {
    String val = req.substring(req.lastIndexOf("setname")+7);
    for(int i=0;i<val.length();i++)
    EEPROM.put(i, val.charAt(i));                                
    names=val;
    s="saved";

  }
  else if (req.indexOf("names") != -1)
    {
      s=names;
    }
  else 
  {
    s="invalid request";
  }
  Serial.println(s);
}
}
//=================================================
// Events to trigger

void clickEvent(int pos) {
  digitalWrite(pins[pos],!digitalRead(pins[pos]));

}
void doubleClickEvent(int pos) {
  boolean bol=!digitalRead(pins[pos]);
   for(int i=14;i<=19;i++){
    digitalWrite(i,bol);
    }
}
void holdEvent(int pin) {
}
void longHoldEvent(int pin) {
}

//=================================================
//  MULTI-CLICK:  One Button, Multiple Events

// Button timing variables
int debounce = 20;          // ms debounce period to prevent flickering when pressing or releasing the button
int DCgap = 250;            // max ms between clicks for a double click event
int holdTime = 1000;        // ms hold period: how long to wait for press+hold event
int longHoldTime = 3000;    // ms long hold period: how long to wait for press+hold event

// Button variables
boolean buttonVal[] = {HIGH,HIGH,HIGH,HIGH,HIGH,HIGH};   // value read from button
boolean buttonLast[] = {HIGH,HIGH,HIGH,HIGH,HIGH,HIGH};  // buffered value of the button's previous state
boolean DCwaiting[] = {false,false,false,false,false,false};  // whether we're waiting for a double click (down)
boolean DConUp[] = {false,false,false,false,false,false};     // whether to register a double click on next release, or whether to wait and click
boolean singleOK[] = {true,true,true,true,true,true};    // whether it's OK to do a single click
long downTime[] = {-1,-1,-1,-1,-1,-1};         // time the button was pressed down
long upTime[] = {-1,-1,-1,-1,-1,-1};           // time the button was released
boolean ignoreUp[] = {false,false,false,false,false,false};   // whether to ignore the button release because the click+hold was triggered
boolean waitForUp[] = {false,false,false,false,false,false};        // when held, whether to wait for the up event
boolean holdEventPast[] = {false,false,false,false,false,false};    // whether or not the hold event happened already
boolean longHoldEventPast[] = {false,false,false,false,false,false};// whether or not the long hold event happened already

int checkButton(int buttonPin) {    
   int event = 0;
   buttonVal[buttonPin] = digitalRead(buttonPin+3);
   // Button pressed down
   if (buttonVal[buttonPin] == LOW && buttonLast[buttonPin] == HIGH && (millis() - upTime[buttonPin]) > debounce)
   {
       downTime[buttonPin] = millis();
       ignoreUp[buttonPin] = false;
       waitForUp[buttonPin] = false;
       singleOK[buttonPin] = true;
       holdEventPast[buttonPin] = false;
       longHoldEventPast[buttonPin] = false;
       if ((millis()-upTime[buttonPin]) < DCgap && DConUp[buttonPin] == false && DCwaiting[buttonPin] == true)  DConUp[buttonPin] = true;
       else  DConUp[buttonPin] = false;
       DCwaiting[buttonPin] = false;
   }
   // Button released
   else if (buttonVal[buttonPin] == HIGH && buttonLast[buttonPin] == LOW && (millis() - downTime[buttonPin]) > debounce)
   {        
       if (not ignoreUp[buttonPin])
       {
           upTime[buttonPin] = millis();
           if (DConUp[buttonPin] == false) DCwaiting[buttonPin] = true;
           else
           {
               event = 2;
               DConUp[buttonPin] = false;
               DCwaiting[buttonPin] = false;
               singleOK[buttonPin] = false;
           }
       }
   }
   // Test for normal click event: DCgap expired
   if ( buttonVal[buttonPin] == HIGH && (millis()-upTime[buttonPin]) >= DCgap && DCwaiting[buttonPin] == true && DConUp[buttonPin] == false && singleOK[buttonPin] == true && event != 2)
   {
       event = 1;
       DCwaiting[buttonPin] = false;
   }
   // Test for hold
   if (buttonVal[buttonPin] == LOW && (millis() - downTime[buttonPin]) >= holdTime) {
       // Trigger "normal" hold
       if (not holdEventPast[buttonPin])
       {
           event = 3;
           waitForUp[buttonPin] = true;
           ignoreUp[buttonPin] = true;
           DConUp[buttonPin] = false;
           DCwaiting[buttonPin] = false;
           //downTime[buttonPin] = millis();
           holdEventPast[buttonPin] = true;
       }
       // Trigger "long" hold
       if ((millis() - downTime[buttonPin]) >= longHoldTime)
       {
           if (not longHoldEventPast[buttonPin])
           {
               event = 4;
               longHoldEventPast[buttonPin] = true;
           }
       }
   }
   buttonLast[buttonPin] = buttonVal[buttonPin];
   return event;
}
  • Do you have external pull-up resistors as you are using INPUT mode for the inputs? – KIIV Mar 23 '17 at 6:37
  • If it stops working after a random time, I would say it looks like a memory exhaustion problem. You could periodically print the available RAM to make sure: code to do so is widely available. If that is indeed the problem, using statically allocated character arrays instead of String objects should help. – Edgar Bonet Mar 23 '17 at 9:46
  • Could it be that the processor is busy dealing with the serial or EEPROM code when you press the button and you release it before the processor has returned? – Code Gorilla Mar 23 '17 at 12:58
  • Yes, I do have pull-up resistors for the button. Normally the button works consistently. But all of a sudden it stops working – Rajendra mayavan Sathyam Mar 24 '17 at 9:19

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.