Friday, June 14, 2013

Modular Arduino coding

The WBMD code was getting to be more complex, and it would have been great to have used object-oriented programming techniques, but I didn't have the C++ tools for doing it.  Instead, I resorted to old-school C programming.

To build Arduino code in a more sensible manner, you can use "tabs".  Each tab is really its own .ino file, and each appears to be compiled as part of the whole.  But, there are special tabs.  If a tab is a ".h" file, it can be included by others, and isn't part of the full compilation unless included.  To include it in one of the .ino files, you use a
#include "name.h"
pre-compiler directive.  Use quotation marks instead of "<" and ">" path-search delimiters.

I chose to build up the code starting with a "globals.h" file.  It's prefixed with the usual guards:
#ifndef GLOBALS
#define GLOBALS
put stuff here
#endif

I then chose to put all the pin assignment information into that file.  That was a little tricky for the WBMD set-up because there were also pin names to be reserved for all 16 of the shift registers' outputs.  I called those Q1A..H and Q2A..H, where 1 and 2 represent which shift register is in use, and A..H are the output pins (corresponding to one of the names used in datasheets I had read).  Putting all the assignments in one place was my visual cue not to assign a pin multiple meanings.

For other "objects" in the world, like the spinner or dumper or proboscis, I'd set up a tab of the same name, and give each one a <name>_setup() function.  Then, the main tab, the one that has the real "setup" and "loop" functions would call all the <name>_setup() functions from its setup() function.  Beyond that, it was up to each tab to declare its own behavior.  Generally speaking I followed a name_function() naming convention for functions.  Example: dumper_dump_balloon() or dumper_return_to_fill_position().  This is part of my normal programming set of rules: name functions very specifically.

Each object also had its own set of feedback choices, so there might be boolean functions named dumper_is_down() or dumper_is_up(), and those might query a digital input pin that's tied to a contact switch.  That would allow the skeleton of the main program to be fleshed out while the actual functionality behind the functions was hardcoded.

No comments:

Post a Comment