Incremental rotary encoders (Part 5)

Part 1234567, 8, 9, 10

Now that we managed to optimize our code, what about making commands and functions available, while their source code would be kept invisible? This is what the libraries are all about!

I am proposing here to decompose the steps from plain code to a (simple) library.

First of all, me must create a directory which will contain all our library components. The path to the library must melibraries: in our case, we shall name the library “RotaryEncoder”

Note: all standard defualt libraries are stored there.

Then create the following empty files:

  • RotaryEncoder.h (the library description file)
  • RotaryEncoder.cpp (the library implementation file)
  • readme.txt (comments file)
  • keywords.txt (the syntax coloring file)

Note: Additionnally, if you plan to make your library public, it is good pratice to create an “example” subdirectory which will contain one or more skteches for illustrating the use of the library.

Starting from plain code, the easiest way is to build the .cpp file. Just copy/paste the code in this file.

Then add the libray name + two “:” signs in front of each routine and function. e.g. byte buttonDown(void) becomes byte RotaryEncoder::buttonDown(void) . There are three exceptions in the present example.

  • The init() routine becomes the constructor and is name is changed to RotaryEncoder::RotaryEncoder(byte PinA, byte PinB, byte PushButton) and that the pin mapping is performed at this stage.
  • The Interrupt Service Request ISR(PCINT2_vect) is left unchanged
  • For some obscure reasons that I cannot explain yet, the ISR cannot contain a routine (even a private routine…) so that I had to change a little bit the code inside ISR(PCINT2_vect)

Copy the whole code and save the file. Open the .h file and paste the code in it.
Note: Oh yes, I know this is trivial and I can hear the gurus puffing; but it is a good way not to forget any routine or function.

Keep only the names of each routine and function and append a “;” sign to the line. e.g.

byte RotaryEncoder::buttonDown(void) {
	return(enc_buttonState);
}

leads to:

byte RotaryEncoder::buttonDown(void) ;

Encapsulate the routine and function names in a class, just like this:

class RotaryEncoder {
public:
	byte buttonDown(void); // 0 true
	int getCounter(void);
	RotaryEncoder(byte encPinA, byte encPinB, byte encPushButton);
	void setCounter(int counts);
	byte state(void);
private:
	// None
}

Have the class preceeded by a call to the standard Arduino commands and functions by adding the following line:

#include "WProgram.h" // This is where the standard Arduino code lies

and prevent multiple calls to the same library by encapsulating the whole as follows:

#ifndef RotaryEncoder_h // Prevent loading library twice
#define RotaryEncoder_h

#include "WProgram.h" // This is where the standard Arduino code lies

class RotaryEncoder {
public:
	byte buttonDown(void); // 0 true
	int getCounter(void);
	RotaryEncoder(byte encPinA, byte encPinB, byte encPushButton);
	void setCounter(int counts);
	byte state(void);
private:
	// None
};
#endif

Note: Commands and functions from the public section shall be usable by the application which will call he RotaryEncoder library. All the commands and functions which are useless for an application shall be recorded in the private section.

Save the .h file. Next step will consist in mapping our libray’s keyword with the source code text editor. Open the keywords.txt file and paste the following code (which is self explanatory):

#######################################
# Syntax Coloring Map For RotaryEncoder
#######################################

#######################################
# Datatypes (KEYWORD1)
#######################################

RotaryEncoder KEYWORD1

#######################################
# Methods and Functions (KEYWORD2)
#######################################

buttonDown KEYWORD2
counter KEYWORD2
init KEYWORD2
state KEYWORD2

Then put all the comments of interest in the readme.txt file. Have a beer, the library is ready for use. Next step conist in building a test application. Open an Arduino session, et enter the following code:

#include "RotaryEncoder.h" // Load RotaryEncoder library
RotaryEncoder Encoder = RotaryEncoder(PIND6, PIND7, PIND5); // Create an instance of the encoder object

void setup() {
	Serial.begin (115200); // Init serial comm port
	Serial.println("Ready"); // Print readyness message
}

void loop() {
	static int lastCount = 0;
	if (Encoder.buttonDown() == 0x00) // Read push button status (Ground true => 0=down)
		Encoder.setCounter(0); // Reset counter
	int counts = Encoder.getCounter(); // Get counter value
	if (lastCount != counts) { // If counter has changed since last display
		Serial.print(counts, DEC); 	// Print counter value
		Serial.println();
		lastCount = counts; // Record current counter value
	}
	delay(10);
}

Compile the code and upload it to the Arduino platform. Start the console and exercise the encoder, one way, the other and press the shaft.

Note: in the latest versions of Arduino, no .o (Object files) are created within the library directory; on the other hand, you do not have to bother about crunching obsolete object files nor compiling them. Arduino cares about it. Just for your records, in the windows environment, the object files are created on request in the C:Documents and SettingsLocal SettingsTemp directory in the scetch buildxxxxxx.

Any error in the library code will lead to a message at the bottom of Arduino IDE, like here (misspelled function name):

Next post on same subject

Leave a Reply

You must be logged in to post a comment.