Implementeren van blink without delay in u8glib sketch

De uitdaging is een led-simulatie:

Mijn configuratie is als volgt:
Arduino Nano met 128*64 OLED, controller SSD1306, SPI interface.
extern [rood] ledje aan pin 3

Ik heb twee monochrome bitmapjes gemaakt (16x21 pixels): led_OFF en led_ON, en die staan als char array in progmem.

Bijgaande sketch doet het volgende:

bitmapje 'led_OFF' naar OLED
print tekst 'OFF' naar OLED
pin 3 LOW

wacht 1 seconde

bitmapje 'led_ON' naar OLED
print tekst 'ON ' naar OLED
pin 3 HIGH

So far so good! Het enige is dat ik gebruik maak van de delay () functie. Dat wil ik graag omzetten naar 'blink without delay' code;

// OLED_SSD_1306_nano_nano_led_simulation_nn
// four pin white OLED I2c
//
// physical led pin 3
// Sept 11, 2020
// Floris Wouterlood
// public domain
//

  #include <avr/pgmspace.h>
  #include <U8glib.h> 

   #define OLED_SCK  13                                                         // pins on the Arduino 
   #define OLED_MOSI 11
   #define OLED_CS   10    
   #define OLED_DC    9  
   #define OLED_RES   8 
   int j = 0;

   U8GLIB_SSD1306_128X64 u8g(OLED_SCK, OLED_MOSI, OLED_CS, OLED_DC, OLED_RES);  // U8glib constructor OLED display

   const int ledPin = 3;
   int flag=0; 
   long longInterval = 1000;                                                    // interval at which to blink (milliseconds) 

   static const unsigned char led_icon_ON [] PROGMEM = {                        // NOTE - these icons are 16 x 21 pixel monochrome 
 
   0x03, 0xc0,   // ∙∙∙∙∙∙████∙∙∙∙∙∙
   0x07, 0xe0,   // ∙∙∙∙∙██████∙∙∙∙∙
   0x0f, 0xf0,   // ∙∙∙∙∙██████∙∙∙∙∙
   0x1f, 0xf8,   // ∙∙∙∙████████∙∙∙∙
   0x1f, 0xf8,   // ∙∙∙██████████∙∙∙
   0x1f, 0xf8,   // ∙∙∙██████████∙∙∙
   0x1f, 0xf8,   // ∙∙∙██████████∙∙∙
   0x1f, 0xf8,   // ∙∙∙██████████∙∙∙
   0x1f, 0xf8,   // ∙∙∙██████████∙∙∙
   0x1f, 0xf8,   // ∙∙∙██████████∙∙∙
   0x3f, 0xfc,   // ∙∙████████████∙∙
   0x40, 0x02,   // ∙█∙∙∙∙∙∙∙∙∙∙∙∙█∙
   0x40, 0x02,   // ∙█∙∙∙∙∙∙∙∙∙∙∙∙█∙
   0x3f, 0xfc,   // ∙∙████████████∙∙
   0x04, 0x10,   // ∙∙∙∙∙█∙∙∙∙∙█∙∙∙∙
   0x04, 0x10,   // ∙∙∙∙∙█∙∙∙∙∙█∙∙∙∙
   0x04, 0x10,   // ∙∙∙∙∙█∙∙∙∙∙█∙∙∙∙
   0x04, 0x10,   // ∙∙∙∙∙█∙∙∙∙∙█∙∙∙∙
   0x04, 0x10,   // ∙∙∙∙∙█∙∙∙∙∙█∙∙∙∙
   0x04, 0x10,   // ∙∙∙∙∙█∙∙∙∙∙█∙∙∙∙
   0x04, 0x10    // ∙∙∙∙∙█∙∙∙∙∙█∙∙∙∙
   };  

   static const unsigned char led_icon_OFF [] PROGMEM = {      
      
   0x03, 0xc0,   // ∙∙∙∙∙∙████∙∙∙∙∙∙
   0x06, 0x60,   // ∙∙∙∙∙██∙∙██∙∙∙∙∙
   0x0c, 0x30,   // ∙∙∙∙██∙∙∙∙██∙∙∙∙
   0x18, 0x18,   // ∙∙∙∙██∙∙∙∙██∙∙∙∙
   0x10, 0x08,   // ∙∙∙██∙∙∙∙∙∙██∙∙∙
   0x10, 0x08,   // ∙∙∙█∙∙∙∙∙∙∙∙█∙∙∙
   0x10, 0x08,   // ∙∙∙█∙∙∙∙∙∙∙∙█∙∙∙
   0x10, 0x08,   // ∙∙∙█∙∙∙∙∙∙∙∙█∙∙∙
   0x10, 0x08,   // ∙∙∙█∙∙∙∙∙∙∙∙█∙∙∙
   0x10, 0x08,   // ∙∙∙█∙∙∙∙∙∙∙∙█∙∙∙
   0x3f, 0xfc,   // ∙∙████████████∙∙
   0x40, 0x02,   // ∙█∙∙∙∙∙∙∙∙∙∙∙∙█∙
   0x40, 0x02,   // ∙█∙∙∙∙∙∙∙∙∙∙∙∙█∙
   0x3f, 0xfc,   // ∙∙████████████∙∙ 
   0x04, 0x10,   // ∙∙∙∙∙█∙∙∙∙∙█∙∙∙∙
   0x04, 0x10,   // ∙∙∙∙∙█∙∙∙∙∙█∙∙∙∙
   0x04, 0x10,   // ∙∙∙∙∙█∙∙∙∙∙█∙∙∙∙
   0x04, 0x10,   // ∙∙∙∙∙█∙∙∙∙∙█∙∙∙∙
   0x04, 0x10,   // ∙∙∙∙∙█∙∙∙∙∙█∙∙∙∙
   0x04, 0x10,   // ∙∙∙∙∙█∙∙∙∙∙█∙∙∙∙
   0x04, 0x10    // ∙∙∙∙∙█∙∙∙∙∙█∙∙∙∙
   };
  
