Release 2016.8.19 / Update 2017.6.26

Avoiding from chattering by a programming

Lighting LED is your first task with the Arduino. Then you use a switch for the next step, don’t you?

I wrote a chattering-less switch library with “gauging” method.
(26.6.2017)

This is a simple example for using a switch. Taking digital signal from pin 4, judging, apply the result to 6 pin which is set LED.

void setup() {
  pinMode(6, OUTPUT);
  pinMode(4, INPUT_PULLUP);
}

void loop() {
  digitalWrite(6 !digitalRead(4));
}

Pin 4 is used ‘internal pullup’ so that you don’t have to use any other electronic parts. Instead, logic of 4 pin is inverted. So ‘digitalRead’ on 7 line is also inverted by a sign ‘!’. Then this value allows you to apply result directly.

In this sketch, LED light turns off when you stop pushing swtich. So I prepare global variable ‘button’ for LED state and keep it turn on.

boolean button  = 0;
boolean but_old = 0;

void setup() {
  pinMode(6, OUTPUT);
  pinMode(4, INPUT_PULLUP);
  Serial.begin(9600);
}

void loop() {
  boolean but_now = !digitalRead(4);

  if (but_now && but_old == 0)
  {
    button = !button;
    Serial.println(button);
  }

  but_old = but_now;

  digitalWrite(6, button);
}

Also I have to prepare ‘button_now’ and ‘button_old’. Beause Arduino is so fast that “on or off judgement” is repeated at your one push. On first repeat, there is no push in ‘button_old’. But ‘button_old’ is updated to ‘pushed’. So, reversing ‘button’ task can not work on second repeat.

Could it be worked ? Yes there are wrong reactions sometimes.

This is what you call ‘chattering’.

Chattering

chattering_anim

A switch is very simple mechanism. It’s have two contact for electro and are energized by push.

But it is bouncing after pushing or release at very short moment. This is like a phenomenon that let it fall a ball on the ground. It occurs under 100 millisecond. But Arduino resonse is so fast that tell the difference between bouncing.

In short, ‘chattering’ is a physical problem.

Well known methods

There are no ‘chattering’ on your electronic products. Because they have took a countermeasure in advance for their product. You can see many methods for avoiding from ‘chattering’ on Web.

  • Electricity storage methods by condenser circuit.
  • Schmitt trigger circuit by electronic parts.

These are basic way to avoid from ‘chattering’. Also there are several ways to avoid by programming.

  • Take a few ‘delay’ after reading pins.
  • Take samplings for several value of readings, and analyze the values.

There are so many different ways for avoiding from ‘chattering’ by detail. Please check them out at yourself.

To avoid from ‘chattering’ by a programming

Typical way

Before my theory, I show you a typical example to avoid from ‘chattering’ by using ‘delay’.

#define LED 6
#define SW  4
boolean button = 0;

void setup() {
  pinMode(LED, OUTPUT);
  pinMode(SW, INPUT_PULLUP);
  Serial.begin(9600);
}

void loop() {

  if (!digitalRead(SW))
  {
    button = !button;
    Serial.println(button);
  }
  digitalWrite(LED, button);
  delay(100);
}

Arduino waits for a while after ‘digitalRead’. So, Arduino never encounters to the ‘chattering’. Some people uses interrupt timer, because it stops all task.

But those methods can judge only in certain duration pushing. They cannot tell fastest finger move. I wanted to that. But I dislike to calculate on electronic circuit.

I had a trial and error. Then I got a idea.

“Judging by gauge” methods

I wrote a chattering-less switch library with “gauging” method.
(26.6.2017)

I was inspired by a avoidance of condenser circuit. The circuit is using storage effect of condenser.

“It may work, if I reproduce the same thing on programming ?”

This is a sketch of the idea.

#define LED 6
#define SW  4
boolean button = 0;

#define PUSH_SHORT 100

void setup() {
  pinMode(LED, OUTPUT);
  pinMode(SW, INPUT_PULLUP);
  Serial.begin(9600);
}

void loop() {
  unsigned long gauge = 0;

  while (!digitalRead(SW))
  {
    gauge++;
  }

  if (gauge > PUSH_SHORT)
  {
    button = !button;
    Serial.print(button);
    Serial.print(":");
    Serial.println(gauge);
  }
  digitalWrite(LED, button);
}

If there is a digital signal in pin 4, Arduino keep counting. If pin 4 has released, then it judge the gauge value. If gauge value reaches ‘PUSH_SHORT’, it becomes ‘push’.

