Millis counter acting strange

I've made this pretty simple counter using millis() in a blank code. I want to use it for a OLED display as an interval of switching from showing temperature to humidity to ppm...
The millis counter alone works perfect as shown below.

unsigned long prevTime = 0;
int SSD_State; 

void setup() {
  Serial.begin(9600);
}

void loop() {

  if (millis() - prevTime >= 5000) {
    SSD_State += 1;
    Serial.println(SSD_State);
    
    prevTime = millis();
  }
  if (SSD_State >= 5){
    SSD_State = 0;
  }
}

But when i integrate it in de actual code i want to use it in. It doesn't really count and keeps switching really fast.

#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>  
#include "SparkFunHTU21D.h"
HTU21D myHumidity;

#define SCREEN_WIDTH 128 // OLED display width, in pixels
#define SCREEN_HEIGHT 32 // OLED display height, in pixels
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT);  

unsigned long prevTime = 0;
int SSD_State = 0; 

void setup() {
  Serial.begin(9600);
  myHumidity.begin();

  display.begin(SSD1306_SWITCHCAPVCC, 0x3C);
  display.clearDisplay();
  display.setTextColor(SSD1306_WHITE);
}

void loop() {

  float humd = myHumidity.readHumidity();
  float temp = myHumidity.readTemperature();
  
if(millis() - prevTime >= 1000){
        SSD_State += 1;
        Serial.println(SSD_State);
        prevTime = millis();
    }  

  // display temperature
if (SSD_State = 1) {
  display.clearDisplay();
  display.setTextSize(1);
  display.setCursor(0,0);
  display.print("Temperatuur:");
  display.setTextSize(3);
  display.setCursor(12,11);
  display.print(temp);
  display.print(" ");
  display.setTextSize(1);
  display.setCursor(105,13);
  display.cp437(true);
  display.write(167);
  display.setTextSize(2);
  display.print("C");
  display.display(); 
 }  

  // display humidititty
if (SSD_State = 2) {
  display.clearDisplay();
  display.setTextSize(1);
  display.setCursor(0,0);
  display.print("Luchtvochtigheid:");
  display.setTextSize(3);
  display.setCursor(12,11);
  display.print(humd);
  display.print(" ");
  display.setTextSize(1);
  display.setCursor(105,13);
  display.setTextSize(2);
  display.print("%");
 display.display(); 
 }  
}

I don't see in the code where you resetting SSD_state value after displaying the content.

Hello lil_chimp

Consider

#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#include "SparkFunHTU21D.h"
HTU21D myHumidity;

#define SCREEN_WIDTH 128 // OLED display width, in pixels
#define SCREEN_HEIGHT 32 // OLED display height, in pixels
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT);

unsigned long prevTime = 0;
int SSD_State = 0;

void setup() {
  Serial.begin(9600);
  myHumidity.begin();

  display.begin(SSD1306_SWITCHCAPVCC, 0x3C);
  display.clearDisplay();
  display.setTextColor(SSD1306_WHITE);
}

void loop() {

  float humd = myHumidity.readHumidity();
  float temp = myHumidity.readTemperature();

  if (millis() - prevTime >= 1000) {
    SSD_State = (SSD_State+1)%2;
    Serial.println(SSD_State);
    prevTime = millis();
  }

  // display temperature
  if (SSD_State == 0) {
    display.clearDisplay();
    display.setTextSize(1);
    display.setCursor(0, 0);
    display.print("Temperatuur:");
    display.setTextSize(3);
    display.setCursor(12, 11);
    display.print(temp);
    display.print(" ");
    display.setTextSize(1);
    display.setCursor(105, 13);
    display.cp437(true);
    display.write(167);
    display.setTextSize(2);
    display.print("C");
    display.display();
  }

  // display humidititty
  if (SSD_State == 1) {
    display.clearDisplay();
    display.setTextSize(1);
    display.setCursor(0, 0);
    display.print("Luchtvochtigheid:");
    display.setTextSize(3);
    display.setCursor(12, 11);
    display.print(humd);
    display.print(" ");
    display.setTextSize(1);
    display.setCursor(105, 13);
    display.setTextSize(2);
    display.print("%");
    display.display();
  }
}

