Understanding multitasking structures

Hey all,

Thank you so much for being here to help each other grow, it is appreciated.

I have been on the steep end of the learning curve for a few days trying to get a coherent code complied. I can get individual steps to work, but once mashed together the flow seems to fall wayward. The last section i am stuck on is a simple time out for an LED. I can get it to come on with the time interval that it is to turn off. I can get nothing, or just get the lights to stay on, no matter how I have tried the code I cannot grasp the steps involved.

Bottom line..... when button pushed 3 times UVLED's turn on and need to stay on for 15 min, then shut off, or shut off when button push = 5 . I am close but jumbling this last bit of the code.
As it sits when button push = 3 the lights "flash" on/off 4000mills after button press, then repeats the "flash" every 4000mills.

I have put the uvLightsOut function at the bottom,


 
	// pin connections constant won't change:

const int buttonPin = 2;  // the pin that the pushbutton is attached to
const int ledPins[] ={8, 9, 10 };    //the pins that the ambient LED's are attached to
const int motorPin = 3;   //the pin the motor is attached to 
const int uvPin = 4;   // the pin that the UV LED's are attached to
//const int speakerPin = 5;  //TBA pin the attached connect to 


	// Button control Variables will change:

int buttonPushCounter = 0;  // counter for the number of button presses
int buttonState = 0;        // current state of the button
int lastButtonState = 0;    // previous state of the button


	// UV timeout settings
int ledState = LOW;
unsigned long uvPreviousMillis = 0;
const long uvTimeOut = 4000; //TBA 900000 (15 min) for final code
		
		//knight rider timing
unsigned long previousMillis = 0;
static long TIMER = 75;
int knightLight = 0;
int knightCounter = 1;

	  
void setup() {
 		 //knight rider setup start
  for (int p = 0; p < 3; p++) {
  pinMode(ledPins[p], OUTPUT);
}  		//knight rider setup end

	// Initialize button pin
  pinMode(buttonPin, INPUT_PULLUP);	// initialize the button pin as a input:

  	// initialize the uvLED's,motor and speaker as an output:

  pinMode(motorPin, OUTPUT);
  pinMode(uvPin, OUTPUT);
  //pinMode(speakerPin, OUTPUT); 
  Serial.begin(9600);	 // initialize serial communication:
}


void loop() {

  	// read the pushbutton input pin:
  buttonState = digitalRead(buttonPin);

 	 // compare the buttonState to its previous state
  if (buttonState != lastButtonState) {
   
   	// if the state has changed, increment the counter
   
    if (buttonState == HIGH) {
      	// if the current state is HIGH then the button went from off to on:
      buttonPushCounter++;
      Serial.print("Button Pushes");
      Serial.println(buttonPushCounter);
    } 
    }
    
  
  	// save the current state as the last state, for next time through the loop
  lastButtonState = buttonState;


  	// Controlling the Clicks
  
  if (buttonPushCounter ==1<=5) {   
   knightRider();   //one click turns on the ambient LED with effect  
   }
   
  if (buttonPushCounter == 2){
    digitalWrite(motorPin, HIGH);   //two cliks turns on the motor while ambient LED stays on
  }
  
  if (buttonPushCounter == 3){
  uvLightsOut();
  }				//three clicks turns on the uvLEDs while motor & ambient LEDs stays on
  
  if (buttonPushCounter == 4){
    //digitalWrite(speakerPin, HIGH);   //four clicks turns on speaker
      }
  
  if (buttonPushCounter == 5){
    digitalWrite(motorPin, LOW);
    digitalWrite(uvPin, LOW); 
   // digitalWrite(speakerPin, LOW);  //Five clicks turns all LED's, motor and speaker off
  }
  
  if(buttonPushCounter == 5)buttonPushCounter = 0;  //reset button counter to 0

}

	//knightRider function