void setup() {
  
   pinMode (ledPin,OUTPUT);
   Serial.begin (9600);
   Serial.println (); 
   Serial.println ("SSD 1306 OLED 128*64 led simulation - uses delay()"); 
   Serial.println (); 
   Serial.print ("let's start"); 
   Serial.println ();  
   u8g.setColorIndex(1);                                                        // display draws with pixel on
   u8g.setFont (u8g_font_unifont);                                              // select font                                
}

void loop() {
   
   {
   u8g.firstPage();
        do {
            draw();
        } while (u8g.nextPage());
       
        flag++;
        if (flag>1) flag =0;  
          Serial.println (flag);  

        if (flag ==0) 
          Serial.println ("led OFF");
       
       else if (flag=1) 
          Serial.println ("led ON");
                      
       delay (longInterval);    
       Serial.println ("delay intervalactive ");

       if (flag ==0) 
          digitalWrite (ledPin,LOW); 
         
       else if (flag=1) 
          digitalWrite (ledPin,HIGH);
       }             
}

void draw(void){

   u8g.drawCircle(40,35, 18);  
   if (flag ==0) 
       u8g.drawBitmapP (33, 25, 2, 21, led_icon_OFF); 

   else if (flag==1)
       u8g.drawBitmapP (33, 25, 2, 21, led_icon_ON);   

   if (flag ==0) 
       u8g.drawStr ( 73, 52, "OFF");

   else if (flag==1)
       u8g.drawStr ( 73, 52, "ON ");
}

de vraag is: blink without delay maakt gebruik van subroutines. U8glib gaat daat niet goed mee om, en het ledje blijft voortdurend op ON staan.
Is het mogelijk om bijgaand, op delay () draaiend sketchje op mijn configuratie draaiend te krijgen met behulp van millis(). Ik ben er nog niet uit, en daarom is elke suggestie welkom! u8glib staat namelijk allerlei creatieve dingen toe, maar geen subroutines. Oplossing?

BWOD maakt geen gebruik van subroutines (functies in C/C++).

En ja, zodra je het BWOD voorbeeld begrijpt kun je simpel BWOD implementeren in je programma.

void loop()
{

  static unsigned long lastTime;
  unsigned long currentTime = millis();

  if (currentTime - lastTime >= longInterval)
  {
    lastTime = currentTime;

    // your code without delay here

  }
}

Verder is dit een bug in je code

    else if (flag = 1)

Het idee is simpel.

Je kijkt op the klok; dat is lastTime.
2)
Vervolgens kijk je regelmatig weer op de klok (currentTime); dat is wat loop() voor je doet.
3)
Als de gewenste tijd verstreken is, doe je iets. Om te repeteren op het gewenste interval moet je wel lastTime bijhouden.

Hoi Photoncatcher.

