Issue with 0.96" display, code issue?

I'm making a Christmas Countdown Ornament, but I'm having issues. I don't know how to explain this in smart-people terms, so bear with me please.

I have run the basic Adafruit 0.96" 128x64 display code (with all the shapes and animations) and it works perfectly fine. I run my code, and it freezes the screen. If I unplug my board and plug it back in, the display doesn't even turn on.

Here is my code. Again, I know it's messy, but I just want to know what the issue is.

/*
Parts included: 128x64 OLED Graphic Screen
                DS3231 RTC Clock Module
                Arduino Uno
                Prototype Sheild
                Remote IR Sensor
                Various Wires
*/
int receiverpin = 8;
#include "Wire.h"
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#include <IRremote.h>

#define DS3231_I2C_ADDRESS 0x68
#define SCREEN_WIDTH 128 // OLED display width, in pixels
#define SCREEN_HEIGHT 64 // OLED display height, in pixels

IRrecv irrecv(receiverpin);
decode_results results;

int days, hours, minutes, seconds, totalHours, totalMinutes, totalSeconds = 0;
bool irRecieved = false;

// Declaration for an SSD1306 display connected to I2C (SDA, SCL pins)
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, -1);


byte decToBcd(byte val) {
  return( (val/10*16) + (val%10) );
}
// Convert binary coded decimal to normal decimal numbers
byte bcdToDec(byte val) {
  return( (val/16*10) + (val%16) );
}

void setDS3231time(byte second, byte minute, byte hour, byte dayOfWeek, byte dayOfMonth, byte month, byte year) {
  // sets time and date data to DS3231
  Wire.beginTransmission(DS3231_I2C_ADDRESS);
  Wire.write(0); // set next input to start at the seconds register
  Wire.write(decToBcd(second)); // set seconds
  Wire.write(decToBcd(minute)); // set minutes
  Wire.write(decToBcd(hour)); // set hours
  Wire.write(decToBcd(dayOfWeek)); // set day of week (1=Sunday, 7=Saturday)
  Wire.write(decToBcd(dayOfMonth)); // set date (1 to 31)
  Wire.write(decToBcd(month)); // set month
  Wire.write(decToBcd(year)); // set year (0 to 99)
  Wire.endTransmission();
}
void readDS3231time(byte *second, byte *minute, byte *hour, byte *dayOfWeek, byte *dayOfMonth, byte *month, byte *year) {
  Wire.beginTransmission(DS3231_I2C_ADDRESS);
  Wire.write(0); // set DS3231 register pointer to 00h
  Wire.endTransmission();
  Wire.requestFrom(DS3231_I2C_ADDRESS, 7);
  // request seven bytes of data from DS3231 starting from register 00h
  *second = bcdToDec(Wire.read() & 0x7f);
  *minute = bcdToDec(Wire.read());
  *hour = bcdToDec(Wire.read() & 0x3f);
  *dayOfWeek = bcdToDec(Wire.read());
  *dayOfMonth = bcdToDec(Wire.read());
  *month = bcdToDec(Wire.read());
  *year = bcdToDec(Wire.read());
}

void translateIR() {
  switch (results.value) {
    case 0x10:
      irRecieved = false;
      daysHoursMinutes();
      break;
    case 0x810:
      irRecieved = false;
      daysHoursMinutesSeconds();
    case 0x410:
      irRecieved = false;
      totalHoursMinutesSeconds();
      break;
    case 0xC10:
      irRecieved = false;
      totalHoursTotalMinutesTotalSeconds();
      break;
    case 0x210:
      irRecieved = false;
      totalDays();
      break;
    case 0xA10:
      irRecieved = false;
      totalHour();
      break;
    case 0x610:
      irRecieved = false;
      totalMinute();
      break;
    case 0xE10:
      irRecieved = false;
      totalSecond();
      break;
      
  }
}

