Hi all, I’m working on a candy machine for halloween. Basically when someone touches the button, it dispenses a piece of candy, then runs through a 10 for loop as a ‘cooldown’ (the seconds count down on an LCD) to make sure kids don’t spam it. The problem is, I have two dispensers, so if one dispenser is in its ‘cooldown’ phase, if the other dispenser’s button is pressed, I want candy to dispense out of it. It’s ok if the cooldown is terminated in the process. I’ve tried countless ways with booleans, to if-statements inside of the for loop but I can’t test to see if the second button is touched while one dispenser’s cooldown phase is running. Here is my for-loop cooldown:
By making use of millis timers, you can create non-blocking delays, so both can run simultaneously. Alternatively, software timers can be used that trigger each second, and are topped when reaching the cool down time.
It turns out this works, but after you press the button it’s not being displayed on the lcd.
int mill = millis();
mill = 0;
if (millis()-lastPublish > delaySeconds) {
// Remember when we published
lastPublish = millis();
lcd.clear();
int time = 11-lastPublish/1000;
if(time > -1){
lcd.print("Test:" + String(time));
}
}
That’s the cool down part, but this is the whole button touch part. For some reason the cool down isn’t displayed and the lcd is going blank:
if(but1state == HIGH){//fist motor
digitalWrite(1, HIGH);
lcd.clear();
lcd.print(" Candy!");
Particle.publish("Touched", 0, 60, PRIVATE);
Serial.print("********************Touched!");
myStepperRight.step(stepsDown);
lcd.clear();
lcd.print(" Candy coming!");
delay(1800);
myStepperRight.step(-stepsUp);
delay(200);
//this is where the cool down is:
int mill = millis();
mill = 0;
if (millis()-lastPublish > delaySeconds) {
// Remember when we published
lastPublish = millis();
lcd.clear();
int time = 11-lastPublish/1000;
if(time > -1){
lcd.print("Test:" + String(time));
}
}
@BulldogLowell@Moors7
It compiles fine. The time is just from the millis(). Is that why it doesn´t print? I forgot to mention that I created a blank lcd program, and the only thing I had it printing, was the cooldown, and it prints on the lcd just fine. So in the program, it just must be skipping over it for some reason. I have no idea why it would be skipping…
It looks like you never close the original if statement for the button press. I'm assuming you are trying to do everything inside of that original if statement which will only run while the button is pressed.
Maybe closing that bracket will do what you are trying to do, it would be a lot easier to use two FSM (state machines) to handle the two sperate dispensers.
Its 3:30 and i need sleep i[ll explain more fully tomorrow
I always have a check to see if mills() < lastPublish to handle the case wherein millis() has rolled over. This will happen approximately every 49 days and I believe I’ve had devices operate without rebooting for that period of time. Without the check, the code will only work for the first 49 days and then never work again until the device reboots.
Interesting clarification. Thank you. However, I often see, as above, integer variables being used and I’m assuming (yep, bad practice) that if either variable is signed, the operation will be a signed. I’ll be careful to follow your technique in the future and keep my code a bit cleaner.
Well, when an expression contains both signed and unsigned int values, the signed int will be automatically converted to unsigned int, therefore the result will not be less than 0.
you can test that:
uint32_t x = 32;
int32_t y = 33;
Serial.println((x-y));
#include "elapsedMillis.h";
elapsedMillis elapsedTime;
typedef enum{
WAITING = 0,
DISPENSING_1,
DISPENSING_2,
COOLDOWN_INIT,
COOLDOWN_PRINT,
COOLDOWN_WAIT,
COOLDOWN_END
} dispensor_state_t;
dispensor_state_t rightDispensor = WAITING;
int countDown=11;
void button1StateMachine(){
switch(rightDispensor){
case WAITING:
// BUTTON DEBOUNCING SHOULD BE HERE, ALSO MAYBE USE ACTIVE LOW
if(but1State == HIGH){
rightDispensor=DISPENSING_1;
}
break;
case DISPENSING_1:
myStepperRight.step(stepsDown);
lcd.clear();
lcd.print(" Candy coming!");
elapsedTime=0;
rightDispensor=DISPENSING_2;
break;
case DISPENSING_2:
if(elapsedTime > 1800){ // if it has been longer than 1800 ms set the countDown to 11 seconds and move to the cooldown print state
myStepperRight.step(-stepsUp);
elapsedTime=0;
rightDispensor=COOLDOWN_INIT;
}
break;
case COOLDOWN_INIT:
if(elapsedTime > 200){
rightDispensor=COOLDOWN_PRINT;
}
case COOLDOWN_PRINT:
char buffer[20];
sprintf(buffer, "Test %d", countDown);
lcd.clear();
lcd.print(buffer);
// if countdown is not at zero move to wait, otherwise go back to the original state waiting for a new button press
if(countDown>0){
elapsedTime=0;
rightDispensor=COOLDOWN_WAIT;
}
else{
rightDispensor=COOLDOWN_END;
}
break;
case COOLDOWN_WAIT:
if(elapsedTime > 1000){ // if it has been 1 second decrease coundown time by one and go back to print
countDown-=1;
rightDispensor=COOLDOWN_PRINT;
}
break;
case COOLDOWN_END:
countDown=11;
rightDispensor=WAITING;
break;
}
}
void setup(){
}
void loop(){
button1StateMachine();
//button2StateMachine();
}