void knightRider() {
  unsigned long currentMillis = millis();
  if (currentMillis - previousMillis > TIMER) {
    previousMillis = currentMillis;
    // reset last knightlight
    digitalWrite(ledPins[knightLight], LOW);
    // calc new knight light
    knightLight = knightLight + knightCounter;
    if (knightLight > 3 ) {
      knightLight = 3;
      knightCounter = -1;
    }
    if (knightLight < 0) {
      knightLight = 0;
      knightCounter = 1;
    }
    // set new knight light
    digitalWrite(ledPins[knightLight], HIGH);
  }
}  
	// Timeout for UV light Function
void uvLightsOut() {
	// check to see if it's time to turn off the uvLED; that is, if the difference
  	// between the current time and last time you turned on the LED is bigger than
  	// the timeOut at which you want to turn off the uvLED.
unsigned long uvCurrentMillis = millis();

  if (uvCurrentMillis - uvPreviousMillis >= uvTimeOut) {
    // save the time uvLED turned on
    uvPreviousMillis = uvCurrentMillis;
    if (buttonPushCounter == 3);{
  digitalWrite(uvPin, HIGH);
  }

    // if the LED is on turn it off
    if (ledState == HIGH) {
      ledState = LOW;
    }

    // set the LED with the ledState of the variable:
    digitalWrite(uvPin, ledState);
  
}

}

Screenshot from 2023-11-25 17-28-37

Thank you

Tell us what this does ?

if (buttonPushCounter ==1<=5)

I forgot that was there. Early on in my head logic I was having the knight rider effect turn off when pushing button the second time to turn on the motor. So the logic in my head was if the push counter is 1 turn on but keep looping if two three or four is in the button counter, but pay attention to count #5. It seemed to work in the tinkercad simulator. I was pulling at straws, it passed the debugger and for some reason it worked. I thought i cleaned it up but it is still sitting in the sim and the sim works minus the uv led time out

if (buttonPushCounter ==1<=5) {   
   knightRider();   //one click turns on the ambient LED with effect  
   }

ouch..
do you see it??

~q

yes i see that and when that is out in the code the uvled come on and stay on. I am trying to get the uvtimeout to work with that. i call the digitalWrite in the uvTimeOut Loop to at least get the lights to momentarily flash at my set rate.

looking at the last section......being a clone of blink without delay,

void uvLightsOut() {
	// check to see if it's time to turn off the uvLED; that is, if the difference
  	// between the current time and last time you turned on the LED is bigger than
  	// the timeOut at which you want to turn off the uvLED.
unsigned long uvCurrentMillis = millis();

  if (uvCurrentMillis - uvPreviousMillis >= uvTimeOut) {
    // save the time uvLED turned on
    uvPreviousMillis = uvCurrentMillis;
    if (buttonPushCounter == 3);{
  digitalWrite(uvPin, HIGH);
  }

    // if the LED is on turn it off
    if (ledState == HIGH) {
      ledState = LOW;
    }

    // set the LED with the ledState of the variable:
    digitalWrite(uvPin, ledState);
  
}

cannot i not cut it short?, so it reads uvPin HIGH, start clock, turn off after 4000mills, and dont turn on again. As you can see i removed the

} else {
      ledState = LOW;
    }

that goes at the end of blink without delay.

As the other poster said, youve got an extra semi colon in there

quite a few small things..
try this..

// pin connections constant won't change:

const int buttonPin = 2;  // the pin that the pushbutton is attached to
const int ledPins[] = {8, 9, 10 };   //the pins that the ambient LED's are attached to
const int motorPin = 3;   //the pin the motor is attached to
const int uvPin = 4;   // the pin that the UV LED's are attached to
//const int speakerPin = 5;  //TBA pin the attached connect to


// Button control Variables will change:

int buttonPushCounter = 0;  // counter for the number of button presses
int buttonState = 0;        // current state of the button
int lastButtonState = 1;    // previous state of the button
unsigned long lastPush = 0;
byte intervalDebounce = 50;


// UV timeout settings
int ledState = LOW;
unsigned long uvPreviousMillis = 0;
const long uvTimeOut = 4000; //TBA 900000 (15 min) for final code
bool timeExpired = false;//have we timed out yet..

