How To's‎ > ‎

How To Document and Organize Your Arduino Code

Introduction

Programming style is about how you organize and document your code. Style is more than a matter of aesthetic interest. A program written following a consistent style is easier to read, easier to correct and easier to maintain.

A program may be written only once, but is read many times:

  • During debugging
  • When adding to the program
  • When updating the program
  • When trying to understand the program

Anything that makes a program more readable and understandable saves lots of time, even in the short run.

Most programmers agree that coding standards are important. The problem is that there is no single standard for C++. As a professional programmer, you must be prepared to adapt your style to the standards of your company or project.

This course follows often-used industry coding standards. Some portion of the grade for most programming assignments is based on your coding style and how well it conforms to this document.

^ top

Naming Conventions

Use Meaningful Names

Choose names that suggest their purpose. Good names help you understand the problem you are solving.

Variable Names

There are two commonly-used styles you may use. However, you must be consistent and only use one of them in a program. The instructor's preference is the first style.

  1. Start with a lower-case letter and use uppercase letters as separators. Do not use underbars ('_').
  2. int myVar;
    
  3. Use all lower case letters and use underbars ('_') as separators.
  4. int my_var;
    

Constant Names

Use all capital letters and use underbars ('_') as separators.

const int MY_CONST = 1;

Function Names

There are two commonly-used styles you may use. However, you must be consistent and only use one of them in a program. The instructor's preference is the first style.

  1. Start with a lower-case letter and use uppercase letters as separators. Do not use underbars ('_').
  2. int myFunction()
    
  3. Use all lower case letters and use underbars ('_') as separators.
  4. int my_function()
    

Class Names

Start with an upper-case letter and use uppercase letters as separators. Do not use underbars ('_').

class MyClassName

^ top

Comments

Comments are explanatory notes for the humans reading a program. With good name choices, comments should be minimal in a program. The only required comments are block comments at the beginning of each file and before each function declaration. Block comments are described in the next section.

One other time to add comments, other than block comments, is when your code is unusual or obscure. When something is important and not obvious, it merits a comment.

Block Comments

Doxygen is a tool that examines the declarations and documentation comments of your code to produce a set of HTML pages. Another tool is Ccdoc. The pages produced by these tools describe your code to other programmers. For an example of the documentation produced, see the Introduction to CcDoc.

The documentation comments are derived from block comments, which you create as follows:

  • Indent the first line to align with the code below the comment.
  • Start the comment with the begin-comment symbol (/**) followed by a return.
  • Start subsequent lines with an asterisk *. Indent the asterisks with an additional space so the asterisks line up. Separate the asterisk from the descriptive text or tag that follows it.
  • Add a description of the purpose of the class or function.
  • Insert a blank comment line between the description and the list of tags, as shown.
  • Insert additional blank lines to create various tags.
  • The last line begins with the end-comment symbol (*/) indented so the asterisks line up and followed by a return. Note that the end-comment symbol contains only a single asterisk.
  • /**
    CS-11M Project 3A
    Name: my_multiply_doc
    Purpose: Multiplies two ints obtained from the user.

    @author Ed Parrish
    @version 1.0 8/04/15
    */
  • For more information on the tags, see the CcDoc Directives.

File Comment Block

Every source file must have a comment block at the top containing the course number, assignment number, name of the file and purpose of the file. One or two lines is usually sufficient to explain the purpose. In addition, you must add the author tag containing your name and the version tag containing the date the assignment is due. For example:

/**
CS-11M Project 3A
Name: my_multiply_doc
Purpose: Multiplies two ints obtained from the user.

@author Ed Parrish
@version 1.0 8/04/15

(other information may be added here)
*/

The following tags always must be used:

Function Comment Block

Every function except setup() and loop() must have a comment block before the function signature. For example:

/**
  Converts a color code to its numerical value.

@param colorCode color code to convert.
@return the numerical value of the color code. */ int codeValue(String code)

The first line is a description of what the function does.

Where appropriate, the following tags must be used:

^ top

Example Program Documentation

The following short program shows a brief example of properly-documented source code.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
/**
  CS-11M Project 3A
  Name: my_multiply
  Purpose: Multiplies two ints obtained from the user.

  @author Ed Parrish
  @version 1.0 8/04/15
*/
const int BAUD_RATE = 9600;

void setup() {
  Serial.begin(BAUD_RATE);
  Serial.println("Enter two numbers separated by a space");
}

void loop() {
  if (Serial.available()) {
    int a = Serial.parseFloat();
    int b = Serial.parseFloat();
    int c = myMultiplyFunction(a, b);
    String str = " * ";
    Serial.println(a + str + b + " = " + c);
  }
}

/**
  Multiply two numbers and return the result.
  
  @param x first quantity to multiply.
  @param y second quantity to multiply.
  @return result of the multiplication operation
*/
int myMultiplyFunction(int x, int y) {
  int result;
  result = x * y;
  return result;
}

