Go Down

Topic: Ramdom pixels on SSD1306 with DHT22 & DS3231 (Read 562 times) previous topic - next topic

Antrix

Hi, I'm interfacing with a DHT22 sensor utilizing the U8G2 library. The setup also includes a DS3231 RTC module. The problem I'm facing is there is a undesired random pattern that gets drawn every two seconds into the program. Below is an animated gif of the display in action. Please take a look at the minutes section "08". There is a random number generator at the top right corner which also ceases when the random lines appear at the bottom of the display.



The setup is driven by the following code:

Code: [Select]

#include <Arduino.h>
#include <U8g2lib.h>
#include "RTClib.h"
#include "DHT.h"

#ifdef U8X8_HAVE_HW_SPI
#include <SPI.h>
#endif
#ifdef U8X8_HAVE_HW_I2C
#include <Wire.h>
#endif


RTC_DS3231 rtc;
#define DHTPIN 9     // what pin we're connected to
#define DHTTYPE DHT22   // DHT 22  (AM2302)
DHT dht(DHTPIN, DHTTYPE); //// Initialize DHT sensor for normal 16mhz Arduino

U8G2_SSD1306_128X64_NONAME_F_HW_I2C u8g2(U8G2_R0, /* reset=*/ U8X8_PIN_NONE);

char daysOfTheWeek[7][12] = {"SUN", "MON", "TUE", "WED", "THU", "FRI", "SAT"};
float LocalH;  //Stores humidity value
float LocalT; //Stores temperature value

long randNumber;


void setup() {
  u8g2.begin();
  dht.begin();
  Serial.begin(9600);     // initialize serial communication only for debugging purpose
}


void loop(void) {
  u8g2.firstPage();
  do {

    // DATE AND TEMPERATURE
    DateTime now = rtc.now();
    u8g2.setFont(u8g2_font_logisoso16_tr);
    u8g2.setCursor(0, 16);
    u8g2.print(now.day(), DEC); u8g2.print(" "); u8g2.print(daysOfTheWeek[now.dayOfTheWeek()]); u8g2.print(" ");
    //u8g2.setCursor(58, 16);
    u8g2.setFont(u8g2_font_logisoso16_tr);
    u8g2.print(LocalT, 0); u8g2.print(" "); u8g2.setFont(u8g2_font_logisoso16_tr);
    LocalH = dht.readHumidity() * 1; // Sensor compensation
    LocalT = dht.readTemperature() * 0.955; // Sensor compensation

    // TIME
    u8g2.setFont(u8g2_font_logisoso42_tn);
    u8g2.setCursor(0, 64);
    byte hourNow;
    if (now.hour() > 12 )
    {
      hourNow = now.hour() - 12;
    }
    else
    {
      hourNow = now.hour();
    }
    if (hourNow < 10) {      // Zero padding if value less than 10 ie."09" instead of "9"
      u8g2.print("0"); u8g2.print(hourNow, DEC);
    }
    else {
      u8g2.print(hourNow, DEC);
    }
    u8g2.print(":");
    if (now.minute() < 10) {      // Zero padding if value less than 10 ie."09" instead of "9"
      u8g2.print("0"); u8g2.print(now.minute(), DEC);
    }
    else {
      u8g2.print(now.minute(), DEC);
    }

    randNumber = random(1, 10);
    u8g2.setFont(u8g2_font_logisoso16_tr);
    u8g2.setCursor(118, 16);
    u8g2.print(randNumber);

  } while ( u8g2.nextPage() );
}


Is there any way to get rid of the random lines at the bottom and also avoid the display to freeze as reflected by the random counter?

Thanks.

robtillaart

If you remove the calls to the DHT22, does the effect disappear?
Rob Tillaart

Nederlandse sectie - http://arduino.cc/forum/index.php/board,77.0.html -
(Please do not PM for private consultancy)

Antrix

If you remove the calls to the DHT22, does the effect disappear?

Thank you for the suggestion. Now, I tried it without the DHT22 code in loop section, and the lines disappear, even the screen does not freeze! But I need temperature and humidity. Is it possible to keep the DHT22 code and still avoid the artifacts?

Thanks!

robtillaart

