oled_i2c / oled_i2c_sw.c    


Mit oled_i2c / oled_i2c_sw kann ein monochromes OLED-Display (wie in nebenstehendem Bild) mit einem I2C-Interface und einer Auflösung von 128*64 Pixel betrieben werden. Der Unterschied der beiden Versionen besteht darin, dass oled_i2c die interne I2C-Hardware zur Ansteuerung verwendet, während oled_i2c_sw den I2C-Bus mittels Software und direktem An- und Ausschalten von GPIO-Pins (Bit-Banging) den I2C-Bus realisiert. Die Benutzerfunktionen sind bei beiden Softwareversionen identisch, im Header sind Einstellungen bezüglich der I2C-Schnittstelle dann natürlich unterschiedlich.

    Einstellungen des Headers (nur für oled_i2c_sw.h gültig)


Die nur für oled_i2c_sw gültigen Einstellungen betreffen lediglich die Anschlusspins, auf denen der I2C-Bus kommunizieren soll.

Per Default sind hier eingestellt PC1 für den SDA Anschluss, PC2 für den SCL Anschluss. Da der I2C-Bus mittels Bitbanging realisiert ist, können hierfür jede verfügbare GPIO-Pins verwendet werden.
  
  #define i2c_sda_hi()      PC1_float_init()
  #define i2c_sda_lo()      { PC1_output_init(); PC1_clr(); }
  #define i2c_is_sda()      is_PC1()

  #define i2c_scl_hi()      PC2_float_init()
  #define i2c_scl_lo()      { PC2_output_init(); PC2_clr(); }
  

    Einstellungen des Headers (nur für oled_i2c.h gültig)


Die nur für die Hardwareversion oled_i2c gültige Einstellung betrifft die Taktrate des internen I2C-Taktgenerators. Ein OLED-Display kann bei nicht all zu langen Leitungen gut mit einer Taktrate von 1 MHz betrieben werden, mit
  
  #define i2c_clkrate        1000000
  
kann dieses eingestellt werden. Die Werteangabe entspricht der Frequenz in Hz, hier also 1 MHz.


Gemeinsame Einstellungen für oled_i2c / oled_i2c_sw



I2C Device-Adresse

Die wichtigste Einstellung im Header ist die Deviceadresse des Displays. Hier kann es schon die erste "Verwirrung" im Umgang einem I2C-Displays geben.

Grundsätzlich besteht eine I2C-Adresse aus 7 Bits, die in einem Byte jedoch die Position D1 bis D7 einnimmt. D0 eines Bytes beinhaltet ein sogenanntes r/w - Flag. Da in einem Byte diese 7 - Bit Adresse um eine Position nach links verschoben ist, entspricht dieses einer Multiplikation mit 2. Die Angabe hier im Header bezieht sich auf eine Adresse, die in einem Byte bereits um eine Stelle nach links verschoben ist.

Die allermeisten Displaymodule werden mit der Adresse 0x78 ausgeliefert. Sollte ein Display eine andere Adresse haben, manche Display besitzen Lötbrücken um die Adresse einstellbar zu machen, so ist eine geänderte Adresse hier anzugeben.
  
  #define ssd1306_addr       0x78                // I2C-Adresse Display
  
Schriftstile / Fonts

In der Quelldatei sind 2 Arrays enthalten, die die Bitmaps für die entsprechenden Ascii-Zeichen in der Größe 5*7 Pixel und 8*8 Pixel beinhalten. Da diese Bitmaps relativ viel Speicherplatz benötigen, empfiehlt es sich, vor allem wenn der Flashspeicher knapp wird, zu überlegen, ob beide Schriftstile benötigt werden.

Außerdem sind für die Schriftgröße 8*8 Pixel nicht nur die Ascii-Zeichen bis 127 (keine deutschen Umlaute) enthalten. Bei Bedarf kann hier der Ascii-Zeichensatz für die Codepage 850 Erweiterung eingeschaltet werden.

