How to display an image to oled and at the same time blinking a LED

Hi all! need a little help here…
i want to add one more push off switch that works like a sidestand switch in a motorcycle, so i want this button to intterupt the currently running function in my OLED and display a warning image to my OLED and blinking LED at the same time when the sidestand is down.

When the sidestand is up i want it to go back to the normal function before(currently my OLED function is only displaying engine temp, air temp, and voltmeter. these 3 function is operated by using a push button)
im using debouncing and StateChangeDetection to detect when a button becomes pressed. and use that to increment a counter and run my functions based on the counter value.

my problem right now is that when the sidestand is down the OLED display an image and LED is run in a sequence(not at the same time like i want it to be) and keep on looping like that in a sequence…

here’s my code

#include <Bounce2.h>
#include <U8glib.h>
#include <OneWire.h>
#include <DallasTemperature.h>
OneWire bus(2);
DallasTemperature sensors(&bus);
U8GLIB_SSD1306_128X64 u8g(U8G_I2C_OPT_DEV_0|U8G_I2C_OPT_NO_ACK|U8G_I2C_OPT_FAST);

DeviceAddress TemperatureEngine = {0x28, 0x7C, 0x78, 0x84, 0x04, 0x00, 0x00, 0xE1};
DeviceAddress TemperatureAir = {0x28, 0x11, 0x66, 0x83, 0x04, 0x00, 0x00, 0x30};

float Engine;
char TemperatureStringEngine[6] = "-";

float Air;
char TemperatureStringAir[6] = "-";

float vin=0.0;
float temp=0.0;
float r1=9800.0;
float r2=4700.0; 

int LED = 10;
int BUTTONS = 9;

Bounce button;

//assign new image
static unsigned char warning[] U8G_PROGMEM = {image code goes here};

static unsigned char logodoang[] U8G_PROGMEM = {image code goes here};

static unsigned char mt25[] U8G_PROGMEM = {image code goes here};

static unsigned char icobattery[] U8G_PROGMEM = {image code goes here};

static unsigned char icoengine[] U8G_PROGMEM = {image code goes here };

static unsigned char icoair[] U8G_PROGMEM = {image code goes here};


//create new function
void sidestand() {
u8g.drawXBMP( 36, 0, 56, 48, warning);
u8g.setFont(u8g_font_helvB10);
u8g.drawStr(29, 64, "Sidestand !");
}

void splash1() {
u8g.drawXBMP( 32, 0, 64, 64, logodoang);
}

void splash2() {
u8g.drawXBMP( 0, 20, 128, 28, mt25);
}

void enginetemp() {
u8g.setFont(u8g_font_helvB14);
u8g.drawStr(0, 19, "Engine");
u8g.drawXBMP(105, 1, 23, 20, icoengine);
u8g.drawLine(0, 24, 128, 24);
u8g.setFont(u8g_font_fur35n);
u8g.drawStr(18, 64, TemperatureStringEngine);
u8g.setFont(u8g_font_helvB14);
u8g.drawStr(98, 64, "\260C");
}

void airtemp() {
u8g.setFont(u8g_font_helvB14);
u8g.drawStr(0, 19, "Air");
u8g.drawXBMP(105, 0, 23, 23, icoair);
u8g.drawLine(0, 24, 128, 24);
u8g.setFont(u8g_font_fur35n);
u8g.drawStr(18, 64, TemperatureStringAir);
u8g.setFont(u8g_font_helvB14);
u8g.drawStr(98, 64, "\260C");
}

void voltmeter() {
u8g.setFont(u8g_font_helvB14);
u8g.drawStr(0, 19, "Battery");
u8g.drawXBMP(105, 4, 23, 17, icobattery);
u8g.drawLine(0, 24, 128, 24);
u8g.setFont(u8g_font_fur35n);
u8g.setPrintPos(9,64);
u8g.print(vin,1);
u8g.setFont(u8g_font_helvB14);
u8g.drawStr(105, 64, "V");
}

void setup() {
  sensors.setResolution(TemperatureEngine, 9);
  sensors.setResolution(TemperatureAir, 9);
  
  pinMode(LED,OUTPUT);
  pinMode(BUTTONS,INPUT);
  
  u8g.firstPage();  
  do {
    splash1();
  } while( u8g.nextPage() );
  delay(1800);
  u8g.firstPage();
   do {
    splash2();
  } while( u8g.nextPage() );
  delay(1400);

  button.attach(A1, INPUT_PULLUP);
}

