Getting Back Up To Speed With Arduino

Have you ever wanted to code something cool and new with your Arduino but its been a few months and getting back up to speed with coding your Arduino seems like a bit of a monumental task? If so, this blog is for you (and me). Truth is, I have found myself here many times. Now, instead of cracking out my favorite books about programming Arduino, I am writing this blog so I can quickly get back up and running with a cool Arduino development board.

The Official Arduino Reference

First of all, there is the official Arduino Reference. IT describes every function, variable, and structure available in the standard Arduino. Don’t skip this reference if you have not already looked through the Arduino reference.

Looking for a library to make your development easier? Check out the Arduino Library Reference for a list of common community contributed libraries.

Also be sure to check out my favorite books and other resources for learning Arduino. Let’s get started by covering some of the most common tags and then we will go into some example code.

#include

If you are using some peripheral like an OLED display or a sensor, you will likely need to pull in a library that allows you to easily interact with the extra device or sensor. Libraries can be downloaded using the library manager found at tools > manage libraries in your menu bar on a Mac or PC. If a library asks to download dependencies, you generally want to download everything the library is asking for.

A few of my favorite libraries are:

You will find libraries that work for you by using boards and chips commonly used for Arduino and looking through some example code.

To find where your libraries are stored, go to arduino > preferences then check the sketchbook location. This is the path where all of your arduino libraries and sketches are found. Also, after you install a new library, you might need to restart your IDE (the arduino code editor) to be able to start using the new library.

const vs #define

Constants are often needed at the beginning of a sketch. Constants are used for hooking up the pins needed to hook up peripherals (such as LEDs, buttons, and signals). The const is Constant and will not be allowed to change anywhere in your code. It is constant – not a variable, after all.

Using the const tag is considered superior to the use of #define because #define is replaced by the text of the variable at compile-time and can lead to problems.

const int ledPin = 13;  // sets ledPin as pin 13 on the arduino board 
const int inputPin = 2; // sets inputPin as pin 2 on the arduino board

// Note: To get pins to function you will also need to set pinMode in void setup()

int

int stands for integer. These are your primary data-type for number storage.

int variableName = value; // creates a variable interger called variableName

pinMode

pinMode configures the specified pin to behave either as an input or an output.

pinMode(ledPin, OUTPUT);      // sets ledPin (digital pin 13 from above) as output
pinMode(inputPin, INPUT);     // sets inputPin (digital pin 2 from above) as input
digitalWrite(inputPin, HIGH); // sets internal pull-up resistor for inputPin (digital pin 2 from above)

// Alternative 
pinMode(inputPin, INPUT_HIGH) // as of arduino 1.0.1 this will set the pin
                              // as both input and will set the pull-up resistor to high 
                              // in on step

digitalWrite

digitalWrite is used for two main tasks. Setting an output pin to HIGH or LOW

  • Setting an output pin to HIGH or LOW
  • Setting the internal pullup resistor
const int ledPin = 13;
const int inputPin = 2;

void setup () {
    pinMode(ledPin, OUTPUT);      // sets ledPin as OUTPUT
    pinMode(inputPin, INPUT);     // sets inputPIN as INPUT
    digitalWrite(ledPin, HIGH);   // sets ledPin to HIGH
    digitalWrite(inputPin, HIGH); // because this pinMode is set to INPUT, setting
                                  // digitalWrite to HIGH sets pull-up resistor to HIGH 
}

Serial.begin

Serial.begin, Serial.print, Serial.println

const int ledPin = 13;       
const int inputPin = 2;      

void setup() {
    pinMode(ledPin, OUTPUT);
    pinMode(inputPin, INPUT);
    digitalWrite(inputPin, HIGH);
    Serial.begin(9600);            // Initalize serial monitor
}

void loop () {

    static int variable = 0;       // creates local variable called variable
    variable = variable + 100;     // increases variable by 1 at each loop
    Serial.print("Prints text ");
    Serial.print(variable);        // Prints variable up to 32700 then goes negative
                                   // 32700 is as high as int can go
    Serial.println(" Prints text with a line break");
    
}

Global, Local, and Static Variables use in Functions

  • Global Variables – Defined at the top of the code
  • Local Variables – Defined inside a function
  • Static Variables – Defined inside a function, only defined the first time it is ran (Keeps variable from being reset every time it is ran)

