The digitalWrite() function serves as the gateway between an Arduino‘s digital pins and the physical world. It single-handedly enables Arduino boards to blink LEDs, drive motors, operate relays, read sensors and much more. This definitive guide takes you further into how to properly leverage digitalWrite() for robust projects.

DigitalWrite() Basics

We first review the digitalWrite() syntax:

digitalWrite(pin, value);  

Where pin is the Arduino pin number, and value is either HIGH or LOW. For example:

digitalWrite(9, HIGH); //Set Arduino pin D9 to 5V
digitalWrite(9, LOW); //Set Arduino pin D9 to 0V 

This sets pin D9 to either 5V (HIGH) or 0V (LOW). We can visualize this with an LED circuit:

+5V ----------┤├─|>|─💡
                D9

Here we supply +5V power to one leg of the LED while the other connects to pin D9. Calling digitalWrite(9, HIGH) switches D9 to +5V, lighting the LED. digitalWrite(9, LOW) switches it to 0V, turning it off.

This is how all digital output components are wired to Arduino pins like D9. You simply use digitalWrite() to flip between powering or grounding the device.

Key Electrical Characteristics

When wiring devices, understanding the pins‘ electrical limits is key:

Voltage

  • HIGH outputs 5V (or 3.3V on 3.3V boards)
  • LOW sinks 0V to ground

Total Current per Pin

  • 40mA (Uno), up to 800mA with Mega

You must design projects Respecting these currents. An LED may use ~10mA, but a motor can require 500mA or higher. We will revisit these limits later.

First, let‘s explore example projects.

Example #1: Controlling an RGB LED

A common beginner project is lighting a multi-color RGB LED using three digital pins. This traces each element: red, green and blue channels:

          5V
       |

R - D6 -> 💡
|

     GND


       5V

       |

G - D5 -> 💡

       |

      GND


      5V

       |

B - D3 -> 💡

       |

      GND

We can fade through hues with digitalWrite():

int redPin = 6;
int greenPin = 5; 
int bluePin = 3;

void setup() {
  pinMode(redPin, OUTPUT);
  pinMode(greenPin, OUTPUT); 
  pinMode(bluePin, OUTPUT);
}

void loop() {

  digitalWrite(redPin, HIGH);   
  digitalWrite(greenPin, LOW);
  digitalWrite(bluePin, LOW); 
  //Red ON

  delay(1000);

  digitalWrite(redPin, LOW);        
  digitalWrite(greenPin, HIGH);
  digitalWrite(bluePin, LOW);
  //Green ON  

  delay(1000);

  //Additional colors
  //Purple, yellow, teal
  //White = R,G,B all HIGH
}

This shows how digitalWrite() can mix colors by changing each element‘s brightness. The same applies to RGB LED strips on a larger scale.

Example #2: Controlling a DC Motor

DC motors draw much higher currents impractical for connecting directly to Arduino pins. We therefore use an NPN bipolar junction transistor (BJT) circuit to control a DC motor:

          Motor
           +    |  
           |    |
 +5V  ->   TIP120    ->  | 6-9V       
           |                |
           └────┤ Base     -> D5 
           └───── Emitter ─┘
                 (Arduino)         
             GND

The TIP120 acts as a digital switch for the motor‘s power. When D5 goes HIGH, it allows current flowing across its collector/emitter pins, spinning the motor. LOW stops current flow.

We can toggle directions by swapping the motor leads, using a second "H-bridge" transistor or an integrated circuit.

Our code simply toggles D5 HIGH/LOW:

int motorPin = 5;

void setup() {
  pinMode(motorPin, OUTPUT); 
}

void loop() {
  digitalWrite(motorPin, HIGH); // Enable motor 
  delay(2000); // Run for 2 seconds

  digitalWrite(motorPin, LOW); // Disable
  delay(1000); // Wait 1 second
}

The same transistor concept applies to driving lamps, pumps, actuators and more. It keeps high current devices isolated from Arduino pins.

Expanding Digital I/O

The Arduino Uno provides 14 total digital pins. However many projects demand increased pinouts – driving multiple LEDs or motors at once.

