User Tools

Site Tools


arduino:arduino_crash_course:digital_input

Digital Input

The Arduino literature refers to “digital” inputs, and while this is strictly accurate, a better name for these kinds of inputs is “Boolean” or “logical” inputs. However, we will use the more common “digital input” to avoid confusion.

An Arduino digital input is one that responds to two different levels: anything above a certain threshold is considered HIGH, and anything below a certain voltage is considered LOW. Anything in between is not defined. The threshold levels will vary with specific Arduino implementation, so to learn what they are you should consult the documentation.

Applying signals to an Arduino that are higher than the supply voltage or lower than 0 volts may permanently damage the device.

Digital output signals are typically designed so that when HIGH they have a value equal to the supply voltage and when LOW they are equal to 0 volts.

We've already seen an example of Arduino digital inputs in the Basic Interaction examples. Here is the LightSwitchPullup2.ino example but using an additional variable type that better matches the role of the buttonState variable. Variables of type boolean can store the values true and false. Since the button has two states, pushed and not pushed, using a variable that can store only two states, true and false makes sense. We have chosen to let true correspond to the button's “pushed” and false correspond to “not pushed.” It is typical for variables used to store digital inputs be of type boolean.

We have also added the const modifier to the pushButtonPin and ledPin variables to say that their values won't change in the program. In fact, when you add the const modifier to a variable declaration, the value of the variable can't change.

LightSwitchPullup2a.ino
/*
 LightSwitchPullup2a
 Turn an LED on and off.
 Internal pullup version.
 */
 
const int pushButtonPin = 2;  // connect the push button to digital pin 2
const int ledPin = 13;        // connect the LED to pin 13
boolean buttonState;          // stores current button state 
 
void setup() {
  pinMode(pushButtonPin, INPUT);  // make the pushbutton's pin an input
  digitalWrite(pushButtonPin, HIGH);  // turn on internal pullup resistors
  pinMode(ledPin, OUTPUT);        // make LED's pin an output
}
 
void loop() {
  buttonState = digitalRead(pushButtonPin);  // read the input pin
 
  // set LED state accordingly
  // note the inverted logic resulting from using pullup resistors.
  digitalWrite(ledPin, !buttonState);        // turn the LED on or off
}

Toggling state

Below is an attempt to write an Arduino program that toggles power to an LED when a button is pressed. In other words, if the pushbutton is pressed while the LED is off, it should turn on; when the pushbutton is pressed again, the LED should turn off.

To implement this functionality, we must keep track of the state of the program. In particular, in each loop iteration, we will need to know if the button is being pressed, and in addition we will need to keep track of whether the button was pressed during the previous time though the loop.

Our first attempt at writing the program is below. Be cautioned that it won't work as expected. It is logically correct, but it doesn't account for a physical characteristic of real-world switches. We will address this problem and its solution in the next section.

LightToggleLogic.ino
/*
 LightToggleLogic
 Toggle an LED on and off.
 */
 
const int pushButtonPin = 2;    // connect the push button to digital pin 2
const int ledPin = 13;          // connect the LED to pin 13
boolean ledState = LOW;         // used to set LED
boolean lastButtonState = LOW;  // value of buttonState from previous loop iteration
 
void setup() {
  pinMode(pushButtonPin, INPUT);      // make the pushbutton's pin an input
  digitalWrite(pushButtonPin, HIGH);  // turn on pullup resistors
  pinMode(ledPin, OUTPUT);            // make LED's pin an output
  digitalWrite(ledPin, ledState);
}
 
void loop() {
  boolean buttonState = digitalRead(pushButtonPin);  // read the input pin
 
  // if button goes down and previously it was high...
  if (buttonState == LOW && lastButtonState == HIGH) {
    if (ledState == HIGH)            // toggle LED
      ledState = LOW;
    else
      ledState = HIGH;
 
    digitalWrite(ledPin, ledState);  // turn the LED on or off
  }
 
  lastButtonState = buttonState;
}

Debouncing

Software debouncing

A very simple approach to fixing the debouncing problem in software is to introduce a delay whenever a relevant switch press is detected. The delay must be greater than the time it takes for the switch to settle and will vary from switch to switch, so experimentation will likely be required.

LightToggleDebounced.ino
/*
 LightToggleDebounced
 Toggle an LED on and off (with s/w debouncing)
 */
 
