The purpose of this github page is to provide you with the tools and knowledge to set up a 99% compile-able arduino folder complete with state machines skeletons, accompanying timers and other supplemental modules. Simple syntax makes it use-able for both beginning as well as experience programmers alike.
The main aims are:
Further documentation is provided on this github page. You can find information about the software timers, round robin tasks and the state machines.
Once you are set up, the basis usage is very simple. There are just two things you have to do to create a new project folder.
The script will prompt you for which hardware you will be coding for. This is important so the script can properly configure the build scripts. This script will also ask you if you want to include any modules from the module list. You can pick a module by entering the corresponding numbers. Type 'done' once you are finished and hit Enter again to close the program.
The script will generate source and header files, copy existing files and move some files to your new project folder. Any copies of your yEd diagrams are also moved to the new folder.
The assembled project ends up in the parent folder of the state-machine-script folder. Without added state machines, the assembled project is 100% compile-able.
The state machines however require one action before they can be compiled. Every state machine needs to have his 'beginState' defined. By default the #define is commented out which will trigger #error
directive. If you try to compile the compile error will show you precisely what you must do. It is a fail-safe method which forces you to specify which state is to run first.
//#define beginState
#ifndef beginState
#error beginState not yet defined
#endif
Once this 'beginState' is defined your project is compile-able. From this point on you can start coding.
N.B. There is one side note for the upload script. This script needs to know which comport you will be using. It wil automatically pick the last listed comport of your system. If you plug in your arduino board before you assemble your project you have a really good chance that the script will pick the correct comport.
IO are managed in io.tab
. A script called updateIO.py
is used to generate the source files and header files. This always happens before compiling. This serves one single purpose.
I use the .tab file and the script so I can manage all IO in one single place. It is not uncommon for a programmer to forget to add the pinMode()
instruction after adding a new IO. Manually changing IO also means editing two places in two places. Now you just have to alter one line in one place.
In io.tab
you simply fill in a pin number followed by: tab, name/description, tab, iodir (OUTPUT, INPUT or INPUT_PULLUP) like:
7 sensorLeft INPUT_PULLUP
The script will generate the source files. #defines are made for all descriptions in the header file and the source file will contain the initIO()
function. This function sets the pinModes for us. Therefor we can not forget to type a pinMode instruction. initIO()
is called from void setup()
this part is also generated for us.
These IO files come with integrated support for the MCP23017 I2C IO extender. Making IO for these devices can be done in the exact same manner. There can be as much as 8 MCP23017 devices. Take note that every slave has only 16 GPIO. So use 0-15 for all IO pins. In order to use an MCP23017, you can enter the desired IO in io.tab underneath the reguar IO. You do need to label these parts with MCPx like in the following example.
7 sensorLeft INPUT_PULLUP
MCP1
15 sensorMidde INPUT
MCP2
4 led4 OUTPUT
// ETC
initIO()
does the configuring of these devices for us. The tri-state registers are automatically configured correctly for you. To control the IO you can use two functions called mcpWrite(io, state);
and mcpRead(io);
. They work the exact same as digitalWrite(io, state);
and digitalRead(io)
The beauty is that we do not have to remember which IO is on which mcp device and on which port. These functions calculate the correct slave, port and pin numbers. Writing to a pin does not affect other pins. If you write to a pin with mcpWrite()
it will first fetch the current state, than ORs and ANDs the current state with the desired IO change and sends it back.
The only condition is that the hardware adresses of the slaves must be in the correct order. That means that MCP1 must have hardware address 0x20, MCP2 must have address 0x21, etc
Your new folder has the following items in it:
The src/ folder in your new projects hold supplementing scripts as well as a couple of source files.
You will find files for the state machines, IO and there is the macros.h
with some useful macros including my REPEAT_MS() macro.
Within the src subfolder there is also a python script called addDate.py
. This script is always run before compiling and it generates date.cpp
and date.h
. Within date.cpp
there is one function which prints the hardcoded time on the serial monitor. If an upload will fail, you should be able to see that in an incorrect timestamp.
void printDate()
{
Serial.println("2021-11-23 16:16:01.401446") ;
}
If you have chosen to copy modules with the project those will also be inside the src folder.