I see you use the Adafruit DHT library which I do not know in detail.
It might be that it disables interrupts during handshake which could be used in the LCD lib for timing.

I isolated the DHT calls and added a small delay after them to separate them from the display calls.
please give it a try
(this is not a final solution, just to understand behavior)

Code: (test) [Select]

#include <Arduino.h>
#include <U8g2lib.h>
#include "RTClib.h"
#include "DHT.h"

#ifdef U8X8_HAVE_HW_SPI
#include <SPI.h>
#endif
#ifdef U8X8_HAVE_HW_I2C
#include <Wire.h>
#endif


RTC_DS3231 rtc;

#define DHTPIN 9            // what pin we're connected to
#define DHTTYPE DHT22       // DHT 22  (AM2302)
DHT dht(DHTPIN, DHTTYPE);   // Initialize DHT sensor for normal 16mhz Arduino

U8G2_SSD1306_128X64_NONAME_F_HW_I2C u8g2(U8G2_R0, /* reset=*/ U8X8_PIN_NONE);

char daysOfTheWeek[7][12] = {"SUN", "MON", "TUE", "WED", "THU", "FRI", "SAT"};

float LocalH;     // Stores humidity value
float LocalT;     // Stores temperature value

long randNumber;


void setup() {
  u8g2.begin();
  dht.begin();
  Serial.begin(9600);     // initialize serial communication only for debugging purpose
}


void loop(void) {

  u8g2.firstPage();

  do {

    LocalH = dht.readHumidity() * 1;          // Sensor compensation
    LocalT = dht.readTemperature() * 0.955;   // Sensor compensation
    delay(100);

    // DATE AND TEMPERATURE
    DateTime now = rtc.now();

    u8g2.setFont(u8g2_font_logisoso16_tr);
    u8g2.setCursor(0, 16);
    u8g2.print(now.day(), DEC);
    u8g2.print(" ");
    u8g2.print(daysOfTheWeek[now.dayOfTheWeek()]);
    u8g2.print(" ");

    //u8g2.setCursor(58, 16);
    u8g2.setFont(u8g2_font_logisoso16_tr);
    u8g2.print(LocalT, 0);
    u8g2.print(" ");
    u8g2.setFont(u8g2_font_logisoso16_tr);


    // TIME
    u8g2.setFont(u8g2_font_logisoso42_tn);
    u8g2.setCursor(0, 64);
    byte hourNow = now.hour();
    if (hourNow > 12 ) hourNow -= 12;
    if (hourNow < 10) {                  // Zero padding "09" instead of "9"
      u8g2.print("0");
    }
    u8g2.print(hourNow, DEC);

    u8g2.print(":");
    if (now.minute() < 10) {             // Zero padding "09" instead of "9"
      u8g2.print("0");
    }
    u8g2.print(now.minute(), DEC);

    randNumber = random(1, 10);
    u8g2.setFont(u8g2_font_logisoso16_tr);
    u8g2.setCursor(118, 16);
    u8g2.print(randNumber);

  } while ( u8g2.nextPage() );
}


Rob Tillaart

Nederlandse sectie - http://arduino.cc/forum/index.php/board,77.0.html -
(Please do not PM for private consultancy)

Antrix

I see you use the Adafruit DHT library which I do not know in detail.
It might be that it disables interrupts during handshake which could be used in the LCD lib for timing.

I isolated the DHT calls and added a small delay after them to separate them from the display calls.
please give it a try
(this is not a final solution, just to understand behavior)

Code: (test) [Select]

#include <Arduino.h>
#include <U8g2lib.h>
#include "RTClib.h"
#include "DHT.h"

#ifdef U8X8_HAVE_HW_SPI
#include <SPI.h>
#endif
#ifdef U8X8_HAVE_HW_I2C
#include <Wire.h>
#endif


RTC_DS3231 rtc;

#define DHTPIN 9            // what pin we're connected to
#define DHTTYPE DHT22       // DHT 22  (AM2302)
DHT dht(DHTPIN, DHTTYPE);   // Initialize DHT sensor for normal 16mhz Arduino

U8G2_SSD1306_128X64_NONAME_F_HW_I2C u8g2(U8G2_R0, /* reset=*/ U8X8_PIN_NONE);

