My Pi Description

My Experiences With the Raspberry Pi -- Tracking My Learning -- My Pi Projects
Showing posts with label Creating Arduino Library. Show all posts
Showing posts with label Creating Arduino Library. Show all posts

Saturday, July 5, 2014

My 1-Wire Arduino Library for DS18B20 Temperature Sensor

This is a continuation of my last blog post.

The Include File For the 1-Wire DS18B20 Library

This 1-wire library will work equally well with an Arduino and a Gertboard.
At the top of the file are #define statements to account for your hardware set-up. Unless you use the same hardware choices I made, you make the appropriate changes to the file and save the file.
The first #define is for CLOCK_FACTOR. I reported in an earlier post that the delayMicroseconds(), Arduino IDE, function is not accurate when using the Gertboard. I tested this thoroughly, at different values, using an oscilloscope. My results show that you must divide the desired delay by 0.67 to get an accurate delay. Consequently, if you use the Gertboard, make the clock_factor 0.67. Select 1.0 for the Arduino. The difference is caused by the 12MHz clock frequency of the Gertboard compared to 16MHz of the Arduino. The delay() function requires no correction.
The rest of the #defines relate to the selection of the two Arduino data pins you select. One pin is the data pin for the 1-wire bus, and the other is the pin that controls the transistor for parasitic power. I will have a post devoted to the parasitic power transistor circuit. Hopefully, my comments, in the file, are enough to guide you through the selections.
If you use the Gertboard you can take the pin names as they appear by the J28 connector (PB1 for example). These are the same designations as used in the ATmega's data sheet, and, more importantly, the same designation as used in the avr/io.h include file. If you use the Arduino, where pin numbers are 0 to 13, you will need to convert them to the ATmega numbers.
Arduino ATmega Arduino Atmega Arduino Atmega
0 PD0 5 PD5 10 PB2
1 PD1 6 PD6 11 PB3
2 PD2 7 PD7 12 PB4
3 PD3 8 PB0 13 PB5
4 PD4 9 PB1
The rest of the file declares the functions in the library source file. These are the public functions, those that can be called from a sketch, and the private functions, those that are not available from sketches.

The Soruce File For the 1-Wire DS18B20 Library

Most of the functions are short. Their comments are longer than the code. You will have to be familiar with ATmega register programming and bit manipulation. I have tutorial on useing direct register programming here.
In the next several posts, I'll go into some detail on the search_device() and calculateCRC_byte() functions. But, first, I need to address parasitic power and what to do about it. That's next.

Tuesday, May 13, 2014

Arduino Libraries - DON'T DO THAT!

Don't do what? Well, lets lead up to the answer to that question.
I wrote a fairly long library .cpp file (and, of course its .h file). It worked just fine in my sketch. But, I decided to make some changes. Not wanting to lose what I had (I knew it worked) I made copies of both the .h and .cpp files, appending "save" to the file name for each of the two files. I had four files: something.h, something_save.h, something.cpp, and something_save.cpp. All four files were under home/pi/sketchbook/libraries. I wanted to minimize the changes to my sketch (.ino file). Therefor, I did not want to change any of the function names in the library files. I made my changes, and compiled the sketch. The result: I received a list of compiler errors that went on and on and on.
To illustrate what happened, I repeated the sequence of events with a really small, and trivial example:
The only differences I made were to append a "+ 1" to "c = a + b" in the original .cpp file, just to make something different, and to append "_save" and "_SAVE" to the top lines of the bottom two files. I compiled the sketch and you can see what occured:
That's a lot of error messages for a tiny example sketch. I know it's a little hard to read the error messages because of the red text. Here is what it says:
Mylibraries/ridicules.cpp.o: In function RIDICULES::addNumbers(int, int)':
/home/pi/sketchbook/libraries/Mylibraries/ridicules.cpp:8 multiple definition of RIDICULES::RIDICULES()'
Mylibraries/ridicules_.cpp.o:/home/pi/sketchbook/libraries/Mylibraries/ridicules_save.cpp:8> first defined here
Those three messages are repeated three times. Please note I created a directory under home/pi/sketchbook/libraries called "Mylibraries". I stick my libraries there to separate them from the ones that came pre-installed with the IDE.
Note what I have colored red. This is reference to my ridicules_save.cpp file. My sketch does not reference "ridicules_save". Why is "ridicules_save" part of the build? To start to understand things, I did a search for the object files (".o") referenced in the compiler errors. I knew they were not in the Mylibraries directory. Here is what I found:
Note that all of these object files were created at the same time. They are all created every time you compile.
The IDE generates an object file (with an .o extension) of every .cpp file it finds in Mylibraries. It also makes an object file of .cpp files not in the sketch/libraries path. These ".o" files are needed to support Arduino functionality. There are other .cpp files in the sketch/libraries path that are skipped. This includes, for example, OneWire.cpp. Perhaps these are not included because I have never compiled a sketch using them.
I would have thought the IDE would only make an object file of the .cpp files you call for in your sketch and not all the others in your directory. But it does, so now that we know we can answer that question at the top:
Don't have more than one .cpp file with functions that have the same name in the libraries directory. If you need to keep copies of older versions of library files stick them in a directory outside of /home/pi/sketchbook/libraries.
By the way, you can have two files with addNumber() functions, just not two RIDICULES::addNumbers functions. Make one VERY_RIDICULES::addNumbers and you will be OK.