We can dramatically expand I/O using 8-bit shift registers like the 74HC595. This contains eight latches allowing a single Arduino pin to control eight external devices. By cascading multiple shift registers (connecting several 74HC595‘s), we create high density I/O ports, maximizing digitalWrite()‘s capabilities.

Modern Ethernet, SPI or I2C I/O expander chips provide even more flexibility. But shift registers offer a simple hardware multiplexing introduction.

Example #3: Reading a Pushbutton

The previous examples focused on digital outputs. But we can also leverage digital inputs to read button presses, thermometer contacts, motion sensors and more.

This requires wiring a switch to +5V and an Arduino pin, setting the pin as input:

           Switch
            +─┤├─ 5V
               |
               └─── D2 (Input)

When closed, the switch connects +5V to D2. Opening breaks the connection. Without a resistor, this forms an open collector circuit.

We read the voltage using Arduino‘s digitalRead() function, testing if the pin reads HIGH or LOW:

int buttonPin = 2; 

void setup() {
  pinMode(buttonPin, INPUT);   
}

void loop() {

  if(digitalRead(buttonPin) == HIGH){
     //Button is pressed 
     digitalWrite(ledPin, HIGH); 
  } 
  else{
     //Button released
     digitalWrite(ledPin, LOW);
  }
}  

Here we light an LED only when digitalRead() sees +5V meaning the button is pressed. This applies to any manner of switches, levers and motion sensors.

Using Internal Pullup Resistors

The above circuit can falsely trigger when the switch floats between HIGH and LOW. We improve reliability using Arduino‘s internal pullup resistors accessed through:

pinMode(buttonPin, INPUT_PULLUP);

This attaches a 20K-50K ohm resistor between the pin and +5V rail. Now when the switch opens, the resistor pulls the voltage high preventing floating. LOW only occurs if we intentionally ground connection. This simplifies wiring and improves input signal integrity.

Key Electrical Design Principles

When advancing into complex projects utilizing many digitalWrite()/digitalRead() pins, several vital electrical principles help ensure correct behavior:

Voltage Dividers

Output pins can only source limited current. So when driving multiple LEDs, motors or lamps, we wire resistors to divide voltages rather than directly connecting everything to +5V.

Current Sinking vs Sourcing

DigitalWrite transitions pins between LOW (sinking to ground) versus HIGH (sourcing from +5V). We must understand whether devices source or sink current for appropriate switching.

Floating Inputs

Inputs can "float" producing erratic switching. Pullup/pulldown resistors prevent this defined logic state when inputs get disconnected.

Filtering Noise

Long wires act as antennas injecting noisy spikes that can reset logic circuits. Capacitors/inductors filter interference improving signal integrity.

Antenna Design

For projects involving wireless communication modules, antenna placement plays a vital role maximizing range and stability. Wrong orientation can nullify transmissions.

These examples demonstrate that digitalWrite() requires much deeper understanding than simply typing HIGH or LOW in code. Robust design practices prevent errant behaviors.

Moving Beyond Arduino

While Arduino provides an excellent prototyping platform, at some point more advanced I/O control is necessary. This is where general microcontrollers like ARM Cortex M4‘s or higher end Field Programmable Gate Array (FPGA) integrated circuits prove useful.

Such chips integrate dedicated pulse width modulation (PWM) engines, hardware UARTS, analog comparators and timers. Entire battery backed subsystems capable of running digitalWrite() equivalent functions exist without any CPU aid. This enables extremely timing sensitive or low power period I/O toggling unfettered by code interpretation delays.

Furthermore, purpose built sensor hub ICs like Maxim‘s MAX32660 incorporate specific regulated supplies ideal for precision input monitoring. ISM band radios simplify delivering sensor data wirelessly compared to wiring up Xbee or BLE modules.

The realm of microelectronics offers a rich spectrum between ease of use versus hardcore performance. As projects evolve, continually reevaluating appropriate core controller hardware helps unlock next level digital I/O capabilities down the road. Arduino shields make swapping out the main MCU simple to retain previous code investment.

I hope this guide gives confidence for not only using but mastering digitalWrite() across diverse empedded systems challenges. Let me know if any questions come up!

Similar Posts

Leave a Reply

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