Der Nachfolger des WDR-Computerclub mit Wolfgang Back und Wolfgang Rudolph - ...und immer ein Bit übrigbehalten!


Das Forum zur C-Control-1
Welche C-Control-Varianten existieren?
Übersicht - Suchen - Neueste 50 Beiträge - Neuer Beitrag - Login - Registrieren
INFO - FAQ - CC2-Forum - CCPro-Forum 

 Demoprogramm: Mandelbrot-Menge ("Apfelmännchen") auf dem Display Kategorie: Open-Micro/Open-Mini/Open-Midi/Open-Macro/Open-Maxi (von Dietmar, Homepage - 23.08.2019 11:35)
 Als Antwort auf Re: OLED-I2C-Grafikdisplay für 5,99 EUR von das |_ Team - 8.08.2019 16:43
Dietmar nutzt:  Open-Micro, Open-Mini, Open-Midi, Open-Macro, Open-Maxi, Open-Mini M-Unit, Open-Mini Station


' ---------------------------------------------------------------------------
' Berechnung und Darstellung der Mandelbrot-Menge ("Apfelmännchen")
' von Dietmar Harlos am 1. Juli 2006 bis 3. Dezember 2012
' Version vom 22. August 2019: Darstellung auf dem OLED-I2C-Grafikdisplay
' ---------------------------------------------------------------------------

' Dieses Beispielprogramm zeigt, wie sich auf den OM-Controllern die
' sogenannte Mandelbrot-Menge berechnen und darstellen laesst.

' Die Mandelbrot-Menge ist ein fraktales (selbstaehnliches) Gebilde und wird
' durch die sehr einfache Berechnungsvorschrift "z=z^2+c" erzeugt. Besonders
' beim Hineinzoomen zeigen sich sehr interessante Welten.

' Siehe "http://de.wikipedia.org/wiki/Mandelbrot-Menge".

' In diesem Programm wird die Mandelbrot-Menge mittels 8-Bit-Fixkommazahlen
' in Assembler berechnet. Die Grafik wird auf dem OLED-I2C-Grafikdisplay
' ausgegeben. Bedingt durch die Auflösung des Displays ist die Darstellung
' horizonal gestreckt.

' Das diesem Code zugrundeliegende Original-Programm befindet sich im ZIP-
' Archiv des OCBASIC-Compilers im Verzeichnis OM. Dort wird die Grafik auf
' der Seriellen Schnittstelle ausgegeben.

' Dieses Programm belegt nur 612 Byte FLASH-Speicher und 13 RAM-Bytes!

' --- Definitionen für das System -------------------------------------------

INCLUDE "omax.def"              ' Definitionen für die Open-Maxi

' --- Definitionen des Anwenders --------------------------------------------

DEFINE OLED_I2C_ADDR  &h78      ' Konstanten für OLED-I2C-Display
DEFINE OLED_DISP_OFF &hAE
DEFINE OLED_DISP_ON   &hAF
DEFINE DISPLAY_WIDTH 128
DEFINE DISPLAY_HEIGHT 64
DEFINE DISPLAYSIZE 1024

DIM a,b,c,data,x,y BYTE         ' einige Variablen definieren

DIM IMc  BYTE                   ' Deklarierung der Mandelbrot-Variablen
DIM REc  BYTE
DIM iter BYTE

DIM buffer,buffm BYTE           ' Buffer für Ausgabe auf Display

' --- Das Hauptprogramm -----------------------------------------------------

End2Host=ON
PrintSpc=ON

PRINT "OLED-I2C-Display: Mandel"

i2c_init                        ' I2C-Bus initialisieren
oled_init                       ' OLED-I2C-Display initialisieren

FOR x=0 TO 127

  REc=-126+(x*39) SHR 5         ' Realteil; (30--126)/128*32 = 39

  buffer=0 : buffm=1            ' Buffer für 8 Punkte

  FOR y=0 TO 63

    IMc=-72+(y*72) SHR 5        ' Imaginärteil; (72--72)/64*32 = 72

    mandel                      ' einen Punkt der Mandelbrotmenge berechnen

    IF iter>=11 THEN
      buffer=buffer OR buffm    ' Punkt im Buffer setzen
    ENDIF

    buffm=buffm SHL 1           ' Maske eine Stelle nach links (mal 2)

    IF buffm=0 THEN             ' 8 Punkte berechnet?
      oled_gotoxy x,y
      oled_data buffer          ' dann Buffer auf Display ausgeben
      buffer=0 : buffm=1
    END IF

  NEXT y
NEXT x

END                             ' zurueck in den Hostmodus

' ---------------------------------------------------------------------------

DEFINE REz    BYTE              ' Deklarierung der Assembler-Variablen
DEFINE IMz    BYTE
DEFINE REc_dz FREERAM2
DEFINE IMc_dz FREERAM3
DEFINE REzQ   FREERAM4
DEFINE IMzQ   FREERAM5

