Skip to content

Programming

Prerequisites

To begin, we assume you have a working Nerdle. You have the Arduino software installed, with the proper Nerdle additions, and have a USB cable to connect the Nerdle to your computer.

Hello, World!

The traditional “first program” for people learning programming is often referred to as “Hello, world!” It usually just prints out the phrase “Hello, world!” but demonstrates that everything required to write interesting and fun programs is working.

Copy and paste the following into the main Arduino window, and save it with a new name, something like nerdle_hello_world_01.

/*Nerdle Example Program #1 "Incessant beeping!"
7/25/2010
http://www.wayneandlayne.com/projects/nerdle/
Adam Wolf & Matthew Beckler

This sketch makes two different kinds of beeps.

Uploading instructions:  
Bootloader mode is used for updating the sketch on the device,
not updating words.

To upload sketches to your Nerdle, connect the  Nerdle to the PC
using the mini-b USB cable.  Then, press the reset button on the
Nerdle.  The screen should go blank, and the device is now in 
"bootloader mode." 

Upload a sketch using the keyboard shortcut Ctrl-U or using the
upload button in the top bar.  The sketch will run on the 
device after it is uploaded.  To upload again, keep the device 
plugged into USB and press reset again.

If you enter bootloader mode and don't want to upload anything,
unplug it from USB, and press reset.  The stored program will
run.
*/

int speaker_pin=9;

void setup()
{
  tone(speaker_pin, 1000);
  delay(250);
  noTone(speaker_pin);
}

void loop()
{
  tone(speaker_pin, 250);
  delay(250);
  noTone(speaker_pin);
  delay(250);
}

Upload the program to your Nerdle. Observe the beeps. When you’re ready for the beeps to stop, plug the Nerdle into USB and press reset to get back into bootloader mode.

What’s going on?

The thing you copied and pasted into the Arduino program is source code and it is a human-readable set of instructions. When you press the upload button, the source code is compiled, or reduced down into a set of instructions that can be executed by a computer. These instructions are in binary, but they correspond to very simple things, like “add one to a variable” or “skip the next instruction if a certain variable is zero.” After the source code is compiled, the compiled code is then uploaded, or transferred, to the microcontroller in the Nerdle. The Nerdle then runs the compiled program, instruction by instruction.

The process of writing source code, compiling it, watching it run, and then fixing the mistakes is called programming, and it can be very rewarding!

Each of the following activities will start with an example program. You’ll run the program, learn a little about how it works, and then be asked a few questions.

A line-by-line breakdown

Arduino programs are essentially written in a C-like language. Technically, it’s a lot like C, with some C++ features, and some helpers to reduce some of the tedium and make it easier for beginners.

Anything on a line after a

//

is a comment. Comments are ignored by the compiler, so they’re used to take notes and keep track of what’s going on. Also, if you want to have a comment go over a few lines, you can start a comment block with

/*

and then anything on any following lines until the next

*/

is a comment.

As you can see, the first half of the entire “Hello, World” program is a comment. It has a short name, the date, the author’s name, and a brief explanation of what it does. After that, it explains further. This is a good habit.


int speaker_pin=9;

This creates a new variable named speaker_pin and sets it to be equal to the number nine. A variable is similar to a variable in algebra. It is a container in the computer that can contain something, and that something can change. In some computer languages, like this one, the container has a certain type. This means the container is supposed to hold a certain type of thing–like a whole number, or a decimal number, or a character like the letter e. The variable speaker_pin has the type int. Ints can go from -32768 to 32767, and are only whole numbers.



void setup()
{

All Arduino programs have two parts. A setup section, that runs at the beginning of the program, and then a loop section, that runs over and over until the power is turned off. This is the beginning of the setup section. It starts with the opening curly brace, {, and doesn’t end until the matching closing curly brace, }.


  tone(speaker_pin, 1000);

This is a function call. The function’s name is tone, and here, it takes two inputs, or parameters. Tone generates a tone for a speaker hooked up to the microcontroller. The speaker is hooked up to a certain pin on the microcontroller chip. On the Nerdle, it is attached to pin 9. This is the same on all Nerdles, and never changes–but on an Arduino, you can change how the hardware is hooked up, and you might have the speaker hooked up to a different place. The tone also has to have a frequency. This is measured in hertz, and corresponds to the pitch. High frequency tones are high pitched, and low frequency tones are low pitched. The first parameter is the pin number. Here, we use the name of a variable to stand in for the number nine. This increases readability and makes the program code more flexible. There is a comma to separate the parameters, and then another number. This second number is the frequency, in Hertz (Hz). We set it to 1000 hz.


  delay(250);

This is another function call. The delay function waits for a certain amount of time before proceeding. The parameter is the number of milliseconds to wait.


  noTone(speaker_pin);

The noTone function stops a running tone. It only takes one parameter–the pin on which to stop the tone. We use the name of a variable we have already set.


}

