1

I have a OLED SSD1306 & DS3231 RTC, 2 buttons to set the time & date. My project is to display a scrolling text at the top of the OLED, the RTC time in the middle, the day & date on the last line. My issue is I can't get the scrolling text & the time to run right when in the loop together, individually they work normal. When they are together, the scrolling text is fine, but the time is static, its not displaying the current RTC. Then after 1 loop cycle the time seconds text become jumbled, then after a 2nd cycle the minutes & seconds become jumbled. I have tried putting display.clearDisplay(); display.display(); at the end of the loop, doing this fixes the time from becoming jumbled by clearing the buffer before the next cycle, but does not fix the time from being static. How can I get the time to not be static anymore? Any help would be greatly appreciated. Here is my sketch:

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

#define SCREEN_WIDTH 128 // OLED display width, in pixels
#define SCREEN_HEIGHT 64 // OLED display height, in pixels
 
#define OLED_RESET 4
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
 
#define button1    9                       // Button B1 is connected to Arduino pin 9
#define button2    8                       // Button B2 is connected to Arduino pin 8
 
void setup(void) {
  pinMode(button1, INPUT_PULLUP);
  pinMode(button2, INPUT_PULLUP);
  delay(1000);
 
  // by default, the high voltage from the 3.3v line
  display.begin(SSD1306_SWITCHCAPVCC, 0x3c);  // initialize with the I2C address 
  // init done
 
  // Clear the display buffer.
  display.clearDisplay();
  display.display();
 
  display.setTextColor(WHITE, BLACK);
}
 
char Time[]     = "  :  :  ";
char Calendar[] = "  /  /20  ";
byte i, second, minute, hour, day, month, date, year;

void display_day(){
  switch(day){
    case 1:  draw_text(0, 50, " SUNDAY  ", 1); break; //(Column,Row,Data to be displayed,Font size)
    case 2:  draw_text(0, 50, " MONDAY  ", 1); break; //(Column,Row,Data to be displayed,Font size)
    case 3:  draw_text(0, 50, " TUESDAY ", 1); break; //(Column,Row,Data to be displayed,Font size)
    case 4:  draw_text(0, 50, "WEDNESDAY", 1); break; //(Column,Row,Data to be displayed,Font size)
    case 5:  draw_text(0, 50, "THURSDAY ", 1); break; //(Column,Row,Data to be displayed,Font size)
    case 6:  draw_text(0, 50, " FRIDAY  ", 1); break; //(Column,Row,Data to be displayed,Font size)
    default: draw_text(0, 50, "SATURDAY ", 1); //(Column,Row,Data to be displayed,Font size)
  }
}
 
void DS3231_display(){
  // Convert BCD to decimal
  second = (second >> 4) * 10 + (second & 0x0F);
  minute = (minute >> 4) * 10 + (minute & 0x0F);
  hour   = (hour >> 4)   * 10 + (hour & 0x0F);
  month  = (month >> 4)  * 10 + (month & 0x0F);
  date   = (date >> 4)   * 10 + (date & 0x0F);
  year   = (year >> 4)   * 10 + (year & 0x0F);
  // End conversion
 
  Time[7]     = second % 10 + 48;
  Time[6]     = second / 10 + 48;
  Time[4]     = minute % 10 + 48;
  Time[3]     = minute / 10 + 48;
  Time[1]     = hour   % 10 + 48;
  Time[0]     = hour   / 10 + 48;
  Calendar[9] = year   % 10 + 48;
  Calendar[8] = year   / 10 + 48;
  Calendar[4] = date   % 10 + 48;
  Calendar[3] = date   / 10 + 48;
  Calendar[1] = month  % 10 + 48;
  Calendar[0] = month  / 10 + 48;

//Print text
  draw_text(60, 50, Calendar, 1); // Display the date (format: mm/dd/yyyy)
  draw_text(15, 25, Time, 2); // Display the time
}

void blink_parameter(){
  byte j = 0;
  while(j < 10 && digitalRead(button1) && digitalRead(button2)){
    j++;
    delay(25);
  }
}
 
