Fads to Obsessions and Beyond...




Free domain for life, exceptional technical support, website transfer

ATtiny85 Button Debouncing

Demonstrate button interfacing with ATtiny85/Digispark and the use of various software debouncing methods.

Interfacing a button to an ATtiny85 microcontroller is rather straight forward, however, it is often unappreciated that the majority of buttons rarely give a single signal per push of the button. This is due to the inherient noisy nature of the switch contacts.

This means that when the switch is pressed, instead of a single 5V pulse (for example) indicating a logic high, there can be perhaps a number of "noisy" spikes above the logic high voltage threshold, which the microcontroller will then interpret/process as a number of button presses, instead of a single event as intended. Such behaviour if not accounted for via hardware/software can lead to apparent "intermittent" faults and or erratic behaviour of the application.

This bouncing between logic states due to noisy switch contacts (instead of a clean immediate transition) before the signal settles into a steady state can be dealt with via hardware, and conveniently via a software approach, particularly amenable in a microcontroller solution (as external components can then be eliminated).

Software approaches to switch debouncing are demonstrated for an ATtiny85/Digispark using the Arduino IDE and available libraries.

Details on how to setup the Arduino IDE and environment to programme ATtiny85 microcontrollers are given in the ATtiny85 introduction.


The Digispark board has a surface mount ATtiny85 with headers for all pins. Additionally, the board provides a 5V regulator for external DC power input and PCB copper traces that enable insertion into standard USB connector which can then be used for DC power source. There is an onboard LED to indicate power-on and an additional LED/resistor connected to pin1 for user control.

For convenience for this simple test, the USB power supply is used.

Again for convenience for this simple test, the ATtiny85 onboard oscillator is used rather than an external crystal source.

ISP programming is used as detailed in the ATtiny85 introduction.

Connection between the ATtiny85/Digispark and USB to TTL converter cables is given in the Schematics Section (also see the Photographs Section for physical demonstation).

A toggle button is connected to pin B4 using a pull-up resistor. A pull-up resistor is required and not just simply connect the button between the ATtiny85/Digispark pin and positive or negative rail in order to ensure a defined voltage is present at both possible button states.


Note: Image loading can be slow depending on server load.

  • ATtiny85 SchematicATtiny85 Schematic

    Silver Membership registration gives access to full resolution schematic diagrams.

    ATtiny85 Schematic

    ATtiny85 Schematic

This project did not require a PCB.

The construction was done using prototyping board. See the photographs and schematic diagram sections.

Qty Schematic Part-Reference Value Notes
Resistors
1R110k1/4W, 10% 
Integrated Circuits
1U1Digispark/ATtiny85microcontroller datasheet
Miscellaeous
3J1wiresDupont pin jumper wires
1Z1USB-TTLUSB-TTL converter module
1SW1SwitchMomentary close toggle switch
Description Downloads
Bill of Materials Text File Download

Before connecting the Digispark to the USB port, check for any shorts (direct positive voltage to ground connection) as this could damage both the Digispark board and the USB/PC.

Toggle Switch no Debouncing

A single button is connect to ATtiny85/Digispark pin B4 so that when the button is unpressed a logical zero or low is present, and conversely when the button is pressed a logical one or high is present.

The sketch presented in Code Snippet 1 demonstrates the simplest scenario in which a single button is used to control a LED, with the LED only changing state (either on or off) if the button is pressed or released. However, all buttons due to inherent 'noisy' nature to the contacts that form the switch do not give a single signal transition when pressed (i.e., either high to low or vise-versa) but rather a series of voltage spikes (in very rapid succession) before flattening out to a steady state, either high or low depending upon the current state of the button.

Therefore, when using the circuit and code in Snippet 1, it would appear that each time the button is pressed that the LED is illuminated. However, due to the ATtiny85 rapidly cycling through the loop() routine, in fact the LED is turned on and off a number of times depending upon the noise of the switch, but the slowness of the human eye fails to detect this, and it appears that the LED just turns on or off in response to the button. While perhaps this is not a problem in this scenario (just turning the LED on or off), if the situation was incrementing a counter with each button press, this would clearly lead to error.

This 'noisy' switch problem (and apparent 'intermitent' errors that this can lead to) is demonstrated by using a counter to trace the number of times a logical high is actually recorded for each button press, and display this on the Arduino serial monitor, rather than just relying on the human eye and a LED.

The extra code for this serial output of the counter to the Arduino serial monitor is given in code Snippet 2 and the results presented in the Video Section. How to use serial communications with the ATtiny85 is detailed in ATtiny85 serial communications.

The solution to the 'noisy' switch problem is to use 'debouncing' which can be done via hardware and or software. The software approach is advantageous in that additional hardware components are avoided, which in a situation using an ATtiny85, it is likely the small size of the ATtiny85 was attrative in keeping project PCB size small and inexpensive. See the next section for software debouncing code example.

When installing Digispark boards as part of the Arduino IDE (see ATtiny85 introduction) the SoftSerial.h library for serial communications is available (1).

Code Snippet 1: Toggle Switch no Debouncing


#define buttonPin 4    // the number of the pushbutton pin
#define ledPin 1       // the number of the LED pin

int buttonState = 0;   // variable for reading the pushbutton status
int lastButtonState = LOW;

void setup() {
  // initialize the LED pin as an output:
  pinMode(ledPin, OUTPUT);
  // initialize the pushbutton pin as an input:
  pinMode(buttonPin, INPUT);
}