void createCountdownVariables() {
  byte second, minute, hour, dayOfWeek, dayOfMonth, month, year;
  readDS3231time(&second, &minute, &hour, &dayOfWeek, &dayOfMonth, &month, &year);
  if (month == 11) {
    int days = (29-dayOfMonth) + 25;
  } else if (month == 12) {
    int days = 24-dayOfMonth;
  } else {
    int days = 0;
  }
  int hours = 23-hour;
  int minutes = 59-minute;
  int seconds = 59-second;
  int totalHours = (days*24) + hours;
  int totalMinutes = (totalHours*60) + minutes;
  int totalSeconds = (totalMinutes*60) + seconds;
}

void daysHoursMinutes() {
  for (int timer = 0; timer++; timer < 3600 || irRecieved == true) {
    createCountdownVariables();
    display.clearDisplay();
    display.setTextSize(2);
    display.setTextColor(WHITE);
    display.setCursor(7, 7);
    display.println("Days: ");
    display.println(days);
    display.setCursor(7, 26);
    display.println("Hours: ");
    display.println(hours);
    display.setCursor(7, 50);
    display.println("Minutes: ");
    display.println(minutes);
    delay(50);
    irRecieve();
  }
  display.clearDisplay();
}

void daysHoursMinutesSeconds() {
  for (int timer = 0; timer++; timer < 3600 || irRecieved == true) {
    createCountdownVariables();
    display.clearDisplay();
    display.setTextSize(2);
    display.setTextColor(WHITE);
    display.setCursor(7, 5);
    display.println("Days: ");
    display.println(days);
    display.setCursor(7, 20);
    display.println("Hours: ");
    display.println(hours);
    display.setCursor(7, 35);
    display.println("Minutes: ");
    display.println(minutes);
    display.setCursor(7, 50);
    display.println("Seconds: ");
    display.println(seconds);
    delay(50);
    irRecieve();
  }
  display.clearDisplay();
}

void totalHoursMinutesSeconds() {
  for (int timer = 0; timer++; timer < 3600 || irRecieved == true) {
    createCountdownVariables();
    display.clearDisplay();
    display.setTextSize(2);
    display.setTextColor(WHITE);
    display.setCursor(7, 7);
    display.println("Total Hours: ");
    display.println(totalHours);
    display.setCursor(7, 26);
    display.println("Minutes: ");
    display.println(minutes);
    display.setCursor(7, 50);
    display.println("Seconds: ");
    display.println(seconds);
    delay(50);
    irRecieve();
  }
  display.clearDisplay();
}

void totalHoursTotalMinutesTotalSeconds() {
  for (int timer = 0; timer++; timer < 3600 || irRecieved == true) {
    createCountdownVariables();
    display.clearDisplay();
    display.setTextSize(2);
    display.setTextColor(WHITE);
    display.setCursor(7, 7);
    display.println("Total Hours: ");
    display.println(totalHours);
    display.setCursor(7, 26);
    display.println("Total Minutes: ");
    display.println(totalMinutes);
    display.setCursor(7, 50);
    display.println("Total Seconds: ");
    display.println(totalSeconds);
    delay(50);
    irRecieve();
  }
  display.clearDisplay();
}

void totalDays() {
  for (int timer = 0; timer++; timer < 3600 || irRecieved == true) {
    createCountdownVariables();
    display.clearDisplay();
    display.setTextSize(2);
    display.setTextColor(WHITE);
    display.setCursor(7, 50);
    display.println("Days: ");
    display.println(days);
    delay(50);
    irRecieve();
  }
  display.clearDisplay();
}

void totalHour() {
  for (int timer = 0; timer++; timer < 3600 || irRecieved == true) {
    createCountdownVariables();
    display.clearDisplay();
    display.setTextSize(2);
    display.setTextColor(WHITE);
    display.setCursor(7, 50);
    display.println("Total Hours: ");
    display.println(totalHours);
    delay(50);
    irRecieve();
  }
  display.clearDisplay();
}

void totalMinute() {
  for (int timer = 0; timer++; timer < 3600 || irRecieved == true) {
    createCountdownVariables();
    display.clearDisplay();
    display.setTextSize(2);
    display.setTextColor(WHITE);
    display.setCursor(7, 50);
    display.println("Total Minutes: ");
    display.println(totalMinutes);
    delay(50);
    irRecieve();
  }
  display.clearDisplay();
}

