Autres articles / Other articles

Gestion de l'afficheur SSD1306 OLED 128x32

publication: 10 février 2022 / mis à jour 22 février 2022

Read this page in english

 

Appel à collaboration

Vous développez des montages, simples ou complexes avec ESP32 et ESP32forth.

Partagez-les ici sur ce site.

ESP32forth ne pourra se développer qu'avec la collaboration active de toutes les bonnes volontés.

Vos montages peuvent aider d'autres développeurs.

Les montages des autres développeurs peuvent vous aider.

Pour proposer un article ou un montage, cliquez ici



Listing complet des commandes OLED: Manage commands for OLED SSD1306 128x32 display

Utilisation de la librairie Wire

Ceci est la première utilisation du port I2C géré à partir de la librairie Wire. ici, nous allons voir en détail comment gérer un afficheur OLED SSD1306 128x32 pixels.

Tous les mots nécessaires à la gestion du port I2C sont disponibles dans le vocabulaire Wire. Accès à ce vocabulaire:

--> Wire vlist
Wire.flush Wire.peek Wire.read Wire.available Wire.write Wire.requestFrom
Wire.endTransmission Wire.beginTransmission Wire.getTimeout Wire.setTimeout
Wire.getClock Wire.setClock Wire.begin

Dans ce vocabulaire, les mots essentiels pour notre application sont Wire.begin, Wire.beginTransmission, Wire.endTransmission et Wire.write.

Sur la carte ESP32, les deux ports GPIO dédiés à la transmission sur le port I2C sont:

L'affectation de ces ports GPIO au bus I2C s'effectue en exécutant le mot Wire.begin:

21 22 wire.begin drop 

Chaque séquence de transmission sur le bus I2C est encadrée par les mots Wire.beginTransmission et Wire.endTransmission. Exemple:

addrSSD1306 Wire.beginTransmission 
CTRL_COMMANDS Wire.tx 
\ ....here transmission of command 
addrSSD1306 Wire.endTransmission drop 

La transmission des commandes ou données s'effectue à l'aide du mot Wire.write. Ce mot accepte en entrée une zone mémoire pointée par l'adresse de début de cette zone et la longueur de cette zone. Nous verrons plus loin comment définir de telles zones de données.

Branchement de l'afficheur OLED SSD1306 128x32

Voici le branchement de notre afficheur OLED à la carte ESP32:

La très faible consommation de cet afficheur OLED permet de l'alimenter à partir de la carte ESP32.

Commande de l'afficheur OLED

Nous aurions pu gérer cet afficheur à partir d'une librairie ARDUINO en l'intégrant au code source de ESP32Forth et recompiler ce code avec ARDUINO IDE. Il nous semble plus intéressat de repartir de zéro et créer nos propres définitions, indépendemment des libraries du langage C:

On commence d'abord par définir quelques constantes essentielles:

\ for SSD1306_128_64 
\     128 constant SSD1306_LCDWIDTH 
\      64 constant SSD1306_LCDHEIGHT 
 
\ for SSD1306_128_32 
    128 constant SSD1306_LCDWIDTH 
     32 constant SSD1306_LCDHEIGHT 
 
\ definition of SSD1306 display dimensions in pixels 
SSD1306_LCDWIDTH  constant DISPLAY_WIDTH 
SSD1306_LCDHEIGHT constant DISPLAY_HEIGHT 
 
$91 constant SSD1306_SETCONTRAST 
$a4 constant SSD1306_DISPLAYALLON_RESUME 
$a5 constant SSD1306_DISPLAYALLON 
$a6 constant SSD1306_NORMALDISPLAY 
$a7 constant SSD1306_INVERTDISPLAY 
$a8 constant SSD1306_SETMULTIPLEX 
$ae constant SSD1306_DISPLAYOFF 
$af constant SSD1306_DISPLAYON 
$d3 constant SSD1306_SETDISPLAYOFFSET 
$da constant SSD1306_SETCOMPINS 
$db constant SSD1306_SETVCOMDETECT 
$d5 constant SSD1306_SETDISPLAYCLOCKDIV 
$d9 constant SSD1306_SETPRECHARGE 
\ $00 constant SSD1306_SETLOWCOLUMN 
\ $10 constant SSD1306_SETHIGHCOLUMN 
$40 constant SSD1306_SETSTARTLINE 
$20 constant SSD1306_MEMORYMODE 
$21 constant SSD1306_COLUMNADDR 
$22 constant SSD1306_PAGEADDR 
$c0 constant SSD1306_COMSCANINC 
$c8 constant SSD1306_COMSCANDEC 
$a0 constant SSD1306_SEGREMAP 
$8d constant SSD1306_CHARGEPUMP 
$01 constant SSD1306_EXTERNALVCC 
$02 constant SSD1306_SWITCHCAPVCC 
 