' ---------------------------------------------------------------------------

' Berechnung eines Punktes der Mandelbrotmenge
' von Dietmar Harlos am 1. Juli 2006
' die Anzahl der benoetigten Iterationen wird in iter zurueckgeliefert

PROC mandel INLASM

! lda REc        '-128..32      ' RE(c) muss in der Aufloesung reduziert
! asra                          ' werden, damit es in den folgenden Berech-
! adc #0                        ' nungen nicht zu einem Ueberlauf kommt.
! sta REc_dz     '-64..16       ' Dabei wird gerundet.
! sta REz

! lda IMc        '-72..72       ' IM(c) ebenso reduzieren. Die Zahlen sind
! asra                          ' jetzt mit dem Faktor 32 skaliert, was
! adc #0                        ' dem Linksshiften um 5 Stellen entspricht.
! sta IMc_dz     '-36..36       ' -64..16 -> -64/32..16/32 -> -2.0..0.5
! sta IMz

! clr iter                      ' Anzahl der Iterationen festhalten
#mandel_1
! lda REz        '-64..63       ' RE(z)^2 berechnen und festhalten, da es
! tax                           ' unten noch einmal benoetigt wird.
! bsr imul
! asrx
! rora
! adc #0
! sta REzQ       '0..128

! lda IMz        '-64..63       ' IM(z)^2 berechnen und festhalten, da es
! tax                           ' unten noch einmal benoetigt wird.
! bsr imul
! asrx
! rora
! adc #0
! sta IMzQ       '0..128

! add REzQ                      ' Abfrage RE(z)^2+IM(z)^2 >= 128 (= 4.0)
! blt mandel_2   '(N XOR V)=1   ' Schleife beenden, wenn Betrag von z >= 2.0

! inc iter                      ' Iterationszaehler um eins inkrementieren
! lda #14                       ' und auf maximale Anzahl der Iterationen
! cbeq iter,mandel_2            ' ueberpruefen

! lda REz        '-64..63       ' IM(z) = 2*RE(z)*IM(z) + IM(c)
! ldx IMz        '-64..63
! bsr imul       '-4032..4096 -> x:a= $ff:04..$01:$00
! adc IMc_dz     '-36..36 -/+ 1
! bcc mandel_3
! incx                          ' Die Multiplikation mit 2 liefert ein
#mandel_3                       ' 16-Bit-Ergebnis, deshalb muss auch die
! brclr #7,IMc_dz,mandel_4      ' Addition in 16-Bit durchgefuehrt werden.
! decx
#mandel_4
! sta IMz

! pushx                         ' Schleife verlassen, falls das 16-Bit-
! poph                          ' Ergebnis zu gross oder zu klein ist.
! tax                           ' Wenn IM(z) z.B. -65, dann waere IM(z)^2
! cmphx #63                     ' gleich 132. Die Schleife wuerde also nach-
! bgt mandel_2                  ' folgend beim "blt mandel_2" verlassen.
! cmphx #-64
! blt mandel_2

! lda REzQ       '0...126       ' RE(z) = RE(z)^2-IM(z)^2 + RE(c)
! sub IMzQ       '0...126 -> -126..126
! add REc_dz     '-64..15
! tax                           ' Schleife verlassen, falls bei der Addition
! tpa                           ' ein Ueberlauf im 2-er-Komplement auftrat
! tsta
! bmi mandel_2   'V - Overflow Flag - A7 & M7 & ~R7 | ~A7 & ~M7 & R7
! stx REz

! cmpx #63                      ' Schleife verlassen, falls das Ergebnis
! bgt mandel_2                  ' zu gross oder zu klein ist. Begruendung
! cmpx #-64                     ' siehe oben.
! bge mandel_1

#mandel_2
! rts                           ' Ruecksprung nach BASIC


' Vorzeichenbehaftete Multiplikation im mit 32 skalierten 8-Bit-Fixkommaformat
' von Dietmar Harlos am 1. Juli 2006

#imul
! clr OSTEMP
! tsta           ' Zum Verstaendnis, Multiplikation 1.75 mal 1.5:
! bpl imul_1     ' Die Zahlen sind skaliert: 1.75*32=56, 1.5*32=48
! inc OSTEMP     ' Multiplikation liefert: 1.75*1.5*32*32=2688
! nega           ' Zur Anpassung an die Skalierung wird durch 32
#imul_1          ' geteilt, also 5-mal nach rechts geshiftet.
! tstx           ' Das Ergebnis 2688/32=84 ist somit 84/32=2.625.
! bpl imul_2
! inc OSTEMP
! negx           ' Maximaler Rueckgabewert (Ergebnis):
#imul_2          ' -64*-64= 4096/2^4= 256 -> x:a = $01:$00
! mul            ' -64* 63=-4032/2^4=-252 -> x:a = $ff:$04
#imul_4
! brclr #0,OSTEMP,imul_3
! comx
! nega
! bne imul_3
! incx
#imul_3
! asrx
! rora           ' Eigentlich sind 5 Schiebe- und Rotierbefehle
! asrx           ' notwendig, aber im Hauptprogramm muss an
! rora           ' einer Stelle das Ergebnis der Multiplikation
! asrx           ' mit zwei multipliziert werden. Deshalb wird
! rora           ' das fuenfte Schieben inklusive Runden bei
! asrx           ' Bedarf im Hauptprogramm durchgefuehrt.
! rora
! rts