Have a nice day and enjoy coding in C++.

== ?

2 Likes

maybe

if (2 < ++SSD_State)
    SSD_State = 1;

may be better to test for 0 & 1

just it:

if (SSD_State == 2) {
  display.clearDisplay();

  .... displaying....

  SSD_State = 0;
 }  

PS the main cause of problem is an error catched by @kolaha

#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#include "SparkFunHTU21D.h"
HTU21D myHumidity;

#define SCREEN_WIDTH 128 // OLED display width, in pixels
#define SCREEN_HEIGHT 32 // OLED display height, in pixels
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT);


void setup() {
  Serial.begin(9600);
  myHumidity.begin();

  display.begin(SSD1306_SWITCHCAPVCC, 0x3C);
  display.clearDisplay();
  display.setTextColor(SSD1306_WHITE);
}

void loop() {
  static unsigned long prevTime = 0;
  static byte SSD_State = 0;

  float humd = myHumidity.readHumidity();
  float temp = myHumidity.readTemperature();

  if (millis() - prevTime >= 1000) {
    SSD_State += 1;
    Serial.println(SSD_State);
    prevTime += 1000;
  }

  // display temperature
  if (SSD_State == 1) {
    display.print("Temperatuur:");
    SSD_State += 1;
  }

  // display humidititty
  if (SSD_State == 3) {
    display.print("Luchtvochtigheid:");
    SSD_State = 0;
  }
}

@paulpaulson and @kolaha I think that updating the display can be in the millis timer as well, and when doing that, getting the humidity and temperature can also be in the millis timer. Updating the mode (temperature or humidity) has to be in the millis timer as well.

There is no need to flood the I2C bus when there is no need for it (data from sensor that is not used and writing to display that is already on the display). The temperature of the sensor might increase with a lot of I2C activity.

Global structure of the code:

void loop()
{
  millis_timer
  {
    is mode set to temperature ?
    {
      request temperature
      display temperature
   }
   else if mode is humidity
   {
      request humidity
      display humidity
   }

   change mode
}

The Wokwi simulator does not have a HTU21D, so I used random numbers.

// Forum: https://forum.arduino.cc/t/millis-counter-acting-strange/1123451/
// This Wokwi project: https://wokwi.com/projects/363877972648732673

#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
// #include "SparkFunHTU21D.h"
// HTU21D myHumidity;

#define SCREEN_WIDTH 128 // OLED display width, in pixels
#define SCREEN_HEIGHT 32 // OLED display height, in pixels
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT);

unsigned long prevTime = 0;
int SSD_State = 0;

void setup()
{
  Serial.begin(9600);
  //  myHumidity.begin();

  display.begin(SSD1306_SWITCHCAPVCC, 0x3C);
  display.clearDisplay();
  display.setTextColor(SSD1306_WHITE);
}

void loop()
{
  if (millis() - prevTime >= 1000)
  {
    prevTime = millis();

    // display temperature
    if (SSD_State == 0)
    {
//    float temp = myHumidity.readTemperature();
      float temp = (float) random(2000, 2500) / 100.0;

      display.clearDisplay();
      display.setTextSize(1);
      display.setCursor(0, 0);
      display.print("Temperatuur:");
      display.setTextSize(3);
      display.setCursor(12, 11);
      display.print(temp);
      display.print(" ");
      display.setTextSize(1);
      display.setCursor(105, 13);
      display.cp437(true);
      display.write(167);
      display.setTextSize(2);
      display.print("C");
      display.display();
    }
    else if (SSD_State == 1)        // display humidititty
    {
//    float humd = myHumidity.readHumidity();
      float humd = (float) random(0, 101);

      display.clearDisplay();
      display.setTextSize(1);
      display.setCursor(0, 0);
      display.print("Luchtvochtigheid:");
      display.setTextSize(3);
      display.setCursor(12, 11);
      display.print(humd);
      display.print(" ");
      display.setTextSize(1);
      display.setCursor(105, 13);
      display.setTextSize(2);
      display.print("%");
      display.display();
    }

    SSD_State += 1;
    if ( SSD_State > 1)     // 0 and 1 are valid, bigger than 1 is not
      SSD_State = 0;
//  Serial.println(SSD_State);
  }
}