//knight rider timing
unsigned long previousMillis = 0;
static long TIMER = 75;
int knightLight = 0;
int knightCounter = 1;


void setup() {
  //knight rider setup start
  for (int p = 0; p < 3; p++) {
    pinMode(ledPins[p], OUTPUT);
  }  		//knight rider setup end

  // Initialize button pin
  pinMode(buttonPin, INPUT_PULLUP);	// initialize the button pin as a input:

  // initialize the uvLED's,motor and speaker as an output:

  pinMode(motorPin, OUTPUT);
  pinMode(uvPin, OUTPUT);
  //pinMode(speakerPin, OUTPUT);
  Serial.begin(9600);	 // initialize serial communication:
}


void loop() {

  unsigned long now = millis();


  if (now - lastPush >= intervalDebounce) {
    // read the pushbutton input pin:
    buttonState = digitalRead(buttonPin);

    // compare the buttonState to its previous state
    if (buttonState != lastButtonState) {
      lastPush = now;//start debouncing..
      lastButtonState = buttonState;
      // if the state has changed, increment the counter
      if (buttonState == HIGH) {
        // if the current state is HIGH then the button went from off to on:
        buttonPushCounter++;
        Serial.print("Button Pushes");
        Serial.println(buttonPushCounter);
        if (buttonPushCounter == 3) uvPreviousMillis = now;//set count down timer..
      }
    }
  }


  // save the current state as the last state, for next time through the loop


  // Controlling the Clicks

  if (buttonPushCounter > 0) {
    knightRider();   //one click turns on the ambient LED with effect
  }

  if (buttonPushCounter > 1) {
    digitalWrite(motorPin, HIGH);   //two cliks turns on the motor while ambient LED stays on
  }

  if (buttonPushCounter > 2) {
    if (!timeExpired) {
      //turn uv lights on..
      digitalWrite(uvPin, HIGH);
      ledState = HIGH;
    }

    uvLightsOut();
  }				//three clicks turns on the uvLEDs while motor & ambient LEDs stays on

  if (buttonPushCounter > 3) {
    //digitalWrite(speakerPin, HIGH);   //four clicks turns on speaker
  }

  if (buttonPushCounter > 4) {
    digitalWrite(motorPin, LOW);
    digitalWrite(uvPin, LOW);
    // digitalWrite(speakerPin, LOW);  //Five clicks turns all LED's, motor and speaker off
  }

  if (buttonPushCounter == 5)buttonPushCounter = 0; //reset button counter to 0

}

//knightRider function
void knightRider() {
  unsigned long currentMillis = millis();
  if (currentMillis - previousMillis > TIMER) {
    previousMillis = currentMillis;
    // reset last knightlight
    digitalWrite(ledPins[knightLight], LOW);
    // calc new knight light
    knightLight = knightLight + knightCounter;
    if (knightLight > 3 ) {
      knightLight = 3;
      knightCounter = -1;
    }
    if (knightLight < 0) {
      knightLight = 0;
      knightCounter = 1;
    }
    // set new knight light
    digitalWrite(ledPins[knightLight], HIGH);
  }
}
// Timeout for UV light Function
void uvLightsOut() {
  // check to see if it's time to turn off the uvLED; that is, if the difference
  // between the current time and last time you turned on the LED is bigger than
  // the timeOut at which you want to turn off the uvLED.
  unsigned long uvCurrentMillis = millis();

  if (uvCurrentMillis - uvPreviousMillis >= uvTimeOut) {
    //time to turn off..
    timeExpired = true;//our time has expired
    ledState = LOW;//set led state low
    // set the LED with the ledState of the variable:
    digitalWrite(uvPin, ledState);
  }
}

should clear the code up..
now that breadboard is a bit scary..
the uno is not a power source, it's digital pins are rated to 20ma..
8 uv leds on one pin is too much and the motor too..
Need to use external power supply and transistors for the uv and motor..
The actual parts needed depends on current consumption..
Maybe you are already aware of all of this??