byte edit(byte x_pos, byte y_pos, byte parameter){
  char text[3];
  sprintf(text,"%02u", parameter);
  while(!digitalRead(button1));                      // Wait until button B1 released
  while(true){
    while(!digitalRead(button2)){                    // If button B2 is pressed
      parameter++;
      if(i == 0 && parameter > 12)                   // If month > 12 ==> month = 1
        parameter = 1;      
      if(i == 1 && parameter > 31)                   // If date > 31 ==> date = 1
        parameter = 1;
      if(i == 2 && parameter > 99)                   // If year > 99 ==> year = 0
        parameter = 0;
      if(i == 3 && parameter > 23)                   // If hours > 23 ==> hours = 0
        parameter = 0;
      if(i == 4 && parameter > 59)                   // If minutes > 59 ==> minutes = 0
        parameter = 0;
      sprintf(text,"%02u", parameter);
      draw_text(x_pos, y_pos, text, 1);
      delay(200);                                    // Wait 200ms
    }
    draw_text(x_pos, y_pos, "  ", 1);
    blink_parameter();
    draw_text(x_pos, y_pos, text, 1);
    blink_parameter();
    if(!digitalRead(button1)){                       // If button B1 is pressed
      i++;                                           // Increment 'i' for the next parameter
      return parameter;                              // Return parameter value and exit
    }
  }
}
 
void draw_text(byte x_pos, byte y_pos, char *text, byte text_size) {
  display.setCursor(x_pos, y_pos);
  display.setTextSize(text_size);
  display.print(text);
  display.display();
}

void scroll_text(){
  draw_text(0, 0, "The Pumpkin Express", 1);
  display.display();
  display.startscrollright(0x00, 0x00);
  delay(8500);
  display.stopscroll();
  delay(4000);
  }