\ Scrolling constants 
$2f constant SSD1306_ACTIVATE_SCROLL 
$2e constant SSD1306_DEACTIVATE_SCROLL 
$a3 constant SSD1306_SET_VERTICAL_SCROLL_AREA 
$26 constant SSD1306_RIGHT_HORIZONTAL_SCROLL 
$27 constant SSD1306_LEFT_HORIZONTAL_SCROLL 
$29 constant SSD1306_VERTICAL_AND_RIGHT_HORIZONTAL_SCROLL 
$2a constant SSD1306_VERTICAL_AND_LEFT_HORIZONTAL_SCROLL 
 
\ Addressing modes 
$00 constant HORIZONTAL_ADDRESSING_MODE 
$01 constant VERTICAL_ADDRESSING_MODE 
$02 constant PAGE_ADDRESSING_MODE 
 
 
\  control: $00 for commands 
\           $40 for datas 
$00 constant CTRL_COMMANDS 
$40 constant CTRL_DATAS 
 
 
\ set adress of OLED SSD1306 display 128x32 pixels 
$3c constant addrSSD1306 

Nous avons repris les les mêmes noms de constantes que les codes en langage C:

 #define SSD1306_MEMORYMODE 0x20
 #define SSD1306_COLUMNADDR 0x21
 #define SSD1306_PAGEADDR 0x22
 #define SSD1306_SETCONTRAST 0x81
 #define SSD1306_CHARGEPUMP 0x8D
 #define SSD1306_SEGREMAP 0xA0
 #define SSD1306_DISPLAYALLON_RESUME 0xA4
 #define SSD1306_DISPLAYALLON 0xA5
 #define SSD1306_NORMALDISPLAY 0xA6
 #define SSD1306_INVERTDISPLAY 0xA7
 #define SSD1306_SETMULTIPLEX 0xA8
 #define SSD1306_DISPLAYOFF 0xAE
 #define SSD1306_DISPLAYON 0xAF
 #define SSD1306_COMSCANINC 0xC0
 #define SSD1306_COMSCANDEC 0xC8
 #define SSD1306_SETDISPLAYOFFSET 0xD3
 #define SSD1306_SETDISPLAYCLOCKDIV 0xD5
 #define SSD1306_SETPRECHARGE 0xD9
 #define SSD1306_SETCOMPINS 0xDA
 #define SSD1306_SETVCOMDETECT 0xDB
 
 #define SSD1306_SETLOWCOLUMN 0x00
 #define SSD1306_SETHIGHCOLUMN 0x10
 #define SSD1306_SETSTARTLINE 0x40
 
 #define SSD1306_EXTERNALVCC 0x01
 #define SSD1306_SWITCHCAPVCC 0x02
 
 #define SSD1306_RIGHT_HORIZONTAL_SCROLL 0x26
 #define SSD1306_LEFT_HORIZONTAL_SCROLL 0x27
 #define SSD1306_VERTICAL_AND_RIGHT_HORIZONTAL_SCROLL 0x29
 #define SSD1306_VERTICAL_AND_LEFT_HORIZONTAL_SCROLL 0x2A
 #define SSD1306_DEACTIVATE_SCROLL 0x2E
 #define SSD1306_ACTIVATE_SCROLL 0x2F
 #define SSD1306_SET_VERTICAL_SCROLL_AREA 0xA3

Certaines de ces constantes ont une action complexe. Le fait de reprendre les mêmes noms du code source en langage C pour définir nos constantes en langage FORTH permet de rechercher la documentation dorrespondant à ces constantes utilisées comme commandes pour l'afficheur OLED.

Ici, nous avons trois constantes essentielles:

On définit ensuite un certain nombre de mots qui vont simplifier l'envoi d'une séquence de commandes ou de données vers notre afficheur OLED:

\ begin I2C transmssion to SSD1306 OLED display 
: SSD1306beginTransmission ( -- ) 
    addrSSD1306 Wire.beginTransmission 
  ; 
 