happy coding.. ~q

at about midnight i realized a bool would be needed after researching then crashed as i tried putting things together. Much respect for your skills. Any good sources that you can recommend to explain bool better. I understand it is a true false bucket, but c++ documentation I have come across is only as clear as mud.

I see where the triggers are placed for the millis count.

Yah she loaded.... This is why i am using the sim instead of a real board at the moment. The motor is powered and controlled with its own controller, the red LED is on the power switch, and powered separate from the board. Leaves me with the LED's that will need external power source, still. This project is my jump into learning new skills for an old ditch digger.

I have learned so much from the community here that it gives me hope I can see this project through. it's all baby steps.

That being said, this project is for an open source project to revitalize water. improving water quality and structure is a passion, and I figured I would take all my analog methods and try automating the process. The market has such devices for hundreds to thousands of dollars , this project is to get a fully loaded system for under $100. If anyone is interested in knowing more let me know and I can share links to the project as it sits. 3D printer arrives next week to get into testing of some of the build components.

Everyone have a darn great day..

PS. The code works great in the sim. Now to expand to external power source control.

3 Likes

oh yah .....there should be a buy a person a coffee or beer button on this platform.

You all are too kind

1 Like

relay control, this appears to be a decent plug and play option for managing the power.
am I barking up the right tree?

better yes, just be careful not all relay boards are the same, some offer isolation and some do not..
there's lot's of posts on relay boards on here..

good luck.. ~q

  • Many of the relay modules out there require you to GND an IN input terminal to get a relay to pick (energize).

  • We need to see the exact module to comment.

  • Your external 5v supply might be able to be used to power the UNO.

The system in sim is not very power hungry, bench testing shows close to same results. The power demand should all be handled by 5v usb plug in.

so a relay with isolation and enough pins for UVLED, ambient LED, and motor is where i am at.

that's the Knightrider, only got one led per pin, best to leave that off the relays, relays are slow switchers, might mess the effect..
besides the digital pin can easily handle one led..

~q

  • Motors usually are low resistance. This means you need to drive them with very low resistance drivers i.e. transistors, relays …
  • Your schematic shows a potentiometer in series with the motor, don't do this.
  • Motors generate large voltage spikes when de-energized; we need to add kickback protection to snub these spikes.

That i understand, for sim purpose it was used to represent a ( DC 5V-35V 5A Mini DC Motor PWM Speed Controller,Speed Adjustable Switch Module,6V 12V 24V Variable Voltage Regulator with LED Indicator) this is what the mock up has been running on for weeks. So that needs to be connected to the relay to get the on/off signal. An arduino 4 rlay shield should do the trick no?

Pic of the mock up to prove concept. In this state alone it works quite well, i am pushing for a little better refinement.

Yes, I concur inductive loads tend to fly back at you..
motor and relay coils are inductive..

2 small 2n2222 transistors could work..

google "2n2222 circuit examples" and look at the pics..

~q

quick look and scan that is placed between the arduino and the the motor controller. any inductance feedback from the motor through the motor controller is snuffed at the transistor.
totally high level recap here

--- is this the direction is should be heading? Arduino Control Relay - Tutorial #5

um, no it would blow the transistor..
still need a flyback diode across motor, similar to the diagram you posted a link too..

~q

I have build a WOKWI-simulation for your setup
and used user @qubits-us code posted in post # 7 to test it

The first cycle of button pushes 1,2,3,4,5 works.
But on the second, third 4th.... cycle 1,2,3,4,5

The UV-Leds are not switched on.
After 5 button-press the knight-rider leds stay as they are.
I modified this to switch them all off

I took this code as a base and did modificate it with these aims:

put code and variables that belong to each other and that do not interact with other code into their own function. => code is more structured

Using a non-bocking timing function that reduces the number of variables that are nescessary to make the non-blocking timing work.
Again variables that belong to the timing and that must not interact with other code are inside the function => code is more structured and easier to understand.

The code is shorter and / or easier to analyse and understand.

best regards Stefan