^ top

Curly Braces

A fervent issue of great debate in programming circles is placement of curly braces.

Placement of Curly Braces

Either of the following two styles is acceptable in this course:

  1. Place the initial brace on the same line as the keyword and the trailing brace inline on its own line with the keyword:
  2. if (condition) {
        ...
    }
    
    while (condition) {
        ...
    }
    
  3. Place brace under and inline with keywords:
  4. if (condition)
    {
        ...
    }
    
    while (condition)
    {
        ...
    }
    

The first style is traditional for Unix and C programmers and is the personal preference of the instructor and Bjarne Stroustrup.

When Braces are Needed

All if, for, while and do statements must either have braces or be on a single line. This helps to make sure someone adding a line of code does not forget to add braces.

^ top

Whitespace

Always layout your source code so that elements that are part of a group go together. Many whitespace problems can be corrected using the Auto Format function in the Arduino IDE. Press Ctrl-T or use the menus: Tools > Auto Format.

No Tab Characters

Do not have any tab characters in your source code. It is difficult to impossible to read source code if your tab settings are different than the author(s) of the file.

To fix tab settings, use the Auto Format function in the Arduino IDE. Press Ctrl-T or use the menus: Tools > Auto Format.

Line Length

Limit your line length to about 80 characters since long lines make it difficult to read your program code, especially on smaller screens.

Spacing Around Operators

Always put spaces before and after binary operators. This improves the readability of expressions. For example:

int a = Serial.parseInt();
int b = Serial.parseInt();
int c = Serial.parseInt();
int d = -a * b / c + c - b;
Serial.println(d);

Indentation

Always indent within curly braces. The Arduino standard is to use 2 spaces. For example:

void func() {
  if (something happened) {
    if (another thing happened) {
      while (more input) {
        ...
      }
    }
  }
}

To fix indentations, use the Auto Format function in the Arduino IDE. Press Ctrl-T or use the menus: Tools > Auto Format

if-else-if-else Formatting

Always line up if statements with their associated else statement. Beyond that, there are two common styles that you may use:

  1. Place the initial brace on the same line as the keyword and the trailing brace inline on the same line as the next statement. For example:
  2. if (condition) {               // Comment
        ...
    } else if (condition) {        // Comment
        ...
    } else {                       // Comment
        ...
    }
    
  3. Place brace under and inline with keywords. For example:
  4. if (condition)                 // Comment
    {
        ...
    }
    else if (condition)            // Comment
    {
        ...
    }
    else                           // Comment
    {
        ...
    }
    

^ top

Limit Magic Numbers

A magic number is a numeric literal that is not defined as a constant. It's magic because no one has a clue what it means after 3 months, including the author. From widespread use, -1, 0, 1, and 2 are not considered magic numbers.

Whenever you assign a number to a variable, try to use a constant instead (see below). If you must use global variables, add a comment to explain why and justify the choice.

C++ Style Constants

In C++, you declare constants, which are variables that cannot change, using the keyword const. You may use local constants within functions, member constants declared in a class, or global constants declared outside of any class or function.

const int MY_CONSTANT = 10;

Because of their special meaning, write constants in all upper case and use underbars ('_') as separators.

The advantage of C++ style constants is that the compiler does type checking on the number to prevent problems with incompatible types. In addition it respects scope.

C Style Constants

Another option to const is the #define directive. The #define command allows you to associate a value with a name, like:

#define MY_CONSTANT 10

Notice that the #define directives does not use an "=" between the name and the value. Nor does it need a semicolon at the end of the line. The #define directive is called a preprocessor directive that runs before the compiler. The #define directive simply substitutes text and therefore does not type checking.

The advantage of #define is that it does not take up any RAM space, either program storage space or dynamic memory. Thus if your program space is running short you may want to consider #define.

^ top

Minimize Global Variables

A global variable is declared outside of any function and can be accessed by any function in a program. For example, in the following code startPin and numBits are global variables.

int startPin = 7;  // global variable
int numBits = 4;   // global variable

void setup() {
  for (int i = 0; i < numBits; i = i + 1) {
    pinMode(i + startPin, OUTPUT);
  }
}

void loop() {
  for (int i = 0; i < numBits; i = i + 1) {
    digitalWrite(i + startPin, HIGH);
  }
}

Global variables make a program harder to understand and to maintain as the program size grows. Thus it is better if we convert the above global variables to global constants as follows

const int START_PIN = 7; // global constant
const int NUM_BITS = 4;  // global constant

void setup() {
  for (int i = 0; i < NUM_BITS; i = i + 1) {
    pinMode(i + START_PIN, OUTPUT);
  }
}

void loop() {
  for (int i = 0; i < NUM_BITS; i = i + 1) {
    digitalWrite(i + START_PIN, HIGH);
  }
}

However, because setup() and loop() do not have parameters, we may need to use global variables to communicate between them. If you must use global variables, add a comment to explain why and justify the choice.

^ top