char daysOfTheWeek[7][12] = {"SUN", "MON", "TUE", "WED", "THU", "FRI", "SAT"};

float LocalH;     // Stores humidity value
float LocalT;     // Stores temperature value

long randNumber;


void setup() {
  u8g2.begin();
  dht.begin();
  Serial.begin(9600);     // initialize serial communication only for debugging purpose
}


void loop(void) {

  u8g2.firstPage();

  do {

    LocalH = dht.readHumidity() * 1;          // Sensor compensation
    LocalT = dht.readTemperature() * 0.955;   // Sensor compensation
    delay(100);

    // DATE AND TEMPERATURE
    DateTime now = rtc.now();

    u8g2.setFont(u8g2_font_logisoso16_tr);
    u8g2.setCursor(0, 16);
    u8g2.print(now.day(), DEC);
    u8g2.print(" ");
    u8g2.print(daysOfTheWeek[now.dayOfTheWeek()]);
    u8g2.print(" ");

    //u8g2.setCursor(58, 16);
    u8g2.setFont(u8g2_font_logisoso16_tr);
    u8g2.print(LocalT, 0);
    u8g2.print(" ");
    u8g2.setFont(u8g2_font_logisoso16_tr);


    // TIME
    u8g2.setFont(u8g2_font_logisoso42_tn);
    u8g2.setCursor(0, 64);
    byte hourNow = now.hour();
    if (hourNow > 12 ) hourNow -= 12;
    if (hourNow < 10) {                  // Zero padding "09" instead of "9"
      u8g2.print("0");
    }
    u8g2.print(hourNow, DEC);

    u8g2.print(":");
    if (now.minute() < 10) {             // Zero padding "09" instead of "9"
      u8g2.print("0");
    }
    u8g2.print(now.minute(), DEC);

    randNumber = random(1, 10);
    u8g2.setFont(u8g2_font_logisoso16_tr);
    u8g2.setCursor(118, 16);
    u8g2.print(randNumber);

  } while ( u8g2.nextPage() );
}



Thanks Rob for the support. I tried the code with delay. The issue seems to be that witout delay, the artifact skips past quickly. With the delay in place, it stays a bit longer, so it appears prominetly at the moment.

Meanwhile, I tried the same code with SimpleDHT, while it does not result into scrambled lines, it further reduces the refresh rate so the random generator refreshed 2-3 times a second. This would in general affect further integration of functions to the display.

robtillaart


OK, as the temperature and humidity does not change 20x per second the program could be set up differently.
You can request an update of both e.g. once every two seconds.

Furthermore by using a smarter random algorithm, you can generate random numbers between 1..10 much faster.

Idea is to generate a random number between 0 and 999.999.999 -> then you have 9 random digits in one call.
you can put these on the page one after another, The code below shows a random10() function that does exactly this.

Give it a try

Code: (not tested) [Select]

#include <Arduino.h>
#include <U8g2lib.h>
#include "RTClib.h"
#include "DHT.h"

#ifdef U8X8_HAVE_HW_SPI
#include <SPI.h>
#endif
#ifdef U8X8_HAVE_HW_I2C
#include <Wire.h>
#endif


RTC_DS3231 rtc;

#define DHTPIN 9            // what pin we're connected to
#define DHTTYPE DHT22       // DHT 22  (AM2302)
DHT dht(DHTPIN, DHTTYPE);   // Initialize DHT sensor for normal 16mhz Arduino

U8G2_SSD1306_128X64_NONAME_F_HW_I2C u8g2(U8G2_R0, /* reset=*/ U8X8_PIN_NONE);

char daysOfTheWeek[7][12] = {"SUN", "MON", "TUE", "WED", "THU", "FRI", "SAT"};

float LocalH;     // Stores humidity value
float LocalT;     // Stores temperature value
// timing var
uint32_t lastUpdate = 0;

uint8_t randNumber;


// a random function to generate 0..9
uint8_t random10()
{
  static uint32_t bigrandom = 0;
  static uint8_t rndcnt = 0;

  uint8_t rv = 0;
  if (rndcnt == 0)
  {
    bigrandom = random(1000000000);
    rndcnt = 9;
  }

  rv = bigrandom % 10;
  bigrandom /= 10;
  rndcnt--;

  return rv;
}