Die Einstellungen im Header sind:
  
   /* --------------------------------------------------
       Schriftstile
     -------------------------------------------------- */

  #define font5x7_enable        0            // 1: Schriftstil verfuegbar, 0: nicht verfuegbar
  #define font8x8_enable        1            // 1: Schriftstil verfuegbar, 0: nicht verfuegbar

  #define use_full_ascii        1            // 0: Ascii-Zeichen bis 127 verfuegbar
                                             // 1: Ascii-Zeichen bis 255 verfuegbar, Codepage 850

  
Displayeigenschaften


Unter Displayeigenschaften sind #defines angegeben, die das Verhalten des Displays steuern. Derzeit betreffen diese Eigenschaften lediglich die Auflösung des Displays sowie das Einschalten eines Framebuffers.

In der aktuellen Version der Sourcecodes wird noch keine andere Auflösung als 128x64 Pixel unterstützt (für andere Mikrocontrollerfamilien wurde dieses jedoch bereits erarbeitet und so wird es wahrscheinlich auch für CH32V003 in einer späteren Version Quellcode für weitere Auflösungen geben).

Da derzeit jedoch, wie bereits geschrieben, keine weitere Auflösung unterstützt wird, sollten die Angaben für _xres und _yres uangetastet bleiben.

Die zweite Eigenschaft betrifft den Framebuffer. Ein Framebuffer ist deshalb notwendig, weil das Ram des Display nur Byteweise beschrieben werden kann und nicht rücklesefähig ist. D.h. ein einzelnes Pixel ist nicht setzbar, ohne das weitere 8 Pixel geschrieben werden. Für Grafikausgaben, die eben das Setzen einzelner Pixel verlangen, muß die Ausgabe erst in einen Zwischenspeicher (eben dem Framebuffer) geschrieben und dieses dann als ganzes in das Displayram geschrieben werden.

Aufgrund des wenigen RAM des CH32V003 kann es für manche Projekte jedoch ratsam sein, auf Grafikausgaben zu verzichten und das SSD1306 OLED-Display als reines Textdisplay zu verwenden. Hierfür ist der Framebuffer abschaltbar.

Ein abgeschalteter Framebuffer bedeutet, dass der RAM (hier 1038 Byte von insgesamt 2048) nicht belegt wird und somit für das Anwenderprogramm zur Verfügung steht.

Anmerkung: Textausgaben werden mit oled_i2c / oled_i2c_sw grundsätzlich nicht über den Framebuffer ausgegeben, sondern werden direkt in das Displayram geschrieben (für Textausgaben in den Framebuffer existiert eine gesonderte Funktion).

Die Einstellungen im Header sind:
  
  /* --------------------------------------------------
                   Displayeigenschaften
     -------------------------------------------------- */
  #define _xres                 128
  #define _yres                 64


  #define  fb_enable            1       //   Framebuffer enable
                                        //   1 = es wird RAM fuer Framebuffer
                                        //       reserviert und Grafikfunktionen werden eingebunden
                                        //   0 = kein Displayram und keine Grafikfunktionen

  #define  fb_size              1038    // Framebuffergroesse in Bytes (wenn fb_enable)
  



Funktionen von oled_i2c



lcd_init

void lcd_init(void);

initialisiert zuerst das I2C-Interface und anschließend das OLED-Display zur Benutzung

clrscr

void clrscr(void);

löscht den Displayinhalt mit der in der globalen Variable bkcolor angegebenen "Farbe" (0 = schwarz, 1 = hell).

setfont

void setfont(uint8_t fnr);

legt die Schriftgröße für die Ausgabe sowohl im Textdirektmodus wie auch für den Framebuffer fest.

Übergabe:
      fnr :      0 => Font 5x7
                 1 => Font 8x8
      
Hinweis: Im Header ist ein Enumerator deklariert, dessen Mitglieder in Verbindung mit setfont die Schriftgröße ebenfalls auswählen:
  
  setfont(fnt5x7);
  setfont(fnt8x8);
  