Blink without delay is zo recht door zee, dat het ingewikkeld kan worden.
Dit is omdat je daarmee dingen moet doen in de code, die je als mens automatisch verwerkt.
Maar als je er goed over nadenkt, dan bevatten alle delen van BWOD, dingen die je zelf ook zou doen.

Ik vermoed dat je een beetje te ver doorgedacht hebt over wat BWOD eigenlijk inhoudt.
En ik vraag me ook af waarom je denkt dat subroutines noodzakelijk zouden zijn voor deze methode.

Sterretje's uitleg hierboven is bijna compleet.
Ik mis daarin nog wat duidelijker uitleg dat je voor deze methode, meer dingen moet onthouden (lees tussentijds opslaan) dan je misschien hoeft te onthouden wanneer je wel delay gebruikt.
Deze toepassing is nogal klein en heeft niet zo heel veel te onthouden.
Maar door BWOD toe te passen, hoef je maar 1 maal per seconde iets op je scherm te tekenen (dat duurt relatief lang), en de rest van de tijd kun je dan iets anders doen.
Het mooie van deze methode is dan ook nog dat je de controle een aantal malen kunt uitvoeren, en anders heel veel andere zaken tussendoor kunt doen.
Dus als je een sketch hebt die 5 seconden (een eeuwigheid) duurt om door loop() te lopen, kun je nog steeds je OLED display mooi op tijd laten knipperen.
De andere methode gaat je dan heel veel timing problemen opleveren.

Nogmaals mijn vraag, waarom denk je dat er subroutines nodig zijn ?

Buitengewoon hartelijk dank. Jullie antwoorden leveren inspiratie op om verder te gaan met pogingen om BWOD goed aan de praat te krijgen met dit u8glib-afhankelijke OLED. Bij TFT display met ILI controllers die draaien onder <mcufriend_kbv> is het allemaal niet zo'n probleem met m'n bitmapjes. Daar werkt BWOD prima. Bij mij is het zo dat ik op een gegeven moment vastloop in hopleoos ingewikkelde sketches waarbij, als je helder logisch denkt, de oplossing bij nader inzien heel eenvoudig is. Menselijke breinen werken nu eenmaal niet volgens keiharde logica en als je eenmaal de mist in gaat duurt het even voordat die optrekt..

Ik ben een fan van subroutines omdat daarmee een sketch modulair wordt, overzichtelijk, en omdat problemen per subroutine kunnen worden opgelost. Het is ook vrij eenvoudig om goed werkende subroutines copy-paste in nieuwe projecten te gebruiken. Heel, heel lang geleden, in MBASIC, was het sport veel GOSUBs te programmeren. Zelfde idee.
Nu dus aan het werk met BWOD in u8glib en daarna u8g2lib om displays te 'temmen'

Hoi Photoncatcher.

De subroutines die jij kent, zijn echte BASIC dingen en ik ken ze nog van de C64.
In C++ word met functies gewerkt, die lijken het meest op de subroutines die jij kent.
Het is helemaal geen probleem om met functies te werken in combinatie met BWOD.
En wanneer je code groter en complexer word, is dat zelfs een heel goed idee.

Maar eigenlijk heeft BWOD erg weinig met functies of dergelijke te maken.
Wanneer je code dus erg groot geworden is, kun je vaker kijken of het al tijd is om je blink te toggelen, en dan de betreffende functie oproepen (function call is dus 1 op 1 met GOSUB).

BWOD helpt om efficiëntere code te krijgen.
Dat komt niet alleen doordat je niet meer heel veel zit te niksen, maar ook omdat je daarmee aan het denken word gezet om het zo efficiënt mogelijk te doen.
Ik zie in jouw code bijvoorbeeld een while staan.
While kan heel nuttig zijn, maar dat is ook blokkerende code, net als delay().
Want terwijl while wordt uitgevoerd, zal er niets anders gedaan worden.
In dit geval word de inhoud van het scherm getekend totdat dat klaar is.
Ik zie ook aan de rest van de code dat dit een stukje is dat je vermoedelijk uit een voorbeeld hebt gehaald, onderaan dit bericht laat ik zien waaraan ik dat heb herkend en wat hier al werd toegepast.

En ik zie dat je een int gebruikt voor een variabele (flag) die alleen maar 0 of 1 hoeft te worden.
Dat is niet zo heel efficiënt in gebruik van het toch al krappe Arduino geheugen, dus kun je daar beter bool voor gebruiken.
Nogmaals, voor alleen de sketch zoals die nu is maakt dit niets uit, maar wel als je dit in een veel grotere sketch wil integreren.