Try it in Wokwi:

Surely another solution is possible. :nerd_face:

Thanks alot, saved me a lot of stress!

Okay, well.
It worked perfectly fine for the OLED display alone, but now that i have integrated it to the full code, the SSD_State doesn't change anymore.
Other functions, like humidity and fan don't switch on or off at the right time.
Everytime worked perfectly when tested seperatly, so its not a hardware problem.

Here's the full code:

#include <BH1750.h>
#include <SoftwareSerial.h>
#include <MHZ.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>  
#include "SparkFunHTU21D.h"
#include <DS3231.h>
HTU21D myHumidity;
DS3231  rtc(SDA, SCL);
BH1750 lightMeter;
MHZ co2(6, MHZ14A);
Time t;

#define SCREEN_WIDTH 128 // OLED display width, in pixels
#define SCREEN_HEIGHT 32 // OLED display height, in pixels
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT);  

unsigned long prevTime = 0;
int SSD_State = 0;

void setup() {
  Serial.begin(9600);
  myHumidity.begin();
  rtc.begin();
  lightMeter.begin();

  display.begin(SSD1306_SWITCHCAPVCC, 0x3C);
  display.clearDisplay();
  display.setTextColor(SSD1306_WHITE);

  pinMode(2, OUTPUT);     // R2.4 Verdamper
  pinMode(3, OUTPUT);     // R2.3 Exit Fan
  pinMode(4, OUTPUT);     // R2.2 Luchtcirculatie
  pinMode(5, OUTPUT);     // R2.1 Entry Fan
  pinMode(6, INPUT);      // PWM CO2 Meter

  pinMode(10, OUTPUT);     // R1.4 -
  pinMode(11, OUTPUT);     // R1.3 -
  pinMode(12, OUTPUT);     // R1.2 -

  //RTC Instellen van de TIJD
  rtc.setDOW(FRIDAY);     // Set Day-of-Week to SUNDAY
  rtc.setTime(15, 10, 50);     // Set the time to 12:00:00 (24hr format)
  rtc.setDate(5, 5, 2023);   // Set the date to January 1st, 2014
}