void loop() { 
  // read the state of the pushbutton value:  
  buttonState = digitalRead(buttonPin);
  // if the pushbutton is pressed the buttonState is HIGH
  if (buttonState != lastButtonState) {
    if (buttonState == HIGH) {     
      digitalWrite(ledPin, HIGH); //turn LED on
    } else {    
      digitalWrite(ledPin, LOW);  //turn LED off
    }
    lastButtonState = buttonState;
  }
}
   				

Code Snippet 2: Toggle Switch no Debouncing/Serial Output


#include 
TinyDebugSerial mySerial = TinyDebugSerial();
                
#define buttonPin 4    // the number of the pushbutton pin
#define ledPin 1       // the number of the LED pin

int buttonState = 0;   // variable for reading the pushbutton status
int lastButtonState = LOW;
unsigned int counter=0;

void setup() {
  // initialize the LED pin as an output:
  pinMode(ledPin, OUTPUT);
  // initialize the pushbutton pin as an input:
  pinMode(buttonPin, INPUT);
  mySerial.begin(115200);
  delay(3000); //give a delay so can connect the port in the receiving software
  mySerial.println("hello");
}

void loop() { 
  // read the state of the pushbutton value:  
  buttonState = digitalRead(buttonPin);
  // if the pushbutton is pressed the buttonState is HIGH
  if (buttonState != lastButtonState) {
    if (buttonState == HIGH) {     
      digitalWrite(ledPin, HIGH); //turn LED on
      counter=counter+1;
    } else {    
      digitalWrite(ledPin, LOW);  //turn LED off
    }
    lastButtonState = buttonState;
  }
  if (counter==10) {
    mySerial.print("="); mySerial.println(counter);
    counter=0;
  }  
}                
                

Toggle Switch with Software Debouncing

As previously discussed, push buttons and toggle switchs etc often generate extra 'spurious' pulses when pressed, due to the mechanical nature of these components, and these extra pulses may be read as multiple presses in a very short time and therefore lead to the software/firmware giving incorrect response. The usual software approach to 'debouncing' these 'bouncing' signals when a button is pressed or released is to record the signal from the button, and then check the signal again after a short time period (a few milliseconds). If the signal is the same between the first and next reading after this short interval, then the program can interpret the signal as being a definite single press or release of the button.

The following code snippet demonstrates how to use the millis() function to use this 'multiple reading after a short time period' approach to debouncing a button input. The extra code in relation to the 'counter' and TinyDebugSerial library is added in order to demonstrate that the debouncing algorithm is actually working. The results of the ATtiny85 running this code is demonstrated by a video in the Video Section.

Code Snippet 3: Toggle Switch with Software Debouncing


#include 
TinyDebugSerial mySerial = TinyDebugSerial();
                
#define buttonPin 4    // the number of the pushbutton pin
#define ledPin 1       // the number of the LED pin

int buttonState = 0;   // variable for reading the pushbutton status
int lastButtonState = LOW;
unsigned long lastDebounceTime = 0;  // the last time the LED was toggled
unsigned long debounceDelay = 50;    // the debounce time
unsigned int counter=0;

void setup() {
  // initialize the LED pin as an output:
  pinMode(ledPin, OUTPUT);
  // initialize the pushbutton pin as an input:
  pinMode(buttonPin, INPUT);
  mySerial.begin(115200);
  delay(3000); //give a delay so can connect the port in the receiving software
  mySerial.println("hello");
}

void loop() { 
  // read the state of the pushbutton value:  
  int reading = digitalRead(buttonPin);
  if (reading != lastButtonState) {
    lastDebounceTime = millis();
  }
  if ((millis() - lastDebounceTime) > debounceDelay) {
    if (reading != buttonState) {
      buttonState = reading;
      if (buttonState == HIGH) {
        // turn LED on:
        digitalWrite(ledPin, HIGH);
        counter=counter+1;
      } else {
        // turn LED off:
        digitalWrite(ledPin, LOW);
      }
    }
  }
  if (counter==10) {
    mySerial.print("="); mySerial.println(counter);
    counter=0;
  }  
}                 
                

Toggle Switch with Button Library

text

The Button library for handling interfacing of switches is available (2).

Code Snippet 4: Toggle Switch with Button Library


text                
               

The circuit is the basic minimum required to enable the ATtiny85 microcontroller to operate after being programmed with a suitable .hex file. So this circuit was only laid out on a breadboard.

Before connecting the Digispark to the USB port, check for any shorts (direct positive voltage to ground connection) as this could damage both the Digispark board and the USB/PC.

The circuit involving interfacing a toggle button is straight forward and should not present problems. In relation to the ATtiny85/Digispark, refer to the Schematics Section as the Digispark board has additional resistors/diodes etc on some of the ATtiny85 pins that enable onboard LEDs and the USB connectivity. These addtional passive components may interfere with a simple button connection.

Also with the Digispark board, pin 5 is generally reset and is not available as a GPIO. Although this can be changed, but then bootloader/USB programming is not enabled.

Additionally, note that the most rapid stable baud rate was used on the ATtiny85 serial communications. This is because the serial communications library uses interrupts to process the communications stream, and while the interrupt is being processed, the remainder of the code is being 'blocked'. Using the quickest stable baud rate means the maximum number of CPU cycles from the ATtiny85 will be avaiable for the loop() sketch routine.

Note: Video loading can be slow depending on server load.


Comments/Questions

No comments yet.

Add Comment/Question

Only Logged-In Members can add comments

"If we could sell our experiences for what they cost us, we'd all be millionaires".

Please donate any amount to help with hosting this web site.

If you subscribe (only $2/annum) you can view the site without advertisements and get emails abouts updates etc.

X

Sorry!

Only logged-in users with Silver Membership and above can download.


Silver Membership is only $2, so join now!