// four state FSM version
// the posted vesrion is in a tab over there -->
// https://wokwi.com/projects/400042875593055233
// now https://wokwi.com/projects/400052399351512065 with doorDoor
// and now https://wokwi.com/projects/400141987251449857 with FSM loop
// https://forum.arduino.cc/t/one-if-statement-overwriting-another-if-statement/1269008
// now replacing the loop
# include "doorSim.h"
const int upsensPin = 4; // UP SENSOR tells door is open
const int downsensPin = 5; // DOWN SENSOR tells door is down
const int buttonPin = 6; // CONTROL SWITCH
const int powerrelayPin = 9; // green power relay energize
const int uprelayPin = 10; // blue up relay energize
const int downrelayPin = 11; // orange down relay energize
// not used yet.
# define ENERGIZED = HIGH; // one stop shop for changining relay sense
# define OFF = LOW; // one stop shop for changining relay sense
int buttonState;
int previousButtonState;
enum State {UP, MOVING_DOWN, DOWN, MOVING_UP, NONE} state = DOWN;
char *sTags[] = {"UP", "going DOWN", "DOWN", "going UP", "NONE"};
void setup() {
Serial.begin(9600);
Serial.println("\nFSM door control world!\n");
pinMode(buttonPin, INPUT_PULLUP);
pinMode(upsensPin, INPUT_PULLUP); //... because switches
pinMode(downsensPin, INPUT_PULLUP); //... because switches
previousButtonState = digitalRead(buttonPin) == LOW; // read so we don't get spurious activity
pinMode(powerrelayPin, OUTPUT);
pinMode(uprelayPin, OUTPUT);
pinMode(downrelayPin, OUTPUT);
allStop();
// here's where the limit swtiches coulr be checked to acquire the current door position
// and set the appropriate state (and direction if in between)
setupSimulation();
}
unsigned long now; // millis for the entire not-blocked loop
void loop() {
//... housekeeping
now = millis();
advanceSimulation();
static State lastState = NONE;
if (lastState != state) {
lastState = state;
Serial.print("state is "); Serial.println(sTags[state]);
}
// INPUT
bool doorAtBottom = digitalRead(downsensPin) == LOW;
bool doorAtTop = digitalRead(upsensPin) == LOW;
if (doorAtBottom && doorAtTop) Serial.println("IMPOSSIBLE ERROR!");
bool buttonPress = false;
buttonState = digitalRead(buttonPin) == LOW; // true pressed
if (buttonState != previousButtonState) {
previousButtonState = buttonState;
if (buttonState) {
buttonPress = buttonState;
Serial.println(" button got pressed!");
}
}
// PROCESS
switch (state) {
case UP :
if (buttonPress) state = MOVING_DOWN;
break;
case MOVING_DOWN :
if (doorAtBottom) state = DOWN;
if (buttonPress) state = MOVING_UP;
break;
case DOWN :
if (buttonPress) state = MOVING_UP;
break;
case MOVING_UP :
if (doorAtTop) state = UP;
if (buttonPress) state = UP;
break;
case NONE :
default :
Serial.println("whose default is this!");
break;
}
// OUTPUT
if (state == MOVING_DOWN) {
doorGoDown();
}
else if (state == MOVING_UP) {
doorGoUp();
}
else {
allStop();
}
delay(20); // poor man's debounce, who cares?
}
// talk to the door motors, yeah?
void doorGoUp()
{
// Serial.println("turn on and go UP");
digitalWrite(downrelayPin, HIGH);
digitalWrite(uprelayPin, LOW);
digitalWrite(powerrelayPin, LOW);
}
void doorGoDown()
{
// Serial.println("turn on and go DOWN");
digitalWrite(uprelayPin, HIGH);
digitalWrite(downrelayPin, LOW);
digitalWrite(powerrelayPin, LOW);
}
void allStop()
{
// Serial.println("turn off");
digitalWrite(powerrelayPin, HIGH);
digitalWrite(uprelayPin, HIGH);
digitalWrite(downrelayPin, HIGH);
}
/* no, it's in tabs now */
# if 0
// below this line are functions to produce a simulation of the physical process
// it places the sensor output on the processOutput pin, which
// can be fed directly to the processInput pin for measurement and monitoring
// initiate the process with the goose button
// control the speed for testing with the slide fader at processSpeedControl
# include <Adafruit_NeoPixel.h>
# define PIN 7 // the pin
# define NPIXELS 16 // number of LEDs on strip
# define UPA A0 // make it go up manually
# define DOWNA A3 // make it go down manually
# define upLED A2 // on (LOW) when door is at extreme
# define downLED A1 // on (LOW) when door is at other extreme
# define PRESST LOW
Adafruit_NeoPixel doorStrip(NPIXELS, PIN, NEO_GRB + NEO_KHZ800);
static int doorPostition; // pixel number for door traveler
void setupSimulation()
{
doorStrip.begin();
doorStrip.fill(0x606060, 0, NPIXELS);
doorStrip.setPixelColor(1, 0xff00ff);
doorStrip.show();
delay(500);
doorStrip.fill(0x606060, 0, NPIXELS);
doorStrip.show();
delay(500);
pinMode(UPA, INPUT_PULLUP);
pinMode(DOWNA, INPUT_PULLUP);
pinMode(upLED, OUTPUT);
pinMode(downLED, OUTPUT);
doorPostition = 0;
doorStrip.setPixelColor(doorPostition, 0xff0000);
doorStrip.show();
}
// if the up motor is powered, move the door up
// if the down motor is powered, move the door down
# define SPEED 200 // milliseconds per step
# define ON LOW
# define OFF HIGH
void advanceSimulation()
{
static unsigned long timer;
if (timer && (now - timer < SPEED)) return;
timer = now;
// later the real outputs will hook into the buttons for automatic control
bool goUp = digitalRead(UPA) == PRESST;
bool goDown = digitalRead(DOWNA) == PRESST;
// plausible request?
if (goUp && goDown) {
Serial.println("up and down at once impossible.");
goUp= false;
goDown = false;
}
// do it one step closer
if (goUp) {
doorStrip.setPixelColor(doorPostition, 0x606060);
doorPostition++;
if (doorPostition >= NPIXELS) {
doorPostition = NPIXELS - 1; // door fully opened
}
doorStrip.setPixelColor(doorPostition, 0xff0000);
}
if (goDown) {
doorStrip.setPixelColor(doorPostition, 0x606060);
doorPostition--;
if (doorPostition < 0) {
doorPostition = 0; // door fully closed
}
doorStrip.setPixelColor(doorPostition, 0xff0000);
}
// update limit switches output
if (doorPostition == 0) {
digitalWrite(downLED, ON);
digitalWrite(upLED, OFF);
}
else if (doorPostition == NPIXELS - 1) {
digitalWrite(upLED, ON);
digitalWrite(downLED, OFF);
}
else {
digitalWrite(upLED, OFF);
digitalWrite(downLED, OFF);
}
doorStrip.show();
}
# endif
BUTTON
POWER---UP---DOWN
LIMIT SWITCHES ->
MOTOR CONTROL ->