lcd_putchar

void lcd_putchar(uint8_t ch);

gibt ein Zeichen direkt ohne "Umweg" über den Framebuffer auf dem Display aus. Folgende Steuerzeichen für bspw. printf) sind implementiert:
      13 = carriage return
      10 = line feed
       8 = delete last char
Übergabe:
      ch :      auszugebendes Zeichen
      

showimage

void showimage(uint16_t ox, uint16_t oy, const uint8_t* const image, char mode);

zeigt ein monochromes Bitmap an den Koordinaten x,y an, wie es bspw. vom Konverterprogramm IMAGE2C (im Archiv enthalten) erzeugt worden ist.

showimage schreibt hier NICHT in den Framebuffer, sondern zeigt das Bitmap direkt auf dem Display an!

Übergabe:
        ox,oy : Koordinaten, an dem das Bitmap ausgegeben werden soll. Da in 
                Y-Auflösung immer nur 8 Pixel gleichzeitig gesetzt werden 
                können, entspricht die Y-Koordinate einer Textkoordinate,	
                d.h.: für oy= 0 entspricht dieses der Grafikkoordinate 0, für oy= 1 
                entspricht dieses der Grafikkoordinate 8! Die Angabe für ox 
                entspricht einer Grafikkoordinate. Deshalb sind gültige 
                Werte für ox 0..127, für oy 0..7.
    
       mode   : Zeichenmodus
                   0 = Bitmap wird mit der in bkcolor angegebenen Farbe gelöscht
                   1 = Bitmap wird so wie es ist gezeichnet
                   2 = Bitmap wird invertierend gezeichnet
      
Speicherorganisation des Bitmaps:
            
                                    X-Koordinate
       ----------------------------------------------------------------------
                       0  1  2  3  4  5  6  7     8  9 10 11 12 13 14 15  ...
    
                          Byte (0)                    Byte (1)
       Y= Zeile 0     D7 D6 D5 D4 D3 D2 D1 D0     D7 D6 D5 D4 D3 D2 D1 D0
    
                       Byte (Y*X_Bytebreite)       Byte (Y*X_Bytebreite)+1
       Y =Zeile  1    D7 D6 D5 D4 D3 D2 D1 D0     D7 D6 D5 D4 D3 D2 D1 D0
       ----------------------------------------------------------------------      
        
      


Framebuffer - Funktionen


fb_init

void fb_init(uint8_t x, uint8_t y);

initialisiert den Framebuffer

Übergabe:
     x = Framebuffergröße in x Richtung
     y = Framebuffergröße in y Richtung
         Aufloesung der y-Pixel muss durch 8 geteilt werden

Beispiel für einen Framebuffer der Pixelgröße 84x48
  
                fb_init(84, 6);
  
fb_clear

void fb_clear(void):

löscht den Inhalt des Framebuffers


fb_show

void fb_show(uint8_t x, uint8_t y);

zeigt den Framebufferspeicher ab der Koordinate x,y (linke obere Ecke) auf dem Display an.

Da die Speicherorganisation in Y-Achse jeweils 8 Pixel per Byte umfassen, ist die möglichste unterste
Y- Koordinate 7 (entspricht Pixelkoordinate 7 * 8 = 56)

Übergabe:
     x,y :  Position, an der der Inhalt des Framebuffers angezeigt wird

fb_putpixel

void fb_putpixel(uint8_t x, uint8_t y, uint8_t col);

setzt im Framebuffer einen Pixel an Position der Koordinate x,y.

Übergabe:
     x, y : Koordinate, an der der einzelne Pixel ausgegeben wird
      col : 0 = Pixel wird gelöscht
            1 = Pixel wird gesetzt
            2 = Pixel wird mit dem bisherigen Inhalt des Framebuffers XOR-verknüpft

line

void line(int x0, int y0, int x1, int y1, uint8_t col);