//SIDESTAND CODE HERE!
void loop() {
  if(digitalRead(BUTTONS) == HIGH){
        u8g.firstPage();  
        do {
        sidestand();
        } while( u8g.nextPage());
digitalWrite(LED,HIGH);
delay(40);
digitalWrite(LED,LOW);
delay(500);
  }
  static byte selectFunction = 1;
  static unsigned long lastAction;
  unsigned long topLoop = millis();
  
  if (button.update()) {
    if (button.fell()) {
      if (++selectFunction >= 4) {
        selectFunction = 1;
      }
      lastAction = 0;  // this starts the selected function directly
      switch (selectFunction) {
        case 1:
             Serial.println(F("Select Engine Temperature"));
          break;
          
        case 2:
            Serial.println(F("Select Air Temperature"));
          break;
          
        case 3:
            Serial.println(F("Select Voltmeter"));
          break;
      }
    }
  }
  if (topLoop - lastAction >= 750) {
    lastAction = topLoop;
    switch (selectFunction) {
      case 1:
        sensors.requestTemperatures();
        Engine = sensors.getTempC(TemperatureEngine);
        dtostrf(Engine, 2, 0, TemperatureStringEngine);
    
        u8g.firstPage();  
        do {
        enginetemp();
        } while( u8g.nextPage() );
       break;
        
      case 2:
        sensors.requestTemperatures();
        Air = sensors.getTempC(TemperatureAir);
        dtostrf(Air, 2, 0, TemperatureStringAir);
    
        u8g.firstPage();  
        do {
        airtemp();
        } while( u8g.nextPage() );
        break;
        
      case 3:
        int analog_val=analogRead(A7);      // read the value of analog pin A7 and store it in the variable analog_val
        temp = (analog_val * 5.0)/1024.0;   
        vin = temp/(r2/(r1+r2));
        if(vin<0.1)
        {
        vin=0.0;
        }
        
        u8g.firstPage();  
        do {
        voltmeter();
        } while( u8g.nextPage() );
        break;
    }
  }
}

Can anyone help me how to make that OLED display image and blink LED at the same time until the sidestand is up ? and after the sidestand is up the OLED display get back to the 3 function before that i operate with the push button.
Thanks a lot before!

so i want this button to intterupt the currently running function in my OLED

If your Arduino is calling a function that communicates with the OLED, and that function is taking a long time to transfer data, interrupting it doesn't make sense. The OLED doesn't run functions.

Can anyone help me how to make that OLED display image and blink LED at the same time until the sidestand is up ?

You will HAVE to get rid of the delay()s. Look at the blink without delay example. You need a boolean variable that says whether the LED should be blinking. If it should, it may, or may not, be time to toggle the LED. If it is, do it, and update the lastToggled time. Do NOT call the last toggled time previousMillis. Do not call now currentMillis.

If you do, it will be evidence that you do not understand what you are doing.

When you have removed the current blinking mess, and replaced it with millis() based blinking, you should look at the state change detection example. BUTTONS is a crappy name for a pin. There is NOTHING about the name that reflects what the button was sewn onto the Arduino for. sidestandSwitchPin causes no such issues.

It seems to me that you want to do/stop doing something when the sidestand is lowered or raised, not when the sidestand is up or down.

PaulS:
If your Arduino is calling a function that communicates with the OLED, and that function is taking a long time to transfer data, interrupting it doesn't make sense. The OLED doesn't run functions.

yes, sorry what i mean is that interrupting the arduino not the OLED.

You will HAVE to get rid of the delay()s. Look at the blink without delay example. You need a boolean variable that says whether the LED should be blinking. If it should, it may, or may not, be time to toggle the LED. If it is, do it, and update the lastToggled time. Do NOT call the last toggled time previousMillis. Do not call now currentMillis.

If you do, it will be evidence that you do not understand what you are doing.

okay i'll try to learn how to use the blink without delay and that boolean variable thing and implement it in my code for now.

When you have removed the current blinking mess, and replaced it with millis() based blinking, you should look at the state change detection example. BUTTONS is a crappy name for a pin. There is NOTHING about the name that reflects what the button was sewn onto the Arduino for. sidestandSwitchPin causes no such issues.

sure i'll keep an update after i succesfully change that blinking mess with millis() blinking. Yeah right, sorry for that BUTTONS pin name. i just randomly create that crappy name to make it different from my push button in a hurry. i'll change it with the sidestandSwitchPin name that you just suggest :grinning:

It seems to me that you want to do/stop doing something when the sidestand is lowered or raised, not when the sidestand is up or down.

yup, thats what i really want to do. sorry for my bad english..
btw thanks for all the advice !

Hi here’s a little update on my code…

#include <Bounce2.h>
#include <U8glib.h>
#include <OneWire.h>
#include <DallasTemperature.h>
OneWire bus(2);
DallasTemperature sensors(&bus);
U8GLIB_SSD1306_128X64 u8g(U8G_I2C_OPT_DEV_0 | U8G_I2C_OPT_NO_ACK | U8G_I2C_OPT_FAST);