Dit stukje code is op zich niets mis mee, het zal gewoon werken als bedoeld:

      flag++;
        if (flag>1) flag =0; 
          Serial.println (flag);

Maar dit doet exact hetzelfde:

      flag != flag;
          Serial.println (flag);

Het inverteert dus de waarde van flag, en wanneer dat een boolean is, dan zal die dus van 0 naar 1 gaan of van 1 naar 0.

Dit kan ook efficiënter:

      if (flag ==0)
          Serial.println ("led OFF");
       
       else if (flag=1)
          Serial.println ("led ON");

Hier doe je 2 maal een test, de ene keer test je of de waarde nul is, en dan test je of de waarde 1 is.
Elke test kost tijd.

Dit zal ook werken:

      if (flag)
          Serial.println ("led ON");
       
       else   
          Serial.println ("led OFF");

Wanneer je boolean 1 is, dan is het resultaat van de test positief (ook een 1) en word LED ON verstuurd.
Wanneer de boolean niet 1 was, dan was ie automatisch nul, en hoef je daar dus niet meer op te testen.
De else zorgt er voor dat dit alleen word uitgevoerd als niet aan de vorige voorwaarde werd voldaan.
Dit kun je dus 4 maal in je sketch toepassen, en is eerder in je code ook al toegepast.

Dit zijn wel allemaal dingen die niet noodzakelijk zijn, maar ik ben nou eenmaal een muggenzifter.
Ik vind het een goed idee om bewust te zijn van wat je allemaal verbruikt, in tijd en in geheugenruimte.

Ik ben eerlijk gezegd als autodidact/hobbyist niet zo bekend met booleans. Ik leer heel veel van voorbeelden, snippets en van discussie op dit forum. Op het gebied van booleans ligt een uitdaging en ik ga er zeer zeker mee aan de slag

Ik ben dol op de Arduino juist vanwege de noodzaak om zoveel mogeijk efficient in het piepkleine stukje beschikbare geheugen te proppen. Ik kwam met het maken van een Dino stop-motion tot 28 beeldjes 112x62 pixels in progmem bij dezelfde nano/OLED configuratie als op het plaatje boven ("Sketch uses 29872 bytes (97%) of program storage space. Global variables use 482 bytes (21%) of dynamic memory")
De Dino is gepubliceerd (met wat minder beeldjes dan mijn record) op thesolaruniverse.wordpress.com

Nogmaals: dank! Als de BWOD sketch met de SSD1306 OLED werkt en is opgepoets zal ik hem hier posten.

Heel goed, ik mag mezelf ook autodidact noemen.
Van jou heb ik al veel moois voorbij zien komen en weet daarom dat het voor mij een welbesteedde inspanning is om dingen toe te lichten.
Jouw Dino sketch heb je op het internationale (displays) forum ook al laten zien en was me dus bekend.

Het is een goed idee eens een paar keer door te lezen welke data types er allemaal beschikbaar zijn.
Het helpt je weer je code te optimaliseren.
Helaas is er wel een link beschikbaar naar data-types op de Arduino site, maar die levert een lege pagina op.
Vanwege die leegte heeft het niet veel zin om daar te gaan kijken.
Daar achter liggen wel pagina's die specifiek over de verschillende types, zoals bool gaan.
Wanneer je dat een paar keer gelezen en toegepast hebt, heb je ook wat meer efficiëntie in de vingers.

Hoi MAS3,

Het is me gelukt om BWOD te implementeren in de led-simulatie met de SSD1306 OLED (zie plaatje aan het begin van dit lijntje)

Echter als ik van flag een boolean maak en dan de instructie flag=flag! invoer krijg ik een kryptische compilatie foutmelding bij deze regel, namelijk " expected ';' before '!' token ". Ik heb [nog] geen idee wat dit betekent.

De uitdagingen rijgen zich aaneen - zoals altijd - uitzoeken of deze foutmelding wordt veroorzaakt door de eigenaardigheden van <u8glib.h> of door eigen gebrek aan inzicht.

hier is de code van het BWOD resultaat:

// OLED_SSD_1306_nano_led_simulation_millis_nn
// Sketch for Arduino Uno - Nano 
// display on 128*64 SSD 1306 OLED
// two monochrome bitmap frames that alternate
// frames are 1-bit 16x21 pixel
//
// led on pin 3
// timer uses millis() function - blink without delay
//
// September 17, 2020
// Floris Wouterlood
// public domain
//

   #include <U8glib.h> 

   #define OLED_SCK  13                                                         // pins on the Arduino 
   #define OLED_MOSI 11
   #define OLED_CS   10    
   #define OLED_DC    9  
   #define OLED_RES   8 

   U8GLIB_SSD1306_128X64 u8g(OLED_SCK, OLED_MOSI, OLED_CS, OLED_DC, OLED_RES);  // U8glib constructor OLED display

   const int ledPin = 3;
   int flag=0; 
   long longInterval = 1000;                                                    // interval at which to blink (milliseconds) 
   unsigned long previousMillis = 0;                                            // will store last time LED was updated
   unsigned long currentMillis;                    
   int radius = 50;
  
 // NOTE - these icon images are 16x21 pixel monochrome

   static const unsigned char led_icon_ON [] PROGMEM = {       
 
   0x03, 0xc0,   // ∙∙∙∙∙∙████∙∙∙∙∙∙
   0x07, 0xe0,   // ∙∙∙∙∙██████∙∙∙∙∙
   0x0f, 0xf0,   // ∙∙∙∙∙██████∙∙∙∙∙
   0x1f, 0xf8,   // ∙∙∙∙████████∙∙∙∙
   0x1f, 0xf8,   // ∙∙∙██████████∙∙∙
   0x1f, 0xf8,   // ∙∙∙██████████∙∙∙
   0x1f, 0xf8,   // ∙∙∙██████████∙∙∙
   0x1f, 0xf8,   // ∙∙∙██████████∙∙∙
   0x1f, 0xf8,   // ∙∙∙██████████∙∙∙
   0x1f, 0xf8,   // ∙∙∙██████████∙∙∙
   0x3f, 0xfc,   // ∙∙████████████∙∙
   0x40, 0x02,   // ∙█∙∙∙∙∙∙∙∙∙∙∙∙█∙
   0x40, 0x02,   // ∙█∙∙∙∙∙∙∙∙∙∙∙∙█∙
   0x3f, 0xfc,   // ∙∙████████████∙∙
   0x04, 0x10,   // ∙∙∙∙∙█∙∙∙∙∙█∙∙∙∙
   0x04, 0x10,   // ∙∙∙∙∙█∙∙∙∙∙█∙∙∙∙
   0x04, 0x10,   // ∙∙∙∙∙█∙∙∙∙∙█∙∙∙∙
   0x04, 0x10,   // ∙∙∙∙∙█∙∙∙∙∙█∙∙∙∙
   0x04, 0x10,   // ∙∙∙∙∙█∙∙∙∙∙█∙∙∙∙
   0x04, 0x10,   // ∙∙∙∙∙█∙∙∙∙∙█∙∙∙∙
   0x04, 0x10    // ∙∙∙∙∙█∙∙∙∙∙█∙∙∙∙
   };  

   static const unsigned char led_icon_OFF [] PROGMEM = {      
      
   0x03, 0xc0,   // ∙∙∙∙∙∙████∙∙∙∙∙∙
   0x06, 0x60,   // ∙∙∙∙∙██∙∙██∙∙∙∙∙
   0x0c, 0x30,   // ∙∙∙∙██∙∙∙∙██∙∙∙∙
   0x18, 0x18,   // ∙∙∙∙██∙∙∙∙██∙∙∙∙
   0x10, 0x08,   // ∙∙∙██∙∙∙∙∙∙██∙∙∙
   0x10, 0x08,   // ∙∙∙█∙∙∙∙∙∙∙∙█∙∙∙
   0x10, 0x08,   // ∙∙∙█∙∙∙∙∙∙∙∙█∙∙∙
   0x10, 0x08,   // ∙∙∙█∙∙∙∙∙∙∙∙█∙∙∙
   0x10, 0x08,   // ∙∙∙█∙∙∙∙∙∙∙∙█∙∙∙
   0x10, 0x08,   // ∙∙∙█∙∙∙∙∙∙∙∙█∙∙∙
   0x3f, 0xfc,   // ∙∙████████████∙∙
   0x40, 0x02,   // ∙█∙∙∙∙∙∙∙∙∙∙∙∙█∙
   0x40, 0x02,   // ∙█∙∙∙∙∙∙∙∙∙∙∙∙█∙
   0x3f, 0xfc,   // ∙∙████████████∙∙ 
   0x04, 0x10,   // ∙∙∙∙∙█∙∙∙∙∙█∙∙∙∙
   0x04, 0x10,   // ∙∙∙∙∙█∙∙∙∙∙█∙∙∙∙
   0x04, 0x10,   // ∙∙∙∙∙█∙∙∙∙∙█∙∙∙∙
   0x04, 0x10,   // ∙∙∙∙∙█∙∙∙∙∙█∙∙∙∙
   0x04, 0x10,   // ∙∙∙∙∙█∙∙∙∙∙█∙∙∙∙
   0x04, 0x10,   // ∙∙∙∙∙█∙∙∙∙∙█∙∙∙∙
   0x04, 0x10    // ∙∙∙∙∙█∙∙∙∙∙█∙∙∙∙ 
   };
     
  