const int pushButtonPin = 2;    // connect the push button to digital pin 2
const int ledPin = 13;          // connect the LED to pin 13
const int debounceTime = 5;     // number of millisecods to delay after button press
 
boolean ledState = LOW;         // used to set LED
boolean lastButtonState = HIGH; // value of buttonState from previous loop iteration
boolean buttonState = HIGH;
 
boolean debounce(int pinNum) {
  delay(debounceTime);
  return digitalRead(pinNum);
}
 
void setup() {
  pinMode(pushButtonPin, INPUT);      // make the pushbutton's pin an input
  digitalWrite(pushButtonPin, HIGH);  // turn on pullup resistors
  pinMode(ledPin, OUTPUT);            // make LED's pin an output
  digitalWrite(ledPin, ledState);
}
 
void loop() {
  buttonState = debounce(pushButtonPin);  // read the input pin
 
  // if button goes down and previously it was high...
  if (buttonState == LOW && lastButtonState == HIGH) {
    ledState = !ledState;
  }
 
  lastButtonState = buttonState;
  digitalWrite(ledPin, ledState);  // turn the LED on or off
}

More elaborate debouncing techniques have also been used. For example, you can measure the time between HIGH-to-LOW or LOW-to-HIGH transitions and when they have gotten long enough you can assume that the switch is no longer bouncing. We leave it to the reader to research and explore these.

User-defined functions

The the example above places the switch reading and debouncing code into its own function. One advantage of doing this is that it creates clarity in the code by allowing you to give a good name to the process you have encapsulated. Another reason is that it makes it easier to change and experiment with different algorithms for, in this case, debouncing. Yet another reason is that it gives you a clear block of code that you can re-use in other projects.

Hardware debouncing

Debouncing switch contacts in software is appealing because of its cost: since it's done entirely in software, there are no added hardware expenses. However, often times you will not be able to use software debouncing. For example, because of the Arduino's interrupt architecture, it is very difficult use software debouncing with interrupt inputs.

There are many approaches that have been taken to debouncing switches in hardware. These will not be covered here, but a Web search for the topic should lead you to a number of options.

Multiple state

The example above is a program that is essentially in of two states: the LED is on or off. Below are two examples where the program has multiple states. The first is a timer-driven and the second a push-button driven three-light blinky-thing.

MultipleLEDsTimer.ino
/*
 MultipleLEDsTimer
 Cycle through three LEDs with a timer.
 */
 
const int delayTime = 500;  // time to wait between LED changes
const int led0 = 13;        // connect an LED to pin 13
const int led1 = 12;        // connect an LED to pin 12
const int led2 = 11;        // connect an LED to pin 11
 
int ledState;               // used to decide which LED is on (0 to 2)
 
void setup() {
  // make LED pins outputs
  pinMode(led0, OUTPUT);          
  pinMode(led1, OUTPUT);
  pinMode(led2, OUTPUT);
 
  // initialize state
  ledState = 0;
 
  // turn the correct LED on and the others off
  digitalWrite(led0, HIGH);
  digitalWrite(led1, LOW);
  digitalWrite(led2, LOW);
}
 
void loop() {
  delay(delayTime);
  ledState = (ledState + 1) % 3;    // cycle through 0,1,2
 
  // turn the correct LED on and the others off  
  if (ledState == 0)
  {
    digitalWrite(led0, HIGH);  
    digitalWrite(led1, LOW);  
    digitalWrite(led2, LOW);  
  }
  else if (ledState == 1)
  {
    digitalWrite(led0, LOW);  
    digitalWrite(led1, HIGH);  
    digitalWrite(led2, LOW);  
  }
  else if (ledState == 2)
  {
    digitalWrite(led0, LOW);  
    digitalWrite(led1, LOW);  
    digitalWrite(led2, HIGH);  
  }
  else // turn all LEDs on to indicate an error state.
  {
    digitalWrite(led0, HIGH);  
    digitalWrite(led1, HIGH);  
    digitalWrite(led2, HIGH);  
  }
}
MultipleLEDsPushButton.ino
/*
 MultipleLEDsPushButton
 Cycle through three LEDs with a pushnutton
 */
 
