Skip to content

The comparator machine

Tinkerspy edited this page Jul 2, 2016 · 11 revisions

This state machine monitors an analog input with a configurable sample period and fires off a callback whenever one of a list of thresholds are crossed. Optionally keeps a moving average to smooth out peaks and troughs.

Shapes

  • skip()

Synopsis

#include <Automaton.h>

Atm_comparator cmp;

void cmp_callback( int idx, int v, int up ) {
  // Do something when one of the thresholds is crossed
  Serial.print( "Value: " );
  Serial.println( cmp.state() );
}

void setup() {
  Serial.begin( 9600 );
  static uint16_t threshold_list[] = 
    { 100, 200, 300, 400, 500, 600, 700, 800, 900, 1000 }; 

  cmp.begin( A0, 50 )
    .threshold( threshold_list, sizeof( threshold_list ) )
    .onChange( cmp_callback );
}

void loop() {
  automaton.run();
}

Atm_comparator & begin( int attached_pin, int samplerate )

Attaches the comparator to an analog input pin and sets the sample period. The sample period is in milliseconds per sample.

void cmp_callback( int idx, int v, int up ) {
  // Do something when one of the thresholds is crossed
}

void setup() {
  ...
  cmp.begin( A0, 50 )
    .threshold( threshold_list, sizeof( threshold_list ) )
    .onChange( cmp_callback, 99 )
  ...
}

The callback has 3 arguments:

Argument Function
idx The idx value passed to the onChange method (in the example here: 99)
v The index of the threshold that was crossed
up The direction in which the threshold was crossed (1 = up, 0 = down)

The current value of the input can be accessed with the state() method.

Atm_comparator & threshold( uint16_t * v, uint16_t size, bool catchUp = false )

Sets a list of thresholds to monitor. If the measured analog input crosses one of these thresholds the callback is called. Arguments are a pointer to a list of 16 bit unsigned integers and the size of the list.

void setup() {
  static uint16_t threshold_list[] = 
    { 100, 200, 300, 400, 500, 600, 700, 800, 900, 1000 }; 

    cmp.begin( A0, 50 )
      .threshold( threshold_list, sizeof( threshold_list ), true )
      .onChange( cmp_callback, 99 );
}

Declare the list as a global variable or as static. The threshold list can hold a maximum of 64 entries.

If the optional catchUp argument is set to true the state machine will catch up to the current value as soon as the state machine starts cycling. It does this by calling your callback as many times as necessary if the current value is larger than at least one threshold value. So in the above situation, if you have a thermistor attached to A0 and its current value is 511, the callback will be called 5 times in quick succession, once each for the 100, 200, 300, 400 and 500 threshold values. If catchUp is set to false or omitted from the threshold() call, when the state machine starts, the callback will not be called until a threshold is crossed.

Compatibility note: Note that, unlike in previous versions, the size argument now takes the byte size of the array!

Atm_comparator & onChange( bool status, {connector}, {connector-arg} )

Specify a machine or callback to be triggered whenever a threshold is crossed in either the upward (status true) or downward (status false) direction.

void setup() {
  static uint16_t threshold_list[] = 
    { 100, 200, 300, 400, 500, 600, 700, 800, 900, 1000 }; 

  cmp.begin( A0, 50 )
    .threshold( threshold_list,  sizeof( threshold_list ), true )
    .onChange( true, step, step.EVT_STEP )
    .onChange( false, step, step.EVT_BACK );
}

Atm_comparator & onChange( {connector}, {connector-arg} )

Specifies a machine or callback to be triggered whenever the comparator machine crosses any threshold in any direction.

#include <Automaton.h>

Atm_comparator cmp;

void setup() {
  static uint16_t threshold_list[] = 
    { 100, 200, 300, 400, 500, 600, 700, 800, 900, 1000 }; 

  Serial.begin( 9600 );
  cmp.begin( A0, 50 )
    .threshold( threshold_list,  sizeof( threshold_list ), true )
    .onChange( [] ( int idx, int v, int up ) {
       Serial.println( threshold_list[v] );
    });
}

void loop() {
  automaton.run();
}

Atm_comparator & average( uint16_t * v, uint16_t size )

Connects an averaging buffer to the state machine. This will cause the state machine to monitor a moving average instead of the momentary value. Tune the size of this buffer and the sample rate to get the smoothing behavior you want.

uint16_t avgbuffer[256];

void setup() {
  static uint16_t threshold_list[] = 
    { 100, 200, 300, 400, 500, 600, 700, 800, 900, 1000 }; 

  cmp.begin( A0, 50 )
    .threshold( threshold_list,  sizeof( threshold_list ), true )
    .average( avgbuffer, sizeof( avgbuffer ) )
    .onChange( cmp_callback );

}

The buffer variable is used as a ring buffer to store the sampled values. The value the comparator uses to check the thresholds is computed as the average of the values in the ring buffer. The call to average() fills up the ringbuffer with samples so the average will make sense right from the start.

Compatibility note: Note that, unlike in previous versions, the size argument now takes the byte size of the array!

int state( void )

Returns the current value (after optional averaging) of the analog input.

Atm_comparator & trace( Stream & stream )

To monitor the behavior of this machine you may log state change events to a Stream object like Serial.

Serial.begin( 9600 );
cmp.trace( Serial );

WARNING: This machine changes state for every sample taken and will produce a lot of log output quickly

Clone this wiki locally