DeviceAddress TemperatureEngine = {0x28, 0x7C, 0x78, 0x84, 0x04, 0x00, 0x00, 0xE1};
DeviceAddress TemperatureAir = {0x28, 0x11, 0x66, 0x83, 0x04, 0x00, 0x00, 0x30};

float Engine;
char TemperatureStringEngine[6] = "-";

float Air;
char TemperatureStringAir[6] = "-";

float vin = 0.0;
float temp = 0.0;
float r1 = 9800.0;
float r2 = 4700.0;

//HERE
const int sidestandSwitchPin = 9;
const int ledPin = 10;

boolean ledState = LOW;
boolean previousButtonState = HIGH;
boolean buttonState = LOW;

long duration = 0;

unsigned long previousMillisSidestand = 0;

const long interval = 500;
//HERE

Bounce button;

//assign new image
static unsigned char warning[] U8G_PROGMEM = {image code goes here};

static unsigned char logodoang[] U8G_PROGMEM = {image code goes here};

static unsigned char mt25[] U8G_PROGMEM = {image code goes here};

static unsigned char icobattery[] U8G_PROGMEM = {image code goes here};

static unsigned char icoengine[] U8G_PROGMEM = {image code goes here };

static unsigned char icoair[] U8G_PROGMEM = {image code goes here};


//create function
void sidestand() {
  u8g.drawXBMP( 36, 0, 56, 48, warning);
  u8g.setFont(u8g_font_helvB10);
  u8g.drawStr(29, 64, "Sidestand !");
}

void splash1() {
  u8g.drawXBMP( 32, 0, 64, 64, logodoang);
}

void splash2() {
  u8g.drawXBMP( 0, 20, 128, 28, mt25);
}

void enginetemp() {
  u8g.setFont(u8g_font_helvB14);
  u8g.drawStr(0, 19, "Engine");
  u8g.drawXBMP(105, 1, 23, 20, icoengine);
  u8g.drawLine(0, 24, 128, 24);
  u8g.setFont(u8g_font_fur35n);
  u8g.drawStr(18, 64, TemperatureStringEngine);
  u8g.setFont(u8g_font_helvB14);
  u8g.drawStr(98, 64, "\260C");
}

void airtemp() {
  u8g.setFont(u8g_font_helvB14);
  u8g.drawStr(0, 19, "Air");
  u8g.drawXBMP(105, 0, 23, 23, icoair);
  u8g.drawLine(0, 24, 128, 24);
  u8g.setFont(u8g_font_fur35n);
  u8g.drawStr(18, 64, TemperatureStringAir);
  u8g.setFont(u8g_font_helvB14);
  u8g.drawStr(98, 64, "\260C");
}

void voltmeter() {
  u8g.setFont(u8g_font_helvB14);
  u8g.drawStr(0, 19, "Battery");
  u8g.drawXBMP(105, 4, 23, 17, icobattery);
  u8g.drawLine(0, 24, 128, 24);
  u8g.setFont(u8g_font_fur35n);
  u8g.setPrintPos(9, 64);
  u8g.print(vin, 1);
  u8g.setFont(u8g_font_helvB14);
  u8g.drawStr(105, 64, "V");
}


void setup() {
  sensors.setResolution(TemperatureEngine, 9);
  sensors.setResolution(TemperatureAir, 9);

  pinMode(ledPin, OUTPUT);
  pinMode(sidestandSwitchPin, INPUT);

  u8g.firstPage();
  do {
    splash1();
  } while ( u8g.nextPage() );
  delay(1800);
  u8g.firstPage();
  do {
    splash2();
  } while ( u8g.nextPage() );
  delay(1400);

  button.attach(A1, INPUT_PULLUP);
}