Global Variables are defined before void setup() These are variables that can be used anywhere but be careful. The use of global variables all over your code can make your code confusing and hard to debug. Global variables also go against the principle of encapsulation – the idea that you should wrap everything that you need in a feature inside a function like a nice little package that is reusable. Using the principle of encapsulation also helps you write DRY code – Meaning Don’t Repeat Yourself. Don’t repeat code over and over, rather call a function that performs a task efficiently and in a way that is easy to debug.

Local variables are declared inside a function and only can be used within the scope of that function. The local variable will not be available for use in other parts of your code.

Passing Variables to Functions

int ledPin = 13;                         // Global variable
int delayPeriod = 500;                   // Global variable

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

void loop () {
  flash(4, delayPeriod);                 // Calls the flash 
  delay(2000);
}

void flash(int numFlashes, int newDelay) { // Passes numFlashes and delayPeriod into flash() function. 
                                           // New internal variables numFlashes and newDelay are also created here 
                                           // like this - void function(int varable 1, int variable 2) 
                                           // These variable can only be used inside the flash() function.
                                           // This is good practice because all of the functionality need to run flash() 
                                           // is wrapped up in this single function. 
                                           
  
  for (int i = 0; i < numFlashes; i ++)    // for  runs for 4 times in this case because numFlashes is set
                                           // to 4 in void loop, flash(4, nextPerameter)
  {
    digitalWrite(ledPin, HIGH);
    delay(newDelay);                       // newDelay is passed to this function from global int delayPeriod
    digitalWrite(ledPin, LOW);             // then flash(4, delayPeriod) to void flash(int variable, int newDelay)
    delay(newDelay);
  }
  
  
}

Declaring Local Variables When Passing Parameters To Functions

int ledPin = 13;             
int delayPeriod = 500;       


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

void loop () {
  setX(15);                   // This calls fucntion setX and passes a peramiter of 15 to int X below
  delay(2000);
}


void setX(int x) {            // this is the setX function and creates a local variable int X
  flash(x, 250);              // the value of X is passed on to the flash function as the value
}                             // for numFlashes

void flash(int numFlashes, int newDelay) { 
  for (int i = 0; i < numFlashes; i ++)    
  {
    digitalWrite(ledPin, HIGH);
    delay(newDelay);                       
    digitalWrite(ledPin, LOW);             
    delay(newDelay);
  }  
}

Call A Function, Pass A Perimeter, and Return A Result

It is possible to call a function, pass it a perimeter and set a variable equal to the result of that function. void function name() is used

Calling Functions

In the void loop function, you can call other functions, like this: functionName

  • functionName();
  • functionName(valueToBePassed); – Passes variable to function
  • int variableName = functionName(valueToBe Passed); – Passes value to function and returns a value to variableName

Running Functions

After your void loop function you can create functions that preform some specific task in your code. It is best practice to call a function when needed rather than running all the time in your void loop. Rather call the fucntion and run it when needed. Here are ways you can write out the function name for specific scenarios.

The void means nothing is returned by the function. The int means something is returned by the function.

  • void functionName() – used when function does not return anything and no perimeters are passed to the function
  • void functionName(int valueThatIsPassed) – Creates local variable to be used in the function called int valueThatIsPassed. valueThatIsPassed set to value passed from void loop.
  • int functionName(int valueThatIsPassed) – Creates local variable to be used in the function called int valueThatIsPassed. valueThatIsPassed set to value passed from void loop. Function returns a value to int variableName in void loop

Here is an example of a fucntion being called in void loop and being passed a value. Then that function runs. The function returns a value to a variable in void loop.

// Inspired by Arudino Cookbook example 2.10
 

const int ledPin = 13;          // output pin for the LED
const int inputPin = 2;         // input pin for the switch

void setup() {
  pinMode(ledPin, OUTPUT);
  pinMode(inputPin, INPUT);
  digitalWrite(inputPin,HIGH); // set the internal pull-up resistor 
  Serial.begin(9600);
}