This closing brace matches with the opening brace of the setup function, and indicates the end of the function.



void loop()
{

This is the start of the loop function. This is the second function that all Arduino programs must have. When this function reaches the end, it will start again.


  tone(speaker_pin, 250);

This is another tone call. It is on the same pin as before, but it is a different frequency.


  delay(250);

This is another delay call, waiting for 250 milliseconds before proceeding.


  noTone(speaker_pin);

noTone stops the running tone.


  delay(250);

This delay waits another 250 milliseconds.


}

This closing brace matches the opening brace of loop, and indicates the end of the loop function

Activities

(Select the text below each question to reveal the answer.)

  • How long is a millisecond in seconds? How long is 250 milliseconds? How long is a typical “blink of the eye” in milliseconds?
  • A millisecond is 1/1000 of a second. 250 milliseconds is 1/4 of a second. A typical “blink of the eye” is 300 to 400 milliseconds, according to Wikipedia.

  • This microcontroller is running at 16 MHz. That means that the “clock” inside of the chip happens 16 million times each second. How many seconds does each of these ticks take? How does that compare to milliseconds?
  • Each tick takes 62.5 nanoseconds! That seems fast, but realize your home computer probably runs between 1 and 3 GHz! Every millisecond is 1 million nanoseconds.

  • What do you think would happen if you exchanged the contents of the loop function with the contents of the setup function? You can do this by changing the word setup to the word loop, and then further down, changing the word loop to the word setup. Think about it, and then try it. (Be ready to press the reset button to turn it off!)
  • The low pitched beep will happen once, and then there will be a long high pitched beep that lasts until power is stopped, because there is no delay after the tone stops.

  • What happens if you change the variable name “speaker_pin” in the setup function to have all capital letters?
  • There is a red error in the bottom. Things in almost all programming languages are case sensitive which means you have to be consistent about your capitalization.

  • How would you make the tones twice as long? How would you make the sounds be half the frequency they are now?
  • Change the parameters to the tone and delay function. By making the tone frequency parameter higher, the pitch will go up. By decreasing it, the pitch will go down. By increasing the delay parameter, the tones will last longer. By decreasing it, they will go shorter.

Wrapping it up

So far, we’ve learned how to upload a program and also how to modify it. We’ve explained every line of a simple program. We’ve done some exploration, and learned that microcontrollers are fast! We’ve also learned some of the syntax of Arduino programs–like what the setup and loop function mean, and that things are case-sensitive.


More beeps!

Copy and paste the following into the main Arduino window, and save it with a new name, something like nerdle_beeps_01.

#include <LiquidCrystal.h>
#include <Nerdle.h>
LiquidCrystal lcd(LCD_RS, LCD_E, LCD_DB4, LCD_DB5, LCD_DB6, LCD_DB7);


int speaker_pin = 9;

void setup()
{
  init_lcd(lcd);
  lcd.print("Hello!");
}

void one_beep(int frequency)
{
  tone(speaker_pin, frequency);
  delay(100);
  noTone(speaker_pin);
}


void loop()
{
  lcd.clear();
  lcd.print("One low beep");
  one_beep(250);
  delay(200);
  lcd.clear();
  lcd.print("A higher one");
  one_beep(1200);
  delay(200);
  lcd.clear();
  lcd.print("and two fast");
  lcd.setCursor(0,1);
  lcd.print("beeps");
  one_beep(600);
  delay(100);
  one_beep(600);
  delay(100);
}

Upload the program to your Nerdle. Observe the beeps. When you’re ready for the beeps to stop, plug the Nerdle into USB and press reset to get back into bootloader mode.

What’s going on?

This program is much like the first one, but we’ve introduced a way to wrap up certain pieces of code together.

When writing instructions in any endeavor, each instruction can be usually broken down into more steps, at a more basic level. For example to make a box cake, you might write the following instructions:

  1. Preheat oven to 400 degrees F.
  2. Beat eggs, water, oil, and cake mix in a bowl for three minutes.
  3. Pour batter into greased 13-by-9 cake pan.
  4. Put the cake in the oven.
  5. After 25 minutes, check if the cake is done.

That may seem like a complete set of instructions, but every one of those instructions can be broken down further. To preheat the oven to 400 degrees F, you might have to:

  1. Turn temperature knob to 400.
  2. Turn the other knob to “Preheat”.