void loop() {

  t = rtc.getTime();
  int ppm_pwm = co2.readCO2PWM();
  float lux = lightMeter.readLightLevel();
  float humd = myHumidity.readHumidity();
  float temp = myHumidity.readTemperature();

Serial.println(SSD_State);

if (millis() - prevTime >= 5000) {
    SSD_State = (SSD_State+1)%5;
    Serial.println(SSD_State);
    prevTime = millis();
  }  
  
    // display time 
if (SSD_State == 0){
  display.clearDisplay();
  display.setTextSize(1);
  display.setCursor(0,0);
  display.print("Tijd:");
  display.setTextSize(3);
  display.setCursor(12,11);
  display.print(t.hour);  
  display.setCursor(42,11);
  display.print(":"); 
  display.setCursor(54,11);  
  display.print(t.min);  
  display.display();   
 }
  // display temperature
if (SSD_State == 1) {
  display.clearDisplay();
  display.setTextSize(1);
  display.setCursor(0,0);
  display.print("Temperatuur:");
  display.setTextSize(3);
  display.setCursor(12,11);
  display.print(temp);
  display.print(" ");
  display.setTextSize(1);
  display.setCursor(105,13);
  display.cp437(true);
  display.write(167);
  display.setTextSize(2);
  display.print("C");
  display.display(); 
 }  

  // display humidititty
if (SSD_State == 2){
  display.clearDisplay();
  display.setTextSize(1);
  display.setCursor(0,0);
  display.print("Luchtvochtigheid:");
  display.setTextSize(3);
  display.setCursor(12,11);
  display.print(humd);
  display.print(" ");
  display.setTextSize(1);
  display.setCursor(105,13);
  display.setTextSize(2);
  display.print("%");
  display.display(); 
 }
  // Display CO2 
 if (SSD_State == 3){
  display.clearDisplay();
  display.setTextSize(1);
  display.setCursor(0,0);
  display.print("CO2 gehalte:");
  display.setTextSize(3);
  display.setCursor(12,11);
  display.print(ppm_pwm);   
  display.display();  
 }
  // Display Light intensity
 if (SSD_State == 4){
  display.clearDisplay();
  display.setTextSize(1);
  display.setCursor(0,0);
  display.print("Lichtintensiteit:");
  display.setTextSize(3);
  display.setCursor(12,11);
  display.print(lux);   
  display.display();  
 } 

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ EFFECTIEVE REGELING >\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\//
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

// Luchtbevochter
  if(lux >= 100) {                 //Aanschakelen aan de hand van LICHTSTERKTE
    if(humd <= 78){
      digitalWrite(2, LOW);
    }
    if(humd >= 82){
      digitalWrite(2, HIGH);
    }
   else{
     digitalWrite(2, HIGH);
   }
  }

// Entry Fan
  if(lux >= 100){
    digitalWrite(5, LOW);
  }else{
    digitalWrite(5, HIGH);
  }
  
  // Exit Fan
  if(temp >= 29.0 || humd >= 85){
    digitalWrite(3, LOW);
  }else {
    digitalWrite(3, HIGH);
  }  
  
// Luchtcirculatie ventilator
  if(lux >= 100){        //Tijd wanneer ventilator aanstaat
    digitalWrite(4, LOW);
  } else{
    digitalWrite(4, HIGH);
  }  
}

Which Arduino board do you use ?

Can you give links to the sensors (a link to where you bought them).
Which MHZ library do you use ?
How is everything connected ? The cheap DS3231 modules overcharge the battery when used with 5V. Are you using a cable for the I2C bus ? or perhaps even a flat ribbon cable ?
The OLED displays are known for disturbing the I2C bus for others, especially if you don't have a Adafruit OLED display and you have a 5V Arduino board.

What worries me most is the SoftwareSerial interfering with others and the SRAM usage. The SoftwareSerial library takes over the completely Arduino board. There is a AltSoftSerial which is less demanding: https://www.pjrc.com/teensy/td_libs_AltSoftSerial.html
Adafruit has a test for the memory "freeMemory()": https://learn.adafruit.com/memories-of-an-arduino/measuring-free-memory#sram-370031 Can you run that at the end of setup().

millis() increments every 1.024 mS not every 1 mS, thus it drifts slightly for about 42 times (1024 / 24) and then gets corrected . Thus the most it would be out is 1 mS (just before being corrected).

Since it corrects by 2 every 42 or 43ms, wouldn't it be off by 2ms just before that correction?

2 less than the real time.
1 off compared to an "ideal" 1ms interrupt (which will also be 1ms behind, just before it changes. Or maybe 0.5ms off of some idealized intermediate time. Frame of reference and relativity, you know.)

I would like to do some more tests with the arduino uno, but i can not upload another sketch to it. No errors are showing up when uploading, but the sketch i posted above keeps running no matter what other code i upload to it. Even in serial monitor it says it's not connected. Doesn't matter which COM port i use, sometimes it says acces denied, other times it works but not changing anything.

For full information, here's my wiring:


At the moment i'm using an arduino uno R3
For the MHZ-14a, i'm using the library found here:

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