Tuesday, March 18, 2014

Writing An Arduino Library

My last post included a script for controlling the angle of rotation of a small dc servo. That script expects the user to input a floating point number from the terminal. I wanted that script to concentrate on the servo code, so to avoid encumbering the script with the process of handling the user's input, I put the input handling code into a library. Never having created a library, I wanted to learn how that is done. I read several tutorials but they all seemed rather simplistic. One of my concerns was how to pass values between the code that uses the library and the library functions themselves. I started with simple functions and built on those until I arrived at the function I needed for the servo
When you use the Arduino "Serial.read()" function to read from your terminal, you get only one character from each call. If you need more than one character, you need successive reads and a way to put those characters together into something meaningful. You also need to know when the last character was entered and some way to deal with characters entered in error. My servo script wants the user to input positive or negative floating point numbers of indeterminate length.
Note added June 22, 2014 concerning the last paragraph. If you use an Arduino instead of the Gertboard, you can use the serial monitor provided by the Arduino IDE. This serial monitor works quite differently. Rather than only returning one character for each call, it buffers your key presses and returns all of the characters when you hit "enter". In switching my next project from the Gertboard to the Arduino I had to modify the library created below to accommodate this change. See my post of June 15, 2014.

Final Script

Figure 1 below is my final script to control the servo. This is the same as in my previous post. The leading comments in that script were all about making the servo work so I removed them here. This script uses the library I wrote. You cannot see any of the details associated with inputting the floating point number. Only two lines, 2, 4, and 26 deal with the library:
FIGURE 1: Final Script - Without Leading Comments

Getting Started Making A Library

First, you develop the code, as usual, in a script using the Arduino IDE. Identify the parts of the code that will eventually be part of your library: functions, commands, and variables. Make sure there is test code that thoroughly tests the soon-to-be library. Compile and upload this script to make certain it will run properly. Try to break the code by changing conditions.
My test code is the code to control the servo. Figure 2 is my script. I call it my all inclusive script because it contains everything, in one script: the code to input numbers and code to control the servo:
Figure 2: Original All Inclusive Script - No Leading Comments
Most of the code (lines 3 to 68) deals with inputting the floating point number and just a few lines with the servo control.
The code to handle inputting the number accepts any digit, accepts a minus sign only if it is the first character, accepts one, and only one, decimal point, and accepts the backspace key to make a correction. All other characters are ignored. The function returns the floating point number to the calling code. This is not a perfect solution. I don't have a way to correct individual characters. When the backspace key is pressed, a space prints on the terminal after the last character, and the entire number must be entered from scratch.
I think it is pretty clear how the code works so I won't dwell on the details. We have two functions "termNumb()" and "clearVars()", and several variables. "clearVars()" is only called from "termNumb(). "termNumb()" is called from the program in line 91. The variables (lines 3 - 5), one int, three floats, and three boolean are needed by both functions so are global.

Now We Give The Code Some Class

Now that the code is working and tested as thoroughly as possible, it is time to define a class. We will tie those soon-to-be library functions to that class as well as those global variables we spoke about above. This script still contains the test code for controlling the servo. Figure 3 is the new script:
Figure 3: The Script With Class
At the top we create a class called "TERMNUMB". A class defines a data type (like an int or float). Elements you give that class are available to use when you use this class in other code. The elements of our data type, "TERMNUMB", are three functions (or methods): "TERMNUMB()", "termNumb()" and "clearVars()" and seven variables. The first two functions are declared as "Public" meaning they can be accessed by other code outside of the code that implements the class. The function "clearVars()" and the seven variables are declared as "Private" which means they are not known to code that call this class, but are seen by the functions declared in the class. There is no need for "clearVars()" to be public since it is only called from "termNumb()"
The functions "termNumb()" and "clearVars()" are the same as seen in the original, all inclusive, script as seen in Figure 2. "TERMNUMB() is new and is a special type of function called a constructor. Notice it has no return type and its name is exactly the same as the name of the class. The constructor is the first thing you see in the code below the class creation.
Note the function "termNumb()" has a float return type. When called, the function will return a floating point number to the calling program.
"TERMNUMB" class also declares seven variables and these variables, as indicated above, are declared as private. Notice these are the same variables declared in Figure 2, the all inclusive script above. I have added an underscore to the names of these variables. This differentiates them from variables that are declared within the functions themselves (like inChar).
Now that the class is created we define the three functions referenced in the class. The first function to be defined (line 14) is the constructor introduced above. Notice, in this example, there is no code associated with this function. The purpose of this function is to create an instance of the class "TERMNUMB". The way we associate "TERMNUMB()" to our class "TERMNUMB" is to use this strange syntax "::". The structure "::" is called the scope resolution operator and it says that "TERMNUMB()" is within the scope of class "TERMNUMB". The same must be done for our two other functions. "clearVars()" in the all inclusive script (Figure 2) becomes "TERMNUMB::clearVars()". "termNumb()" becomes "TERMNUMB::termNumb()".
The code from lines 17 through 78 define the implementation of our two functions "TERMNUMB::clearVars()" and "TERMNUMB::termNumb()". The code is nearly identical to the code in the all inclusive script (Figure 2) lines 7 - 68. The only differences are in the function names, just discussed, and the underscore attached to the names of the private variables.
We have created a class and defined the workings of the functions in that class. Now it's time to use it in our code to control our servo. Like declaring any type of variable, such as an int or float, we declare our class. This is done in line 80. We are declaring "inFromTerm" to be of type "TERMNUMB". One of the elements in "inFromTerm" is the function "termNumb()". That is exactly what we need to get the floating point number that becomes the angle our servo is to steer to. All of the work we have done culminates in line 102. The variable "angle" will be the return value from member "termNumb()" of data type "inFromTerm".
Make sure you compile and upload this code. Test it to make sure it works as desired.