\ memoryze transmitted bytes, interval [00..31] 
variable maxBytesSended 
 
\ end I2C transmssion to SSD1306 OLED display 
: SSD1306endTransmission ( -- ) 
    -1 Wire.endTransmission drop 
    0 maxBytesSended ! 
  ; 
 
\ if sended bytes > 32 end and restart transmission 
: incrementMaxBytes ( -- ) 
    1 maxBytesSended +! 
    maxBytesSended @ 31 > if 
        SSD1306endTransmission 
        SSD1306beginTransmission 
    then 
  ; 
 
\ Send code c to I2C bus 
: Wire.send ( c -- ) 
    >r 0 <# r> hold #> 
    Wire.write drop 
    incrementMaxBytes 
  ; 
 
 
\ send a data array to SSD1306 connected via I2C bus 
\ CAUTION: array size max 32 bytes 
: sendStringToSSD1306 ( addr len -- ) 
    SSD1306beginTransmission 
    Wire.write drop 
    SSD1306endTransmission 
  ; 

ATTENTION

Au cours du développement et essai de nos définitions, nous avons découvert que le tampon d'envoi de données sur le bus I2C est limité à 32 octets.

Les données sont placées dans ce tampon et transmises seulement quand le mot SSD1306endTransmission est exécuté.

Passons maintenant aux choses sérieuses.

On va définir une structure de données, créée à l'aide des mots streamCreate: et ;endStream:

\ define a command or data stream for SSD1306 
: streamCreate: ( comp:  | exec: -- addr len ) 
    create 
        here    \ leave current dictionnary pointer on stack 
        0 c,    \ initial lenght data is 0 
    does> 
        dup 1+ swap c@ 
        toSSD1306 
  ; 
 
\ store at  addr length of datas compiled beetween 
\  and here 
: ;endStream ( addr-var len ---) 
    dup 1+ here 
    swap -      \ calculate cdata length 
    \ store c in first byte of word defined by streamCreate: 
    swap c! 
  ; 

A l'aide de ces mots, on définit deux structures, dispSetup et dispReset permettant l'initialisation de l'afficheur OLED:

\ Initialize SSD105 128x32 display 
streamCreate: dispSetup 
    CTRL_COMMANDS c, 
    SSD1306_DISPLAYOFF c, 
    SSD1306_SETDISPLAYCLOCKDIV c,  $80 c, 
    SSD1306_SETMULTIPLEX c,   DISPLAY_HEIGHT 1- c, 
    SSD1306_SETDISPLAYOFFSET c,   $00 c, 
    SSD1306_SETSTARTLINE $00 or  c, 
    SSD1306_CHARGEPUMP c,  $14 c,   ( CHARGE_PUMP_ON ) 
    SSD1306_SEGREMAP $01 or c,   ( Reverse mapping ) 
    SSD1306_COMSCANDEC c, 
    SSD1306_SETCOMPINS c,   $02 c, 
    SSD1306_SETCONTRAST c,   $7f c, 
    SSD1306_SETPRECHARGE c,   $22 c, 
    SSD1306_SETVCOMDETECT c,   $40 c, 
\     SSD1306_MEMORYMODE c,  HORIZONTAL_ADDRESSING_MODE c, 
    SSD1306_DISPLAYALLON_RESUME c, 
    SSD1306_NORMALDISPLAY c, 
    SSD1306_DISPLAYON c, 
    ;endStream 
 
\ Reset SSD105 128x32 display 
streamCreate: dispReset 
    CTRL_COMMANDS c, 
    SSD1306_DISPLAYOFF c, 
    SSD1306_MEMORYMODE c,  HORIZONTAL_ADDRESSING_MODE c, 
    SSD1306_COLUMNADDR c,   \ $21 
    $00 c,  \ start 
    $7f c,  \ end 
    SSD1306_PAGEADDR c,     \ $22 
    $00 c,  \ start 
    $07 c,  \ end 
    SSD1306_DISPLAYON c, 
    ;endStream 
 
\ main INITialization for SSD1306 128x32 OLED display 
: dispInit ( -- ) 
    \ start the I2C interface using pin 21 and 22 on ESP32 DEVKIT V1 
    \ with 21 used as sda and 22 as scl. 
    21 22 wire.begin drop 
    dispSetup 
    dispReset 
  ; 

Exécution de dispInit. L'affichage de ces pixels indique que l'initiatialisation de l'afficheur OLED s'est exécutée avec succès:

Voici d'autres commandes utilisables ensuite pour contrôler l'affichage:

streamCreate: dispOn      \ toggle display on 
    CTRL_COMMANDS c, 
    $af c, \ DISPLAYON 
    ;endStream 
 
streamCreate: dispOff     \ toggle display off 
    CTRL_COMMANDS c, 
    $ae c, \ DISPLAYOFF 
    ;endStream 
 
\ store normal | inverse display state 
SSD1306_NORMALDISPLAY value _SSD1306_DISPLAY 
 
\ set display mode normal 
: dispNormal  ( -- ) 
    SSD1306beginTransmission 
    CTRL_COMMANDS Wire.send 
    SSD1306_NORMALDISPLAY Wire.send 
    SSD1306endTransmission 
    SSD1306_NORMALDISPLAY to _SSD1306_DISPLAY 
  ; 
 
\ invert display mode 
: dispInvert 
    SSD1306beginTransmission 
    CTRL_COMMANDS Wire.send 
    SSD1306_INVERTDISPLAY Wire.send 
    SSD1306endTransmission 
    SSD1306_INVERTDISPLAY to _SSD1306_DISPLAY 
  ; 
 
: OledInvert ( -- ) 
    \ test if actual display mode is normal 
    _SSD1306_DISPLAY SSD1306_NORMALDISPLAY = if 
        dispInvert 
    else 
        dispNormal 
    then 
  ; 

Commandes avec paramètres

Le souci, avec les mots définis par streamCreate:, c'est que leur contenu n'intègre pas de paramètre. On va contourner ceci en créant le mot Wire.tx qui transmet un seul code binaire intégré dans une pseudo-chaine de texte:

\ Send code c to I2C bus 
: Wire.send ( c -- ) 
    >r 0 <# r> hold #> 
    Wire.write drop 
    incrementMaxBytes 
  ; 

On peut maintenant définir ces mots:

: setLine { page -- } 
    SSD1306beginTransmission 
    CTRL_COMMANDS Wire.send 
    SSD1306_COLUMNADDR Wire.send 
    $00 Wire.send  \ start 
    $7f Wire.send  \ end 
    SSD1306_PAGEADDR Wire.send 
    page Wire.send  \ start 
    page Wire.send  \ end 
    SSD1306endTransmission 
  ; 
 
        \ pointer for current page [0..3] 
0 value currentPage 
 
\ move pointer to next page 
: crLine ( ---) 
    currentPage 1+ 3 and to currentPage 
    currentPage setLine 
  ; 
 
\ Reset SSD105 128x32 display 
streamCreate: dispReset 
    CTRL_COMMANDS c, 
    SSD1306_MEMORYMODE c,  HORIZONTAL_ADDRESSING_MODE c, 
    SSD1306_COLUMNADDR c,   \ $21 
    $00 c,  \ start 
    $7f c,  \ end 
    SSD1306_PAGEADDR c,     \ $22 
    $00 c,  \ start 
    $03 c,  \ end 
    ;endStream 
 
\ send 32x 0 value 
streamCreate: sendBlock32bytesWith0 ( -- ) 
    CTRL_DATAS c, 
    $00 c, $00 c, $00 c, $00 c, $00 c, $00 c, $00 c, $00 c, 
    $00 c, $00 c, $00 c, $00 c, $00 c, $00 c, $00 c, $00 c, 
    $00 c, $00 c, $00 c, $00 c, $00 c, $00 c, $00 c, $00 c, 
    $00 c, $00 c, $00 c, $00 c, $00 c, $00 c, $00 c, $00 c, 
    ;endStream 
 
\ clear a complete line 
: lineCLS ( -- ) 
    4 for 
        aft 
            sendBlock32bytesWith0 
        then 
    next 
  ; 
 
\ clear complete screen 
: OledCLS  ( -- ) 
    dispReset 
    DISPLAY_HEIGHT 8 / for 
        aft 
            lineCLS 
        then 
    next 
  ; 

Le mot LineCLS vide l'afficheur de son contenu.

Le mot crLine force l'affichage vers la ligne suivante. Ce mot boucle sur la ligne 0 après la ligne 3.

Le mot setContrast ajuste la luminosité de l'afffichage.

Dans l'article suivant, on expliquera l'affichage de texte.


Legal: site web personnel sans commerce / personal site without seling