void loop(){
  Serial.println("Press and hold the switch to count number of blinks between button presses.");
  int blinkCounter = blinkFunction(325); // variable blinkCounter is set to the result of 
                                         // a function called blinkFunction
                                         // This also calls the blinkFunction below and 
                                         // sets int period to 325
  Serial.print("The number of times the LED blinked between button presses was ");
  Serial.println(blinkCounter);
  Serial.println(" ");
}

// The following function blinks an LED basses on a perimeter passed to the fucntion
// It also returns a result, meaning this entire function can be set equal to a variable 
// Whatever value this function returns will be the value of int blinkCounter in void loop above

int blinkFunction(int thisIsThePassedPerimeter)
{
  int resultValue = 0;
  int switchVal = HIGH; //with pull-ups, this will be high when switch is up

  while(switchVal == HIGH)  // repeat this loop until switch is pressed
                            // (it will go low when pressed)
  {
    digitalWrite(13,HIGH);
    delay(thisIsThePassedPerimeter);
    digitalWrite(13,LOW);
    delay(thisIsThePassedPerimeter);
    resultValue = resultValue + 1; // increment the result value by 1 each time this is ran
    switchVal = digitalRead(inputPin);  // read input value of the switch
  }
  // here when switchVal is no longer HIGH because the switch is pressed
  return resultValue;  // this value will be returned
}

Debouncing A Button

It seems every project I do involves a button, and if you can’t debounce your buttons it is likely you are going to have whacky problems with your code. So, debouncing a button is pretty important.

Below is an example from Adafruit’s article about debouncing. This article is very good and worth a read. Their article goes into more hardware options for debouncing, such as using a 0.1 uF capacitor across the switch contacts.

Debouncing a button is something that seems like it should be easy, but it takes a few steps to make the debounce reliable.

/*
  Debounce example from Adafruit
 
  Each time the input pin goes from LOW to HIGH (e.g. because of a push-button
  press), the output pin is toggled from LOW to HIGH or HIGH to LOW. There's a
  minimum delay between toggles to debounce the circuit (i.e. to ignore noise).
 
  This example code is in the public domain.
 
  http://www.arduino.cc/en/Tutorial/Debounce
*/
 
const int buttonPin = 2;     // the number of the pushbutton pin
const int ledPin = 13;       // the number of the LED pin

int ledState = LOW;          // the initial state of the output pin
int buttonState = HIGH;      // the current reading from the input pin
int lastButtonState = HIGH;  // the previous reading from the input pin
 
// the following variables are unsigned longs because the time, measured in
// milliseconds, will quickly become a bigger number than can be stored in an int.
unsigned long lastDebounceTime = 0;  // the last time the output pin was toggled
unsigned long debounceDelay = 50;    // the debounce time; increase if the output flickers
 
void setup() {
  pinMode(buttonPin, INPUT_PULLUP);
  pinMode(ledPin, OUTPUT);
 
  // set initial LED state
  digitalWrite(ledPin, ledState);
}
 
void loop() {
  debounce();
}

void debounce() {
  int reading = digitalRead(buttonPin);       // read buttonPin
  if (reading != lastButtonState) {           // check if reading has changed
    lastDebounceTime = millis();              // set lastDeboucnceTime to time since program started
  }
  if ((millis() - lastDebounceTime) > debounceDelay) {    // If button has retained the same state for more than 50 milliseconds
    if (reading != buttonState) {             // and if there is a new buttonState
      buttonState = reading;                  // set button state to the new buttonState
      if (buttonState == HIGH) {              // if button is no longer pressed - button goes low when pressed
        ledState = !ledState;                 // change the ledState from TRUE to FALSE or FALSE to TRUE, depending on current state
      }
    }
  }
  digitalWrite(ledPin, ledState);             // write ledPin to ledState, no matter how long button was pressed
  lastButtonState = reading;                  // write lastButtonState to whatever the digitalReading of buttonPin is, no matter how long button was pressed 
}                                             // repeat loop
    

if else

The arduino reference has a good guide for if statements. One thing to be sure of is to use one of the Comparison Operators instead of an Assignment Operator. Meaning use x == 10 rather than x = 10. The former will evaluate if x is equal to 10. The later will set x to 10 and always evaluate as TRUE. Not the desired result when using an ‘if’ statement.

// Inpsired by Arduino Cookbook example 2.12 