void totalSecond() {
  for (int timer = 0; timer++; timer < 3600 || irRecieved == true) {
    createCountdownVariables();
    display.clearDisplay();
    display.setTextSize(2);
    display.setTextColor(WHITE);
    display.setCursor(7, 50);
    display.println("Total Seconds: ");
    display.println(totalSeconds);
    delay(50);
    irRecieve();
  }
  display.clearDisplay();
}

void irRecieve() {
  if (irrecv.decode(&results)) {
    irRecieved= true;
    translateIR();
    for (int z = 0; z < 2; z++) {
      irrecv.resume();
    }
  }
}

void setup() {
  irrecv.enableIRIn();
  Serial.begin(115200);
  setDS3231time(00, 00, 10, 6, 1, 12, 2023);
  if(!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) { // Address 0x3D for 128x64
    Serial.println(F("SSD1306 allocation failed"));
    for(;;);
  }
  delay(2000);
  
  display.clearDisplay();
  daysHoursMinutesSeconds();

}

void loop() {
  irRecieve();
  
}

I appreciate any and all help. This is really bothering me and I would like to get it working by tonight. Thanks in advance.

Those are not pointers. Your function returns an int so just assign it to the variable

second = bcdToDec(Wire.read() & 0x7f);
...

I see. Thank you for pointing that out.

I don't see how that would fix the problem with the display not doing it's thing.

hi @algorithmmusic,

From recollection of using the Adafruit display library, you need to add

  display.display();

at the end of the display command set as shown in below example -

void daysHoursMinutes() {
  for (int timer = 0; timer++; timer < 3600 || irRecieved == true) {
    createCountdownVariables();
    display.clearDisplay();
    display.setTextSize(2);
    display.setTextColor(WHITE);
    display.setCursor(7, 7);
    display.println("Days: ");
    display.println(days);
    display.setCursor(7, 26);
    display.println("Hours: ");
    display.println(hours);
    display.setCursor(7, 50);
    display.println("Minutes: ");
    display.println(minutes);
    display.display();   // INSERT THIS HERE
    delay(50);
    irRecieve();
  }
  display.clearDisplay();
}

I think this should resolve your issue.

HTH?

1 Like

Thank you for the help, but it didn't seem to resolve the issue. The display still won't light up (and it's not like it's a wiring problem; I have the same wiring setup as for the Adafruit example)

You also seem to be missing the code that defines the display I2c address -

#define SCREEN_ADDRESS 0x3D ///< See datasheet for Address; 0x3D for 128x64, 0x3C for 128x32

That should be inserted as shown below -

// Declaration for an SSD1306 display connected to I2C (SDA, SCL pins)
#define SCREEN_ADDRESS 0x3D ///< See datasheet for Address; 0x3D for 128x64, 0x3C for 128x32
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, -1);

HTH?

I really appreciate you trying to help- I'm super grateful.

The display - even after adding the screen address definition - hasn't turned on.

I'm sorry to keep bothering you.

these displays do take a fair amount of memory and your board doesn't have a lot to start with. Maybe take your code and try removing other things & libraries to see if you are running out of memory.

I recall having a similar problem but definitely have it working. Those little screens are great. I think it was the screen address issue someone else already pointed out, but I don't recall.

General suggestions that will help when you're stuck on pretty much anything:

  • To help debug, get your serial monitor going and watch it. It'll tell you if it can't init the OLED. Add more Serial.println() lines in various spots in your code to help you see what your code is doing.

  • Put some simple display commands into setup(). I have it as kind of a boot screen as I initialize everything in setup. I put a quick snippet below. Make sure this shows up on the screen when you start your device.

  • Create a new, small script from scratch. Include only what you need to get a "Hello, world!" going to the display. Now compare this to the code that isn't working. You'll probably see what worked in one but not the other. I can't tell you how many times I've done this!

Your IR receiver code may not be working, for example, and you could be chasing the wrong thing. It looks like nothing displays unless you hit a button on the remote control, so if that routine is wrong, it'll look like a dead display. So try doing some display stuff at setup(), and add Serial.println in various spots in your code to see what's happening.