Making the Library Files

The hard work is done. What remains is to create two files. These two files will constitute the library. Essentially, they will be cut-and-pasted from file in Figure 3 above. The first file is the header file with a .h extension. The second is the object file that has a .cpp extension.
Unfortunately, you can not make these files from the Arduino IDE because it only allows you to save a file with an .ino extension. You will have to use one of the text editors available with your Linux distribution like nano, vi, or leafpad to create, edit, and save the two files.

Header File

Figure 4, below, is the header file:
Figure 4: Header File InputNumbFromTerminal.h
As you can see, lines 22 - 31, in the header file, are exactly the same as lines 3 - 12 in Figure 3 above. Note we have added some comments to describe how the class will function.
Lines 17, 18, and 33 prevent "TERMNUMB" from defining multiple times and from creating duplication in the final binary file. Those lines assure that the class will only be created if it had not been created before. This is standard practice when creating header files.
Line 20 is absolutely necessary if your object code uses any of the special Arduino functions available from the Arduino IDE. In our case, that includes "Serial.read()" and "Serial.print()". If you have a pre Arduino 1.0 IDE you would use WProgram.h instead of Arduino.h.

Object File

The object file follows:
Figure 5: Object File InputNumbFromTerminal.cpp
The object file,Figure 5, "InputNumbFromTerminal.cpp" is the implementation of the class "TERMNUMB". Lines 4 - 68 are exactly the same as lines 14 - 78 in Figure 3 above. In lines 1 and 2, we include the two header files: Arduino.h (WProgram.h for pre Arduino 1.0 IDE), and the header file we just created, InputNumbFromTerminal.h.
Notice that the variables declared in lines 3 - 5 in the original, all inclusive, script (Figure 2) are not declared in the object file. Instead, these are the private variables declared in the header file. In the object file, they appear with the same names except they include the underscore as their last character.
None of the code to control the servo can be found in either the header or object files. No test software is included. That is why the testing is done before making the library files.

The Header and Object Files Are Now Created - What's Next

The library, consisting of the header and object files, must be placed in the correct location in your file structure. For the RaspberryPi, all user libraries must go into the "/home/pi/Sketchbook/libraries/" directory or a subdirectory of "home/pi/Sketchbook/libraries/".
VERY IMPORTANT:Once your files are located within the proper directory structure, you must close your Arduino IDE and any files open in the Arduino IDE. Only then, when you reopen the Arduino IDE, can your library be accessed by other code.

Putting It All Together - Revisiting The Final Sketch

I'm going to repeat the final sketch here in Figure 6 showing how we use the library to input the floating point number.
Figure 6: Final Script - Without Leading Comments
To access the library to input the floating point number we include the header file. This is done in line 2. Note we have declared "inFromTerm" to be of the data type "TERMNUMB". We also used "inFromTerm" in the code Figure 3. We did not have to use the same name. If we had called it something else in the final sketch we would need to match that name in line 26.

Quick Example Of Passing Values To A Library

Before I developed a library, I was not certain how you pass values to a library and how you pass a value from a library. The library above shows how the latter is done, but not the former. I have a really simple library that accepts two integers from a calling program, adds them together and prints the result to the terminal. The following are the header file, the object file, and the script using the library:
Figure 7: Header File
Figure 8: Object File
Figure 9: Script Calling The Library
Note, unlike in the library created above, we actually have some code within the constructor REALSIMPLE::REALSIMPLE().
I hope this tutorial has been helpful.