const int ledPin = 13;                  // choose the pin for the LED
const int inputPin = 2;                 // choose the input pin (for a pushbutton)

void setup() { 
  pinMode(ledPin, OUTPUT);              // declare LED pin as output
  pinMode(inputPin, INPUT);             // declare pushbutton pin as input
}  

void loop(){
   ifElse();                            // calls a function called ifElse
}

void ifElse() {                         // Runs a function (This could be done in void loop also
  int val = digitalRead(inputPin);      // read input value
  if (val == HIGH)                      // check if the input is HIGH
  {
     // do this if val is HIGH
     digitalWrite(ledPin, HIGH);        // turn LED on if switch is pressed
  } 
  else 
  {
    // else do this if val is not HIGH
    digitalWrite(ledPin, LOW); // turn LED off }
  }
}

For

The for statement has some tricky looking syntax. But if you just accept it for what it does and move on with your life it is much easier to use. Again the arduino reference is good to check out.

The for statement will:

  • Repeat a block of statements enclosed in curly braces
  • Increment a counter
  • Once the counter reaches a condition, the for statement stops repeating and the arduino moves on to the next block of code.
for (initialization; condition; increment) {
   // statements that will be repeated until for loop condition is met
}

// Initialization happens first and only happens one time. So int i = 0 only this first time it is ran
// The condition is tested every time the loop repeats. For will run until the condition if FALSE
// i++ adds 1 to i every time the loop is ran. So it just increments i up by 1 each time. Its a counter basilcy.

// Syntax

void loop() {
   for (int i = 0; i <= 255; i++) {
      
// This program uses 'for' to either increase brightness of an LED or 
// increase and decrease brigntness of an LED based on a button press

int PWMpin = 10;       // LED connected to Arduino pin 10 (PWM pin)
int inputPin = 2;      // Switch connected to pin 2
 
void setup() {
  pinMode(PWMpin, OUTPUT);
  pinMode(inputPin, INPUT);
  digitalWrite(inputPin, HIGH);
}

void loop() {
  int val = digitalRead(inputPin);
  if (val == LOW) {    // switch goes LOW when pressed
    increaseAndDecreaseBrightness();
  }
  else {
    increaseBrightness();
  }
}

void increaseBrightness() {
  for (int i = 0; i <= 255; i++) {
    analogWrite(PWMpin, i);
    delay(10);
  }
}

void increaseAndDecreaseBrightness() {
  int x = 1;
  for (int i = 0; i > -1; i = i + x) {
    analogWrite(PWMpin, i);
    if (i == 255) {
      x = -1;  // switch direction at peak
    }
    delay(10);
  }
}

While

A while() loop will continously and infinitely loop – until the expression inside the parenthesis () becomes FALSE. This means that something inside the while loop must change the condition being tested, otherwise the while loop will never exit. Usually this is done by incrementing a value or testing an external condition such as a sensor or a button press.

If you are testing the condition of a sensor. Usually a digitalRead(inputPin) = variable will be placed inside the while loop. The condition will be set to that variable.

// syntax

while(condition) {
   // Statement(s)
}

// example

const int ledPin = 13;       // output pin for the LED
const int inputPin = 2;      // input pin for the switch

void setup() {
    pinMode(ledPin, OUTPUT);
    pinMode(inputPin, INPUT);
    digitalWrite(inputPin, HIGH); // use interal pull-up resistor (Recipe 5.2)
    Serial.begin(9600);
}

void loop() {

int switchVal = digitalRead(inputPin);               // sets internal variable to HIGH           

while(switchVal == HIGH) {          // while loop repeats until switch is pressed
   digitalWrite(ledPin, HIGH);      // switch goes LOW when pressed
   delay(200);
   digitalWrite(ledPin, LOW);
   delay(200);  
   switchVal = digitalRead(inputPin);  // Checks if switch is pressed
   Serial.println(switchVal);
   }
}

Do…While

The Do…While is similar to the while keyword. But, in the Do…While keyword, the condition is tested at the end of the loop so the do loop will always run at least once before the condition is checked.

I have more to learn about Do…While. I am going to fix up the first part of the blog then get back to this. I hope this blog has been helpful – please comment below if you see anything that needs to be updated!

Leave a Comment

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