Using ticker library and delay()

I'm a casual user of arduino and i'm looking for some easy to understand code for a pretty simple problem that comes up allot, using delay() with libraries that use the timer functions. I'm using an ESP board to grab data from remote sensors inside a vacuum chamber, and then work the relay for the pump. The code below gets the psi from the other esp... but i'm wondering if there is a good way to turn on the pump to bring the pressure down to 8 psi, then keep it there for 5 minutes. The relevant code:

 if (currentMillis - previousMillis < interval) {
    if ((psi >= 8)) && (psi <= 9 {
      digitalWrite(relayPin, HIGH);
      Serial.println("hello from psi");
    } else {
      digitalWrite(relayPin, LOW);
    }
   } else {
    pressurized = false;
    digitalWrite(relayPin, LOW);
    Serial.println("gello");
    previousMillis = currentMillis;
    x = 1;
   }

I would've solved it by just putting in a delay(5000) then test for the psi again. Any suggestions? 


/*
 * Functions: grabs data for co2, humidity, temperature, and pressure and stores it to the SD card
 *            grabs pressure reading data and turns on/off a relay
 *            sets a lower bound for the pressure, turns on pump, operates pump till the desired pressure is achieved, and keeps the pressure low for a specified amount of time.
 *            ticker one: SD card... grabs data every 5 minutes except when in pressurized mode. 
 *            ticker two: sets the interval for pulling pressure, once an hour!
 *            millis() sets how long the pressure remains low, 5 minutes. 
 */
#include <Ticker.h>
#include <ESP8266WiFi.h>
#include <WiFiUdp.h>
#include <SPI.h>
#include <SD.h>
  
// Set WiFi credentials
#define WIFI_SSID "TheOtherESP"
#define WIFI_PASS "flashmeifyoucan"

//SD
File myFile;
String datalabel1 = "Pressure";
String datalabel2 = "CO2";
String datalabel3 = "Humidity";
String datalabel4 = "Temperature";
bool label = true;
const int chipSelect = D8; 

// UDP
WiFiUDP UDP;
IPAddress remote_IP(192,168,4,1);
#define UDP_PORT 4210
char packet[255];

//drops the millis to zero on execution of the pressureDrop function, then back to one upon dataDrop
int x = 0;

// pins used
const int  relayPin = D4;
  
// Ticker 
Ticker flipper;
bool pressurized = false;

unsigned long currentMillis = millis();
unsigned long previousMillis = 0;
long interval = 10000 + 15000;
//////////////////////////////////////////////////////////////////////////////////////////////
void setup() {
  pinMode(relayPin, OUTPUT);
  pinMode(D2, OUTPUT);

  Serial.begin(9600);
  while (!Serial) {
    ; 
  }

  //SD card
  Serial.print("Initializing SD card...");
  if (!SD.begin(chipSelect)) {
    Serial.println("initialization failed!");
    while (1);}
    Serial.println("initialization done.");
  
  // Begin WiFi
  WiFi.begin(WIFI_SSID, WIFI_PASS);
  WiFi.mode(WIFI_STA);
  Serial.print("Connecting to ");
  Serial.print(WIFI_SSID);
  // Loop continuously while WiFi is not connected
  while (WiFi.status() != WL_CONNECTED)
  {
    delay(100);
    Serial.print(".");
  }
  Serial.println();
  Serial.print("Connected! IP address: ");
  Serial.println(WiFi.localIP());

    // Begin UDP port
  UDP.begin(UDP_PORT);
  Serial.print("Opening UDP port ");
  Serial.println(UDP_PORT);

  // Ticker
  flipper.attach(300, dataDrop);
  flipper.attach(15, pressureDrop);
  
}
//////////////////////////////////////////////////////////////////////////////////////////////
void loop() {
  currentMillis = millis();
  digitalWrite(D2, LOW);

  if (x == 2) {
    String myString;
    int psi;
    int packetSize;
    pressurized = true;
   
      UDP.beginPacket(IPAddress(192,168,4,1), 4210);
      UDP.write("pressure");
      UDP.endPacket();
      
   packetSize = UDP.parsePacket();
   myString = String(packet);
   psi = (myString.toInt())*.0145;
   Serial.println(psi);

 Serial.println(currentMillis - previousMillis);
    
  if (currentMillis - previousMillis < interval) {
    if ((psi >= 8)) && (psi <= 9 {
      digitalWrite(relayPin, HIGH);
      Serial.println("hello from psi");
    } else {
      digitalWrite(relayPin, LOW);
    }
   } else {
    pressurized = false;
    digitalWrite(relayPin, LOW);
    Serial.println("gello");
    previousMillis = currentMillis;
    x = 1;
   }
  }




  // If packet received...
  int packetSize = UDP.parsePacket();
  if (packetSize) {
    Serial.print("Received packet! Size: ");
    Serial.println(packetSize); 
    int len = UDP.read(packet, 255);
    if (len > 0)
    {
      packet[len] = '\0';
    }
    Serial.print("Packet received: ");
    Serial.println(packet);
 
  }
   
}
/////////////////////////////////////////////////////////////////////////////////////////////
void dataDrop() {
      
      UDP.beginPacket(IPAddress(192,168,4,1), 4210);
      UDP.write("Loser");
      UDP.endPacket();
      int packetSize = UDP.parsePacket();
      
  
  myFile = SD.open("data.csv", FILE_WRITE);
  if (pressurized == false) {
    x = 0;
   if (myFile) {
      while (label) {
        myFile.print(datalabel1);
        myFile.print(",");
        myFile.print(datalabel2);
        myFile.print(",");
        myFile.print(datalabel3); 
        myFile.print(",");
        myFile.println(datalabel4);
        label=false;
      } 

      myFile.println(packet);

      myFile.close();
      } else {
      Serial.println("error opening test.txt");
      }
  }
 }
///////////////////////////////////////////////////////////////////////////////////////////
void pressureDrop() {
  
   currentMillis = previousMillis;
   x = 2;
 
}


1 Like

The way you have it now, currentMillis - previousMillis will always be less than interval since your are resetting previousMillis when the if() is true.

It really depends on your system. Do you just turn on the pump and then wait 5 minutes? Or, does the pump have to cycle on/off to maintain the proper PSI? Or do you turn on the pump until the PSI is correct, then turn off the pump and wait 5 minutes?

The easiest way is to think of this as a state machine and then code it to match

Well no, the if statement containing the millis() reset only runs once, while x =2. X is only set to 2 every time the ticker calls the function. I've already tested that part of the code out with the Serial monitor, it took a few times!
What i want is to pull the pressure low for 5 minutes every hour, down to a certain pressure. But i know if i just use if statements then it will flip the pump on and off real fast... i want to pull down to, for example, 8 psi then the leaks in the system will raise the psi slowly but surely which when it reaches about 9 psi to pull it back down to 8 psi, and to keep doing this for the time period set by interval. I realize i could just make more timers with millis(), but i would really enjoy using something like a delay(). Maybe somebody who knows the ticker library knows a good way??

What ticker library are you using? It does not look like this one: GitHub - sstaub/Ticker: Ticker library for Arduino
Something like this will get the job done without that library

/*
   Functions: grabs data for co2, humidity, temperature, and pressure and stores it to the SD card
              grabs pressure reading data and turns on/off a relay
              sets a lower bound for the pressure, turns on pump, operates pump till the desired pressure is achieved, and keeps the pressure low for a specified amount of time.
              ticker one: SD card... grabs data every 5 minutes except when in pressurized mode.
              ticker two: sets the interval for pulling pressure, once an hour!
              millis() sets how long the pressure remains low, 5 minutes.
*/
#include <Ticker.h>
#include <ESP8266WiFi.h>
#include <WiFiUdp.h>
#include <SPI.h>
#include <SD.h>

// Set WiFi credentials
#define WIFI_SSID "TheOtherESP"
#define WIFI_PASS "flashmeifyoucan"

//SD
const int chipSelect = D8;

// UDP
WiFiUDP UDP;
IPAddress remote_IP(192, 168, 4, 1);
#define UDP_PORT 4210
char packet[255];

//drops the millis to zero on execution of the pressureDrop function, then back to one upon dataDrop
int x = 0;

// pins used
const int  relayPin = D4;

// Ticker
Ticker flipper;
bool pressurized = false;

unsigned long currentMillis = millis();
unsigned long previousMillis = 0;
long interval = 10000 + 15000;

const unsigned long runTime = 1000UL * 60 * 5;    // only run pump 5 minutes

//////////////////////////////////////////////////////////////////////////////////////////////
void setup() {
  pinMode(relayPin, OUTPUT);
  pinMode(D2, OUTPUT);

  Serial.begin(9600);
  while (!Serial) {
    ;
  }

  //SD card
  Serial.print("Initializing SD card...");
  if (!SD.begin(chipSelect)) {
    Serial.println("initialization failed!");
    while (1);
  }
  Serial.println("initialization done.");

  // Begin WiFi
  WiFi.begin(WIFI_SSID, WIFI_PASS);
  WiFi.mode(WIFI_STA);
  Serial.print("Connecting to ");
  Serial.print(WIFI_SSID);
  // Loop continuously while WiFi is not connected
  while (WiFi.status() != WL_CONNECTED)
  {
    delay(100);
    Serial.print(".");
  }
  Serial.println();
  Serial.print("Connected! IP address: ");
  Serial.println(WiFi.localIP());

  // Begin UDP port
  UDP.begin(UDP_PORT);
  Serial.print("Opening UDP port ");
  Serial.println(UDP_PORT);

  // Ticker
  //flipper.attach(300, dataDrop);
  //flipper.attach(15, pressureDrop);

}
//////////////////////////////////////////////////////////////////////////////////////////////
void loop() {
  currentMillis = millis();
  digitalWrite(D2, LOW);

  dataDrop();

  unsigned long minutes = currentMillis / 60000;    // number of minutes running
  if ( pressurized == false && minutes % 60 == 0 ) {
    // top of the hour and not running so begin
    startTime = currentMillis;
    Serial.println("starting pressurization");
    pressurized = true;
    UDP.beginPacket(IPAddress(192, 168, 4, 1), 4210);
    UDP.write("pressure");
    UDP.endPacket();

    packetSize = UDP.parsePacket();
    myString = String(packet);
    psi = (myString.toInt()) * .0145;
    Serial.println(psi);

    digitalWrite(relayPin, HIGH);
  }

  if ( pressurized == true ) {
    // check to see if we are done
    if ( currentMillis - startTime >= runTime ) {
      // all done for this hour
      Serial.println("done with pressurization");
      digitalWrite(relayPin, LOW);
      pressurized = false;
    }
    else if ( psi < 8 ) {
      // pressure low enough, stop pump
      Serial.println("pump off");
      digitalWrite(relayPin, LOW);
    }
    else if ( psi >= 9 ) {
      // pressure too high, re-start pump
      Serial.println("pump on");
      digitalWrite(relayPin, HIGH);
    }
  }

  // If packet received...
  int packetSize = UDP.parsePacket();
  if (packetSize) {
    Serial.print("Received packet! Size: ");
    Serial.println(packetSize);
    int len = UDP.read(packet, 255);
    if (len > 0)
    {
      packet[len] = '\0';
    }
    Serial.print("Packet received: ");
    Serial.println(packet);
  }
}

/////////////////////////////////////////////////////////////////////////////////////////////
void dataDrop() {

  static bool label = true;

  static unsigned long lastTime;
  const unsigned long interval = 300; // milliseconds

  if ( millis() - lastTime >= interval ) {
    lastTime = millis();

    UDP.beginPacket(IPAddress(192, 168, 4, 1), 4210);
    UDP.write("Loser");
    UDP.endPacket();
    int packetSize = UDP.parsePacket();

    if (pressurized == false) {
      File myFile = SD.open("data.csv", FILE_WRITE);
      if (myFile) {
        if (label) {
          myFile.println("Pressure,CO2,Humidity,Temperature");
          label = false;
        }
        myFile.println(packet);
        myFile.close();
      }
      else {
        Serial.println("error opening test.txt");
      }
    }
  }
}

I like your code. I was confused about how to keep the pump from flickering but that is the solution! I haven't seen this line before " minutes % 60 == 0 "... maybe thats why i'm confused about how "minutes" will roll back to 0 after the first cycle? I got the ticker library from the library manager, it is different- the code on github doesn't run with the one on arduino.

% is the modulo or modulus operator - https://www.cplusplus.com/reference/functional/modulus/

Standard C++ which is readily google-able :slight_smile:

It didn't have any examples with variables... Just fractions. Not sure what fractions have to do with setting minutes back to zero?

thanks for giving me code with no explanation, might as well code like a blind man! Still, if anyone knows of a way to use delay() and while() with the ticker library I would enjoy seeing the code!

I am confused. There are comments in the code as to intent. If you have questions, just ask them and/or google it.

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.