void setup(void) { 
   
   pinMode (ledPin,OUTPUT);
   Serial.begin (9600);
   Serial.println (); 
   Serial.println ("SSD 1306 OLED 128*64 led simulation - uses millis()"); 
   Serial.println (); 
   Serial.print ("let's start"); 
   Serial.println ();  
   u8g.setColorIndex(1);                                                        // display draws with pixel on
   u8g.setFont (u8g_font_unifont);                                              // select font    
}

void loop (){

   {
   u8g.firstPage();
        do {
            draw();
        } while (u8g.nextPage());
        timing_subunit ();
   }
}


void draw(void){

   u8g.drawCircle(40,35, 18);  
   if (flag ==0) 
       u8g.drawBitmapP (33, 25, 2, 21, led_icon_OFF); 

   else if (flag==1)
       u8g.drawBitmapP (33, 25, 2, 21, led_icon_ON);   

   if (flag ==0) 
       u8g.drawStr ( 73, 52, "OFF");

   else if (flag==1)
       u8g.drawStr ( 73, 52, "ON ");
}
    
 
void timing_subunit (){

  unsigned long currentMillis = millis();
  if (currentMillis - previousMillis >= longInterval)
    {
    previousMillis = currentMillis;
    if (flag == 0) 
       {
        flag = 1;
        digitalWrite (ledPin,flag);  
        Serial.println ("led ON");  
      
       } else 
        
       {
        flag = 0;
        digitalWrite (ledPin,flag);       
        Serial.println ("led OFF");  
       }
       
    Serial.print ("flag = ");   
    Serial.println (flag);
    Serial.println ();
    } 
}

vriendelijke groeten, photoncatcher

photoncatcher:
Echter als ik van flag een boolean maak en dan de instructie flag=flag! invoer krijg ik een kryptische compilatie foutmelding bij deze regel, namelijk " expected ';' before '!' token ".

De syntax is: flag = !flag;

Klopt! En het werkt.

  • met bool geimplementeerd neemt de sketch 11496 bytes in beslag in program storage area. Met vlaggetje 0 en 1 en testen ervan neemt de sketch 11170 bytes in. Kennelijk kost 'boolen' binair meer instructies dan vlaggetje testen?

groetjes, photoncatcher

Ik ben benieuwd.
Wil je de 'bool' code ook laten zien ?

Beste MAS3,

quote: <<<Wil je de 'bool' code ook laten zien ?>>>

Natuurlijk! - hieronder komt de sketch met daarin implementatie van bwod en een boolean flag.

Maar eerst dit: ik heb nu vier sketches die doen wat ik wil: (precies dezelfde output naar serial monitor)

1: met delay() timer en tellertje 0-1 flag-------compiler rapporteert: 11740 bytes
2: met delay() timer en boolean flag----------compiler rapporteert: 11466 bytes
3: met bwod timer en tellertje 0-1 flag--------compiler rapporteert: 11648 bytes
4: met bwod timer en boolean flag-----------compiler rapporteert: 11510 bytes

Het resultaat met sketch 4 is toch wel aardig te noemen!
met dank voor alle tips.
hier is sketch nummer 4: met bwod tmer en boolean flag

groetjes, photoncatcher

