#define MAX_INTERVAL 200 // max time a LED can be off while blinking, in ms
#define STABILITY_THRESHOLD 50 // time the input state must be stable before movement starts, in ms
#define DO_NOTHING 0x00
#define MOVE_UP 0x01
#define MOVE_DOWN 0x02
#define MOVE_FAST 0x04
#define MOVE_UPFAST (MOVE_UP | MOVE_FAST)
#define MOVE_DOWNFAST (MOVE_DOWN | MOVE_FAST)
// what to do for each combination of inputs; any combination of 2 or more active inputs means
// do nothing, only the combinations with exactly one active input, except the middle (neatral) input
// result in movement. These are positions 0x01 (1) for up fast, 0x02 (2) for up slow, 0x04 (4) for neutral,
// 0x08 (8) for down slow, 0x10 (16) for down fast. Note the array index starts at 0
const unsigned char Actions[ 32 ] =
{ DO_NOTHING, MOVE_UPFAST, MOVE_UP, DO_NOTHING, DO_NOTHING, DO_NOTHING, DO_NOTHING, DO_NOTHING, // 0..7
MOVE_DOWN, DO_NOTHING, DO_NOTHING, DO_NOTHING, DO_NOTHING, DO_NOTHING, DO_NOTHING, DO_NOTHING, // 8..15
MOVE_DOWNFAST, DO_NOTHING, DO_NOTHING, DO_NOTHING, DO_NOTHING, DO_NOTHING, DO_NOTHING, DO_NOTHING, // 16..23
DO_NOTHING, DO_NOTHING, DO_NOTHING, DO_NOTHING, DO_NOTHING, DO_NOTHING, DO_NOTHING, DO_NOTHING }; // 24..31
unsigned short InputCounters[ 5 ] = { 0, 0, 0, 0, 0 };
unsigned char ReadInputs, FilteredInputs, PreviousInputs = 0, AutomaticMode = 0, JoystickInput;
unsigned long StabilityCount = 0, ActivityCounter = 0;
void setup()
{
// pin 0 unused; causes problems when loading new software
pinMode( 1, OUTPUT ); // LED for automatic mode
pinMode( 2, INPUT ); // input top LED
pinMode( 3, INPUT );
pinMode( 4, INPUT );
pinMode( 5, INPUT );
pinMode( 6, INPUT ); // input bottom LED
pinMode( 7, OUTPUT ); // move UP output
pinMode( 8, OUTPUT ); // move DOWN output
pinMode( 9, OUTPUT ); // move FAST output (low=fast)
pinMode( 10, OUTPUT ); // Error output
pinMode( 11, INPUT ); // pushbutton for automatic mode
pinMode( 12, INPUT ); // joystick UP
pinMode( 13, INPUT ); // joystick DOWN
pinMode( A0, OUTPUT ); // Debugging status LEDs
pinMode( A1, OUTPUT );
pinMode( A2, OUTPUT );
pinMode( A3, OUTPUT );
pinMode( A4, OUTPUT );
pinMode( A5, OUTPUT );
}
void loop()
{
unsigned char Index;
FilteredInputs = 0;
ReadInputs = ( digitalRead( 2 ) ) | ( digitalRead( 3 ) << 1 ) | ( digitalRead( 4 ) << 2 ) | ( digitalRead( 5 ) << 3 ) | ( digitalRead( 6 ) << 4 );
// this loop monitors each input for recent activity; when an input is active, the timer for that inputs
// is set to MAX_INTERVAL, and starts counting down from there; when it reaches 0, the input is considered
// inactive. MAX_INTERVAL should be set slightly longer than the maximum time the LED for an input can be off
// when blinking
for( Index = 0; Index < 5; Index++ )
{
if( ReadInputs & ( 1 << Index ) )
InputCounters[ Index ] = MAX_INTERVAL;
if( InputCounters[ Index ] )
{
InputCounters[ Index ]--;
FilteredInputs |= 1 << Index;
}
// write each input filter status to a debug LED (A0 + 3 is the same as A3)
digitalWrite( A0 + Index, !InputCounters[ Index ] );
}
if( !FilteredInputs ) // if all timers have expired, not a single input active
ActivityCounter = 2000; // set timer for 2 seconds; only when signal is lost should all timers expire
if( ActivityCounter )
{
ActivityCounter--;
FilteredInputs = 0; // only after 2 seconds without any expired timers should the outputs become active
}
// now check if the input state has been stable for a number of successive cycles, to prevent movement
// when 2 LEDs are blinking, since one can always be detected slightly earlier or later than the other
// If current and previous input states are different, reset stability counter
if( PreviousInputs != FilteredInputs )
StabilityCount = STABILITY_THRESHOLD;
// now store the current input state for the next cycle
PreviousInputs = FilteredInputs;
// if stability counter has not yet reached the threshold, increment it, and force the input state to 0
// to prevent any movement
if( StabilityCount )
{
StabilityCount--;
FilteredInputs = 0;
}
// write Stability status to debug LED
digitalWrite( A5, !StabilityCount );
// write Error LED status; LOW when an error occured (LED with resistor to supply)
digitalWrite( 10, FilteredInputs );
JoystickInput = digitalRead( 12 ) | ( digitalRead( 13 ) << 1 ); // 0x01 = UP, 0x02 = DOWN
if( JoystickInput )
AutomaticMode = 0;
else
if( digitalRead( 11 ) ) // pushbutton for automatic mode
AutomaticMode = 1;
if( AutomaticMode )
{
// lookup what to do for this state and write to outputs
digitalWrite( 7, Actions[ FilteredInputs ] & MOVE_UP );
digitalWrite( 8, Actions[ FilteredInputs ] & MOVE_DOWN );
digitalWrite( 9, !( Actions[ FilteredInputs ] & MOVE_FAST ) );
}
else
{
digitalWrite( 7, JoystickInput == 0x01 ); // valve UP when joystick UP is active (and DOWN isn't)
digitalWrite( 8, JoystickInput == 0x02 ); // valve UP when joystick DOWN is active (and UP isn't)
digitalWrite( 9, 0 ); // fast mode
}
digitalWrite( 1, AutomaticMode );
delay(1); // actual loop interval will be slightly longer, because it also takes some time to execute
}