Zeichnet im Framebuffer eine Linie von den Koordinaten x0,y0 zu x1,y1

Übergabe:
     x0, y0 : Koordinate an der die Linie beginnt
     x1, y1 : Koordinate, an der die Linie endet
     col    : 0 = Pixel werden gelöscht
              1 = Pixel werden gesetzt
              2 = Pixel werden mit dem bisherigen Inhalt des Framebuffers XOR-verknüpft

rectangle

void rectangle(uint8_t x1, uint8_t y1, uint8_t x2, uint8_t y2, uint8_t col);

zeichnet im Framebuffer ein Rechteck von den Koordinaten x0,y0 nach x1,y1

Übergabe:
     x0, y0 : Koordinate linke, obere Ecke des Rechtecks
     x1, y1 : Koordinate rechte, untere Ecke des Rechtecks
     col    : 0 = Pixel werden gelöscht
              1 = Pixel werden gesetzt
              2 = Pixel werden mit dem bisherigen Inhalt des Framebuffers XOR-verknüpft

ellipse

void ellipse(int xm, int ym, int a, int b, uint8_t col );

zeichnet im Framebuffer eine Ellipse mit Mittelpunkt an der Koordinate xm, ym und einem Höhen- Breitenverhältnis a:b

Übergabe:
     x, y : Mittelpunktkoordinate der Ellipse
     a, b : Höhen- Breitenverhältnis der Ellipse
     col  : 0 = Pixel werden gelöscht
            1 = Pixel werden gesetzt
            2 = Pixel werden mit dem bisherigen Inhalt des Framebuffers XOR-verknüpft

circle

void circle(int x, int y, int r, uint8_t col );

zeichnet im Framebuffer einen Kreis mit Mittelpunt an der Koordinate xm,ym und dem Radius r

Übergabe:
     x, y : Mittelpunktkoordinate des Kreises
     r    : Radius
     col  : 0 = Pixel wird gelöscht
            1 = Pixel wird gesetzt
            2 = Pixel wird mit dem bisherigen Inhalt des Framebuffers XOR-verknüpft

fastxline

void fastxline(uint8_t x1, uint8_t y1, uint8_t x2, uint8_t col);

zeichnet im Framebuffer eine Linie in X-Achse mit den X Punkten x1 und x2 auf der Y-Achse y1

Übergabe:
     x1, y1 : Koordinate Startpunkt der X-Linie
     x2     : Endpunkt x-Koordinate der Linie
     col    : 0 = Pixel werden gelöscht
              1 = Pixel werden gesetzt
              2 = Pixel werden mit dem bisherigen Inhalt des Framebuffers XOR-verknüpft

fillrect

void fillrect(int x1, int y1, int x2, int y2, uint8_t col);

zeichnet im Framebuffer ein ausgefülltes Rechteck von den Koordinaten x0,y0 nach x1,y1

Übergabe:
     x0, y0 : Koordinate linke, obere Ecke des Rechtecks
     x1, y1 : Koordinate rechte, untere Ecke des Rechtecks
     col    : 0 = Pixel werden gelöscht
              1 = Pixel werden gesetzt
              2 = Pixel werden mit dem bisherigen Inhalt des Framebuffers XOR-verknüpft

fillellipse

void fillellipse(int xm, int ym, int a, int b, uint8_t col );

zeichnet im Framebuffer eine ausgefüllte Ellipse mit Mittelpunt an der Koordinate xm, ym und einem Höhen- Breitenverhältnis a:b

Übergabe:
     x, y : Mittelpunktkoordinate der Ellipse
     a, b : Höhen- Breitenverhältnis der Ellipse
     col  : 0 = Pixel werden gelöscht
            1 = Pixel werden gesetzt
            2 = Pixel werden mit dem bisherigen Inhalt des Framebuffers XOR-verknüpft

fillcircle

void fillcircle(int x, int y, int r, uint8_t col );