void setup() {
  u8g2.begin();
  dht.begin();
  Serial.begin(9600);     // initialize serial communication only for debugging purpose

  LocalH = dht.readHumidity() * 1;          // Sensor compensation
  LocalT = dht.readTemperature() * 0.955;   // Sensor compensation
  lastUpdate = millis();
}


void loop(void) {

  u8g2.firstPage();

  do {
    if (millis() - lastUpdate > 2000)
    {
      LocalH = dht.readHumidity() * 1;          // Sensor compensation
      LocalT = dht.readTemperature() * 0.955;   // Sensor compensation
      lastUpdate = millis();
    }


    // DATE AND TEMPERATURE
    DateTime now = rtc.now();

    u8g2.setFont(u8g2_font_logisoso16_tr);
    u8g2.setCursor(0, 16);
    u8g2.print(now.day(), DEC);
    u8g2.print(" ");
    u8g2.print(daysOfTheWeek[now.dayOfTheWeek()]);
    u8g2.print(" ");

    //u8g2.setCursor(58, 16);
    u8g2.setFont(u8g2_font_logisoso16_tr);
    u8g2.print(LocalT, 0);
    u8g2.print(" ");
    u8g2.setFont(u8g2_font_logisoso16_tr);


    // TIME
    u8g2.setFont(u8g2_font_logisoso42_tn);
    u8g2.setCursor(0, 64);
    byte hourNow = now.hour();
    if (hourNow > 12 ) hourNow -= 12;
    if (hourNow < 10) {                  // Zero padding "09" instead of "9"
      u8g2.print("0");
    }
    u8g2.print(hourNow, DEC);

    u8g2.print(":");
    if (now.minute() < 10) {             // Zero padding "09" instead of "9"
      u8g2.print("0");
    }
    u8g2.print(now.minute(), DEC);

    randNumber = random10() + 1;
    u8g2.setFont(u8g2_font_logisoso16_tr);
    u8g2.setCursor(118, 16);
    u8g2.print(randNumber);

  } while ( u8g2.nextPage() );
}
Rob Tillaart

Nederlandse sectie - http://arduino.cc/forum/index.php/board,77.0.html -
(Please do not PM for private consultancy)

Antrix

OK, as the temperature and humidity does not change 20x per second the program could be set up differently.
You can request an update of both e.g. once every two seconds.

Furthermore by using a smarter random algorithm, you can generate random numbers between 1..10 much faster.

Idea is to generate a random number between 0 and 999.999.999 -> then you have 9 random digits in one call.
you can put these on the page one after another, The code below shows a random10() function that does exactly this.

Give it a try

Code: (not tested) [Select]

#include <Arduino.h>
#include <U8g2lib.h>
#include "RTClib.h"
#include "DHT.h"

#ifdef U8X8_HAVE_HW_SPI
#include <SPI.h>
#endif
#ifdef U8X8_HAVE_HW_I2C
#include <Wire.h>
#endif


RTC_DS3231 rtc;

#define DHTPIN 9            // what pin we're connected to
#define DHTTYPE DHT22       // DHT 22  (AM2302)
DHT dht(DHTPIN, DHTTYPE);   // Initialize DHT sensor for normal 16mhz Arduino

U8G2_SSD1306_128X64_NONAME_F_HW_I2C u8g2(U8G2_R0, /* reset=*/ U8X8_PIN_NONE);

char daysOfTheWeek[7][12] = {"SUN", "MON", "TUE", "WED", "THU", "FRI", "SAT"};

float LocalH;     // Stores humidity value
float LocalT;     // Stores temperature value
// timing var
uint32_t lastUpdate = 0;

uint8_t randNumber;


// a random function to generate 0..9
uint8_t random10()
{
  static uint32_t bigrandom = 0;
  static uint8_t rndcnt = 0;

  uint8_t rv = 0;
  if (rndcnt == 0)
  {
    bigrandom = random(1000000000);
    rndcnt = 9;
  }

  rv = bigrandom % 10;
  bigrandom /= 10;
  rndcnt--;

  return rv;
}