//SIDESTAND HERE !
void loop()
{
  unsigned long currentMillisSidestand = millis();

  if (currentMillisSidestand - previousMillisSidestand >= interval && buttonState == HIGH )
  {
    previousMillisSidestand = currentMillisSidestand;
    if (ledState == LOW)
    {
      ledState = HIGH;
    }
    else
    {
      ledState = LOW;
    }
  
  if (millis() >= duration)
  {
    previousButtonState = buttonState;
    buttonState = LOW;
    ledState = LOW;
  }
  digitalWrite(ledPin, ledState);
        u8g.firstPage();  
        sidestand();
        
}

if (digitalRead(sidestandSwitchPin) == HIGH)
{

  if (previousButtonState == HIGH)
  {
    buttonState = HIGH; 
  }
  else
  {
    buttonState = LOW;
  }
  duration = millis() + 500;
}

static byte selectFunction = 1;
static unsigned long lastAction;
unsigned long topLoop = millis();

if (button.update()) {
  if (button.fell()) {
    if (++selectFunction >= 4) {
      selectFunction = 1;
    }
    lastAction = 0;  // this starts the selected function directly
    switch (selectFunction) {
      case 1:
        Serial.println(F("Select Engine Temperature"));
        break;

      case 2:
        Serial.println(F("Select Air Temperature"));
        break;

      case 3:
        Serial.println(F("Select Voltmeter"));
        break;
    }
  }
}
if (topLoop - lastAction >= 750) {
  lastAction = topLoop;
  switch (selectFunction) {
    case 1:
      sensors.requestTemperatures();
      Engine = sensors.getTempC(TemperatureEngine);
      dtostrf(Engine, 2, 0, TemperatureStringEngine);

      u8g.firstPage();
      do {
        enginetemp();
      } while ( u8g.nextPage() );
      break;

    case 2:
      sensors.requestTemperatures();
      Air = sensors.getTempC(TemperatureAir);
      dtostrf(Air, 2, 0, TemperatureStringAir);

      u8g.firstPage();
      do {
        airtemp();
      } while ( u8g.nextPage() );
      break;

    case 3:
      int analog_val = analogRead(A7);    // read the value of analog pin A7 and store it in the variable analog_val
      temp = (analog_val * 5.0) / 1024.0;
      vin = temp / (r2 / (r1 + r2));
      if (vin < 0.1)
      {
        vin = 0.0;
      }

      u8g.firstPage();
      do {
        voltmeter();
      } while ( u8g.nextPage() );
      break;
  }
}
}

am i doing it right implementing the blink without delay and that boolean variable thing ?
i have no error right now in my code and the LED is blinking without using delay()…
one question right now is where do i put my void sidestand() function to display it in the OLED at the same time when the LED blinks start ?
thanks :slight_smile:

  unsigned long currentMillisSidestand = millis();

What does this name mean to you? The value that millis() returns is now. So, don't use ridiculously long names that mean nothing.

unsigned long previousMillisSidestand = 0;

Is this the last time there was a sidestand? If you use names that make sense, you'd know whether the code was right.

boolean previousButtonState = HIGH;
boolean buttonState = LOW;

The state of what button?

If it was my code, I'd have sidestandUpSwitch pin, sidestandUpSwitchState, and sidestandUpTime (or Down, depending on what the switch is determining).

I'd have a boolean variable, sidestandUp (or Down, whichever is important), that I set when I detected that the sidestand was up or down.

Blinking the LED would happen when sidestandUp was false (possibly for some period of time).

My motorcycles don't have sidestands, and it's been a while since I rode one that did, and even those did not lock the kickstand down when there was no weight on it. So, it's a bit hard to visualize what you are trying to do, especially without knowing how the sidestand switch is positioned.

PaulS:
My motorcycles don't have sidestands, and it's been a while since I rode one that did, and even those did not lock the kickstand down when there was no weight on it. So, it's a bit hard to visualize what you are trying to do, especially without knowing how the sidestand switch is positioned.

to make it easier for you to visualize what i'm tring to do, just forget about the sidestand thing. so basically im just using a push off button. when the push off button is pressed it blinks the led and the display at the same time. it will stay like that until the push off button is released. that's what im trying to do.

You have some event that triggers an action/state (the switch becomes pressed). You have another action (the switch becomes released) that triggers a different action/state.

Independent of the trigger, you are in some state/performing some action, on each pass through loop().

That action/state might involve drawing something on the display. It might involve periodically toggling the state of a pin.

While I don't whole-heartedly endorse Robin2's program structure, because the conditional action all happens in the called function, instead of the function call being conditional, in this case, it is a good idea.

void loop()
{
   readSwitches();
   showSomethingOnTheDisplay();
   blinkTheAnnoyingLED();
}

Each function may, or may not, do something, depending on what it has done before, on what time it is, and/or on what the state of the switches is/has become.

While I don't whole-heartedly endorse Robin2's program structure, because the conditional action all happens in the called function, instead of the function call being conditional, in this case, it is a good idea.

void loop()

{
  readSwitches();
  showSomethingOnTheDisplay();
  blinkTheAnnoyingLED();
}




Each function may, or may not, do something, depending on what it has done before, on what time it is, and/or on what the state of the switches is/has become.

Hi Paul, sorry for the really late reply. about the Robin2's program structure can you explain it to me more about it ? cause i don't really understand about it. it's been a few week im trying to figure out how to make the program work like i want it to be.. but it still keep looping in order. what i mean with looping in order is when the button is pressed, FIRST the oled display image, SECOND the LED light up, THIRD the oled display my other function(temperature, etc) so the warning display in my oled is only blink at the same time like the LED does. i want the display to stay like that with the LED blinking if the button is pressed. when the button released the display will back diplaying my temperature, etc.