Variable millis

This program works fine, except that it worked on delay;
And now to upgrade to millis is a bit of a challenge at:

if (sens > val ) {
digitalWrite (relay0Pin, LOW);
relay0On = false;
currentState = 1;
relay0OnTime =(millis() - relay0OnTime >= analogRead(A2)* multiplier);

I am using a 10K potentiometer on Pin A2 which reads 0 to 15 seconds delay,
which does work when I used the delay function. And yes the whole thing stops and waits till the selected delay is up.

I have tried getting millis to work but with no luck, and I have left this as is to the best of my ability.

Any way I can make this conversion with your help?

Thanks in advance.

JT_Hydropond.ino (3.34 KB)

What do you want to time? On or off?

Let's assume off. In any case, when using millis() turning it off has NO link with the event that turns it on except for the time that happened.

Pseudo code:

if(eventToTurnOn){
  turnOnTime = millis();
  digitalWrite(pin, ON);
}

//seperate if aka NO link
//only checking if output is on
//and it's time to turn it off
if((digitalRead(pin) == ON) && (millis() - turnOnTime > intervalWhichMayComeFromAnalogRead)){
  digitalWrite(pin, OFF);
}

And the turn OFF part must be checked every loop aka all the cases what needs to be satisfied to turn it on don't matter.

This is what I have compiled using the example.
Still does not read variable time potentiometer.

}
if(relay0On){
relay0OnTime = millis();
digitalWrite(relay0Pin, HIGH);
}