I think this works very well in spite of simplicity. This sketch means “I count anyway, but I never admit it has pushed unless over the ‘push_short”. So, Arduino ignores ‘chattering’ which is small count.

gauge_monitor_1

These are certified count values on Serial monitor by Arduino. I pushed a switch so fast, but these values are too large for Arduino. This values prove how human moves slow, to computers.

By the way, you might have been noticed already to another merit.

You can tell long ‘push’ by this methods.

#define LED 6
#define SW  4
boolean button = 0;

#define PUSH_SHORT 100
#define PUSH_LONG  140000

void setup() {
  pinMode(LED, OUTPUT);
  pinMode(SW, INPUT_PULLUP);
  Serial.begin(9600);
}

void loop() {
  unsigned long gauge = 0;

  while (!digitalRead(SW))
  {
    gauge++;
  }

  if (gauge > PUSH_SHORT)
  {
    button = !button;
    Serial.print(button);
    Serial.print(":");
    Serial.print(gauge);
    if (gauge > PUSH_LONG)
    {
      Serial.print("  LONG!");
    }else{
      Serial.print("  SHORT!");
    }
    Serial.println();
  }
  digitalWrite(LED, button);
}

By define value of ‘LONG_PUSH’, it can take different action. I think it’s gonna be a hard sketch to tell a long ‘push’ in ordinary ways. But in this methods, just set a ‘PUSH_LONG’ value.

It’s very simple and practical. But there are few cautions.

  • ‘Gauge’ is not time counting, so its counting depends on microchips speed. You need to tuning for each machine.
  • In this example, Arduino can do nothing but count. He can know ‘push’ after switch has released. If you want to do several task on the same time, you need another scheme on your sketch.

Well, I introduced my unique way for a switch. And I have already used this methods on my DIY follow focus project ‘AR-FOCUS’. Off course, it has worked well, so far. Please check this out.

There is new article about this ‘gauging method’.

Finally, I introduce to you a small game sketch using this methods.

SHOOTER ‘push it fast’

In japan, there was a famous game ‘sh-watch’ once upon a time. This game counts how many times you pushed switches in ten seconds. I thought this gauging methods can reproduce the game easily. So I did. All you need is a switch and LED.

How to play

Push switch. Then it counts three and start game. This game compete how many times you can push the button in 10 seconds. You can see result and dialogs on Serial monitor of your Arduino IDE.

If response of your switch is not good. to comment out 44 line. Because “Serial.print” has a delay.

well, please enjoy it!

#define LED 6
#define SW  4
#define PUSH_SHORT 500


void setup() {
  pinMode(LED, OUTPUT);
  pinMode(SW , INPUT_PULLUP);
  Serial.begin(9600);
  delay(100);
  Serial.println("Shooting Watch GAME   ver 1.0");
}

void loop() {
  unsigned long time_to_go = millis();

  //start game if button is pushed
  if (BUTTON())
  {
    Serial.print("Ready?");

    // 3 seconds pre-roll
    for (byte i = 0 ; i < 3 ; i++)
    {
      time_to_go = millis();
      Serial.print(".");
      while ((millis() - time_to_go) <= 200) digitalWrite(LED, HIGH);
      while ((millis() - time_to_go) <= 800) digitalWrite(LED, LOW);
    }

    //start
    Serial.println("GO!!!");
    int count = 0;
    unsigned long time_to_led;
    time_to_go = millis();
    digitalWrite(LED, HIGH);

    //counting
    while ((millis() - time_to_go) < (10 * 1000))
    {
      if (BUTTON())
      {
        count++;
        Serial.println(count); // comment out here if you want precise counting
        digitalWrite(LED, LOW);
        time_to_led = millis();
      }
      if ((millis() - time_to_led) >= 10) digitalWrite(LED, HIGH);
    }

    //finish and judge
    digitalWrite(LED, LOW);

    Serial.println();
    delay(500);
    Serial.print("your record: ");
    Serial.print(count / 10.0);
    Serial.println(" per sec");
    delay(500);
    if (count >= 160) Serial.print("Awesome!!!");
    else if (count >= 110) Serial.print("Good job!");
    else if (count >= 60) Serial.print("Try again...");
    Serial.println();
    delay(1000);
  }

}


boolean BUTTON() {
  long gauge = 0;

  while (!digitalRead(SW)) gauge++;

  if (gauge > PUSH_SHORT) return true;
  else return false;
}

Leave a Reply

Your email address will not be published. Required fields are marked *

CAPTCHA


This site uses Akismet to reduce spam. Learn how your comment data is processed.