My code from setup():

  // Initialize the OLED
  if(!display.begin(SSD1306_SWITCHCAPVCC, SCREEN_ADDRESS)) {
    Serial.println(F("SSD1306 OLED allocation failed"));
    for(;;); // Gonna hang here...ugh
  }
  display.clearDisplay();
  display.setTextSize(2);
  display.setTextColor(SSD1306_WHITE);
  display.setCursor(0,0);
  display.println(F("Fire"));
  display.println(F("Control"));
  display.display();

Hi @algorithmmusic ,

let's have a look at one of your functions:

void totalMinute() {
  for (int timer = 0; timer++; timer < 3600 || irRecieved == true) {
    createCountdownVariables();
    display.clearDisplay();
    display.setTextSize(2);
    display.setTextColor(WHITE);
    display.setCursor(7, 50);
    display.println("Total Minutes: ");
    display.println(totalMinutes);
    delay(50);
    irRecieve();
  }
  display.clearDisplay();
}

Could you explain what you expect to happen with this

 for (int timer = 0; timer++; timer < 3600 || irRecieved == true) {

Usually it would be

for (initialization; condition; increment) {
 // statement(s);
}

The function createCountdownVariables() which is called there also looks like this

void createCountdownVariables() {
  byte second, minute, hour, dayOfWeek, dayOfMonth, month, year;
  readDS3231time(&second, &minute, &hour, &dayOfWeek, &dayOfMonth, &month, &year);
  if (month == 11) {
    int days = (29-dayOfMonth) + 25;
  } else if (month == 12) {
    int days = 24-dayOfMonth;
  } else {
    int days = 0;
  }
  int hours = 23-hour;
  int minutes = 59-minute;
  int seconds = 59-second;
  int totalHours = (days*24) + hours;
  int totalMinutes = (totalHours*60) + minutes;
  int totalSeconds = (totalMinutes*60) + seconds;
}

Did you know that the data of all local variables are lost when a function is left? So all your data from the RTC and all calculations will not have any effect outside the function ...

The bad news: It is not just a simple bug ...

Whether it can be fixed tonight depends on

  • how much time do you have
  • how much time do we have

to fix it ,,,

Can you explain in words what your sketch should do? That may help ...

[Edit:] After some trials with Wokwi I have the impression that the ssd1306 library plus IRremote may probably not fit into the memory of an UNO or Nano ...

After a lot of trial and error, I think I found the main problem - while, yes, all of the bugs aforementioned are very true.

Turns out I wasn't printing with SSD1306 correctly. I'm currently in the stage of rewriting the code with your replies and uploading to my board every-so-often to make sure it's working properly, and so far, it is.

Thank you all for your help.

Here is a little (probably helpful) early Christmas present for you :wink:

/*

  Forum: https://forum.arduino.cc/t/issue-with-0-96-display-code-issue/1195653
  Wokwi: https://wokwi.com/projects/383021035087828993

*/


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

#define SCREEN_WIDTH 128 // OLED display width, in pixels
#define SCREEN_HEIGHT 64 // OLED display height, in pixels

// Declaration for an SSD1306 display connected to I2C (SDA, SCL pins)
#define OLED_RESET     4 // Reset pin # (or -1 if sharing Arduino reset pin)
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);

RTC_DS1307 rtc;
DateTime now, prev;


void setup() {
  Serial.begin(115200);
  if (!display.begin(SSD1306_SWITCHCAPVCC, 0x3D)) { // Address 0x3D for 128x64
    Serial.println(F("SSD1306 allocation failed"));
    for (;;); // Don't proceed, loop forever
  }
  if (! rtc.begin()) {
    Serial.println("Couldn't find RTC");
    Serial.flush();
    for (;;); // Don't proceed, loop forever
  }
  // Clear the buffer
  display.clearDisplay();
  display.display();

  display.setTextSize(1);                 // Normal 1:1 pixel scale
  display.setTextColor(SSD1306_WHITE);    // Draw white text

}

void loop () {
  now = rtc.now();
  if (now.second() != prev.second()) {
    prev = now;
    printTimeToSerial();
    printTimeToDisplay();
  }
}


