Commit 110ff0b2 authored by Jan Grewe's avatar Jan Grewe
Browse files

add LED toggle via double-click

parent d9f1c342
// Configuration
#define CYCLES 1
#define CYCLES 2
#define ROT_R 2
#define ROT_L 2
#define PAUSE_MIN 2
......@@ -23,51 +23,49 @@ using namespace ace_button;
enum StateType
{
W_INIT, // 0
W_SETUP, // 1
W_IDLE, // 2
W_CYCLE, // 3
W_LEFT, // 4
W_RIGHT, // 5
W_STOP, // 6
W_PAUSE // 7
W_IDLE, // 0
W_CYCLE, // 1
W_RIGHT, // 2
W_LEFT, // 3
W_STOP, // 4
W_PAUSE // 5
};
AccelStepper winder(8, 8, 10, 9, 11, false);
JLed pwr_led = JLed(LED_PIN).FadeOn(1000);
AceButton pwr_sw(SW_PIN);
int TargetPos = 0;
long StartTime = 0;
StateType WState = W_IDLE;
int Rotations = CYCLES;
StateType WState = W_INIT;
int Restart = false;
int Start = false;
int Continue = false;
int StopWind = false;
int WaitMin = PAUSE_MIN;
int Stop = false;
int LedOn = true;
int LastMinute = false;
int TargetPos = 0;
long StartTime = 0;
void handleSwEvent(AceButton *, uint8_t, uint8_t);
void setup()
{
ButtonConfig *buttonConfig = pwr_sw.getButtonConfig();
WState = W_SETUP;
Serial.begin(9600);
Serial.begin(115200);
pinMode(SW_PIN, INPUT_PULLUP);
ButtonConfig *buttonConfig = pwr_sw.getButtonConfig();
buttonConfig->setEventHandler(handleSwEvent);
buttonConfig->setFeature(ButtonConfig::kFeatureClick);
buttonConfig->setFeature(ButtonConfig::kFeatureDoubleClick);
buttonConfig->setFeature(ButtonConfig::kFeatureLongPress);
buttonConfig->setFeature(ButtonConfig::kFeatureSuppressAfterLongPress);
buttonConfig->setFeature(ButtonConfig::kFeatureSuppressAfterDoubleClick);
buttonConfig->setFeature(ButtonConfig::kFeatureSuppressClickBeforeDoubleClick);
buttonConfig->setClickDelay(500);
winder.setMaxSpeed(ROT_SPEED);
winder.setAcceleration(ROT_ACCEL);
WState = W_IDLE;
Serial.println(">>Winder Ready<<");
Serial.println("-- Winder: Ready");
}
void loop()
......@@ -75,42 +73,38 @@ void loop()
StateType old_state = WState;
pwr_sw.check();
pwr_led.Update();
switch (WState)
{
case W_IDLE:
if (Restart || Continue)
if (Start || Continue)
{
Start = false;
StartTime = millis();
winder.enableOutputs();
Rotations = CYCLES;
WState = W_CYCLE;
Restart = false;
}
StartTime = millis();
winder.enableOutputs();
Rotations = CYCLES;
break;
case W_CYCLE:
pwr_led.Blink(1000, 500).Forever();
if (LedOn)
{
pwr_led.Reset();
pwr_led.Blink(1000, 200).Forever();
}
if (StopWind)
if (Stop)
{
WState = W_STOP;
}
else if ((Rotations--) > 0)
{
Serial.print("Counter : ");
Serial.print("## Cycles until Pause: ");
Serial.println(Rotations);
#if (ROT_R > 0)
WState = W_RIGHT;
TargetPos -= (ROT_R * ROT_STEPS); //-4096; // Une rotation complète avec 2048 pas (1 tour environ 4.5sec)
winder.moveTo(TargetPos);
#elif (ROT_L > 0)
WState = W_LEFT;
TargetPos += (ROT_R * ROT_STEPS); //-4096; // Une rotation complète avec 2048 pas (1 tour environ 4.5sec)
TargetPos -= (ROT_R * ROT_STEPS);
winder.moveTo(TargetPos);
#endif
}
else
{
......@@ -123,23 +117,16 @@ void loop()
{
winder.run();
}
else if (StopWind)
else if (Stop)
{
WState = W_STOP;
}
#if (ROT_L > 0)
else
{
WState = W_LEFT;
TargetPos += (ROT_R * ROT_STEPS); //-4096; // Une rotation complète avec 2048 pas (1 tour environ 4.5sec)
TargetPos += (ROT_R * ROT_STEPS);
winder.moveTo(TargetPos);
}
#else
else
{
WState = W_CYCLE;
}
#endif
break; // case W_RIGHT
case W_LEFT:
......@@ -147,7 +134,7 @@ void loop()
{
winder.run();
}
else if (StopWind)
else if (Stop)
{
WState = W_STOP;
}
......@@ -158,54 +145,58 @@ void loop()
break; // case W_LEFT
case W_STOP:
StopWind = false;
Stop = false;
winder.disableOutputs();
StartTime = millis();
WState = W_PAUSE;
if (Continue)
{
pwr_led.Breathe(5000).Forever();
Serial.println(">>Winder Stopped, will continue<<");
Serial.println("<< Winder: Stopped, waiting for next cycle");
WState = W_PAUSE;
if (LedOn)
{
pwr_led.Reset();
pwr_led.Breathe(5000).Forever();
}
}
else
{
Serial.println(">>Winder Stopped, will not continue<<");
Serial.println("<< Winder: Stopped, will not restart");
if (LedOn)
{
pwr_led.Reset();
pwr_led.On();
}
WState = W_IDLE;
}
break; // case W_STOP
case W_PAUSE:
{
long temp = millis() - StartTime;
long delta = 60L * 1000L;
static int last_min = false;
if (Restart)
{
WState = W_IDLE;
}
else if (Continue && temp > (delta * long(PAUSE_MIN))) // ms per minute
if (Start)
{
WState = W_IDLE;
last_min = false;
Serial.print("d_time : ");
Serial.print(temp);
Serial.print(" > ");
Serial.println(delta);
}
else if ((!last_min) && (temp > (delta * long(PAUSE_MIN - 1)))) // ms per minute
// run once, 1 minute before PAUSE_MIN elapses
else if ((!LastMinute) && (temp > (delta * long(PAUSE_MIN - 1))))
{
Serial.println("Last Minute ...");
if (Continue)
Serial.println("<< Winder: Restarting in 1 minute");
if (Continue && LedOn)
{
pwr_led.Reset();
pwr_led.Breathe(1000).Forever();
}
last_min = true;
LastMinute = true;
}
}
break; // W_PAUSE
// PAUSE_MIN has elapsed && Continue
else if (Continue && temp > (delta * long(PAUSE_MIN)))
{
LastMinute = false;
WState = W_IDLE;
}
break; // W_PAUSE
case W_INIT:
case W_SETUP:
default:
winder.disableOutputs();
break;
......@@ -214,62 +205,101 @@ void loop()
if (WState != old_state)
{
Serial.print("STATE : ");
Serial.print("-- Changing State: ");
Serial.print(old_state);
Serial.print(" >> ");
Serial.print(" -> ");
Serial.println(WState);
}
pwr_led.Update();
} // loop
void handleSwEvent(AceButton *button, uint8_t eventType,
uint8_t buttonState)
void handleSwEvent(AceButton *button, uint8_t eventType, uint8_t buttonState)
{
switch (eventType)
{
case AceButton::kEventLongPressed:
Serial.println("SW LONG");
pwr_led.Reset();
case AceButton::kEventClicked:
switch (WState)
{
case W_LEFT:
case W_RIGHT:
case W_IDLE:
case W_PAUSE:
Serial.println(">>Stop Winding<<");
StopWind = true;
Continue = false;
pwr_led.On();
Serial.println(">> Click: Start Winding");
Stop = false;
Start = true;
Continue = true;
WState = W_IDLE;
break;
default:
break;
}
break;
case AceButton::kEventClicked:
Serial.println("SW CLICK");
pwr_led.Reset();
Continue = true;
StopWind = false;
case AceButton::kEventLongPressed:
switch (WState)
{
case W_IDLE:
Serial.println(">>Start Winding<<");
WState = W_CYCLE;
break;
case W_LEFT:
case W_RIGHT:
case W_PAUSE:
Serial.println(">>Restart Winding<<");
Restart = true;
Serial.println(">> LongPress: Stop Winding");
pwr_led.Reset();
pwr_led.Blink(100, 500).Forever();
Stop = true;
Continue = false;
break;
default:
break;
}
break;
case AceButton::kEventDoubleClicked:
pwr_led.Reset();
if (LedOn)
{
Serial.println(">> DoubleClick: LED Disabled");
pwr_led.Stop();
LedOn = false;
}
else
{
Serial.println(">> DoubleClick: LED Enabled");
LedOn = true;
switch (WState)
{
case W_IDLE:
Serial.println("<< LED: On");
pwr_led.On();
break;
case W_PAUSE:
if (!LastMinute)
{
Serial.println("<< LED: Breathe Slow");
pwr_led.Breathe(5000).Forever();
}
else
{
Serial.println("<< LED: Breathe Fast");
pwr_led.Breathe(1000).Forever();
}
break;
case W_LEFT:
case W_RIGHT:
Serial.println("<< LED: Blink");
pwr_led.Blink(1000, 200).Forever();
break;
default:
Serial.println("<< LED: WTF?");
pwr_led.Blink(50, 50).Forever();
break;
}
}
break;
default:
//Serial.print("SW: ");
//Serial.print(eventType);
//Serial.print(", ");
//Serial.println(buttonState);
break;
}
}
......@@ -5,28 +5,32 @@ This allows you to control the cycles of a stepper motor with a momentary switch
## Using the Winder
On powerup, the LED will fade on and the winder will be in standby, waiting for a button press.
The button knows two types of inputs:
* **press**, which is input shorter than 500ms
The button knows three types of inputs:
* **click**, which is input shorter than 500ms
* **long-press**, which is input longer than 500ms
* **double-click**
The winder works in cycles, which means it will do the configured number of cycles (`CYCLES`), with each cycle consisting of a configured number of rotations in each direction (`ROT_R`, `ROT_L`), then wait for the
configured amount of minutes (`PAUSE_MIN`), and eventually restart the cycles. This will be refered to as "_winding_".
### The very short version of a manual:
* press the button to start winding
* click the button to start winding
* long-press the button to stop winding
* double-click to toggle the LED (on/off)
### Switching Modes (a.k.a the slightly longer version of a manual)
* When pressing the button while the winder is in standby, it will start winding.
### Switching States (a.k.a the slightly longer version of a manual)
* When clicking the button while the winder is in standby, it will start winding.
* When long-pressing the button while it is winding, it will return to the home position and stop winding.
* When long-pressing the button while it is waiting for the next cycle, it will stop winding.
* When pressing the buttong while it is waiting for the next cycle, it will start winding again immediately.
* When clicking the button while it is waiting for the next cycle, it will start winding again immediately.
* When double-clicking the button in any state, the LED will turn off if it was on, or on (in the appropriate status mode) if it was off.
## LED Status
* **Solid**: Standby
* **Blinking** (1s on, 0.5s off): Winding
* **Slow Breathing**: Waiting for next cycles
* **Fast Breathing**: Next cycle will start in <1 minute
* **Solid**: Standby / Manually Stopped
* **Slow Blinking** (1s on, 0.2s off): Winding
* **Fast Blinking** (0.1 on, 0.5s off): Stopping, returning to home position (when manually stopped)
* **Slow Breathing**: Paused, waiting for next cycles
* **Fast Breathing**: Paused, the next cycle will start in <1 minute
## Wiring Diagram
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment