Class 2

This class discusses the basics of writing code for an Arduino device.

We begin by writing a class for the cube. We create a class because we are treating the cube as a module; it has functions and variables which are specific to the cube and should be grouped together. We also want to encapsulate variables and functions so that the end-user can interface with the cube without worrying about the specific inter-details of the implementation. We begin by creating the C++ header file. A header file contains all the function declarations, but not the implementation. The purpose of this is to show a user of the class what functions are available without the user having to worry about how they are implemented, which is often not of importance. The implementation is dealt with in the cpp file. Below is the base code for the cube header.

/*
  * File: Cube.h 
  * Author: Jeff Longo
  * Comments: LED cube controller class
*/

#ifndef CUBE_H
#define CUBE_H

#include "Arduino.h"

// Begin pin definitions
#define SERIAL_IN  2
#define LATCH_CLK  3
#define INPUT_CLK  4
#define UPDATE_CLK 5
#define RESET      6
#define SET        7
// End pin definitions

class Cube
{
  private:
    const static byte size = 4;
    const static int period = 100;
    unsigned short buffer[size];
  public:
    // Initializes the cube
    Cube();

    // Add an LED to the buffer at position (x, y, z) with range (0, size - 1)
    void bufferLED(byte x, byte y, byte z);

    // Parses the data from the buffer, displays the frame, and then clears the buffer
    void display();

    // Empties the contents of the buffer
    void clearBuffer();

    // Reset the system
    void reset();
};

#endif // CUBE_H

The first thing to notice is the block of code:

#ifndef CUBE_H
#define CUBE_H

// Cube class code here

#endif // CUBE_H

This is called a header guard. A file is only allowed to be included one time in C++. These compiler directives first check to see if CUBE_H is defined. If it is not defined, it defines it and processes the cube class code. If CUBE_H is already defined, it skips processing the cube class code again and jumps straight to the endif. This way, the cube class code will only be included once.

Next is the line:

#include "Arduino.h"

This includes the Arduino standard functions, namely digitalRead and digitalWrite. These functions can be used to check the state of a pin on the Arduino or to set the state of a pin on the Arduino. We will use these functions in the implementation file.

Following that is:

// Begin pin definitions
#define SERIAL_IN  2
#define LATCH_CLK  3
#define INPUT_CLK  4
#define UPDATE_CLK 5
#define RESET      6
#define SET        7
// End pin definitions

This code sets constant values. For example, everywhere where the word SERIAL_IN appears will be replaced with the number 2. The reason for this is to set convenient names to match with each pin number on the Arduino. This makes it clear what function each pin has when we are reading or writing to pins. For example, we can use the code digitalRead(SERIAL_IN) to read the state of the the SERIAL_IN pin (pin 2). To reiterate the functions of these pins, SERIAL_IN is the input to the 16 bit shift register which is used to load a 16 bit configuration for a layer. LATCH_CLK is used to save the output of the 16 bit shift register when the value is completely loaded into the shift register. INPUT_CLK is used to shift the 16 bits down the shift register. UPDATE_CLK is used to shift the bits of the layer shift register to change layers. RESET is used to reset the layer shift register, which is needed during the inital setup. SET is used to set the initial 1 in the layer shift register.

Now we enter the class definition. You will notice there is public and private section. The public section is accessable from outside the class, whereas the private section is only accessable inside the class. Things should be made private for encapsulation purposes unless the user should absolutely be able to access a specific function or variable that needs to be made public.

There are 3 private variables. size is the fixed size of the cube. In our case we use 4 because the cube is 4 x 4 x 4. period determines the frequency of the layer updates. In this case the cube’s display is refreshed (all 4 layers are displayed) every 100us. This number should be decreased until layers appear to all be active at the same time. buffer[size] is an array of size 4. Each index of the array stores the 16 bit configuration for a specific layer. For example, buffer[0] is the 16 bit configuration for layer 0.

Lastly, we define some functions that we will probably need for the cube:

    Cube();
    void bufferLED(byte x, byte y, byte z);
    void display();
    void clearBuffer();
    void reset();

Cube is a special type of function called a constructor. The constructor has no return type, and must be named the same as the class name. This function is automatically run when an object is initialized. Thus, it can be used to set default values or perform other initialization tasks for the object. bufferLED takes in a coordinate point and enables the correct bit in the 16 bit configuration for layer z. display takes the contents of the buffer and displays them on the cube. This displays the output for 1 frame (4 layer updates). clearBuffer resets the buffer so that the next frame can be configured. reset clears the buffer and restarts the layer shift register.

These functions should be all that is necessary to control the cube using coordinate points.