void printTimeToDisplay(){
  char buf[80];
  sprintf(buf, " %0.2d.%0.2d.%4d  %0.2d:%0.2d:%0.2d",
          now.day(), now.month(), now.year(),
          now.hour(), now.minute(), now.second()
         );
  display.clearDisplay();
  display.setCursor(0,2);
  display.println(buf);
  display.println();
  display.println(" Still to go ...");
  display.setCursor(0,30);
  display.print("    Days:    ");
  display.println(daysUntilXmas());
  display.print(" or Hours:   ");
  display.println(hoursUntilXmas());
  display.print(" or Minutes: ");
  display.println(minutesUntilXmas());
  display.print(" or Seconds: ");
  display.println(secondsUntilXmas());
  display.drawLine(0,10, display.width(),10, SSD1306_WHITE);
  display.display();
}



void printTimeToSerial() {
  char buf[80];
  sprintf(buf, "Current time: %0.2d.%0.2d.%4d  %0.2d:%0.2d:%0.2d",
          now.day(), now.month(), now.year(),
          now.hour(), now.minute(), now.second()
         );
  Serial.println(buf);
  Serial.print("Days until Xmas: \t");
  Serial.println(daysUntilXmas());
  Serial.print("Hours until Xmas:\t");
  Serial.println(hoursUntilXmas());
  Serial.print("Minutes until Xmas:\t");
  Serial.println(minutesUntilXmas());
  Serial.print("Seconds until Xmas:\t");
  Serial.println(secondsUntilXmas());
}


// "days difference" means "days" not (24 hours per day)!!!
// e.g. on 12/23 there will be "1 day to go" until 23:59:59 o'clock
long daysUntilXmas() {
  int XmasYear = now.year();
  if (now.month() == 12 && now.day() > 24) {
    XmasYear++;
  }
  return daysDiff(now.year(), now.month(), now.day(),
                  XmasYear,          12,     24);

}


// Minutes difference based on 12/24 at 0 o'clock in the morning local RTC time
long minutesUntilXmas() {
  int XmasYear = now.year();
  if (now.month() == 12 && now.day() > 24) {
    XmasYear++;
  }
  return minutesDiff(now.year(), now.month(), now.day(), now.hour(), now.minute(),
                     XmasYear,          12,       24,           0,            0);
}

// Full hours difference based on minutesUntilXmas 
long hoursUntilXmas(){
  long minutes = minutesUntilXmas();
  return (minutes/60);  
}


// Seconds difference based on minutesUntilXmas() plus rest of recent minute
long secondsUntilXmas() {
  long minutes = minutesUntilXmas();
  return (60 - now.second() + minutes * 60);
}

//
// Source https://forum.arduino.cc/t/datetime-calculations/354776/17
//  "Julian Day Number"
//
long JD(int year, int month, int day)
{ // COMPUTES THE JULIAN DATE (JD) GIVEN A GREGORIAN CALENDAR
  return day - 32075 + 1461L * (year + 4800 + (month - 14) / 12) / 4 + 367 * (month - 2 - (month - 14) / 12 * 12) / 12 - 3 * ((year + 4900 + (month - 14) / 12) / 100) / 4;
}

long daysDiff(int year1, int mon1, int day1, int year2, int mon2, int day2)
{
  return JD(year2, mon2, day2) - JD(year1, mon1, day1);
}

long minutesDiff(int year1, int mon1, int day1, int hour1, int min1, int year2, int mon2, int day2, int hour2, int min2 )
{
  int mDiff = (hour2 * 60 + min2) - (hour1 * 60 + min1);
  return daysDiff(year1, mon1, day1, year2, mon2, day2) * 1440 + mDiff;
}

Feel free to check it out on Wokwi:

That's how it looks
image

No IR handling but the sketch uses Julian Day calculation (taken from here
DateTime calculations - #17 by jurs ) !

I have checked my calculation with libre Calc and it seems to be quite ok (one never knows :wink: ). It should even give the correct numbers after Christmas evening for the following year ...

Feel free to use it (or not)!

Good luck!
ec2021

1 Like

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