EFA | Processing Input Signals: Digital

Digital Input | digitalRead()

Schematic and Circuit Illustration

All of the code examples below can be tested with the following circuit.

  • Pin 9 is connected to an LED via a current-limiting resistor (470Ω)
  • Pin 2 is connected to a momentary switch
  • 10k pull-down resistor is used to keep the signal LOW when the button is not pressed

Code Example: Simple digitalRead()

Reading digital signals with the Arduino or any other microcontroller is quite simple. You can just use the function digitalRead() which returns a HIGH or LOW depending on the voltage of the pin that you read.

int btnPin = 2;
int ledPin = 9;
int btnState = false;

void setup() {
  // Open the serial port
  Serial.begin(9600);
  // set the button pin to be an input
  pinMode(btnPin, INPUT);
  // set the LED pin to be an OUTPUT
  pinMode(ledPin, OUTPUT);
}

void loop() {
  // read the button pin
  btnState = digitalRead(btnPin);
  Serial.print("Button state: ");
  Serial.print(btnState);
  if (btnState == HIGH) {
    digitalWrite(ledPin, HIGH);
  }
  if (btnState == LOW) {
    digitalWrite(ledPin, LOW);
  }
}

Code Example: Check if the input has changed

The previous code works fine for many things but it has some problems. It’s going to run the code inside your if statements every single loop, which might be undesirable in many cases. Quite often you want your code to only do something once when the input signal has changed. For example, starting to play a sound, triggering some light pattern etc. This example shows how to do something only when the input signal changes.

The code below does the following:

  • Read the state of a digital input pin
  • Check if the state has changed from the previous loop
  • Save the current state to a variable called prevBtnState for the next loop
int btnPin = 2;
int btnState = false;
int prevBtnState = false;

void setup() {
  // Open the serial port
  Serial.begin(9600);
  // set the button pin to be an input
  pinMode(btnPin, INPUT);
}

void loop() {
  // read the button pin
  btnState = digitalRead(btnPin);

  // check if the button state has changed
  if(btnState != prevBtnState){
    // print the changed state
    Serial.print("Button state changed to: ");
    Serial.println(btnState);
  }

  // save the previous button state for the next loop
  prevBtnState = btnState;
}

Code Example: Rising Edge or Falling Edge

In most cases, it’s not enough just to know if the signal changed. You often need to also know if your signal changed from on to off or vice versa.

The change from LOW to HIGH is called Rising Edge
The change from HIGH to LOW is called Falling Edge

The code below does the following:

  • Read the state of a digital input pin
  • Check if the state has changed from the previous loop
  • Prints out a different result depending on if the signal went from LOW to HIGH or vice versa
  • Turns the LED on if the input went from LOW to HIGH
  • Turns the LED off if the input went from HIGH to LOW
  • Keeps a count of how many times the button has been pressed
  • Save the current state to a variable called prevBtnState for the next loop
int btnPin = 2;
int ledPin = 9;
int btnState = false;
int prevBtnState = false;
int counter = 0;

void setup() {
  // Open the serial port
  Serial.begin(9600);
  // set the button pin to be an input
  pinMode(btnPin, INPUT);
  // set the LED pin to be an OUTPUT
  pinMode(ledPin, OUTPUT);
}

void loop() {
  // read the button pin
  btnState = digitalRead(btnPin);

  // check if the button state has changed
  if(btnState != prevBtnState){
    // print the changed state
    Serial.print("Button state changed to: ");
    Serial.println(btnState);
    if(btnState == HIGH){
      Serial.println("Rising edge!");
      digitalWrite(ledPin, HIGH);
      // increase the counter
      counter++;
      Serial.print("Count: ");
      Serial.println(counter);
    }
    if(btnState == LOW){
      Serial.println("Falling edge!");
      digitalWrite(ledPin, LOW);
    }
  }

  // save the previous button state for the next loop
  prevBtnState = btnState;
}

Pull-up VS. Pull-down resistors

The previous examples used a 10kΩ resistor to tie the input signal to ground (LOW) when the button is not pressed. This is called a pull-down resistor. It makes sure that there is a clear signal when the switch is not pressed and additionally protects the circuit from a short-circuit when the switch is pressed down.

You can also do the opposite and connect the same resistor to VCC (5V). In this case, it would be called a pull-up resistor as it is pulling the signal HIGH when the switch is not pressed. Pull-up resistors are more commonly used in commercial applications than pull-down resistors.

We started off by using pull-down resistors since the way they work seems a bit more logical coming from a general knowledge background. (0 means OFF and 1 means ON)

Internal Pull-Up Resistors

Most microcontrollers come with internal pull-up resistors that you can activate with code. Our Arduino Uno boards are no exception, all of the pins capable of being digital inputs have an internal pull-up resistor.

Why would you want to use internal pull-up resistors?

  • To save you from having to use a physical resistor in your circuit
  • This saves you some wiring, space on the PCB, and costs.

Why would you NOT want to use internal pull-up resistors?

  • The internal resistors are pulling the signal up and therefore always connected to the HIGH side of your logic level. This means that for a button the state will be HIGH or 1 when the button is not pressed and will become LOW or 0 when you press it. This is very common in electronics but it might feel backwards for a beginner in the field.
  • Sometimes the components you are working with need to be connected with a pull-down resistor so in those cases you cannot use the internal pull-up.
  • Using many internal pull-up resistors in one project might cause the microcontroller to heat up too much.
  • For a beginner, it might be easier to understand what is happening if you physically see the resistor in your circuit.

How do you use them?
Use the following code in your setup() or wherever you define the pinMode() of your pin

pinMode(2, INPUT_PULLUP); // change the 2 to the pin number you are using