If we had to write at that level of detail, however, our simple recipe for making a cake from a box would certainly take more than a page! We’d get lost following it, and we’d probably need to copy and paste simple instructions more than once–for example, how to open or close the oven door. If we got a new oven, we’d have to go back and change every time we copied and pasted the “how to open and close the oven door” instructions. Instead, we group our ideas together into pieces, and that helps organize our instructions. We can update them easily, and refer to them from other instructions.

Breaking it down

#include <LiquidCrystal.h
#include <Nerdle.h

These two lines are called includes, and are required at the top of your program when you use other people’s functions that aren’t stored inside your code. If they’re not in your code, they’re in libraries, or groups of functions for a common purpose. In the Arduino environment, you can make the program put these lines in by going to Sketch->Import Library. The LiquidCrystal library is commonly used when interfacing with the type of display in the Nerdle. The Arduino site has a great LiquidCrystal reference. It explains what all the functions do and has examples of how to use them.


LiquidCrystal lcd(LCD_RS, LCD_E, LCD_DB4, LCD_DB5, LCD_DB6, LCD_DB7);

This creates a new variable named lcd, of the type “LiquidCrystal”, and gives it some parameters. The parameters represent how the real life display is connected to the microcontroller chip. This line never needs to be modified when using a Nerdle, so you can copy and paste it whenever you need. To make it work, you need to have already included the Nerdle and LiquidCrystal library.


  init_lcd(lcd);

This line is inside the setup function, and comes from the Nerdle library. It turns on the LCD, or “init”ializes it.


  lcd.print("Hello!");

This is one of the ways to make the display show words. This is a function call–but it’s a function call from the lcd. This often happens when using libraries. It’s a way to organize your code further. There are other function calls from the lcd that are possible. They are all shown on the LiquidCrystal reference page.