zeichnet im Framebuffer einen ausgefüllten Kreis mit Mittelpunt an der Koordinate xm,ym und dem Radius r

Übergabe:
     x, y : Mittelpunktkoordinate der Ellipse
     r    : Radius
     col  : 0 = Pixel werden gelöscht
            1 = Pixel werden gesetzt 
            2 = Pixel werden mit dem bisherigen Inhalt des Framebuffers XOR-verknüpft

fb_putcharxy

void fb_putcharxy(int x, int y, uint8_t ch);

gibt ein Zeichen auf dem Framebuffer aus

Übergabe:
     x, y : Grafikkoordinate, an der das Zeichen im Framebuffer ausgegeben wird
     ch   : auszugebendes Zeichen

fb_outtextxy

void fb_outtextxy(int x, int y, char *p);

zeigt einen String im Framebuffer an

Übergabe:
     x, y : Grafikkoordinate, an der der String im Framebuffer ausgegeben wird
     *p   : Zeiger auf den auszugebenden String

fb_showbmp

void fb_showbmp(uint16_t ox, uint16_t oy, const uint8_t* const image, char mode );

kopiert ein Bitmap in den Framebuffer an den Koordinaten ox, oy, wie es bspw. vom Konverterprogramm IMAGE2C erzeugt worden ist.

Übergabe:
     ox,oy : Koordinaten, an dem das Bitmap im Framebuffer ausgegeben werden soll. 
     mode  : Zeichenmodus
                 0 = Bitmap wird mit der in bkcolor angegebenen Farbe gelöscht
                 1 = Bitmap wird so wie es ist gezeichnet
                 2 = Bitmap wird invertierend gezeichnet
Speicherorganisation des Bitmaps:
            
                                    X-Koordinate
       ----------------------------------------------------------------------
                       0  1  2  3  4  5  6  7     8  9 10 11 12 13 14 15  ...
    
                          Byte (0)                    Byte (1)
       Y= Zeile 0     D7 D6 D5 D4 D3 D2 D1 D0     D7 D6 D5 D4 D3 D2 D1 D0
    
                       Byte (Y*X_Bytebreite)       Byte (Y*X_Bytebreite)+1
       Y =Zeile  1    D7 D6 D5 D4 D3 D2 D1 D0     D7 D6 D5 D4 D3 D2 D1 D0
       ----------------------------------------------------------------------      
        
      


Globale Variable von oled_i2c / oled_i2c_sw und deren Funktion



Vom Benutzer können Variable zur Steuerung von Ausgabeoptionen verwendet werden, diese sind:

  • uint8_t bkcolor;

    • bkcolor (für Background-Color) gibt die Farbe vor, die beim Löschen des Displayinhaltes sowie im Modus 0 der Funktion showimage verwendet wird. Folgende Sequenz wird den Displayinhalt mit weißem Hintergrund löschen:
            
                    bkcolor= 1;
                    clrscr();
            
          
  • uint8_t invchar;

    • invchar (für inverted char) gibt an, ob ein Zeichen hell auf dunklem Grund oder dunkel auf hellem Grund (invertiert) ausgegeben werden soll. Folgende Sequenz wird den Text mit dunkler Schrift auf hellem Grund ausgeben:
            
                   invchar= 1;
                   my_printf("Hallo Welt");
            
          
  • uint8_t textsize;

    • textsize ist eine Steuerungsvariable für die Ausgabegröße von Zeichen.
      Für textsize == 0 (default) wird ein Zeichen in der Standardgröße ausgegeben,
      für textsize == 1 wird bei der Ausgabe ein Zeichen in Breite und Höhe durch Vergrößerung eines Zeichenpixels doppelt so groß ausgegeben:
            
                   textsize= 0;
                   my_printf("\n\rkleine Ausgabe");
                   textsize= 1;
                   my_printf("\n\rGross");
                   textsize= 0;
                   my_printf("\n\rwieder klein");