A Lab 2 Code Walkthrough

In Lab 2 we’ll be stepping our programming game up a bit. In this writeup I’ll walk through the code that we’ll be using for the lab with the goal of making it less intimidating.

Part 1 - Fading

This first part of the lab uses an example program that can be found in File -> Examples -> Basics -> Fade. The preamble ought to be reasonably familiar from your lab 1 experience. The author starts by defining some variables and then moves on to setting their output pin to OUTPUT mode.

int led = 9;
int brightness = 0;
int fadeAmount = 5;

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

Having done that there are some new things in the loop function. The analogWrite function is used to write a value between 0 and 255 inclusive to the LED pin. Under the hood the Arduino is using pulse width modulation to accomplish this. For all practical purposes though you can think of 0 being the same as LOW and 255 the same as HIGH from the first lab with the other values filling in the missing space.

A requirement for using analogWrite is that the pin that it is being used on is prefixed by a ~ symbol on your Arduino board. For example, if you take a look at your Arduino Uno from the top you’ll notice that the 8 just has a number while the 9 pin is written as ~9. This means that pin 9 supports analogWrite.

Another funny looking part of the loop function is this:

if (brightness <= 0 || brightness >= 255) {
  fadeAmount = -fadeAmount;
}

If you’ve never worked with the C++ language before the condition inside of our if statement might look a little strange. In a language like python it would roughly translate to something like this:

if brightness <= 0 or brightness >= 255:
  fadeAmount = -fadeAmount

In this case the || symbol means “or”. If either side of the “conditional statement” evaluate to true the “body” of the if statement will be evaluated. I have attempted to draw a picture of this with my keyboard below.

//  /------->  conditional statement
//  |    |
//  v    v
if (a || b) {
    36 + 6;  // <-- body
}

Part 2 - Fading 3 LEDs

This part of the lab largely builds upon concepts that we have some grasp of from the fist lab and the fade example. The code is long but if you tackle it in a reasonably slow fashion it might be readable.

There are two new concepts introduced here that we have not seen in previous labs. The first is writing to the serial console. Lucky for you we already have a tutorial on that. The second is the introduction of a new const keyword in the preamble.

const int redPin = 9;

What this keyword does is prevent you from accidentally changing the redPin variable later in your code. For example, doing something like the following would result in an error:

void loop() {
  redPin = sin(redPin)
}

When you are writing code for your Arduino you may want to consider prefixing values that you do not expect to change with this const keyword.

Intermission

If you’re feeling overwhelmed by all these new programming things please do not. Working with Arduinos is a genuinely difficult task. To help put into perspective how hard what you’re doing is, here is the official documentation about the const keyword.

By using it in your program you are doing something complicated and cool. Congrats.

Part 3 - Serial Communications

This part of the lab is a pretty reasonable extension of the last part that adds some user interaction into the mix. If you have not I’d recommend understanding our serial communications tutorial before tackling this section of the lab.

The big new part of this code is the following conditional statement in the loop function which we’ll walk through.

  // clear the string
  memset(serInString, 0, 100);
  //read the serial port and create a string out of what you read
  readSerialString(serInString);

  colorCode = serInString[0];
  if( colorCode == 'r' || colorCode == 'g' || colorCode == 'b' ) {
    colorVal = atoi(serInString+1);
    Serial.print("setting color ");
    Serial.print(colorCode);
    Serial.print(" to ");
    Serial.print(colorVal);
    Serial.println();
    serInString[0] = 0;                   // indicates we've used this string
    if(colorCode == 'r')
      analogWrite(redPin, colorVal);
    else if(colorCode == 'g')
      analogWrite(greenPin, colorVal);
    else if(colorCode == 'b')
      analogWrite(bluePin, colorVal);
  }

The first question that you might ask about this is what serInString is. It is defined in the preamble as follows:

char serInString[100];

This sort of syntax can be hard to read so lets take it left to right.

  1. A char is much like an int except that instead of holding a number it holds a letter.
  2. serInString is a variable.
  3. [100] indicates that whatever precedes it is in fact a list of 100 of those things. The practical impact of this is to say that serInString is no regular char but is instead a list of 100 characters.

So, in summary, serInString is a list that has space for 100 characters.

Returning to our earlier code block we see that it begins with a call to memset(serInString, 0, 100). memset is a function that takes a list and fills the first N items with a value. In this case we are asking memset to fill serInString with one hundred zeros.

In programming the character 0 is a special character that essentially means “nothing to see here” so this call to memset results in serInString being reset to a whole lot of “nothing to see here.”

Once serInString is reset we make a call to readSerialString which fills it up with whatever data the user has sent to us over the serial port. You’ll likely want to take a look at that function. The new part there is the usage of the strArray[i] expression. This expression yields the i-th value from strArray. For example:

strArray = [1, 2, 3]
strArray[0] => 1
strArray[1] => 2
strArray[2] => 3

Notice that the “first” item in the list is actually accessed by asking for strArray[0]. Forgetting about this is liable to result in some fun bugs later in the semester.

Returning to our loop function, we expect messages in the form <colorLetter><intensity> so once we have the information that the user sent over we check if the colorLetter input is one of r, g, or b.

if( colorCode == 'r' || colorCode == 'g' || colorCode == 'b' ) {

If it is we then need to read the intensity value and set the appropriate LED. To do this we use the atoi function. atoi is a strangely named function which takes a list of characters and converts them into an integer if possible. For example:

atoi(['1', '2', '3'])  => 123
atoi(['1', '2'])       => 12

You’ll notice that we call atoi(serInString+1) and not atoi(serInString). This is because the first item in serInString is a letter and not a number. In order to get the number part of the input we need to move the list over to the right by one.

[r, 1, 2, 3] + 1 => [1, 2, 3]

Having read in the desired brightness with atoi the rest of the code is very close to what we’ve seen before. Nice work making it this far.