if (sens > val ) {
digitalWrite (relay0Pin, LOW);
relay0On = false;
currentState = 1;
if((digitalRead(relay0Pin) == HIGH) && (millis() - relay0OnTime > analogRead(A2)* multiplier)){
digitalWrite(relay0Pin, LOW);
}

Rainbowfish:
This is what I have compiled using the example.
Still does not read variable time potentiometer.

Please post the complete program. The problem is usually in the corner where you aren’t looking :slight_smile:

And please use the code button </> when posting code.

The demo Several Things at a Time illustrates the use of millis() to manage timing without blocking. It may help with understanding the technique.

Have a look at Using millis() for timing. A beginners guide if you need more explanation.

…R

Please see my first post. file : ino

Rainbowfish:
Please see my first post. file : ino

I have the impression from your Reply #2 that you have a more recent version of the program, taking account of the comments in Reply #1?

...R

This is how it should have been posted:

#include <SPI.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#define OLED_RESET 4
Adafruit_SSD1306 display(OLED_RESET);


const int relay0Pin = 10;
const int relay1Pin = 5;
const int led0Pin = 2;
const int button0Pin = A1;
int potFloPin = A3;
int val = 0;
int sensPin = A0;
int sens = 0;
int button0State = 0;
int counter = 0;
int currentState = 0;
int previousState = 0;
unsigned long relay0OnTime;
bool relay0On;
unsigned long time;
int analogVal;
byte potTimePin = A2;
unsigned long multiplier = 15;
unsigned long timer; // the timer
boolean timedOut = false;


void setup()
{
  //Serial.begin(9600);
  display.begin(SSD1306_SWITCHCAPVCC, 0x3C);
  display.clearDisplay();
  display.setTextSize(2);
  display.setTextColor(WHITE);
  display.setCursor(10, 20); // 0=Column; 5=Row
  display.print("Aquaponics");
  display.setTextSize(1);
  display.setCursor(40, 50); // 0=Column; 5=Row
  display.print("Ver.f2");
  display.display();
  delay (3000);


  pinMode(relay0Pin, OUTPUT);
  pinMode(relay1Pin, OUTPUT);
  pinMode(led0Pin, OUTPUT);
  pinMode(button0Pin, INPUT);
  relay0On = false;
  timedOut = false; // allow timer to fire
  timer = millis(); // start timer
}


void loop()
{
  display.setTextSize(1.8);
  time = millis();
  display.setCursor(2, 0); // 0=Column; 5=Row
  display.print("FLOW");
  val = analogRead(potFloPin);
  display.setCursor(120, 0);
  display.print("%");
  display.setCursor(100, 0);
  display.println(val / 10); // to vary 0 to end result, ie 1024/?
  display.fillRect(2, 10, val / 8, 1, 1); // 2=V from left; 61=H from top; val/8= lenght of bar ie, val/16 is half screen with full value; 3= thickness of slide bar; 1= ? colour or brightness


  display.setCursor(2, 20); // 0=Column; 30=Row
  display.print("H2O LEVEL");
  sens = analogRead(sensPin);
  display.setCursor(120, 20);
  display.print("%");
  display.setCursor(100, 20);
  display.println(sens / 10); // to vary 0 to end result, ie 1024/?
  display.fillRect(2, 30, sens / 8, 1, 1); // 2=V from left; 61=H from top; val/8= lenght of bar ie, val/16 is half screen with full value; 3= thickness of slide bar; 1= ? colour or brightness


  display.setCursor(2, 39);
  display.println(time / 1000 / 60);
  display.setCursor(25, 39);
  display.print("MIN");
  display.setCursor(50, 39);
  display.print(counter);
  display.setCursor(72, 39);
  display.print("INTERRUPT");


  display.setCursor(2, 56); // 2=Column; 40=Row
  display.print(analogRead(A2) / 66);
  display.setCursor(25, 56);
  display.print("SECONDS DELAY");
  display.display();
  display.clearDisplay();  // Clear display must be used to clear text etc


  button0State = digitalRead(button0Pin);
  if (button0State == HIGH)
  {
    digitalWrite (relay0Pin, HIGH);
    relay0On = true;
    relay0OnTime = millis();
    digitalWrite (led0Pin, HIGH);
    currentState = 0;
  }
  else
  {
    digitalWrite(led0Pin, LOW);
  }


  if (sens > val )
  {
    digitalWrite (relay0Pin, LOW);
    relay0On = false;
    currentState = 1;
    relay0OnTime = (millis() - relay0OnTime >= analogRead(A2) * multiplier);
    digitalWrite (led0Pin, LOW);
  }


  if (relay0On)
    if (millis() - relay0OnTime > 5000)
    {
      digitalWrite(relay0Pin, LOW);
      relay0On = false;
      currentState = 0;
    }
    
  if (currentState != previousState)
  {
    if (currentState == 1)
    {
      counter = counter + 1;
    }
    previousState = currentState;
  }
}
    relay0OnTime = (millis() - relay0OnTime >= analogRead(A2) * multiplier);

?!? This sets "relay0OnTime" to either 0 (false) or 1 (true).

    if (millis() - relay0OnTime > 5000)

After 5 seconds this will always be true. Did you want the 5000 to vary based on your pot setting?!? Try this:

    relay0OnTime = millis();
    relay0Interval = map(analogRead(A2) , 0, 1023, 0, 15000);  // Set 0 to 15 second delay
    if (millis() - relay0OnTime > relay0Interval)

Thank you for your reply and posting the complete ino. Sorry to all, I was mislead.

The 5 second delay is fine, that part can stay that way.

This part below is the one that should have the variable millis.

if (sens > val )
{
digitalWrite (relay0Pin, LOW);
relay0On = false;
currentState = 1;
relay0OnTime = (millis() - relay0OnTime >= analogRead(A2) * multiplier);
digitalWrite (led0Pin, LOW);
}

Thank you.

    relay0OnTime = (millis() - relay0OnTime >= analogRead(A2) * multiplier);

What is it that you think this line is doing?!?

If for example I set, potTimePin = A2; for 4 seconds and press, sensPin = A0; then I would expect, relay0Pin = 10; to delay with 4 seconds. But as it is now that when I press, sensPin = A0; then relay goes LOW; and after releasing, sensPin = A0; then, relay0Pin = 10; goes HIGH;

I have applied this code:

relay0OnTime = millis();
relay0Interval = map(analogRead(A2) , 0, 1023, 0, 15000); // Set 0 to 15 second delay

but does not do the delay.

Thanks for assisting
Kind regards

Rainbowfish:
If for example I set, potTimePin = A2; for 4 seconds and press, button0Pin = A1; then I would expect, relay0Pin = 10; to delay with 4 seconds. But as it is now that when I press, button0Pin = A1; then relay goes LOW; and after releasing, button0Pin = A1; then, relay0Pin = 10; goes HIGH;

are you trying to achieve something like this?

#define potTimePin A2
#define button0Pin A1
#define relay0Pin 10

unsigned long relay0OnTime;
uint16_t relay0Interval;

void setup() {
  //Initialise your IOs
  pinMode(button0Pin, INPUT);
  pinMode(relay0Pin, OUTPUT);
  digitalWrite(relay0Pin, LOW);
}

void loop() {

  if (digitalRead(button0Pin) == HIGH) { //assuming when you press the button you switch to HIGH
    analogRead(A2);
    relay0Interval = map(analogRead(A2) , 0, 1023, 0, 15000);  // Set 0 to 15 second delay
    digitalWrite(relay0Pin, HIGH); //turn relay ON
    relay0OnTime = millis();

  }
  else if (millis() - relay0OnTime > relay0Interval && digitalRead(relay0Pin) == HIGH) { //interval set is reached
    digitalWrite(relay0Pin, LOW); //turn relay OFF
  }

  delay(100); //100ms arbitrary polling delay
}

Rainbowfish:
If for example I set, potTimePin = A2; for 4 seconds and press, button0Pin = A1; then I would expect, relay0Pin = 10; to delay with 4 seconds.

What do you mean by "delay with 4 seconds"? Do mean:

  • "turn on for four seconds and then turn off"
  • "turn off for four seconds and then turn on"
  • "change state for four seconds and then change back"
  • "not change for four seconds and then turn on"
  • "not change for four seconds and then turn off"
  • "not change for four seconds and then change state"

"turn off for four seconds and then turn on"

please forgive me.

I edited the above as it is not the button0Pin=A1; but infact the sensPin=A0; that when (sens > val)
the relay0Pin should go LOW for 4 seconds.

OK, I had it the other way around. This should turn the Relay pin OFF when the button is pushed and ON a variable time after the WaterLevel input is greater than the FlowRate input (whatever that means).

#include <SPI.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>


const byte LED0Pin = 2;
const byte OLED_RESET = 4;
const byte Relay1Pin = 5;
const byte Relay0Pin = 10;


const byte WaterLevelPin = A0;
const byte Button0Pin = A1;
const byte TimeDelayPin = A2;
const byte FlowRatePin = A3;


Adafruit_SSD1306 display(OLED_RESET);


int FlowRate = 0;
int WaterLevel = 0;
int Button0State = 0;


unsigned long Relay0Time = 0;
unsigned  Relay0Interval = 0;  // 0 to 15345 (1023*15)


bool Relay0On;


unsigned long multiplier = 15;


void setup()
{
  //Serial.begin(9600);
  display.begin(SSD1306_SWITCHCAPVCC, 0x3C);
  display.clearDisplay();
  display.setTextSize(2);
  display.setTextColor(WHITE);
  display.setCursor(10, 20); // 0=Column; 5=Row
  display.print("Aquaponics");
  display.setTextSize(1);
  display.setCursor(40, 50); // 0=Column; 5=Row
  display.print("Ver.f2");
  display.display();
  delay (3000);


  display.setTextSize(1.8);


  pinMode(Relay0Pin, OUTPUT);
  pinMode(Relay1Pin, OUTPUT);
  pinMode(LED0Pin, OUTPUT);
  pinMode(Button0Pin, INPUT);
  Relay0On = false;
  digitalWrite(Relay0Pin, Relay0On);
}




void loop()
{
  unsigned long currentTime = millis();
  FlowRate = analogRead(FlowRatePin);
  WaterLevel = analogRead(WaterLevelPin);
  Button0State = digitalRead(Button0Pin);
  Relay0Interval = analogRead(TimeDelayPin) * multiplier; // Set 0 to 15.345 second delay


  display.setCursor(2, 0); // 0=Column; 5=Row
  display.print("FLOW");
  display.setCursor(120, 0);
  display.print("%");
  display.setCursor(100, 0);
  display.println(FlowRate / 10); // to vary 0 to end result, ie 1024/?
  display.fillRect(2, 10, FlowRate / 8, 1, 1);
  // 2=V from left; 61=H from top; FlowRate/8= lenght of bar ie, FlowRate/16 is half screen with full value; 3= thickness of slide bar; 1= ? colour or brightness


  display.setCursor(2, 20); // 0=Column; 30=Row
  display.print("H2O LEVEL");
  display.setCursor(120, 20);
  display.print("%");
  display.setCursor(100, 20);
  display.println(WaterLevel / 10); // to vary 0 to end result, ie 1024/?
  display.fillRect(2, 30, WaterLevel / 8, 1, 1);
  // 2=V from left; 61=H from top; WaterLevel/8= lenght of bar ie, WaterLevel/16 is half screen with full value; 3= thickness of slide bar; 1= ? colour or brightness


  display.setCursor(2, 39);
  display.println(currentTime / 1000 / 60);
  display.setCursor(25, 39);
  display.print("MIN");
  display.setCursor(50, 39);
//  display.print(counter);
  display.setCursor(72, 39);
  display.print("INTERRUPT");


  display.setCursor(2, 56); // 2=Column; 40=Row
  display.print(analogRead(TimeDelayPin) / 66);
  display.setCursor(25, 56);
  display.print("SECONDS DELAY");
  display.display();
  display.clearDisplay();  // Clear display must be used to clear text etc


  // If the button is pressed, turn on the LED
  digitalWrite (LED0Pin, Button0State);


  // If the button is pressed, turn on the relay
  if (Button0State)
  {
    Relay0On = true;
    digitalWrite (Relay0Pin, Relay0On);
  }


  // If the relay is ON anbd the water level is greater then the flow rate (?!?!?) turn off the relay for an adjustable amount of time.
  if (Relay0On && (WaterLevel > FlowRate))
  {
    // Turn off for variable seconds and then turn on
    Relay0On = false;
    digitalWrite (Relay0Pin, Relay0On);
    Relay0Time = currentTime;


    digitalWrite (LED0Pin, LOW);
  }


  // If the relay is OFF and Relay0Interval has elapsed, turn the relay ON
  if (!Relay0On && currentTime - Relay0Time > Relay0Interval)
  {
    Relay0On = true;
    digitalWrite(Relay0Pin, Relay0On);
  }
}

Looks great,

  1. When the system boots up then
    Relay0Pin = 10; should be LOW;

  2. Only when Button0Pin = A1; is pressed and (LED0Pin, HIGH);
    Relay0Pin = 10; should be HIGH;

  3. When Button0Pin = A1; is released then
    Relay0Pin = 10; should stay on for 5 sec and then go LOW;

  4. When (WaterLevel > FlowRate) even if Button0Pin = A1; is held in, then
    Relay0Pin = 10; should be LOW; //Turn off for variable seconds and then turn on if Button0Pin = A1; is pressed again.

I will post the original that I compiled.
If you need to see it.

Thanks again