// OLED_SSD_1306_nano_led_simulation_millis_bool_nn
// Sketch for Arduino Uno - Nano 
// display on 128*64 SSD 1306 OLED
// two monochrome bitmap frames that alternate
// frames are 1-bit 16x21 pixel
//
// led on pin 3
// timer uses millis() function for timing and a boolean flag
//
// September 17, 2020
// Floris Wouterlood
// public domain
//

   #include <U8glib.h> 

   #define OLED_SCK  13                                                         // pins on the Arduino 
   #define OLED_MOSI 11
   #define OLED_CS   10    
   #define OLED_DC    9  
   #define OLED_RES   8 


   U8GLIB_SSD1306_128X64 u8g(OLED_SCK, OLED_MOSI, OLED_CS, OLED_DC, OLED_RES);  // U8glib constructor OLED display

   const int ledPin = 3;
   boolean flag; 
   long longInterval = 1000;                                                    // interval at which to blink (milliseconds) 
   unsigned long previousMillis = 0;                                            // will store last time LED was updated
   unsigned long currentMillis;                    
   int radius = 50;
  
 // NOTE - these icon images are 16x21 pixel monochrome

   static const unsigned char led_icon_ON [] PROGMEM = {       
 
   0x03, 0xc0,   // ∙∙∙∙∙∙████∙∙∙∙∙∙
   0x07, 0xe0,   // ∙∙∙∙∙██████∙∙∙∙∙
   0x0f, 0xf0,   // ∙∙∙∙∙██████∙∙∙∙∙
   0x1f, 0xf8,   // ∙∙∙∙████████∙∙∙∙
   0x1f, 0xf8,   // ∙∙∙██████████∙∙∙
   0x1f, 0xf8,   // ∙∙∙██████████∙∙∙
   0x1f, 0xf8,   // ∙∙∙██████████∙∙∙
   0x1f, 0xf8,   // ∙∙∙██████████∙∙∙
   0x1f, 0xf8,   // ∙∙∙██████████∙∙∙
   0x1f, 0xf8,   // ∙∙∙██████████∙∙∙
   0x3f, 0xfc,   // ∙∙████████████∙∙
   0x40, 0x02,   // ∙█∙∙∙∙∙∙∙∙∙∙∙∙█∙
   0x40, 0x02,   // ∙█∙∙∙∙∙∙∙∙∙∙∙∙█∙
   0x3f, 0xfc,   // ∙∙████████████∙∙
   0x04, 0x10,   // ∙∙∙∙∙█∙∙∙∙∙█∙∙∙∙
   0x04, 0x10,   // ∙∙∙∙∙█∙∙∙∙∙█∙∙∙∙
   0x04, 0x10,   // ∙∙∙∙∙█∙∙∙∙∙█∙∙∙∙
   0x04, 0x10,   // ∙∙∙∙∙█∙∙∙∙∙█∙∙∙∙
   0x04, 0x10,   // ∙∙∙∙∙█∙∙∙∙∙█∙∙∙∙
   0x04, 0x10,   // ∙∙∙∙∙█∙∙∙∙∙█∙∙∙∙
   0x04, 0x10    // ∙∙∙∙∙█∙∙∙∙∙█∙∙∙∙
   };  

   static const unsigned char led_icon_OFF [] PROGMEM = {      
      
   0x03, 0xc0,   // ∙∙∙∙∙∙████∙∙∙∙∙∙
   0x06, 0x60,   // ∙∙∙∙∙██∙∙██∙∙∙∙∙
   0x0c, 0x30,   // ∙∙∙∙██∙∙∙∙██∙∙∙∙
   0x18, 0x18,   // ∙∙∙∙██∙∙∙∙██∙∙∙∙
   0x10, 0x08,   // ∙∙∙██∙∙∙∙∙∙██∙∙∙
   0x10, 0x08,   // ∙∙∙█∙∙∙∙∙∙∙∙█∙∙∙
   0x10, 0x08,   // ∙∙∙█∙∙∙∙∙∙∙∙█∙∙∙
   0x10, 0x08,   // ∙∙∙█∙∙∙∙∙∙∙∙█∙∙∙
   0x10, 0x08,   // ∙∙∙█∙∙∙∙∙∙∙∙█∙∙∙
   0x10, 0x08,   // ∙∙∙█∙∙∙∙∙∙∙∙█∙∙∙
   0x3f, 0xfc,   // ∙∙████████████∙∙
   0x40, 0x02,   // ∙█∙∙∙∙∙∙∙∙∙∙∙∙█∙
   0x40, 0x02,   // ∙█∙∙∙∙∙∙∙∙∙∙∙∙█∙
   0x3f, 0xfc,   // ∙∙████████████∙∙ 
   0x04, 0x10,   // ∙∙∙∙∙█∙∙∙∙∙█∙∙∙∙
   0x04, 0x10,   // ∙∙∙∙∙█∙∙∙∙∙█∙∙∙∙
   0x04, 0x10,   // ∙∙∙∙∙█∙∙∙∙∙█∙∙∙∙
   0x04, 0x10,   // ∙∙∙∙∙█∙∙∙∙∙█∙∙∙∙
   0x04, 0x10,   // ∙∙∙∙∙█∙∙∙∙∙█∙∙∙∙
   0x04, 0x10,   // ∙∙∙∙∙█∙∙∙∙∙█∙∙∙∙
   0x04, 0x10    // ∙∙∙∙∙█∙∙∙∙∙█∙∙∙∙ 
   };
     
  