void loop() {

  if(!digitalRead(button1)){                         // If button B1 is pressed
    i = 0;
    while(!digitalRead(button1));                    // Wait for button B1 release
    while(true){
      while(!digitalRead(button2)){                  // While button B2 pressed
        day++;                                       // Increment day
        if(day > 7) day = 1;
        display_day();                               // Call display_day function
        delay(200);                                  // Wait 200 ms
      }
      draw_text(0, 50, "         ", 1);
      blink_parameter();                             // Call blink_parameter function
      display_day();                                 // Call display_day function
      blink_parameter();                             // Call blink_parameter function
      if(!digitalRead(button1))                      // If button B1 is pressed
        break;
    }
    //set position of text when editing on button press
    month  = edit(60, 50, month);                    // Edit month
    date   = edit(80, 50, date);                      // Edit date
    year   = edit(110,50, year);                    // Edit year
    hour   = edit(14, 25, hour);                     // Edit hours
    minute = edit(50, 25, minute);                   // Edit minutes
 
    // Convert decimal to BCD
    minute = ((minute / 10) << 4) + (minute % 10);
    hour = ((hour / 10)  << 4) + (hour % 10);
    date = ((date / 10) <<  4) + (date % 10);
    month = ((month / 10)  << 4) + (month % 10);
    year = ((year / 10)  << 4) + (year % 10);
    // End conversion
     
    // Write data to DS3231 RTC
    Wire.beginTransmission(0x68);               // Start I2C protocol with DS3231 address
    Wire.write(0);                              // Send register address
    Wire.write(0);                              // Reset seconds and start oscillator
    Wire.write(minute);                         // Write minute
    Wire.write(hour);                           // Write hour
    Wire.write(day);                            // Write day
    Wire.write(month);                          // Write month
    Wire.write(date);                           // Write date
    Wire.write(year);                           // Write year
    Wire.endTransmission();                     // Stop transmission and release the I2C bus
    delay(200);                                 // Wait 200ms
  }
  
  Wire.beginTransmission(0x68);                 // Start I2C protocol with DS3231 address
  Wire.write(0);                                // Send register address
  Wire.endTransmission(false);                  // I2C restart
  Wire.requestFrom(0x68, 7);                    // Request 7 bytes from DS3231 and release I2C bus at end of reading
  second = Wire.read();                         // Read seconds from register 0
  minute = Wire.read();                         // Read minutes from register 1
  hour   = Wire.read();                         // Read hour from register 2
  day    = Wire.read();                         // Read day from register 3
  month  = Wire.read();                         // Read month from register 4
  date   = Wire.read();                         // Read date from register 5
  year   = Wire.read();                         // Read year from register 6
  Wire.beginTransmission(0x68);                 // Start I2C protocol with DS3231 address
  Wire.write(0x11);                             // Send register address
  Wire.endTransmission(false);                  // I2C restart
  Wire.requestFrom(0x68, 2);                    // Request 2 bytes from DS3231 and release I2C bus at end of reading
                                
  DS3231_display();                             // Display time & calendar
  display_day();                                // Display date
  
  scroll_text();                                // Display scrolling text
              // If i dont use the clear buffers(next 2 line codes), on the 
             //next loop cycle the seconds & minute text becomes jumbled
  //display.clearDisplay();
  //display.display();
 
  delay(50);                                    // Wait 50ms
}
10
  • it is not surprising, your scroll_text() function stops the program execution for 12.5 seconds
    – jsotola
    May 16 at 17:06
  • Thx for the suggestions, I changed the title to my post, & I tried commented out the delays and start & stop in my void scrolling_text(); the text is not scrolling, but is glitching, & the time is all jumbled
    – Stiglitz
    May 16 at 17:15
  • The reason for the delays in the void scrolling_text(); is because I want the text to scroll 1 lap around, pause to display the text, then the scrolling starts back up again. Just like the LCD screen on a train when it is displaying the next train stop
    – Stiglitz
    May 16 at 17:20
  • maybe what you need is a unified display function ... the scroll function does not do any displaying .. it only sets a character buffer ... the time function also does no displaying ... it sets the value of a time variable ... the display function uses the values in the character buffer, and in the time variable, and puts them on the screen
    – jsotola
    May 16 at 17:46
  • So are you saying I should create a new void called void display_text(); & in it put: draw_text(60, 50, Calendar, 1); draw_text(15, 25, Time, 2); draw_text(0, 0, "The Pumpkin Express", 1); ?
    – Stiglitz
    May 16 at 18:29
0

The answer to your title question, "How to get 2 loop functions to cooperate?" is: You can't, because your program can't have two functions with the same name. What you'd need to do instead is redesign your program, keeping in mind the MCU can only do one thing at a time, although you could break up each of several jobs into pieces and interleave them fast enough that we slow humans won't notice.

My approach, when I have a question like this, is to temporarily put aside what I know about coding and about MCUs, and just focus on how to do the job. I list the sub-tasks my code needs to do but without thinking too much about how to do them. Write them down, in the order they required doing, in any note-taking style that suits you.

Now break down each one of those sub-tasks into its sub-tasks. Repeat, until you understand how to code each one. Then you'll know enough to start writing the code.

Update:

@NathanJiang is correct. The solution is not to make two loop() functions (because the language doesn't support that), but to decide how to interleave pieces of each job within 1 function, in such a way that they each appear to operate smoothly and don't interfere with each other. Especially, neither one must call delay(), which stops your code doing anything for the duration. If some piece isn't ready to be done yet, your code must move on to other pieces and do which ever of those is ready. This keeps it checking each piece over and over again, rapidly, doing what is ready and skipping what is not.

2
  • What do you mean I have 2 functions with the same name? All 3 functions have different names, scroll_text(), display_day(), & DS3231_display(). the reason for my title, is because I am having an issue with scroll_text() & DS3231_display() making my program glitch when both are running in the sketch. I can get them to run fine individually.
    – Stiglitz
    May 18 at 0:56
  • I believe that @JRobert means that you cannot have two functions both with the name loop. Jun 17 at 4:36

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.