Thursday, November 8, 2018

Program Structure

OK then. Now here's some Architecture...

I've made a template file for the Arduino main program that uses the libraries and functions that we have so recently been discussing:

    http://www.etantdonnes.com/DATA/Arduino/template/template.ino

As you know, the Arduino system shields you from some of the nitty gritty by requiring only two methods:
  • setup() -- runs once at the beginning of time (after a reset);
  • loop() -- is run repeatedly thereafter;
In my template setup() calls methods to initialize messaging, any output devices that will be used, and the ADC and other inputs:

// the setup routine runs once when you press reset:
void setup()
{
    MessageTask_init();    // init the message system
    RunTask_init();        // init the output system
    ADCTask_init();        // init the input system

    return;
}
Where those methods are declared like this:

/** Do whatever necessary to initialize the message system
 */
void MessageTask_init()
{
    // everyone uses comms
    Serial.begin( 9600 );
    // set message terminator to newline for text input
    Serial.setMsgTerm('\n');
    return;
}

// a global system state, just for Sudhu...
//  actually... to keep track of what the system is doing
word runState;

/** Do whatever necessary to initialize the system output devices.
 */
void RunTask_init()
{
    // set output modes on pins
    pinMode( BPIN, OUTPUT );
    // initialize running state
    runState = 0;
    return;
}

/** Do whatever necessary to initialize the system input devices.
 */
void ADCTask_init()
{
    // set input modes on pins
    pinMode( APIN, INPUT_PULLUP );
    // start the ADC interrupt cycle
    analogRead( 0 );
    return;
}

A word about runState ... I insist on keeping track of the internal system state in order to execute sequences of behaviors and respond appropriately to inputs. So each of my programs has a global state variable which is manipulated by all the Task functions. The use of this will be more apparent if/when we get to the actual Variations Too code, but Sudhu was always teasing me about it so he gets credit here....


The loop() function does two things. Look for messages and post the MessageTask, and then do a pass through the scheduler's list of things to do. If any Tasks are ready to run, they get executed here, and then the scheduler() returns, allowing loop() to return, which then repeats itself. Note that interrupts will execute (except for brief elisions) throughout this, so new functions may be entered on the Task list at anytime.

// the loop() routine runs over and over and again forever:
void loop()
{
    // see if we have a new message and post the receive task
    postTask( 0, MessageTask, nMsg );
    // execute the schip task scheduler
    scheduler();    // schedule the world
    return;
}

The actual tasks that will be executed are declared like this:
 /** Task posted when there is a serial input message
 * @param nmsg -- ignored...
 */
void MessageTask( word nmsg )
{
    // read the message string including '\n' terminator
    // and execute user functions
    return;
}

/** Posted from ADCTask to do something with new sensor values
 *  sState -- condensed bitmap of stuff that happened
 */
void RunTask( word sState )
{
    // look at run and sensor States and do appropriate stuff
    return;
}

/** Task posted when ADC averaging gets a new set of values.
 **/
void ADCTask( word numADC )
{
    // rummage through input stuff and set flag bits in sState
    // execute RunTask(sState) after 0 millis (like real soon now)
    return;
}
 And the rest is, as they say, just implementing stuff....


We'll talk about some of that stuff anon.

No comments:

Post a Comment