void setup(void) { 
   
   pinMode (ledPin,OUTPUT);
   Serial.begin (9600);
   Serial.println (); 
   Serial.println ("SSD 1306 OLED 128*64 led simulation - uses millis()"); 
   Serial.println (); 
   Serial.print ("let's start"); 
   Serial.println ();  
   u8g.setColorIndex(1);                                                        // display draws with pixel on
   u8g.setFont (u8g_font_unifont);                                              // select font    
}


void loop (){

   {
   u8g.firstPage();
     do {
         draw();
     } while (u8g.nextPage());
     bwod_timing_subunit ();
    }
}


void draw(void){

   u8g.drawCircle(40,35, 18);  
 
   if (ledPin, flag) 
       u8g.drawBitmapP (33, 25, 2, 21, led_icon_ON); 
   else 
       u8g.drawBitmapP (33, 25, 2, 21, led_icon_OFF);   

   if (ledPin, flag)
       u8g.drawStr ( 73, 52, "ON");
   else 
       u8g.drawStr ( 73, 52, "OFF ");
}
    
 
void bwod_timing_subunit (){

  unsigned long currentMillis = millis();
  if (currentMillis - previousMillis >= longInterval)
    {
    previousMillis = currentMillis;
   
    flag = !flag;   
         digitalWrite (ledPin,flag);  
    
    if (flag) 
       {
        digitalWrite (ledPin,flag);  
        Serial.println ("led OFF");        
       } 
       
    else        
       {
        digitalWrite (ledPin,flag);       
        Serial.println ("led ON");  
       } 
       
    Serial.print ("flag = ");   
    Serial.println (flag);
    Serial.println ();
    Serial.println ("bwod timing unit active "); 
    } 
}

Dank je voor de code.

De werkelijke benamingen voor de inhoud van een boolean, zijn false (niet waar) of true (waar).
Wanneer je 'm zo leest, snap je wellicht het volgende ook.

In void draw (void) valt me iets op wat ik niet begrijp:

  if (ledPin, flag)

Ik vraag me af of daar gebeurt wat jij bedacht had.

(ledPin, flag) is volgens mij geen geldige operator voor een if...
Het zijn wel 2 variabelen.
En hoe je die ook combineert, de waarde is altijd niet false.

[na research]
Ja en nee.
Het is wel degelijk een geldige operator
En het werkt dan ook nog zoals jij bedoeld had, want alleen de rechter variabele zal gebruikt worden voor de voorwaarde.
Maar het is wel totaal onnodig want ledPin staat daar alleen maar voor de lol.
[/research]

Een if... statement kan 2 uitkomsten hebben; waar (true) of niet waar (false).
En dan geldt daar boven op, dat wanneer iets niet false is, het true is.
Ga je dat dan vergelijken met getallen, dan is ledPin (==3) plus nul, 3
En ledPin plus 1 is 4.
Zowel 3 als 4 zijn geen nul, en dus is de uitkomst daarvan true [bron].

Zou je dit doen:

  if (digitalwrite (ledPin, flag))

Dan doe je ten eerste iets wat je op die plaats niet wil doen, maar aan de voorwaarde (if) wordt altijd voldaan.
Want digitalwrite geeft het antwoord "true" wanneer deze handeling verricht is.

Goed, ook weer opgelost.
Gooi de ledpin, maar weg uit void draw (void).
Leest dan ook weer wat vlotter.

Nog een complimentje:
De functie bwod_timing_subunit vind ik aardig.
Dit hoef je helemaal niet in een functie te doen, maar omdat je dat hier wel doet met daarin een eigen vluchtige variabele voor currentMillis, ga je goed om met de ruimte voor zulke variabelen.
Na verlopen van deze functie, verloopt de variabele namelijk ook en komt de ruimte weer beschikbaar voor iets anders.

Ik weet niet of je dat ook zo bedacht had, maar het pakt leuk uit.