void setup() {
  u8g2.begin();
  dht.begin();
  Serial.begin(9600);     // initialize serial communication only for debugging purpose

  LocalH = dht.readHumidity() * 1;          // Sensor compensation
  LocalT = dht.readTemperature() * 0.955;   // Sensor compensation
  lastUpdate = millis();
}


void loop(void) {

  u8g2.firstPage();

  do {
    if (millis() - lastUpdate > 2000)
    {
      LocalH = dht.readHumidity() * 1;          // Sensor compensation
      LocalT = dht.readTemperature() * 0.955;   // Sensor compensation
      lastUpdate = millis();
    }


    // DATE AND TEMPERATURE
    DateTime now = rtc.now();

    u8g2.setFont(u8g2_font_logisoso16_tr);
    u8g2.setCursor(0, 16);
    u8g2.print(now.day(), DEC);
    u8g2.print(" ");
    u8g2.print(daysOfTheWeek[now.dayOfTheWeek()]);
    u8g2.print(" ");

    //u8g2.setCursor(58, 16);
    u8g2.setFont(u8g2_font_logisoso16_tr);
    u8g2.print(LocalT, 0);
    u8g2.print(" ");
    u8g2.setFont(u8g2_font_logisoso16_tr);


    // TIME
    u8g2.setFont(u8g2_font_logisoso42_tn);
    u8g2.setCursor(0, 64);
    byte hourNow = now.hour();
    if (hourNow > 12 ) hourNow -= 12;
    if (hourNow < 10) {                  // Zero padding "09" instead of "9"
      u8g2.print("0");
    }
    u8g2.print(hourNow, DEC);

    u8g2.print(":");
    if (now.minute() < 10) {             // Zero padding "09" instead of "9"
      u8g2.print("0");
    }
    u8g2.print(now.minute(), DEC);

    randNumber = random10() + 1;
    u8g2.setFont(u8g2_font_logisoso16_tr);
    u8g2.setCursor(118, 16);
    u8g2.print(randNumber);

  } while ( u8g2.nextPage() );
}


Thanks Rob!. This serves the purpose well! Although it does not obliterate the issue, it does push it at bay for a while. I tweaked the millis timer to 30 seconds, so unless someone stares at the display, one is likely to miss it altogether.

That random number generator you incorporated is far superior! How did you orchestrate that algorithm?

Thanks a lot once again for your help!

robtillaart

That random number generator you incorporated is far superior! How did you orchestrate that algorithm?
millions years of experience ;)

more seriously, the standard random number generates 32 random bits per (expensive) call.
You were using only about <4 of them so throwing away >28. I just used those allready random bits.

Nice part is that you can parameterize the algorithm for any range e.g. 27 Then you just do %27 and /27 and the counter starts at another /lower value.
Rob Tillaart

Nederlandse sectie - http://arduino.cc/forum/index.php/board,77.0.html -
(Please do not PM for private consultancy)

robtillaart

#8
Jan 11, 2018, 10:47 pm Last Edit: Jan 11, 2018, 11:56 pm by robtillaart
Variation of random10() to generate random numbers between 2..255 fast
16 bits numbers are left as an exercise ...

Code: [Select]
uint8_t randomFast(uint8_t num)
{
  static uint32_t bigrandom = 0;
  if (bigrandom < num) bigrandom = random();
  uint32_t tmp = bigrandom / num
  uint8_t rv = bigrandom - tmp * num;  // faster than % modulo
  bigrandom = t;
  return rv;
}


this one is probably a tiny bit faster than random10() in the code.
Rob Tillaart

Nederlandse sectie - http://arduino.cc/forum/index.php/board,77.0.html -
(Please do not PM for private consultancy)

Antrix

Variation of random10() to generate random numbers between 2..255 fast
16 bits numbers are left as an exercise ...

Code: [Select]
uint8_t randomFast(uint8_t num)
{
  static uint32_t bigrandom = 0;
  if (bigrandom < num) bigrandom = random();
  uint32_t tmp = bigrandom / num
  uint8_t rv = bigrandom - tmp * num;  // faster than % modulo
  bigrandom = t;
  return rv;
}


this one is probably a tiny bit faster than random10() in the code.
Certainly, it had to be millions of years into conjuring one! I'm overwhelmed! My rest of the code looks primitive to this in comparison!
Thanks Rob, this code will come handy in future!

Go Up