END PROC

' ---------------------------------------------------------------------------
' Subroutinen für das OLED-I2C-Display
' ---------------------------------------------------------------------------

PROCEDURE oled_init
  PAUSE 2                  'etwas warten

  i2c_start
  IF i2c_write(OLED_I2C_ADDR)=0 THEN
    PRINT "OLED-I2C-Display reagiert nicht!"
    END
  END IF

  i2c_write &h00           '0x00 for command, 0x40 for data
  FOR a=0 TO 26
    i2c_write LOOKTABBYTE(init_sequence,a)
  NEXT a
  i2c_stop

  oled_command(OLED_DISP_ON)
  RETURN
END PROCEDURE

PROCEDURE oled_command(c)
  i2c_start
  i2c_write OLED_I2C_ADDR
  i2c_write &h00           '0x00 for command, 0x40 for data
  i2c_write c
  i2c_stop
  RETURN
END PROCEDURE

PROCEDURE oled_data(data)
  i2c_start
  i2c_write OLED_I2C_ADDR
  i2c_write &h40           '0x00 for command, 0x40 for data
  i2c_write data
  i2c_stop
  RETURN
END PROCEDURE

' x von 0 bis 127, y von 0 bis 63 (in 8-er Schritten)

PROCEDURE oled_gotoxy(x,y)
  i2c_start
  i2c_write OLED_I2C_ADDR
  i2c_write &h00           '0x00 for command, 0x40 for data
  i2c_write &hb0+(y SHR 3)
  i2c_write &h21
  i2c_write x
  i2c_write &h7f
  i2c_stop
  RETURN
END PROCEDURE

' ---------------------------------------------------------------------------
' Tabellen
' ---------------------------------------------------------------------------

' Initialization Sequence für OLED-I2C-Display
' nach lcd_text.zip

TABLE init_sequence BYTE
    OLED_DISP_OFF, ' Display OFF (sleep mode)
    &h20, &h00,   ' Set Memory Addressing Mode
                  ' 00=Horizontal Addressing Mode; 01=Vertical Addressing Mode;
                  ' 10=Page Addressing Mode (RESET); 11=Invalid
    &hB0,         ' Set Page Start Address for Page Addressing Mode, 0-7
    &hC8,         ' Set COM Output Scan Direction
    &h00,         ' --set low column address
    &h10,         ' --set high column address
    &h40,         ' --set start line address
    &h81, &h3F    ' Set contrast control register
    &hA1,         ' Set Segment Re-map. A0=address mapped; A1=address 127 mapped.
    &hA6,         ' Set display mode. A6=Normal; A7=Inverse
    &hA8, 63      ' DISPLAY_HEIGHT-1    ' Set multiplex ratio(1 to 64)
    &hA4,         ' Output RAM to Display
                  ' &hA4=Output follows RAM content; &hA5,Output ignores RAM content
    &hD3, &h00    ' Set display offset. 00 = no offset
    &hD5,         ' --set display clock divide ratio/oscillator frequency
    &hF0,         ' --set divide ratio
    &hD9, &h22    ' Set pre-charge period
    &hDA, &h12    ' Set com pins hardware configuration
    &hDB,         ' --set vcomh
    &h20,         ' &h20,0.77xVcc
    &h8D, &h14    ' Set DC-DC enable
END TABLE

' ---------------------------------------------------------------------------
' Die I2C-Routinen einbinden
' ---------------------------------------------------------------------------

INCLUDE "omax_i2c.pro"

' ---------------------------------------------------------------------------
' Die Firmware-Routinen einbinden
' ---------------------------------------------------------------------------

INCLUDE "om_fw.pro"

' --- Programmende ---------------------------------------------------------


Meine Homepage: http://ccintern.dharlos.de

 Antwort schreiben

Bisherige Antworten:

Re: Demoprogramm: Mandelbrot-Menge ("Apfelmännchen") auf dem Display (von Joachim - 24.08.2019 11:29)
    Re: Demoprogramm: Mandelbrot-Menge ("Apfelmännchen") auf dem Display (von Dietmar - 24.08.2019 11:48)