Well it's been a big week in my little land of Arduino. Been on uni holidays for a few weeks and have been coding like crazy. It's about time I got some of my recent learnings documented.
I've realised I'm getting more and more polarised towards using C++ for my Arduino projects. I read other people's C code and, although I can understand what it does, how it works and even appreciate it for its compactness, it still seems wrong to me at a philosophical level. The idea of building classes ("libraries" in Arduino-speak) to encapsulate data and functionality and then "stacking" these to build more complex functionality is far cleaner and neater to my mind. Working in an object-oriented paradigm is far superior I think.
In the time since I last wrote, I finished reading The C Programming Language by Brian Kernighan and Dennis Ritchie - the gurus who wrote the language. I'm truly amazed. The things that can be done just in C are boggling. Pointers (not new to me) are just the most powerful things. I have re-written much of my existing code to dispense with indexes on arrays and instead employing pointer manipulation. So fast, so powerful. Better knowledge of C++'s roots in C have helped my C++ coding no end. I look forward to revisiting this C book (and others, if I can find good ones) once I feel I've mastered what I've learned so far. I can't get it all down in one go.
It's funny. At the moment I seem to work a few hours each day on coding and, having put it down, I "learn" things during the day while I'm doing other things. The thought came to me an hour ago (while jumping on the trampoline with my daughter) that I hadn't yet employed returning objects from functions. Sure, I've got functions returning booleans, integers, characters, pointers to character arrays (strings), and passed multiple values out of functions via input parameters that are pointers to fundamental types. Great! But I now need a function that returns a Time object! I'm guessing C coders would dust off the struct keyword right here and build a Time structure. Awesome. So when I nee to add two times together, where does the code go for that? The struct can't encapsulate that, so it must be a function, right? I suppose the best a C programmer can hope for here is to write these functions into a separate time.c file for organisation's sake. I prefer to make Time a class and have it's data and functions rolled into one little package.
So, to return a type from a function. Hmm. I started a new Arduino project and filled it in with the usual setup() and loop() functions. It compiles, great. I then added Time.h and Time.cpp - my class definition for Time. Here are the listings:
//Time99.pde
#include "Time.h"
void setup()
{
Serial.begin(9600);
Time now(12, 34, 56);
now.debug();
Time today = getNow();
today.debug();
getNow().debug();
}
void loop()
{
}
Time getNow()
{
Time today(1, 2, 3);
return today;
}
//Time.h
#ifndef Time_h
#define Time_h
#include "WProgram.h"
class Time
{
public:
Time(byte hours, byte minutes, byte seconds);
void debug();
private:
byte _hrs;
byte _min;
byte _sec;
};
#endif
//Time.cpp
#include "Time.h"
//Constructor
Time::Time(byte hours, byte minutes, byte seconds)
{
_hrs = hours;
_min = minutes;
_sec = seconds;
}
//Member Functions
void Time::debug()
{
Serial.print("Time: ");
if(_hrs < 10) Serial.print('0');
Serial.print(_hrs, DEC);
Serial.print(":");
if(_min < 10) Serial.print('0');
Serial.print(_min, DEC);
Serial.print(":");
if(_sec < 10) Serial.print('0');
Serial.println(_sec, DEC);
}
After defining the class Time I have instantiated Time objects three ways. It was a bit of a surprise to me that I could use the last two methods. Anyway. The first one is kinda obvious; values are passed to the default constructor and all is well. The second way shows the object being instantiated by another function and being passed to a reference in the local scope. (I'm sure that's not the right terminology, but I know what I mean.)
I'm kind of going around the important point I'm working on here and that's the question "how do you instantiate objects and destroy objects?" Arduino doesn't implement the full C++ functionality in this respect. I'm used to the New and Delete keywords coming into effect at this point. I've already blogged about how to add New and Delete for Arduino, but I haven't actually employed it yet. I've been working on the idea that, as long as you keep objects in scope, they stay alive.
Questions still remain. Like "what happens when an object goes out of scope?" As far as I'm aware Arduino doesn't have automated garbage collection. So how does memory get freed? Should I be using the C free keyword to ensure objects don't linger in memory? So far even with significant string manipulation I haven't managed to lock up the AVR micro-controller. Well, I tell a lie. In trialling a test-driven-development (TDD) methodology I did manage to test too many strings against one function and lock it up completely. Was it out of registers? Did it overflow the stack? Hmmm, I don't know. That's why I'm reading Embedded Systems Design with the Atmel AVR Microcontroller (Seven F. Barrett, University of Wyoming), it seems to cover the hardware and so I hope to understand some of the secret inner workings of this micro-controller's architecture.
Anyway. I'm off to employ my Time class in my Weasley Clock project, which I'm re-writing. I'm ditching the object.begin() workaround, employing constructors on all my classes and using initialiser lists to get over the constructor-calling-constructor failures I faced earlier. So far so good. I have the main sketch instantiating a GPS object via it's default constructor. The GPS constructor has an initialiser list that ensures the SoftwareSerial object it instantiates is created from parameters passed to the GPS constructor. Bewdiful!
That is all.
I'm feeling kind of similar things... I'm leaning towards dumping Arduino in the long run and just do things with GCC-AVR... dump the zero get with the hero :D.
ReplyDeleteArduino might be good for beginners to do simple stuff, but it's badly documented and full of bugs starting with the basics such as #ifdef
http://www.drocop.com