// Rename pins for clarity
#define CWOUT 3 // output for clockwise rotation
#define CCWOUT 4 // output for counterclockwise rotation
#define LEVELIN 5 // float switch to indicate water level
#define STOP 2 // button to pause or resume cycle
#define SHORT 7 // button to run short wash cycle
#define MEDIUM 6 // button to run medium length wash cycle
#define LONG 8 // button to run long wash cycle
#define FILLOPEN 9 // output to open fill valve
#define DRAINOPEN 10 // output to open drain valve
#define HSIN A0 // variable to track number of rotations through Hall sensor
const int hallvmax = 5 * 1023 / 5; // variable to track Hall sensor's output
unsigned long prevtime = 0;
unsigned long starttime = 0;
unsigned long stoptime1 = 0;
unsigned long now = 0;
volatile unsigned long stoptime0 = 0;
bool run = false; // indicates button pressed
bool stalled = false;
int rotations = 0;
volatile bool interrupt = false; // variable to track start/stop
const int pausetime = 1000; // time between spinning
int turns = 120; // number of back and forth rotations for normal wash
const int checktime = 10000; // time in ms between attempts to restart if motor stalled
const int stalltime = 2000; // max reasonable time for the drum to make one rotation
const int cyclenum = 3; // total number of wash/rinse cycles
const unsigned long draintime = 5000; // number of seconds to let water dain out
const int vclosetime = 6000; // time for valve to fully close
const unsigned long soaktime = 5000; // time to soak before washing (1 hr)
// Track start/stop button press
void stopstart(){
stoptime1 = millis(); //log time of button press
if (stoptime1 - stoptime0 > 500) {
interrupt = !interrupt; // toggle interrupt variable with button press
stoptime0 = stoptime1; // reset pause button timer
// prevtime = stoptime1; // reset rotations timer
/*if (interrupt) {
digitalWrite(CWOUT, LOW); // turn off motor if interrupted
digitalWrite(CCWOUT, LOW);
}*/
}
}
// Function to count rotations
void rcount() {
int trigger = analogRead(HSIN); // read in Hall sensor value
now = millis(); // mark time
stoptime1 = now;
if (now - prevtime > stalltime){
interrupt = true;
stalled = true;
} else if (abs(trigger - hallvmax) < 3) {
prevtime = now; // store last time triggered
rotations++; // mark an extra rotation when sensor reads in max value
delay(300); // wait 300 ms to prevent double counting
}
}
// Function to check periodically whether motor is still stalled
void unstall() {
delay(checktime); // wait prescribed interval before trying to start motor again
interrupt = false;
stalled = false;
prevtime = millis();
}
void rotate(int times) {
for (int i = 0; i < times; i+= (1-interrupt)) { // do the cycles a given number of times and stall if interrupt is triggered
if (interrupt == false) {
rotations = 0; // reset rotations counter
prevtime = millis(); // reset stalled motor timer
do {
stoptime1 = millis();
digitalWrite(CCWOUT, HIGH); // power transistor to counterclockwise relay
rcount(); // keep track of rotations
if (stalled) {
digitalWrite(CCWOUT, LOW); // cut motor power if stalled
unstall(); // try to restart motor if stalled
}
} while (rotations < 2 && interrupt == false);
digitalWrite(CCWOUT, LOW); // turn off motor power
stoptime1 = millis();
if (interrupt == false) {
delay(5); // wait 0.5 seconds before switching directions
rotations = 0; // reset rotations counter again IF NOT PAUSED
}
}
if (interrupt == false) {
prevtime = millis(); // reset stalled motor counter
do {
stoptime1 = millis();
digitalWrite(CWOUT, HIGH); // power transitor to clockwise relays
rcount(); // keep track of rotations
if (stalled) {
digitalWrite(CWOUT, LOW); // turn off motor power if stalled
unstall(); // try to restart motor
}
} while (rotations < 2 && interrupt == false);
digitalWrite(CWOUT, LOW); // turn off motor power again
if (interrupt == false) {
delay(500); // for 0.5 seconds
rotations = 0;
}
}
stoptime1 = millis();
}
}
void setup() {
// put your setup code here, to run once:
// Set up pins to provide needed outputs and inputs
pinMode(CWOUT, OUTPUT);
pinMode(CCWOUT, OUTPUT);
pinMode(SHORT, INPUT_PULLUP);
pinMode(MEDIUM, INPUT_PULLUP);
pinMode(LONG, INPUT_PULLUP);
pinMode(STOP, INPUT_PULLUP);
pinMode(LEVELIN, INPUT_PULLUP);
pinMode(FILLOPEN, OUTPUT);
pinMode(DRAINOPEN, OUTPUT);
pinMode(HSIN, INPUT);
attachInterrupt(digitalPinToInterrupt(STOP), stopstart, FALLING); // set up stop pin to interrupt everything else
}
void loop() {
// put your main code here, to run repeatedly:
// Fill drum
if (digitalRead(SHORT) == LOW) {
turns = 1;
run = true;
} else if (digitalRead(MEDIUM) == LOW) {
turns = 2;
run = true;
} else if (digitalRead(LONG) == LOW) {
turns = 3;
run = true;
}
if (run == true) {
for (int j=0; j < cyclenum; j += (1-interrupt)) {
do {
digitalWrite(FILLOPEN, HIGH); // open fill valve to fill drum
} while (digitalRead(LEVELIN) == HIGH); // stop filling when float switch closes
digitalWrite(FILLOPEN, LOW);
delay(vclosetime); // wait for valve to close
// Briefly agitate and let sit first time only
if (j == 0){
// Rotate back and forth
rotate(5);
starttime = millis(); // log time
while (millis() - starttime < soaktime);
}
// Rotate back and forth
rotate(turns);
starttime = millis(); // log time
while (millis() - starttime < draintime) {
digitalWrite(DRAINOPEN, HIGH); // open drain valve to drain drum
}
digitalWrite(DRAINOPEN, LOW);
delay(vclosetime); // wait for valve to close
}
run = false; // stop washing until next button press
}
}