const int pushButtonPin = 2;  // connect the push button to digital pin 2
const int led0 = 13;          // connect an LED to pin 13
const int led1 = 12;          // connect an LED to pin 12
const int led2 = 11;          // connect an LED to pin 11
 
const int debounceTime = 5;     // number of millisecods to delay after button press
 
int ledState;                   // used to decide which LED is on (0 to 2)
boolean lastButtonState = HIGH; // value of buttonState from previous loop iteration
boolean buttonState = HIGH;     // start by assuming button is unpressed
 
boolean debounce(int pinNum) {
  delay(debounceTime);
  return digitalRead(pinNum);
}
 
void setup() {
  pinMode(pushButtonPin, INPUT);      // make the pushbutton's pin an input
  digitalWrite(pushButtonPin, HIGH);  // turn on pullup resistors
 
  // make LED pins outputs
  pinMode(led0, OUTPUT);          
  pinMode(led1, OUTPUT);
  pinMode(led2, OUTPUT);
 
  // initialize state
  ledState = 0;
 
  // turn the correct LED on and the others off
  digitalWrite(led0, HIGH);
  digitalWrite(led1, LOW);
  digitalWrite(led2, LOW);
}
 
void loop() {
  buttonState = debounce(pushButtonPin);  // read the input pin
 
  // if button goes down and previously it was high...
  if (buttonState == LOW && lastButtonState == HIGH) {
    ledState = (ledState + 1) % 3;    // cycle through 0,1,2
  }
 
  // turn the correct LED on and the others off  
  if (ledState == 0)
  {
    digitalWrite(led0, HIGH);  
    digitalWrite(led1, LOW);  
    digitalWrite(led2, LOW);  
  }
  else if (ledState == 1)
  {
    digitalWrite(led0, LOW);  
    digitalWrite(led1, HIGH);  
    digitalWrite(led2, LOW);  
  }
  else if (ledState == 2)
  {
    digitalWrite(led0, LOW);  
    digitalWrite(led1, LOW);  
    digitalWrite(led2, HIGH);  
  }
  else // turn all LEDs on to indicate an error state.
  {
    digitalWrite(led0, HIGH);  
    digitalWrite(led1, HIGH);  
    digitalWrite(led2, HIGH);  
  }
 
  lastButtonState = buttonState;
}

Switch-case selection structure

Both examples above use the nested if-else selection structure. Arduino's programming language also includes another selection structure that is useful in these situations: the switch-case structure. Below we have rewritten MultipleLEDsPushButton to use a swich-case structure.

MultipleLEDsTimer2.ino
/*
 MultipleLEDsTimer2
 Cycle through three LEDs with a timer.
 This version uses a switch-case selection structure.
 */
 
const int delayTime = 500;  // time to wait between LED changes
const int led0 = 13;        // connect an LED to pin 13
const int led1 = 12;        // connect an LED to pin 12
const int led2 = 11;        // connect an LED to pin 11
 
int ledState;               // used to decide which LED is on (0 to 2)
 
void setup() {
  // make LED pins outputs
  pinMode(led0, OUTPUT);          
  pinMode(led1, OUTPUT);
  pinMode(led2, OUTPUT);
 
  // initialize state
  ledState = 0;
 
  // turn the correct LED on and the others off
  digitalWrite(led0, HIGH);
  digitalWrite(led1, LOW);
  digitalWrite(led2, LOW);
}
 
void loop() {
  delay(delayTime);
  ledState = (ledState + 1) % 3;    // cycle through 0,1,2
 
  // turn the correct LED on and the others off  
  switch (ledState) {
    case 0:
      digitalWrite(led0, HIGH);  
      digitalWrite(led1, LOW);  
      digitalWrite(led2, LOW);        
      break;
    case 1:
      digitalWrite(led0, LOW);  
      digitalWrite(led1, HIGH);  
      digitalWrite(led2, LOW);      
      break;
    case 2:
      digitalWrite(led0, LOW);  
      digitalWrite(led1, LOW);  
      digitalWrite(led2, HIGH);       
      break;
    default: 
      digitalWrite(led0, HIGH);  
      digitalWrite(led1, HIGH);  
      digitalWrite(led2, HIGH); 
      break;
  }
}
arduino/arduino_crash_course/digital_input.txt · Last modified: 2017/12/06 01:13 by mithat

Donate Powered by PHP Valid HTML5 Valid CSS Driven by DokuWiki