void one_beep(int frequency)
{

This is the start of a function that we created. If you notice, it isn’t called setup or loop, which means it isn’t automatically called when a program is run. The only way this will run is if setup or loop (or another function called by setup or loop…) call it. It still starts with void, but if you notice, we have the name, one_beep, and then an open parenthesis, and then “int frequency” and a close parenthesis. The parentheses indicate input, like they do when calling a function, but here, we’re specifying what our inputs to the function are going to be, and what we’re going to refer to them by. We’re going to get one input, and it’s of the type int, and we’re going to call it frequency for the rest of this function.

tone(speaker_pin, frequency);
  delay(100);
  noTone(speaker_pin);

This is the inside of the one_beep function. It looks familiar. We’re making a tone of a certain frequency, waiting for 100 milliseconds, and then stopping the tone. The variable “frequency” here matches the name of the variable in the previous part that declared what the function was going to take for inputs. That means that when someone calls this function, it will use the input as the frequency.


  lcd.clear();

This is a function of the lcd, and it clears the display in case anything was written on it. It also moves the cursor to the top left corner. This is where text will be printed the next time anything gets printed to the display.


 lcd.print("One low beep");

This prints out the words “One low beep” to the display at the place where the cursor is, the top left corner.


  one_beep(250);
  delay(200);

This calls our function one_beep with an input of 250. This means that the lines inside of one_beep start to execute. Inside the function, at the very beginning, the variable frequency is set to 250, because that’s what we’re giving to the function as input.


lcd.setCursor(0,1);

lcd.setCursor is another LCD function. It sets where the cursor of the LCD is. The first parameter is which column the cursor should be located at, and the second parameter is which row the cursor should be located at. This specific line makes the next lcd.print() call print to the second line of the screen.

Activities

  • Change the function one_beep to clear the LCD, display the duration, and make a beep.

    void one_beep(int frequency)
    {
      tone(speaker_pin, frequency);
      lcd.clear();
      lcd.print(frequency);
      delay(100);
      noTone(speaker_pin);
    }
    
  • Look at the LiquidCrystal library reference to see the functions that other people have written to work with the LCD. Think of a way you could use one of the functions.
  • Challenge: Write a function called beep that takes in two inputs. One is an integer named frequency and another is an integer called duration. It should make a beep with the frequency, wait for the duration in milliseconds, and then turn off the beep.

    void beep(int frequency, int duration)
    {
            tone(9, frequency);
            delay(duration);
            noTone(9);
    }
    
  • Challenge: modify the example program so it uses beep instead of one_beep.

Wrapping it up

We’ve learned about using the LCD, and we’ve learned about functions that take inputs.


Square-r

Copy and paste the following into the main Arduino window, and save it with a new name, something like nerdle_squarer.

#include <LiquidCrystal.h>
#include <Nerdle.h>

LiquidCrystal lcd(LCD_RS, LCD_E, LCD_DB4, LCD_DB5, LCD_DB6, LCD_DB7);

int speaker_pin = 9;

void setup()
{
  init_lcd(lcd);
  int input = 7;
  lcd.print(input);
  lcd.print(" squared is ");
  lcd.print(square(input));
}

int square(int x)
{
  int output;
  output = x*x;
  return output;
}
void loop()
{
}

Upload the program to your Nerdle. Observe the highly-detailed, intricate mathematical calculations. When you’re ready, plug the Nerdle into USB and press reset to get back into bootloader mode.

What’s going on?

This is a fairly contrived example. What happens here is that we set up a function called square. If you notice, this function doesn’t start with void. Finally! I’m going to explain what void means. Void, in programming, means nothing–and when used before a function name, means the function returns nothing. Functions can have input and output, and we have to label what type they are so the computer knows what to do. At some point, it’s all just strings of 1s and 0s, and the computer needs to know if it needs to interpret it as a character, part of an integer, part of a decimal, or what. So this function we set up, square, has the word int before it. That means when we call it, we can capture a value that comes out of it–its output–into an integer variable, or we can use it as the input to another function that is expecting an int.

Activities

  • Make the part that prints out to the LCD a function called print_square. It should take one integer input, and that’s the number that it squares. Change the program to use your function.
  • Use print_square in your program and call it multiple times to print out all the squares from 1 to 10.
  • Think of another mathematical function you can put in instead of square. It will have to always return an integer. Make that function.

Wrapping up

We learned how to make functions that return an output!


Input!

#include <LiquidCrystal.h>
#include <Nerdle.h>
#include <CapSense.h>


LiquidCrystal lcd(LCD_RS, LCD_E, LCD_DB4, LCD_DB5, LCD_DB6, LCD_DB7);

int speaker_pin = 9;

CapSense cs_up = CapSense(SEND_PIN,BUTTON_UP_PIN);

void setup()
{
  init_lcd(lcd);
}

void loop()
{
   long total0 =  cs_up.capSense(30);
   lcd.clear();
   lcd.print(total0);
}

Upload the program to your Nerdle. Bring your finger close to the up button, and then move it away. Then press the up button. Observe the number on the display. When you’re ready, plug the Nerdle into USB and press reset to get back into bootloader mode.

What’s going on?

The buttons on the Nerdle work using capacitive sensing. A capacitor consists of two separated plates. In the Nerdle, the copper pad is one of the plates, the plastic case is the separation, and your finger is the other pad. The capacitance changes as you move your finger due to the change in the distance between the plates.

When the Nerdle checks a button to see if it’s pressed or not, it charges the capacitor up. If your finger is absent, there isn’t a capacitor there at all, really, and when the microcontroller stops charging it, it doesn’t stay charged for very long. On the other hand, if your finger is pressed right up against it, there’s a higher capacitance, and when the microcontroller stops charging the capacitor, it takes a while for the capacitor to drain its charge. The microcontroller measures how long that takes, and returns an integer representing the delay. Higher numbers mean a closer contact, while lower numbers mean the button isn’t pressed.

There’s a function in the CapSense library that does all this.

More details


CapSense cs_up = CapSense(SEND_PIN,BUTTON_UP_PIN);

This comes from the CapSense library. We’re making a new CapSense, the same way we’d make a new int or LiquidCrystal, and we’re calling it cs_up. We’re telling the CapSense library that there’s a capacitive sensor hooked up on the microcontroller to a pin labeled SEND_PIN and BUTTON_UP_PIN. Every time we want to read the up button in a sketch, we’ll need this at the beginning.


long total0 =  cs_up.capSense(30);

long is a new type–it’s like an integer, only it can hold even bigger numbers. We’re calling the new variable total0, and saying that it should read the capacitance off the cs_up button. We’re telling it it should be read 30 times to give us a more accurate reading. Remember, microcontrollers are fast!

Activities

  • The button that is being read is the up button. It is defined by the Nerdle.h library and labeled BUTTON_UP_PIN. The pin for right is labeled BUTTON_RT_PIN. Try to change the sketch to make it read the right button instead.
  • Make the sketch show both the up button and the right button, and display them both on the LCD.
  • Make the sketch play a tone after reading the up button. Make the tone’s frequency related to the reading from the button. Make sure to stop the tone before reading the button again, or the electrical impulses driving the speaker may interfere with the reading.

Wrapping up

We’ve added reading the capacitive touch buttons to our bag of tricks.