Forum: Projekte & Code SSD1306/1309 Library zum Darstellen von Text auf OLED Displays


von M. K. (sylaina)


Angehängte Dateien:

Lesenswert?

Aktuelle Version hier: 
Beitrag "Re: SSD1306 Library zum Darstellen von Text auf OLED Displays"

Ich habe eine kleine Library für den Displaycontroller SSD1306 
geschrieben, wie er häufig bei den 0.96" OLED-Displays eingesetzt wird. 
Als Schnittstelle wird IIC benutzt. *)
Die Library zeichnet lediglich Text auf das Display.
Der Vorteil bzgl. Adafruit und u8glib ist u.a., dass bei weitem nicht so 
viel Flash benötigt wird (etwa 1400 kByte wenn man nur "Hallo Welt!" 
aufs Display schreibt, Adafruit braucht da rund 10 kByte, u8glib etwa 8 
kByte) und auch beim RAM sieht es erheblich besser aus als bei den 
üblichen Libs die jeweils mit einem Puffer in Displaygröße arbeiten, 
d.h. man braucht über ein 1kByte RAM alleine für die Lib.
Meine Lib arbeitet ohne Puffer, daher wird hierfür auch kein statischer 
RAM für einen Puffer benötigt. Ich hab es nicht getestet, aber auch 128 
Byte RAM müssten locker ausreichend sein.
Um das gesamte Display zu beschreiben (168 Zeichen) benötigt die Lib 
hier bei 400 kHz IIC-Clock nur ca. 35 ms, für eine Zeile (21 Zeichen) 
sind es ca. 4,5 ms. Adafruit und u8glib benötigen beide alleine für eine 
Zeile schon mehr als 20 ms.
Bei den Befehlen für das Display habe ich mich an den Befehlen von Peter 
Fleury's Lib für die HD44780-Displays gehalten.
Getestet hab ich die Lib mit einem ATMega168PA und einem ATMega328P, 
beide mit 16 MHz Quarz, den II2C hab ich auf 400 kHz eingestellt gehabt, 
sie sollte auch auf einem ATMega88PA laufen.

Interessant dürfte die Lib für all jene sein, die kleinere AVRs 
benutzten wollen, als die, die von ADAFRUIT und u8glib erwartet werden.

Als nächstes werde ich mich an die Portierung für die ATTinys dran 
setzen. Eine Grafik-Variante (mit der man auch Zeichnen kann) hab ich 
auch fertig, allerdings braucht die noch Feintuning und sie benötigt 
einen AVR mit mehr als 1 kByte RAM (sie arbeitet mit einem Puffer).

EDIT: Noch ein Foto angehangen.

Edit: Github link https://github.com/Sylaina/oled-display.git

*) SPI wird mittlerweile ebenfalls unterstützt, siehe
Beitrag "Re: SSD1306 Library zum Darstellen von Text auf OLED Displays"

: Bearbeitet durch Moderator
von edsyn (Gast)


Lesenswert?

Hallo,
nur zur Ergänzung.
Nicht alle Arduino-Libs für SSD1306 sind so gross.
Bill Greiman hat auch eine eingedampfte Ascii-Lib:
"Sketch uses 2,622 bytes (8%) of program storage space.
Global variables use 53 bytes (2%) of dynamic memory"
https://github.com/greiman/SSD1306Ascii

von M. K. (sylaina)


Lesenswert?

edsyn schrieb:
> Hallo,
> nur zur Ergänzung.
> Nicht alle Arduino-Libs für SSD1306 sind so gross.
> Bill Greiman hat auch eine eingedampfte Ascii-Lib:
> "Sketch uses 2,622 bytes (8%) of program storage space.
> Global variables use 53 bytes (2%) of dynamic memory"
> https://github.com/greiman/SSD1306Ascii

Die schaut auch interessant aus, keine Frage. Hab ich jetzt nur mal 
überflogen aber scheint auch für Arduino zu sein. Das benutze ich gar 
nicht wennauch ich Arduino Boards habe. Die habe ich aber nur weil die 
Boards ansich recht praktisch sind.
53 Byte für Globale Variablen ist schon einiges, beim Überfliegen hab 
ich so jetzt gar nicht direkt gesehen wofür die nötig sind.
However, gefällt mir auch. Vielleicht mach ich die Tage mit der Lib auch 
noch einen Geschwindigkeitstest um sie in den Vergleich zu meiner Lib 
mit aufzunehmen.

von M. K. (sylaina)


Angehängte Dateien:

Lesenswert?

Ich war dann gestern noch etwas ambitioniert und habe meiner Library 
noch Grafikfunktionen hinzugefügt. Jetzt benötigt die Lib leider schon 
etwas mehr als 4kByte Flash sowie 1029 Byte SRAM.
Da ich die Grafikfunktionen nicht immer benötige hab ich für die 
Grafik-Variante eine eigene Lib gemacht.
In meinem hier gezeigten Beispiel enthält die Refresh-Rate das Zeichnen 
des Rechtecks, des Kreises und des Kreuzes, das Löschen und neu 
Schreiben der letzten Zeile sowie den "Balken" (den lasse ich erst nach 
rechts hin wachsen und wenn er den rechten Rand erreicht hat lösche ich 
da Linie für Linie Richtung links bis er verschwunden ist).
Es wird zunächst in den Puffer geschrieben und dann mittels 
lcd_display() dieser dem Display zur Anzeige geschickt.
Die erste Zeile wird nur beim Start in den Puffer geschrieben. Das Ganze 
dauert, wie man sehen kann, nicht mal 35 ms. IMO gar nicht mal so 
schlecht für den ersten Ansatz.

von Dirk B. (garag)


Lesenswert?

Hallo,

ich finde die Library interessant. Jedoch vermisse ich einen 
Lizenzhinweis. Darf man die Library nun frei verwenden ?

Gruß
Dirk

von M. K. (sylaina)


Lesenswert?

Dirk B. schrieb:
> Darf man die Library nun frei verwenden ?

Upsala, natürlich darf man die Library frei verwenden. Muss mir mal über 
Lizensen und solcher Sachen Gedanken machen, da hast du recht.

von Max M. (maxmicr)


Lesenswert?

Ich wollte mich bei dir auch noch für die Lib bedanken, tolle Arbeit!

von Max M. (maxmicr)


Lesenswert?

Ich hätte einen kleinen Wunsch: Könntest du noch das Zeichen "°" zum 
Font hinzufügen?

: Bearbeitet durch User
von M. K. (sylaina)


Angehängte Dateien:

Lesenswert?

Max M. schrieb:
> Ich hätte einen kleinen Wunsch: Könntest du noch das Zeichen "°" zum
> Font hinzufügen?

Ich habe sogar mehr getan. Neben "°" sind nun auch noch die Umlaute 
"üÜöÖäÄ" und das "ß" verfügbar. ;)
Im Anhang die Text-Variante und die Grafik-Variante.

von Joachim B. (jar)


Lesenswert?

könnte mir ja gefallen nur....

es fehlt die Version für SH1106 mit SSD1306 Ansprache bekomme ich rechts 
Grafikfehler

ein ATmega 1284p (mighty mini z.B. oder nativ) ist auch noch nicht dabei

schade....

von M. K. (sylaina)


Lesenswert?

Richtig, es ist ja auch in der Entwicklungsphase und ich hab halt nur 
einen Atmega328p (bzw. seine kleineren Brüder) und Attiny45/85. SH1106 
muss ich mal spicken, sollte recht simpel umsetzbar sein da dies nur um 
2 byte verschoben ist gegenüber dem ssd1306 soweit ich das jetzt gelesen 
hatte im Netz.
Ich werd mal schaun was sich da machen lässt. Erstmal muss ich schaun, 
dass ich die Attinys an den Start bekomme. Hatte die letzte Woche nicht 
wirklich Zeit hier mal weiter zu arbeiten, ich hoffe auf nächste Woche 
;)

EDIT: Hab mal geschaut. Der Atmega1284p (hab ich persönlich nicht im 
Einsatz, daher kenne ich ihn auch nicht) ist bzgl. i2c identisch mit dem 
Atmega328, d.h. die Zeile 174 in der C-Datei:
1
#if defined(__AVR_ATmega328P__) || defined(__AVR_ATmega168P__) || defined(__AVR_ATmega88P__) || defined(__AVR_ATmega48P__)

muss nur gegen die folgende Zeile
1
#if defined(__AVR_ATmega328P__) || defined(__AVR_ATmega168P__) || defined(__AVR_ATmega88P__) || defined(__AVR_ATmega48P__) || defined(__AVR_ATmega1284P__)

ersetzt werden und schon dürfte auch der Atemga1284p unterstützt werden.

: Bearbeitet durch User
von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

M. K. schrieb:
> etwa 1400 kByte wenn man nur "Hallo Welt!" aufs Display schreibt

1,4 MB, nun, auf einen modernen ARM passt das schon. ;-) <scnr>

Danke schon mal, habe zwar bislang die Variante mit dem 1-KB-Puffer
genutzt, aber richtig toll fand ich das nie.

von Joachim B. (jar)


Lesenswert?

danke

ich mache es mir einfacher in einer pin.h
1
#ifndef _PINS_H_
2
#define _PINS_H_
3
4
#if defined(__AVR_ATmega328P__)
5
  #define   TIMSKx              TIMSK1
6
  #define   OCIExA              OCIE1A
7
  #define   TIMERx_COMPA_vect   TIMER1_COMPA_vect  // ATmega
8
  #define   TCCRxA              TCCR1A
9
  #define   COMxA0              COM1A0
10
  #define   OCRxA               OCR1A
11
  #define   TCCRxB              TCCR1B
12
  #define   WGMx2               WGM12
13
  #define   CSx0                CS10
14
15
  #define LED_ARDUINO           5
16
  #define LED_ARDUINO_DDR       DDRB
17
  #define LED_ARDUINO_PORT      PORTB
18
  #define LED_ARDUINO_ON        LED_ARDUINO_PORT|=(1<<LED_ARDUINO)
19
  #define LED_ARDUINO_OFF       LED_ARDUINO_PORT&=~(1<<LED_ARDUINO)
20
  #define LED_ARDUINO_START  7
21
  #define LED_ARDUINO_ONOFF_TIME  10 // x10ms
22
23
  // arduino nano v3
24
  // DIGITAL
25
  // (Reset)        PC6
26
  // D0 (Rx)        PD0
27
  // D1 (Tx)        PD1
28
  // D2 (Int0)      PD2
29
  // D3 (Int1)      PD3
30
  // D4 (XCK/T0)    PD4
31
  // D5 (T1)        PD5
32
  // D6 (AIN0)      PD6
33
  // D7 (AIN1)      PD7  
34
  // D8 (ICP1)      PB0
35
  // D9 (OC1A)      PB1 (PWM)
36
  // D10(SS/OC1B)   PB2 (PWM)
37
  // D11(MOSI/OC2)  PB3 (PWM)
38
  // D12(MISO)      PB4
39
  // D13(SCK)       PB5 (LED)
40
  
41
  // ANALOG
42
  // A0 (ADC0)      PC0
43
  // A1 (ADC1)      PC1
44
  // A2 (ADC2)      PC2
45
  // A3 (ADC3)      PC3
46
  // ----------------- I2C -----------------
47
  // A4 (ADC4/SDAglb)  PC4
48
  #define PIN_SDA        4 //PC4 -> A4
49
  // A5 (ADC5/SCLgrn)  PC5
50
  #define PIN_SCL        5 //PC5 -> A5
51
  // D12
52
53
 #elif defined(__AVR_ATmega1284P__) // --------------------------------------------------------- m1284p -------------------------------------------------------
54
55
  #define   TIMSKx              TIMSK3
56
  #define   OCIExA              OCIE3A
57
  #define   TIMERx_COMPA_vect   TIMER3_COMPA_vect  // ATmega
58
  #define   TCCRxA              TCCR3A
59
  #define   COMxA0              COM3A0
60
  #define   OCRxA               OCR3A
61
  #define   TCCRxB              TCCR3B
62
  #define   WGMx2               WGM32
63
  #define   CSx0                CS30
64
  #define   UBRRnL              UBRR0L
65
  #define   UBRRnH              UBRR0H
66
  #define   UCSRnA              UCSR0A
67
  #define   U2Xn                U2X0
68
/*
69
  #define   USARTn_RX_vect      USART0_RX_vect
70
  #define   USARTn_UDRE_vect    USART0_UDRE_vect
71
*/  
72
//                                m1284p
73
//    mighty ARDUINO          +----\/----+
74
//                        RST |1  ISP  36| VCC
75
//              RX0 (D 8) PD0 |2         | PB7 (D 7) PWM/SCK 
76
  #define LED_ARDUINO 7
77
  #define LED_ARDUINO_PORT                        PORTB
78
  #define LED_ARDUINO_DDR                         DDRB
79
//              TX0 (D 9) PD1 |3         | PB6 (D 6) PWM/MISO 
80
//        RX1/INT0 (D 10) PD2 |4         | PB5 (D 5) MOSI 
81
//        TX1/INT1 (D 11) PD3 |5         | PB4 (D 4) PWM/SS
82
//             PWM (D 12) PD4 |6         | PB3 (D 3) PWM 
83
//             PWM (D 13) PD5 |7         | PB2 (D 2) INT2 
84
//             PWM (D 14) PD6 |8         | PB1 (D 1) 
85
//             PWM (D 15) PD7 |9         | PB0 (D 0) 
86
//                            |          |
87
//                            |          |
88
//          SCLgrn (D 16) PC0 |10      27| PA0 (AI 0 / D24)
89
  #define  PIN_SCL    16                                    //PC0 -> D16
90
91
//          SDAglb (D 17) PC1 |11      26| PA1 (AI 1 / D25)
92
  #define  PIN_SDA    17                                    //PC1 -> D17
93
//             TCK (D 18) PC2 |12      25| PA2 (AI 2 / D26)
94
//             TMS (D 19) PC3 |13      24| PA3 (AI 3 / D27)
95
//             TDO (D 20) PC4 |14      23| PA4 (AI 4 / D28)
96
//             TDI (D 21) PC5 |15      22| PA5 (AI 5 / D29)
97
//                 (D 22) PC6 |16      21| PA6 (AI 6 / D30)
98
//                 (D 23) PC7 |17      20| PA7 (AI 7 / D31)
99
//                        GND |18      19| AREF
100
//                            +----------+
101
 #endif // defined(__AVR_ATmega1284P__)
102
103
  #ifdef LED_ARDUINO
104
    #ifdef LED_ARDUINO_DDR
105
      #ifdef LED_ARDUINO_PORT
106
        #define LED_ARDUINO_ON       LED_ARDUINO_PORT  |= (1<<LED_ARDUINO)
107
        #define LED_ARDUINO_OFF      LED_ARDUINO_PORT &= ~(1<<LED_ARDUINO)
108
        #define LED_ARDUINO_START  5
109
        #define LED_ARDUINO_ONOFF_TIME  2 // x10ms
110
      #endif // #ifdef LED_ARDUINO_DDR
111
    #endif // #ifdef LED_ARDUINO_PORT
112
  #endif // #ifdef LED_ARDUINO
113
114
115
#endif // _PINS_H_

von M. K. (sylaina)


Lesenswert?

Jörg W. schrieb:
> Danke schon mal, habe zwar bislang die Variante mit dem 1-KB-Puffer
> genutzt, aber richtig toll fand ich das nie.

Das Problem ist dabei halt, dass man beim I2C das Display nicht lesen 
kann. Bzgl. Zeichnen kommt man da halt um den Puffer nicht drum rum. Bei 
reiner Textanwendung aber kann man sich den Puffer tatsächlich sparen. 
Das war eine meiner Motivationen zu der Lib ;)

Joachim B. schrieb:
> ich mache es mir einfacher in einer pin.h

Das ist natürlich auch eine Möglichkeit ;)

von Max M. (maxmicr)


Lesenswert?

M. K. schrieb:
> Ich habe sogar mehr getan. Neben "°" sind nun auch noch die Umlaute
> "üÜöÖäÄ" und das "ß" verfügbar. ;)
> Im Anhang die Text-Variante und die Grafik-Variante.

Super, danke! Mir ist gerade beim portieren auf meinen Controller 
aufgefallen, dass bei mir das '°' nicht den Code 144 hat, deswegen hab 
ich das so verglichen:
1
  if(c == '°'){
2
    c = 101;    //°

ist vllt. einfacher zu lesen. Könntest du die lcd_putc-Funktion nicht 
auch deutlich kürzen, wenn du zuerst die Variable c entsprechend 
bestimmst und dann nur einmal die Schleife hinschreibst, in etwa so:
1
switch (c){
2
 case 156: //vllt. geht hier auch "case 'ü'"
3
  c = 95;
4
  break;
5
 case 150:
6
  c = 99;
7
  break;
8
 ...
9
 default:
10
  c-=32;
11
  break;
12
}
13
for(uint8_t...){
14
//set buffer
15
}

Kam mir nur gerade beim Durchschauen. Tolle Arbeit! Läuft auch auf nem 
STM8S103 mit 1kByte RAM (ich hab den Puffer auf ~630Byte verkleinert) 
super! Ich hoffe es ist in Ordnung, wenn ich deinen Code leicht 
verändert benutze?

: Bearbeitet durch User
von M. K. (sylaina)


Lesenswert?

Hallo Max,
sicher kann ich das noch entsprechend umstricken. Ich muss gestehen, ich 
hab das heute Mittag quasi nur so hingerotzt, Verfeinerungen werden 
später noch kommen ;)

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

M. K. schrieb:
> Bei reiner Textanwendung aber kann man sich den Puffer tatsächlich
> sparen.

Beim Zeichnen geht es auch, wenn man halt immer komplette 8 Pixel
zeichnet.

Klar, mit Puffer hat auch was.

Habe gerade etwas ähnliches durch bei einem Farb-LCD, aber dort
braucht man pro Pixel ein ganzes Byte, damit keinen Puffer.

von M. K. (sylaina)


Lesenswert?

Jörg W. schrieb:
> Beim Zeichnen geht es auch, wenn man halt immer komplette 8 Pixel
> zeichnet.

Hm, mach ich doch, bzw. geht bei dem Display doch gar nicht anders, das 
ist ja quasi das Problem warum man erst einen Puffer braucht: Man kann 
Pixel eigentlich immer nur im 8er-Pack modifizieren, d.h. selbst wenn 
man nur einen Pixel ändern will muss man dem Display Infos für 8 Pixel 
schicken.

Wie soll das funktionieren also ohne Puffer funktionieren? Nehmen wir 
an, es wurde schon etwas auf das Display gezeichnet. Jetzt soll noch 
zusätzlich was dazu gezeichnet werden. Wie kann man das denn ohne Puffer 
etwas dazu zeichnen ohne den bisherigen Displayinhalt zu löschen? Ohne 
Puffer sehe ich da keinen Weg, vielleicht hast du ja einen Tipp für 
mich.

Bei Text hat man ja nur deshalb den Vorteil den Puffer zu sparen weil 
man idR nicht 2, 3, 4, 5 usw. Buchstaben übereinander zeichnen will, man 
will immer nur einen einzigen Buchstaben in einem Feld stehen haben. 
Deshalb ist es da völlig in Ordnung wenn der vorherige Inhalt des Felds 
gelöscht wird. Will man z.B. den Schnittpunkt von zwei Kurven 
bestimmen/visualisieren ist das recht doof wenn beim Zeichnen der 
zweiten Kurve die erste Kurve gelöscht wird. Ohne irgendwo einen Puffer 
zu haben wüsste ich nicht, wie man das Lösen könnte. Und wie schon 
gesagt, toll wäre es, man könnte das Display-RAM als Puffer nutzen nur 
lässt sich das bei I2C leider nicht auslesen, sprich nicht als Puffer 
nutzen.

von Axel R. (Gast)


Lesenswert?

I am very beghosted!
Ich bin sehr begeistert.
Super Arbeit, klasse Beitrag. Jetzt muss ich nur noch mein 0.96"OLED 
wiederfinden.

Nochmal: herzlichen Dank :)

StromTuner

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

M. K. schrieb:
> Wie kann man das denn ohne Puffer etwas dazu zeichnen ohne den
> bisherigen Displayinhalt zu löschen?

Man muss sich halt das Display dann gedanklich in 8er-Schritten
aufteilen – so, wie du es letztlich ja auch beim Text machst.

Braucht mehr Planung (dessen, der damit was machen will), aber
weniger RAM.

OK, so gesehen: der nächstgrößere Controller mit ausreichend RAM
ist wahrscheinlich dann doch die einfachere Wahl.

von Tany (Gast)


Lesenswert?

Jörg W. schrieb:
> dann doch die einfachere Wahl

...und sinnvolle Wahl, die Preis-Differenz ist minimal.

M. K. schrieb:
> Wie kann man das denn ohne Puffer
> etwas dazu zeichnen ohne den bisherigen Displayinhalt zu löschen?

ganz einfach: man löscht nicht den kompletten Displayinhalt, sondern nur 
den Bereich, wo "zusätzlich" geschrieben wird. Es reicht auch zu 
überschreiben.
Dafür braucht man keinen Puffer.

von Joachim B. (jar)


Lesenswert?

Tany schrieb:
> ganz einfach: man löscht nicht den kompletten Displayinhalt, sondern nur
> den Bereich, wo "zusätzlich" geschrieben wird.

beim Arduino TFT Shield habe ich den alten Text mit black vor dem neuen 
Text geschrieben, löscht schneller als rect

von M. K. (sylaina)


Lesenswert?

Tany schrieb:
> ganz einfach: man löscht nicht den kompletten Displayinhalt, sondern nur
> den Bereich, wo "zusätzlich" geschrieben wird. Es reicht auch zu
> überschreiben.
> Dafür braucht man keinen Puffer.

Einfach mal mit dem Display auseinander setzen, dann wüsstest du, dass 
das nicht geht. Die kleinste Einheit, die man bei diesem Display ändern 
kann, sind "Blöcke" mit 8 Pixel Größe. Wie willst du innerhalb eines 
Blockes einen Pixel ändern, ohne die anderen zu beeinflussen und ohne 
Puffer zu haben? Auch hier wieder bedenken: Via I2C lässt sich das 
Display nicht auslesen, nur beschreiben.
Ich sehe hier keinen Weg ohne Puffer, bin aber für konkrete 
Gegenbeispiele sehr offen.

von Tany (Gast)


Lesenswert?

M. K. schrieb:
> Einfach mal mit dem Display auseinander setzen, dann wüsstest du, dass
> das nicht geht
So ein klein habe ich nicht, sondern ein 240x128 Display. Und der 
Controller braucht nicht ein Bit, sondern 5 Bits für ein Pixel. Es geht 
trotzdem ohne Puffer.

von Joachim B. (jar)


Lesenswert?

M. K. schrieb:
> und ich hab halt nur
> einen Atmega328p (bzw. seine kleineren Brüder) und Attiny45/85. SH1106
> muss ich mal spicken, sollte recht simpel umsetzbar sein da dies nur um
> 2 byte verschoben ist gegenüber dem ssd1306 soweit ich das jetzt gelesen
> hatte im Netz.
> Ich werd mal schaun was sich da machen lässt.

wäre schön

hier fand ich auch was
https://forum.arduino.cc/index.php?topic=256374.0

aber ich mag nicht in deinem Code patchen, du kennst ihn ja besser!

wie groß ist dein Font eigentlich, ich habe ja auch Nokia 5110 am Start 
mit 84x48 Pixel und 6x8 Font (oder 5x7?)

mit 128 PIX kommt man weiter, komischerweise kann ich auf dem Nokia 14 
Zeichen auf 6 Zeilen, mit Adafruit zwar 16 Zeichen pro Zeile

bei 128 pix in x müssten über 20 Zeichen pro Zeile möglich sein x 8 
Zeilen

: Bearbeitet durch User
von M. K. (sylaina)


Lesenswert?

Das schau ich mir heute abend mal an. Im Moment fehlt mir mal wieder die 
Zeit mich genauer mit dem Display zu beschäftigen und da ich es aktuell 
nur am Atmega168 benutze habe ich zur Zeit auch keine Notwendigkeit 
dafür. Hoffe in den nächsten Wochen haben ich wieder etwas mehr Luft 
dafür. Wills ja auch noch für den Attiny45 an den Start bekommen.

von Uwe D. (monkye)


Lesenswert?

Die Grafikroutinen werden spürbar kleiner, wenn Du anstatt der vielen 
Mathe-Funktionen sowohl Linien als auch Kreise mit dem Bresenham 
Algorithmus implementierst. Da kommst Du komplett mit Interger zurecht 
und schnell ist es auch.

von M. K. (sylaina)


Lesenswert?

Da hast du recht Uwe, daher habe ich grade noch mal in den Code 
geschaut. Den Kreis hatte ich nämlich schon mit Bresenham implementiert, 
die Linien hab ich vergessen umzubauen. Kommt direkt auf die TODO-Liste 
;)

von Uwe D. (monkye)


Lesenswert?

Bei den kleinen Displays, bei denen man direkt mit einem Byte zur 
Adressierung auskommt (also max 255 Pixel für eine Achse), braucht man 
nicht mal Funkionen für Absolutwerte/Vorzeichen.

von M. K. (sylaina)


Angehängte Dateien:

Lesenswert?

Joachim B. schrieb:
> wie groß ist dein Font eigentlich, ich habe ja auch Nokia 5110 am Start
> mit 84x48 Pixel und 6x8 Font (oder 5x7?)

Mein Font ist auch 6x8 Pixel (wobei die erste Spalte und letzte Zeile 
ungenutzt ist) groß.

Joachim B. schrieb:
> bei 128 pix in x müssten über 20 Zeichen pro Zeile möglich sein x 8
> Zeilen

21 Zeichen sind es bei mir in der aktuellen Version.

Und da sind wir auch schon in der Überleitung:
1. Neuerung: Ich lasse nun nur noch 21 Zeichen pro Zeile zu und es gibt 
auch keinen automatischen Zeilenumbruch mehr da ich den etwas unschön 
fand. Oder sollte ich einen Schalter einführen damit sich der User diese 
Funktionalität aussuchen kann?
2. Neuerung: Ich habe die Linien-Routinen noch auf Bresenham umgestellt, 
wie von Uwe vorgeschlagen. Bei meinem obigen Beispielcode sinkt dabei 
die Bildwiederholrate von rund 34 ms auf rund 28 ms (400 kHz 
Busgeschwindigkeit). Der benötigte Flashspeicher ist von rund 4 kByte 
auf unter 3 kByte gesunken. Am RAM hat sich nichts geändert, es werden 
immer noch 1027 Byte benötigt. OK, oben schrieb ich 1029 Byte, 2 Byte 
jedoch waren von einer Hilfsvariablen (uint16_t) meiner Mainloop, die 
ich übersah. Die gehört natürlich nicht zur Library, daher 1027 kByte ;)
Die aktuelle Version der Grafikvariante meiner Library habe ich 
angehangen.

Ein SH1106-Display hab ich mir zum Testen schon mal bestellt, sollten 
meine Ideen funktionieren werde ich demnächst hier darüber berichten und 
auch wieder eine aktuallisierte Version meiner Library online stellen.

von Joachim B. (jar)


Lesenswert?

kein automatischer Zeilenumbruch, sollen sich die User kümmern was sie 
wollen, über 21 Zeichen splitten und selber für die 2te Zeile sorgen 
oder Laufschrift machen

M. K. schrieb:
> Ein SH1106-Display hab ich mir zum Testen schon mal bestellt

freut mich, ich habe auch noch 2 nachbestellt

vielleicht wäre auch noch alternativ ein größerer Font wählbar möglich

ich finde ja den puren 6x8 zu mickrig, auf dem Nokia passt das.

also 16 Zeichen pro Zeile auf 5 Zeilen wäre eine vergleichbare Größe

: Bearbeitet durch User
von A. S. (Gast)


Lesenswert?

Tany schrieb:
> sondern 5 Bits für ein Pixel. Es geht trotzdem ohne Puffer.

Nicht trotzdem sondern deshalb. Zumindest, wenn die 3 andern Bits 
keinem anderen Pixel zugeordnet sind.

von M. K. (sylaina)


Angehängte Dateien:

Lesenswert?

Joachim B. schrieb:
> freut mich, ich habe auch noch 2 nachbestellt

So, ich hab meine SH1106er nun auch endlich bekommen und konnte heute
experimentieren. Library ist angepasst, Fehler möglich ;).
Es werden nun OLED-Displays mit SSD1306 und SH1106 Controller
unterstützt, entsprechend einzustellen in der jeweiligen Header-Datei.

von Joachim B. (jar)


Lesenswert?

ich warte noch auf meine!

von Max M. (maxmicr)


Lesenswert?

Ich hätte noch zwei Fragen zur Library:

Warum verwendest du in der "ssd1306_init_sequence" kein "LCD_DISP_ON" am 
Ende so wie du es in einer früheren Version von deiner Lib getan hast 
(soweit ich das richtig im Kopf hab)? Oder ist dafür der Parameter 
"dispAttr" der Funktion "lcd_init" zuständig? Du sendest in der 
"lcd_command" Funktion auch die I2C Slave Adresse des Displays nicht 
mit, hab ich da was verpasst, musste man das nicht?

: Bearbeitet durch User
von M. K. (sylaina)


Lesenswert?

Max M. schrieb:
> Warum verwendest du in der "ssd1306_init_sequence" kein "LCD_DISP_ON" am
> Ende so wie du es in einer früheren Version von deiner Lib getan hast
> (soweit ich das richtig im Kopf hab)? Oder ist dafür der Parameter
> "dispAttr" der Funktion "lcd_init" zuständig?

Das hast du richtig erkannt, ob das Display an oder aus sein soll nach 
dem Init wird nun über den Parameter dispAttr gesteuert, äquivalent zu 
Peter Fleurys lcd-Library zum Ansteuern von Displays mit 
HD44780-Controllern.

Max M. schrieb:
> Du sendest in der
> "lcd_command" Funktion auch die I2C Slave Adresse des Displays nicht
> mit, hab ich da was verpasst, musste man das nicht?

Ja, da hast du was verpasst und ja, man muss die Adresse senden. Auch in 
der lcd_command-Funktion wird die Adresse gesendet. Als erstes wird in 
lcd_command die Funktion lcd_send_12c_start aufgerufen und diese 
Funktion stellt die Startbedingung her und sendet die Adresse.

von oberallgeier (Gast)


Lesenswert?

Hallo Michael,

erstmal vielen Dank für die Mühe, das Ganze von arduino.IDE abzulösen - 
sozusagen für simple C-Geister (mein C spricht sich Cäh) wie mich. So 
viel gute Hilfe wie für Deinen Transistortester.

Natürlich wollen Faulpelze immer mehr. Wäre es Dir bitte möglich, ein 
kurzes Main als Beispiel zu posten. So etwas in der Art wie für Dein 
Bild vom 24. Jan. 2017 abends?

Als Gegenleistung könnte ich (wenn das 1306er mal auf meinem NanoClone 
läuft) ein Bildchen bieten vom Oskar zu den I²C-Flanken bei den 400 kHz. 
Ich hatte bei so hohen Frequenzen schon mal Pferde "vor der Apotheke .. 
gesehen".

Danke im Voraus
und viele Grüße
der Joe vom Berg

von Walter J. (oberallgeier)


Lesenswert?

Uuups - war ohne Login.

von M. K. (sylaina)


Lesenswert?

Aber klar doch, die Main ist wirklich sehr einfach gestrickt gewesen. 
Allerdings hab ich noch ein wenig gespielt, ich weiß grad nicht wie die 
Main zum Beispielbild oben genau aussah. Daher hier die völlig 
unaufgeräumte Main:
1
/* Name: main.c
2
 * Author: Michael Koehler
3
 * Copyright: <insert your copyright message here>
4
 * License: <insert your license reference here>
5
 */
6
7
#include "main.h"
8
#include "lcd_ssd1306_gfx.h"
9
#include <stdlib.h>
10
#include <util/delay.h>
11
12
volatile uint16_t overflows;
13
14
int main(void)
15
{
16
    setUpAvr();
17
    lcd_set_contrast(0x0f);
18
  char time[6];
19
  uint8_t myVar = 0;
20
  uint8_t dir =0;
21
  DDRB |= (1 << PB5);
22
  
23
  //lcd_drawCircle(30, 30, 15, WHITE);
24
  //lcd_fillCircle(70, 40, 10, WHITE);
25
    for(;;){
26
    //PORTB ^= (1 << PB5);
27
    lcd_drawRect(10, 10, 40, 40, WHITE);
28
     if( dir == 0) {
29
      lcd_drawLine(0+myVar, 54, 0+myVar, 46, WHITE);
30
      myVar++;
31
       if(myVar == 128) dir = 1;
32
    } else {
33
      if(myVar == 0) dir=0;
34
      myVar--;
35
      lcd_drawLine(myVar, 46, myVar, 54, BLACK);
36
      
37
    }
38
    
39
    lcd_drawCircle(65, 25, 15, WHITE);
40
    lcd_drawLine(90, 10, 120, 40, WHITE);
41
    lcd_drawLine(90, 40, 120, 10, WHITE);
42
    lcd_drawLine(105, 10, 105, 40, WHITE);
43
    lcd_drawLine(90, 25, 120, 25, WHITE);
44
    lcd_gotoxy(0,0);
45
    lcd_puts_p(PSTR("M. Köhler 2016/2017"));
46
    lcd_invert(YES);
47
    lcd_display();
48
    TCCR1B = 0;
49
    dtostrf((overflows*65536UL+TCNT1)*1.0/16.0e3,
50
        6,
51
        3,
52
        time);
53
    overflows = 0;
54
    TCNT1 = 0;
55
    TCCR1B = 1 << CS10;
56
    lcd_gotoxy(0,7);
57
    lcd_puts_p(PSTR("                     "));
58
    lcd_gotoxy(0,7);
59
    lcd_puts_p(PSTR("Refresh: "));
60
    lcd_puts(time);
61
    lcd_puts_p(PSTR("ms"));
62
    //_delay_ms(1000);
63
    }
64
    return 0;   /* never reached */
65
}
66
67
void setUpAvr(void){
68
    /* insert your hardware initialization here */
69
  TIMSK1 |= (1 << TOIE1);
70
    // LCD Initialisierungen
71
  lcd_init(LCD_DISP_ON);
72
  sei();
73
}
74
75
ISR(TIMER1_OVF_vect){
76
  overflows++;
77
}

von STM8-C-Anfänger (Gast)


Angehängte Dateien:

Lesenswert?

Guten Morgen,

ich bin Programmieranfänger. Ich wollte Deine Bibliothek gern für meinen 
STM8S105-Aufbau benutzen. Mittlerweile läuft es auch, (siehe Anhang) ich 
hätte aber trotzdem noch Fragen dazu.

Du hast eine Abstraktion vom hardware-abhängigen Teil eingeführt, 
benutzt sie aber praktisch nicht. Warum?

1
void lcd_command(uint8_t cmd) {
2
    lcd_send_i2c_start();
3
    lcd_send_i2c_byte(0x00);  // 0x00 for command, 0x40 for data
4
    lcd_send_i2c_byte(cmd);
5
    lcd_send_i2c_stop();
6
}
7
void lcd_data(uint8_t data) {
8
    lcd_send_i2c_start();
9
    lcd_send_i2c_byte(0x40);  // 0x00 for command, 0x40 for data
10
    lcd_send_i2c_byte(data);
11
    lcd_send_i2c_stop();
12
}

Das hätte die Portierung erheblich vereinfacht, da der Umgang mit i2c 
bei mir ganz anders gestaltet ist.

Schwierigkeiten hatte ich auch mit den Multibyte-Literalen (Umlaute) im 
Quelltext, was sicher auch anderen so gehen dürfte. (siehe Beitrag von 
maxmicr weiter oben) Nutzt Du einen Mac oder so?

Der Frage nach einem Benutzungsbeispiel aka main.c schließe ich mich 
übrigens an.

PS: Ich habe in meiner Version lcd auf OLED umbenannt, weil ich parallel 
ein I2C-LCD benutze und beides klarer abgrenzen wollte. Es ist 
strenggenommen auch kein LCD.

von STM8-C-Anfänger (Gast)


Lesenswert?

STM8-C-Anfänger schrieb:
> Der Frage nach einem Benutzungsbeispiel aka main.c schließe ich mich
> übrigens an.

Oh, zeitliche Überschneidung, hat sich erledigt, danke. :)

von M. K. (sylaina)


Lesenswert?

STM8-C-Anfänger schrieb:
> Du hast eine Abstraktion vom hardware-abhängigen Teil eingeführt,
> benutzt sie aber praktisch nicht. Warum?

Da hast du recht, das liegt daran, dass ich hier noch nicht weiter 
entwickelt habe. Die Funktionen lcd_command und lcd_data können in der 
aktuellen Version immer nur ein Byte übertragen. Es gibt aber auch 
Situationen, da werden/müssen mehrere Bytes übertragen (Beispiel: 
lcd_gotoxy).
Für eine einfache Portierung musst du nicht lcd_command und lcd_data 
anpassen sondern die vier i2c-Funktionen(init, start, stop und byte), 
das erschien mir logischer weil diese Funktionen die 
Prozessorabhängigkeit beinhalten. ;)

von Manni (Gast)


Lesenswert?

Wie wird eigentlich die Schriftfarbe geändert ?

von Nico W. (nico_w)


Lesenswert?

Manni schrieb:
> Wie wird eigentlich die Schriftfarbe geändert ?

Normal gar nicht. Das Display oben hat ne andere Farbe in dem Bereich. 
Die kann man aber auch nicht ändern.

von STM8-C-Anfänger (Gast)


Angehängte Dateien:

Lesenswert?

Manni schrieb:
> Wie wird eigentlich die Schriftfarbe geändert ?

Diese Displays sind monochrom, auch wenn das auf meinem ersten Foto 
anders aussieht. Da ist ein Streifen gelb, der Rest blau.


M. K. schrieb:
> Es gibt aber auch
> Situationen, da werden/müssen mehrere Bytes übertragen (Beispiel:
> lcd_gotoxy).

Das geht auch gut so:
1
void oled_gotoxy(uint8_t x, uint8_t y){
2
 
3
  if( x > 21 || y > 7) return;  // out of display
4
    x = x * 6;      // one char: 6 pixel width
5
6
    oled_command(0xb0 + y);     // set page start to y
7
    oled_command(0x21);        // set column start to x
8
    
9
#if defined SSD1306
10
    oled_command(x);
11
12
#elif defined SH1106
13
    oled_command(0x00+((2+x) & (0x0f)));             //lowbyte
14
    oled_command(0x10+( ((2+x) & (0xf0)) >> 4 ) );   //highbyte
15
16
#endif
17
    oled_command( 0x7f);        // set column end to 127
18
}

oder so:
1
void oled_init(uint8_t dispAttr){
2
  for (uint8_t i = 0; i < sizeof (ssd1306_init_sequence); i++) {
3
    oled_command(ssd1306_init_sequence[i]);
4
                delay_us(50);
5
  }    
6
  oled_command(dispAttr);
7
    oled_clrscr();
8
}

Jedenfalls funktioniert es so bei mir.

> Für eine einfache Portierung musst du nicht lcd_command und lcd_data
> anpassen sondern die vier i2c-Funktionen(init, start, stop und byte),
> das erschien mir logischer weil diese Funktionen die
> Prozessorabhängigkeit beinhalten. ;)

Ich finde es nicht gut, I2C so häufig innerhalb der OLED-Bibliothek zu 
verwenden. Was passiert z.B., wenn auf SPI umgestellt werden soll? Es 
gibt diese Displays ja auch mit SPI. Dann muss man die ganze Bibliothek 
umschreiben oder aus den I2C-Funktionen leere bzw. SPI-Funktionen 
machen, die aber im Namen I2C tragen. Wäre sehr verwirrend. Ist auch so 
schon verwirrend, jedenfalls für mich. Weniger Zeilen und sprechende 
Funktionsnamen sind einfach besser zu nachzuvollziehen.

von M. K. (sylaina)


Lesenswert?

STM8-C-Anfänger schrieb:
> Das geht auch gut so:

Ja, das geht natürlich auch. Dafür steigt aber auch der Overhead was 
merklich auf die Refresh-Rate geht ;)

STM8-C-Anfänger schrieb:
> Ich finde es nicht gut, I2C so häufig innerhalb der OLED-Bibliothek zu
> verwenden. Was passiert z.B., wenn auf SPI umgestellt werden soll?

Es war auch nie Ziel der Bibliothek, SPI zu unterstützen. Sie war 
ursprünglich nur für I2C gedacht.

Deine Anmerkungen sind sehr gut, ich werde es beherzigen und sehen wie 
ich die Bibliothek allgemeiner halten kann damit es klarer wird, vielen 
Dank dafür.

von STM8-C-Anfänger (Gast)


Lesenswert?

Vielen Dank für Deine Antwort. Meine Beiträge wirken beim Nachlesen 
etwas undankbar, so ist es aber nicht gemeint. Ich freue mich immer, 
wenn jemand für mich brauchbare Software veröffentlicht. Die Fragen 
kamen dann beim Beschäftigen damit auf. Ich mag eben gern einfache, 
klare Strukturen. (hab früher viel hobbymäßig Turbo-Pascal programmiert)

von Walter J. (oberallgeier)


Lesenswert?

M. K. schrieb:
> Aber klar doch, die Main ist wirklich sehr einfach gestrickt gewesen.

Danke für die Mühe. Einfach sicher - wenn man weiß, wo´s lang geht. Ich 
geh in den nächsten zwei, drei Tagen dran (danach bin ich etwas wech..).

von M. K. (sylaina)


Angehängte Dateien:

Lesenswert?

STM8-C-Anfänger schrieb:
> Vielen Dank für Deine Antwort. Meine Beiträge wirken beim Nachlesen
> etwas undankbar, so ist es aber nicht gemeint. Ich freue mich immer,
> wenn jemand für mich brauchbare Software veröffentlicht. Die Fragen
> kamen dann beim Beschäftigen damit auf. Ich mag eben gern einfache,
> klare Strukturen. (hab früher viel hobbymäßig Turbo-Pascal programmiert)

Es hat ein wenig länger gedauert. Grund hierfür waren zwei Fehler. 1. 
ist mir mein AVRISP krepiert. Das dauerte allerdings einige Zeit dies 
festzustellen da ich zunächst meinen Aufbau in Verdacht hatte.
Der 2. Fehler war, dass mein SH1106-Display ebenfalls das Zeitliche 
gesegnet hat.
Diese zwei Fehler haben mich einige überflüssige Oszilloskop-Einsätze 
gekostet.
However, im Anhang die modifizierte Grafik-Lib. Jetzt wird lcd_command 
und lcd_data auch wesentlich sinnvoller eingesetzt und die 
i2c-Funktionen werden nur noch da, in der lcd_command und der lcd_data, 
verwendet.

Walter J. schrieb:
> Danke für die Mühe. Einfach sicher - wenn man weiß, wo´s lang geht. Ich
> geh in den nächsten zwei, drei Tagen dran (danach bin ich etwas wech..).

Ich hab mal ein paar Kommentare eingepflegt, vielleicht macht das es 
noch einfacher.
1
/* Name: main.c
2
 * Author: Michael Koehler
3
 * Copyright: <insert your copyright message here>
4
 * License: <insert your license reference here>
5
 */
6
7
#include "main.h"
8
#include "lcd_gfx.h"
9
#include <stdlib.h>
10
11
volatile uint16_t overflows;
12
13
int main(void)
14
{
15
    // Init und Setup Atmega328
16
    setUpAvr();
17
    // LCD Contrast einstellen
18
    lcd_set_contrast(0x0f);
19
    // Variable definieren zur Aufnahme/Anzeige der verstrichenen Zeit
20
  char time[6];
21
    // diverse Hilfsvariablen zum Zeichnen eines wachsenden/schrumpfenden Balkens
22
  uint8_t myVar = 0;
23
  uint8_t dir =0;
24
    // PB5 als Ausgang schalten (Beim Arduino Uno haengt hier eine LED dran: PIN 13)
25
  DDRB |= (1 << PB5);
26
    lcd_clrscr();
27
  // zeichnen eines Kreises in den Buffer
28
  //lcd_drawCircle(30, 30, 15, WHITE);
29
    // zeichnen eines gefuellten Kreises in den Buffer
30
  //lcd_fillCircle(70, 40, 10, WHITE);
31
    for(;;){
32
        // LED toggeln
33
    PORTB ^= (1 << PB5);
34
        lcd_drawPixel(20, 20, WHITE);
35
        // zeichnen eines Rechtecks
36
    lcd_drawRect(10, 10, 40, 40, WHITE);
37
        // zeichnen eines immer groeßer bzw. kleiner werdenen
38
        // Balkens (in den Buffer). Ob der Balken wächst oder schrumpft hängt von
39
        // seine aktuellen Position ab. Er wächst von links nach rechts bzw.
40
        // schrumpft von rechts nach links
41
     if( dir == 0) {
42
      lcd_drawLine(0+myVar, 54, 0+myVar, 46, WHITE);
43
      myVar++;
44
       if(myVar == 128) dir = 1;
45
    } else {
46
      if(myVar == 0) dir=0;
47
      myVar--;
48
      lcd_drawLine(myVar, 46, myVar, 54, BLACK);
49
      
50
    }
51
    // zeichnen eines Kreises in den Buffer
52
    lcd_drawCircle(65, 25, 15, WHITE);
53
        // zeichnen eines X mit Linien in den Buffer
54
    lcd_drawLine(90, 10, 120, 40, WHITE);
55
    lcd_drawLine(90, 40, 120, 10, WHITE);
56
    lcd_drawLine(105, 10, 105, 40, WHITE);
57
    lcd_drawLine(90, 25, 120, 25, WHITE);
58
        // schreiben von Text in die erste Zeile in den Buffer
59
    lcd_gotoxy(0,0);
60
    lcd_puts_p(PSTR("M. Köhler 2016/2017"));
61
        // uebertragen des Buffers an das Display
62
    lcd_display();
63
        // timer1 für die Zeitmessung anhalten
64
    TCCR1B = 0;
65
        // timer1 Value wird in eine Zeit umgerechnet und in einen String gewandelt fuer
66
        // die Anzeige
67
    dtostrf((overflows*65536UL+TCNT1)*1.0/16.0e3,
68
        6,
69
        3,
70
        time);
71
        // hilfsvariable zur Zeitmessung wird zurueckgesetzt
72
    overflows = 0;
73
        // timer1 Value wird zurueckgesetzt
74
    TCNT1 = 0;
75
        // timer1 wird wieder gestartet
76
    TCCR1B = 1 << CS10;
77
        // Schreiben von Text in die letzte Zeile (in den Buffer)
78
    lcd_gotoxy(0,7);
79
        // Text wird aus dem Flash geholt und in den Buffer geschrieben,
80
        // hier erstmal den vorhandene Text loeschen
81
        lcd_puts_p(PSTR("                     "));
82
        // Cursor fuer Text wird wieder an den Anfang der letzten Zeile gesetzt
83
    lcd_gotoxy(0,7);
84
        // Text wird aus dem Flash geholt
85
    lcd_puts_p(PSTR("Refresh: "));
86
        // Die umgerechnete Zeit wird in den Buffer geschrieben
87
    lcd_puts(time);
88
        // Text wird aus dem Flash geholt
89
    lcd_puts_p(PSTR("ms"));
90
    }
91
    return 0;   /* never reached */
92
}
93
94
void setUpAvr(void){
95
    /* insert your hardware initialization here */
96
    // Timer1 Overflow Interrupt einschalten
97
  TIMSK1 |= (1 << TOIE1);
98
    // LCD Initialisieren
99
  lcd_init(LCD_DISP_ON);
100
    // globale Interrupts einschalten
101
  sei();
102
}
103
104
ISR(TIMER1_OVF_vect){
105
    // Hilfsvariable um eins erhoehen
106
  overflows++;
107
}

von Joachim B. (jar)


Lesenswert?

cool

ich hoffe ich kann es bald nutzen
meine OLED 0.96" und 1.3" sind angekommen

ich hänge nur noch an einer anderen Baustelle fest.

von STM-8-C-Anfänger (Gast)


Lesenswert?

M. K. schrieb:
> However, im Anhang die modifizierte Grafik-Lib.

Vielen Dank dafür. Leider hab ich erst nächste Woche Zeit und Ruhe, mal 
tiefer reinzugucken. Deine Änderungen machen mir die Portierung sicher 
deutlich leichter.

von M. K. (sylaina)


Angehängte Dateien:

Lesenswert?

Der Fehlerteufel hat sich eingeschlichen und es gibt den ein und anderen 
Klammerfehler im SH1106-Bereich. Ein freundlicher User hat mich drauf 
hingewiesen. Die hier angehängte Version sollte nun aber problemlos auch 
mit SH1106-Displays funktionieren (wegen meines defekten SH1106-Displays 
kann ich derzeit leider nicht testen) ;)

von M. K. (sylaina)


Angehängte Dateien:

Lesenswert?

Auf manche Sachen stößt man auch selbst. Der Library fehlte noch eine 
Funktion zum Schreiben vom Text, der im EEPROM des AVRs liegt. Diese 
Funktion habe ich nun auch ergänzt (void lcd_puts_e(const char* 
eemem_s)).

von Walter J. (oberallgeier)


Lesenswert?

Sorry, dass ich die versprochenen Tests noch nicht habe, nicht mal 
angefangen hatte. Ich komm grad vom Schifahren zurück - einfach zu viel 
Tage mit zu viel Spass beim Cross (ohne KO!) und so.

Kurz:
Die ersten Arbeiten ergaben etliche Fehler (Lib´s fehlten eben) wie z.B.
"..
adafruit_ssd1306.h

../Adafruit_SSD1306.h:25:23: error: WProgram.h: No such file or 
directory
../Adafruit_SSD1306.h:48:17: error: SPI.h: No such file or directory
../Adafruit_SSD1306.h:49:26: error: Adafruit_GFX.h: No such file or 
directory
../Adafruit_SSD1306.h:144: error: expected '=', ',', ';', 'asm' or 
'__attribute__' before 'Adafruit_SSD1306'
.."


Danke sylaina für die ausführlich(er) kommentierte Version vom 
28.03.2017 11:09, da gabs auf die Schnelle auch noch Meckereien vom 
Compiler :-/:

"Build started 3.4.2017 at 12:00:34
avr-gcc  -mmcu=atmega328p -Wall -gdwarf-2 -std=gnu99 -DF_CPU=16000000UL 
-Os -funsigned-char -funsigned-bitfields -fpack-struct -fshort-enums -MD 
-MP -MT arno_OLED1306.o -MF dep/arno_OLED1306.o.d  -c 
../arno_OLED1306.c
../arno_OLED1306.c:7:18: error: main.h: No such file or directory
../arno_OLED1306.c: In function 'main':
../arno_OLED1306.c:16: warning: implicit declaration of function 
'setUpAvr'
../arno_OLED1306.c: At top level:
../arno_OLED1306.c:94: warning: conflicting types for 'setUpAvr'
../arno_OLED1306.c:16: warning: previous implicit declaration of 
'setUpAvr' was here
../arno_OLED1306.c: In function 'setUpAvr':
../arno_OLED1306.c:101: warning: implicit declaration of function 'sei'
../arno_OLED1306.c: At top level:
../arno_OLED1306.c:104: warning: return type defaults to 'int'
../arno_OLED1306.c: In function 'ISR':
../arno_OLED1306.c:104: warning: type of '__vector_13' defaults to 'int'
../arno_OLED1306.c:107: warning: control reaches end of non-void 
function
make: *** [arno_OLED1306.o] Error 1
Build failed with 1 errors and 7 warnings..."

Ich werde mir mal selbst die ganze Geschichte ausführlich zu Gemüte 
führen.

von M. K. (sylaina)


Lesenswert?

Mal nur zu meiner lib:

Hast du den Code 1:1 kopiert? Zu meiner mein.c gibt es eine main.h die 
u.a. die Funktion setUpAvr() bekannt macht. Entweder kopierst du die 
setUpAvr in der main.c vor die main()-Funktion oder erstellst noch 
passend eine Header-Datei, den Code packe ich dir hier ans Ende des Post 
(als main.h abspeichern).
Der Rest der Fehlermeldungen sind alles Folgefehler weil die main.h 
fehlt (u.a. wird in der main.h die avr/interrupt.h includiert ;))
1
//
2
//  main.h
3
//  OLED-Demo
4
//
5
//  Created by Michael Köhler
6
//
7
//
8
9
#ifndef main_h
10
#define main_h
11
#include <avr/io.h>
12
#include <avr/sleep.h>
13
#include <avr/interrupt.h>
14
15
void setUpAvr(void);
16
17
#endif /* main_h */

: Bearbeitet durch User
von Johannes R. (Gast)


Angehängte Dateien:

Lesenswert?

Habe die Bibliothek eben mit einem kleineren OLED-Display (0,69 Zoll, 
96x16 Pixel) getestet, leider mit mäßigem Erfolg.

Bild OLED_1.jpg zeigt das Ergebnis, wenn ich die oben gepostete main.c 
ohne Anpassungen verwende. Dass das nicht alles auf den kleinen 
Bildschirm passt ist verständlich, aber es wirkt noch dazu verzerrt.

Bild OLED_2.jpg zeigt den Versuch, nur eine Zeile Text anzuzeigen:
1
  lcd_gotoxy(0,6);
2
  lcd_puts_p(PSTR("mikrocontroller.net"));
3
  lcd_display();

Die DISPLAY_WIDTH und DISPLAY_HEIGHT aus der lcd_gfx.h hab ich dazu 
nicht verändert, aber wenn ich sie auf 96 und 16 setze funktioniert 
überhaupt nichts mehr.
Ich vermute, dass ich auch den Startup-Code in der init_sequence[] 
anpassen müsste. Leider bin ich diesbezüglich aus dem Datenblatt für den 
SSD1306 nicht recht schlau geworden. Hat jemand eine Idee, welche 
Parameter dabei eine Rolle spielen?

von M. K. (sylaina)


Lesenswert?

Versuche mal die Init-Sequence nach diesem Datenblatt (vgl. Seite 10 
ff.) anzupassen 
http://www.buydisplay.com/download/manual/ER-OLED0.69-1_Series_Datasheet.pdf

Ich hab das Display leider nicht, daher kann ich leider nicht testen, 
denke aber auch, dass hier die Init-Sequence angepasst werden muss.

von Johannes R. (Gast)


Angehängte Dateien:

Lesenswert?

Danke für die schnelle Antwort! Das Dokument kannte ich noch nicht. Hab 
jetzt ein bisschen mit der Initialisierungssequenz auf Seite 12 gespielt 
und herausgefunden, dass nur zwei Änderungen gegenüber deinem Code nötig 
sind.

Die "multiplex ratio" muss auf Anzahl der Zeilen minus eins 
(DISPLAY_HEIGHT-1) gesetzt werden, also 0x0F für 16 Zeilen statt 0x3F 
für 64 Zeilen.
1
  0xA8, 0x0F,             // Set multiplex ratio
Das ist allgemeingültig und könntest du als "0xA8, DISPLAY_HEIGHT-1," 
auch in die Bibliothek übernehmen.

Die zweite Änderung hängt mit der internen Verschaltung von SSD1306 und 
Display zusammen. Ich benötige die "Sequential COM pin configuration" an 
Stelle der bei dir verwendeten "Alternative COM pin configuration".
1
  0xDA, 0x02,             // Set com pins hardware configuration

So ganz hundertprozentig funktioniert es leider immer noch nicht. 
Angehängtes Bild OLED_3.jpg zeigt das Ergebnis für folgenden Code:
1
  lcd_gotoxy(0,0);
2
  lcd_puts_p(PSTR("1234567890123456"));
3
  lcd_gotoxy(0,1);
4
  lcd_puts_p(PSTR("abcdefghijklmnop"));
5
  lcd_gotoxy(0,2);
6
  lcd_puts_p(PSTR("ABCDEFGHIJKLMNOP"));
7
  lcd_display();
Irgendwie ist die zweite Zeile also um 8 Pixel nach links verschoben, 
und die (eigentlich unsichtbare) dritte Zeile fängt schon in der zweiten 
Zeile an. Ich fürchte da muss ich noch ein bisschen länger mit den 
Parametern spielen.

von M. K. (sylaina)


Lesenswert?

Das mit dem Display Ratio hab ich direkt mal umgesetzt ;)

Die Verschiebung um 8 Pixel erscheint mir interessant zu sein. Da bin 
ich mal gespannt was das sein wird, weiß aber noch nicht wann ich dazu 
komme mir das genauer anzuschaun.

Die Sache mit der dritten Zeile liegt einfach darin begründet, dass das 
lcd_gotoxy schaut ob die Parameter auch zulässig sind, also x und y 
innerhalb des Displays liegen. Ist dem nicht so wird die Funktion direkt 
wieder verlassen und der Cursor nicht weiter bewegt,  in deinem Fall 
bleibt er dann am Ende des Textes der zweiten Zeile stehen und da wird 
dann der Text hingeschrieben, der eigentlich für die dritte Zeile 
bestimmt war.

von Johannes R. (Gast)


Angehängte Dateien:

Lesenswert?

Den Grund für die Verschiebung der zweiten Zeile habe ich gefunden. Der 
SSD1306 adressiert intern immer 128x64 Pixel und merkt nicht, wenn ein 
kleineres Display angeschlossen ist. Wenn man ihm einen schmäleren 
Puffer übergibt landet der Anfang der zweiten Zeile am (unsichtbaren) 
Ende der ersten Zeile, was in meinem Fall zu einer Verschiebung um 32 
Pixel führt.
Beim Schreiben von displayBuffer[] muss man also die fehlenden Spalten 
mit Dummy-Bytes auffüllen.
1
void lcd_writeBuffer() {
2
  lcd_send_i2c_start();
3
  lcd_send_i2c_byte(0x40);
4
  for (uint8_t i=0; i<(DISPLAY_HEIGHT/8); i++) {
5
    for (uint8_t j=0; j<DISPLAY_WIDTH; j++) {
6
      lcd_send_i2c_byte(displayBuffer[i*DISPLAY_WIDTH + j]);
7
    }
8
    for (uint8_t h=DISPLAY_WIDTH; h<128; h++) {
9
      lcd_send_i2c_byte(0x00);
10
    }
11
  }
12
  lcd_send_i2c_stop();
13
}

OLED_4.jpg zeigt das Ergebnis für den folgenden Code:
1
  lcd_gotoxy(0,0);
2
  lcd_puts_p(PSTR("1234567890123456"));
3
  lcd_gotoxy(0,1);
4
  lcd_puts_p(PSTR("abcdefghijklmnop"));
5
  lcd_display();

Mit den Grafikfunktionen hatte ich auch noch Probleme und musste die 
Funktion lcd_drawPixel() anpassen. Was war der Grund, hier 
DISPLAY_HEIGHT zu referenzieren? Statt durch DISPLAY_HEIGHT/8 wird 
einfach durch 8 geteilt, weil jede Page über acht Zeilen reicht. Die 
Höhe des Displays spielt keine Rolle.
1
  displayBuffer[(uint8_t)(y / 8) * DISPLAY_WIDTH + x] |= (1 << (y % 8));

Jetzt funktioniert alles. Danke für den Code!

von Nico W. (nico_w)


Lesenswert?

Das Problem hatte ich auch mal. Das kann man aber mit der 
Initialisierungssequenz korrekt einstellen. Bin mir nicht ganz sicher 
mehr wo das war. Irgendwas mit addressing mode.

von Joachim B. (jar)


Lesenswert?

M. K. schrieb:
> Auf manche Sachen stößt man auch selbst.

leider nicht auf viele

ich versuche gerade den Code in meinen Arduino zu integrieren
1
void lcd_init(uint8_t dispAttr)
2
{ if(LCD_INIT_I2C == YES) i2c_init();
3
  uint8_t commandSequence[sizeof(init_sequence)+1];
4
  for(uint8_t my_lcd_init_i = 0; my_lcd_init_i < sizeof (init_sequence); my_lcd_init_i++)

du hattest als Laufvariable i gewählt, OK mache ich auch öfter, aber bei 
der Integration was tun wenn i schon anderweitig belegt ist?

Deswegen mache ich immer eindeutige Namen wie my_lcd_init_i

hilft aber hier nicht, wo klemmst denn?

ich mag ja fremde Codes intergrieren, aber derlei Stolpersteine 
vermiesen es, eigentlich wollte ich meine Probleme minimieren und keine 
neuen Nebenschauplätze eröffnen.

lcd_gfx.c: In function 'lcd_init':
lcd_gfx.c:240: error: 'for' loop initial declaration used outside C99 
mode

: Bearbeitet durch Moderator
von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Joachim B. schrieb:
> was tun wenn i schon anderweitig belegt ist?

Interessiert kein Schwein, solange es kein Makro ist (die benennt man
daher ja auch üblicherweise in GROSSBUCHSTABEN), denn die Variable
ist ausschließlich lokal zur Schleife und kollidiert dabei mit rein
gar nichts.

> lcd_gfx.c:240: error: 'for' loop initial declaration used outside C99
> mode

Dann schalt' halt den C99-Modus endlich ein, wenn du's bislang noch
nicht getan hast.  -std=c99 oder -std=gnu99.  Ist eigentlich
unverständlich, warum der Default beim GCC nach wie vor -std=gnu89
ist.

von Joachim B. (jar)


Lesenswert?

Jörg W. schrieb:
> Dann schalt' halt den C99-Modus endlich ein, wenn du's bislang noch
> nicht getan hast.

bin halt kein Informatiker und stolpere das erste Mal drüber,

Jörg W. schrieb:
> Ist eigentlich
> unverständlich, warum der Default beim GCC nach wie vor -std=gnu89
> ist.

da hast du Recht, an wen wendet sich denn der gcc an Hobbyprogger wie 
mich.

Allerding zur LIB

warum in einer Funktion in jeder for Schleife zig mal for ( uint8_i = 
0...

steht ist mir auch ein Rätsel


wenn ich in einer Funktion i öfter benötige, dann wird es in der 
Funktion einmal am Anfang initialisiert.

uint8_t i=0;

das muss nicht in jeder for Schleife, wer tippt denn so gerne uint8_t ?

: Bearbeitet durch User
von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Joachim B. schrieb:

> da hast du Recht, an wen wendet sich denn der gcc an Hobbyprogger wie
> mich.

Keineswegs, der ist genausogut profesionell im Einsatz.

C99 ist ja nun mittlerweile durchaus schon recht betagt (C11 gibt's
bereits als Nachfolger seit einiger Zeit).  Ein großer Teil der
C99-Erweiterungen war im GCC bereits vor dem 1999er Standard aktiv
und ist daher in der Voreinstellung -std=gnu89 schon enthalten, die
Schleifenvariablen der for-Anweisung sind da die wohl prominenteste
Ausnahme.


> warum in einer Funktion in jeder for Schleife zig mal for ( uint8_i =
> 0...
>
> steht ist mir auch ein Rätsel

Weil damit der Gültigkeitsbereich der Variablen (“scope”) explizit
nur auf die Anweisung innerhalb der for-Schleife limitiert wird.
Limitierung des Geltungsbereichs einer Variablen auf das notwendige
Minimum ist durchaus guter Stil.

von Joachim B. (jar)


Lesenswert?

Jörg W. schrieb:
> Weil damit der Gültigkeitsbereich der Variablen (“scope”) explizit
> nur auf die Anweisung innerhalb der for-Schleife limitiert wird.
> Limitierung des Geltungsbereichs einer Variablen auf das notwendige
> Minimum ist durchaus guter Stil.

OK aber das ist mir noch unklar, werden lokale Variablen nicht immer auf 
dem Stack initialisiert?

In jeder for Schleife neu?
Bringt das nicht unnötigen overhead?

Warum sollte man das innerhalb einer Funktion machen? mal abgesehen vom 
Stil.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Joachim B. schrieb:

> OK aber das ist mir noch unklar, werden lokale Variablen nicht immer auf
> dem Stack initialisiert?

Es geht hier nicht um den Speicherort der Variablen (der wird am
Ende sehr wahrscheinlich ein Register sein), sondern um den
Gültigkeitsbereich.
1
  for (int i = 0; i < 10; i++)
2
     tuwas(i);

Nach der Zeile „tuwas(i);“ gibt es die Variable „i“ bereits nicht
mehr.  Das ist danach sowohl dem Menschen als auch dem Compiler klar.

Das nächste „i“ in der nächsten Schleife ist dann bereits eine neue
Variable, die mehr oder minder zufällig genauso heißt.

Der Compiler würde sie natürlich auch in diesem Falle:
1
  int i;
2
  for (i = 0; i < 10; i++)
3
    tuwas(i);

hernach wegwerfen, wenn mit dem „i“ nichts mehr gemacht wird, aber
es könnte dann später nochmal jemand daherkommen, und er müsste für
Code, der gar nichts damit zu tun hat, u. U. noch Verrenkungen
machen, um den Wert von „i“ zu erhalten (sofern er nicht folgern
kann, dass dieser später sowieso auf jeden Fall überschrieben wird).

Da der Gültigkeitsbereich so gut überschaubar ist, muss man eben auch
nicht das_ist_i_in_der_funktion_xyz schreiben, sondern kann sich eine
kurze und knappe Benennung leisten, denn der Betrachter des Codes
kann sofort erkennen, auf wie wenigen Zeilen die Variable tatsächlich
benutzt werden kann.

von Joachim B. (jar)


Lesenswert?

OK ich gebe auf,

kann den Schalter C99 nicht finden, bekomme bei jeder Fehlermeldung die 
ich beseitige neue.

Habe gegoogelt wo man beim Arduino den C99 Schalter setzt, nix gefunden 
aber zurück zum A-Studio 4.18 möchte ich an dieser Stelle nicht.

Das wars dann hier für mich, ich kann das Display ja ansprechen nur eben 
mit einer dickeren LIB statt schlank!

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Joachim B. schrieb:
> Habe gegoogelt wo man beim Arduino den C99 Schalter setzt

https://github.com/01org/corelibs-arduino101/issues/220

Du müsstest also wohl irgendwo eine Datei platform.txt finden, in der
du diese Option ergänzen kannst.

Du kannst auch probieren, ob Michaels Code sich als C++ übersetzen
lässt, indem du die Datei nicht „lcd.c“, sondern „lcd.cc“ oder auch
Arduino-mäßig „lcd.ino“ nennst.  C++ kennt diese Variante der
Laufvariablen in for-Anweisungen schon lange.

von Joachim B. (jar)


Lesenswert?

Jörg W. schrieb:
> oder auch
> Arduino-mäßig „lcd.ino“ nennst.

OK ich versuche es nochmal, danke dir für deine Unterstützung!

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Jörg W. schrieb:
> Du kannst auch probieren, ob Michaels Code sich als C++ übersetzen lässt

Bei mir lässt er sich klaglos auf diese Weise compilieren.

von Joachim B. (jar)


Lesenswert?

hmmm, kompiliert fehlerfrei mit *.ino
1
  lcd_init(LCD_INIT_I2C);
2
  lcd_clrscr();
3
  lcd_gotoxy(0, 0);
4
  lcd_puts("huhu");

aber Display beibt duster,

welche Adresse nutzt er denn? habe ich noch nicht gefunden

meine erfolgreichen Versuche mit anderer LIB waren so
1
      switch(address<<1)
2
      { case 0x78:
3
          DEBUG_PRINTLN(F(" I2C OLED"));
4
          i2c_test_flags|=(1<<I2C_OLED);          
5
          break;
6
        case 0xA0:
7
          DEBUG_PRINTLN(F(" I2C EEPROM"));
8
          i2c_test_flags|=(1<<I2C_EEPROM);          
9
          break;
10
        case 0xD0:
11
          Wire.beginTransmission(DS1307_ID);
12
          printIIC(0x3F);
13
          (Wire.endTransmission()) ? i2c_test_flags|=(1<<I2C_RTC_3231) : i2c_test_flags|=(1<<I2C_RTC_1307);
14
          (i2c_test_flags&(1<<I2C_RTC_3231)) ? DEBUG_PRINTLN(F(" DS3231 RTC")) : DEBUG_PRINTLN(F(" DS1307 RTC"));
15
          break;
16
        default:
17
          DEBUG_PRINTLN(F(""));
18
          break;

: Bearbeitet durch Moderator
von Joachim B. (jar)


Lesenswert?

das muss noch was mit den I2C Routinen zu tun haben
1
#if defined(ARDUINO) 
2
  #if ARDUINO >= 100
3
//check busy
4
    Wire.beginTransmission(DS1307_ID);
5
    printIIC(STATUS_REGISTER);
6
    Wire.endTransmission();
7
    Wire.requestFrom( ( DS1307_ID ), 1);       // request Status Register 1 Byte
8
    if ((readIIC() & 0x00ff) & (1<<BSY))       // auf busy pruefen mit 0x00ff unddieren weil Arduino 16 Bit liest aber nur 8 Bit kommen.
9
      i2c_test_flags|=(1<<I2C_RTC_TEMP_BSY);           // Flag busy setzen
10
    else
11
      i2c_test_flags&=~(1<<I2C_RTC_TEMP_BSY);          // Flag busy loeschen
12
    Wire.endTransmission();
13
    if( !(i2c_test_flags&(1<<I2C_RTC_TEMP_BSY)) )
14
    { // read Temp
15
      Wire.beginTransmission(DS1307_ID);       // DS anwaehlen
16
      printIIC(MSB_TEMP);                      // MSB Byte anwaehlen
17
      Wire.endTransmission();        
18
      Wire.requestFrom( ( DS1307_ID ), 2);     // request temp Hi und Temp low 2 Byte
19
      __temp = (readIIC() & 0x00ff);           // mit 0x00ff unddieren weil Arduino 16 Bit liest aber nur 8 Bit kommen.
20
      __temp <<= 8;      
21
      __temp |= (readIIC() & 0x00ff);          // mit 0x00ff unddieren weil Arduino 16 Bit liest aber nur 8 Bit kommen.    
22
      Wire.endTransmission();
23
  #else 
24
    #include "Arduino_<_100_undefiniert.h"     //#warning gibt es ja in der Arduino Ide nicht
25
  #endif // #if ARDUINO < 100
26
#else // #if not(ARDUINO) 
27
      // nutze die AVR Lib I2C von Fleury      http://homepage.hispeed.ch/peterfleury/i2cmaster.zip
28
      i2c_start_wait(DS3231+I2C_WRITE);        // set device address and write mode
29
      i2c_write(MSB_TEMP);
30
      i2c_rep_start(DS3231+I2C_READ);          // set device address and read mode
31
      __temp=i2c_readAck();
32
      __temp<<=8;
33
      __temp|=i2c_readNak();
34
      i2c_stop();
35
#endif // # AVR != ARDUINO

: Bearbeitet durch Moderator
von Joachim B. (jar)


Lesenswert?

Mist, auf dem Steckbrett versteckt, die alten Augen

So nun bin ich weiter, seine OLED Adresse ist identisch mit meiner!

hängt noch am I2C

mit lcd_init gibt es Schrott auf Serial.print in einer Endlosschleife, 
dabei sollte da noch nichts passieren:
1
void setup() {
2
  Serial.begin(19200);
3
  Serial.println();
4
  Serial.println();
5
  Serial.println();
6
  Serial.println();
7
  Serial.print(F("File:       "));  Serial.println(_name()); 
8
  compile_time();
9
  Serial.print(F("kompiliert: "));  Serial.println(c_str); 
10
  Serial.println();
11
  lcd_init(LCD_INIT_I2C);
12
/*
13
  lcd_clrscr();
14
  lcd_gotoxy(0, 0);
15
  lcd_puts("huhu");
16
*/
17
}

sorry Mod!für code Tags -> hier gleich verbessert

: Bearbeitet durch User
von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Joachim B. schrieb:
> mit lcd_init gibt es Schrott auf Serial.print in einer Endlosschleife,
> dabei sollte da noch nichts passieren

Läuft da irgendwo der RAM über (ggf. auch Stack)?

von Joachim B. (jar)


Lesenswert?

noch ziemlich unwahrscheinlich, ist echt schmal:

doch das war es!!!!

mit OLED

Binäre Sketchgröße: 8.964 Bytes (von einem Maximum von 30.720 Bytes)
advanced_OK.cpp.elf"
   text    data     bss     dec     hex
   8724     240    1760   10724    29e4

hey warum verbraucht die schmale LIB soviel SRAM?

ohne OLED

mein pures Proggi
Binäre Sketchgröße: 6.294 Bytes (von einem Maximum von 30.720 Bytes)
dvanced_OK.cpp.elf"
   text    data     bss     dec     hex
   6070     224     543    6837    1ab5

von Joachim B. (jar)


Angehängte Dateien:

Lesenswert?

da komme ich ja im SRAM mit RTC, OLED und NOKIA schmaler hin

Binäre Sketchgröße: 30.134 Bytes (von einem Maximum von 30.720 Bytes)
C_OLE_EEP_OK.cpp.elf"
   text    data     bss     dec     hex
  29560     574    1031   31165    79bd

: Bearbeitet durch User
von Joachim B. (jar)


Lesenswert?

also 1k statischer Displaybuffer ist mir zu viel

#define DISPLAYSIZE    DISPLAY_WIDTH*DISPLAY_HEIGHT/8
// 128*64/8

nun verstehe ich nix mehr:

M. K. schrieb:
> Meine Lib arbeitet ohne Puffer, daher wird hierfür auch kein statischer
> RAM für einen Puffer benötigt. Ich hab es nicht getestet, aber auch 128
> Byte RAM müssten locker ausreichend sein.

: Bearbeitet durch User
von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Diese Aussage bezieht sich auf die eingangs gepostete Bibliothek zum
Schreiben von Text auf so ein Display.

Die von dir genannte Variable dagegen gehört in die Grafiklib, die
Michael später gepostet hat.  Bei einer solchen ist der Puffer
praktisch unumgänglich, hatten wir weiter oben schon diskutiert.

„Jetzt benötigt die Lib leider schon etwas mehr als 4kByte Flash sowie 
1029 Byte SRAM.“ schrieb er dann auch selbst.

: Bearbeitet durch Moderator
von Joachim B. (jar)


Lesenswert?

Jörg W. schrieb:
> Ich finde ich Michaels Code keine einzige globale oder statische
> RAM-Variable.

im letzten zip
Beitrag "Re: SSD1306 Library zum Darstellen von Text auf OLED Displays"

in lcd_gfx.h
#define DISPLAYSIZE    DISPLAY_WIDTH*DISPLAY_HEIGHT/8

genutzt von in
lcd_gfx.ino // lcd_gfx.c

static uint8_t displayBuffer[DISPLAYSIZE];

wie soll ich das sonst nennen?

ist das nicht statisch und na ja local/global?

ich bin ja kein Progger aber diese Zeile dachte ich verstanden zu haben

static uint8_t displayBuffer[DISPLAYSIZE];

ergibt 1k SRAM Verbrauch bei 128 x 64 Pixel / 8

: Bearbeitet durch User
von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Sorry, hatte erst danach bemerkt, dass es ja zwei Libs sind und
daher meinen Beitrag nochmal geändert.

Mit chronischer RAM-Knappheit hast du auf diesen Displays keine Chance,
auch noch Grafik zu machen.  Das liegt einfach daran, dass sich die
Pixel ja nicht wieder auslesen lassen.  Da acht Pixel in einem Byte
liegen (Monochrom), muss man daher eine Schattenkopie des Displayinhalts
im RAM halten, wenn man Grafik machen will.

Seine Text-Lib war genau darauf ausgelegt, diese Schattenkopie nicht
zu brauchen, aber dann kann man eben nur Text darstellen.

von M. K. (sylaina)


Lesenswert?

Jörg W. schrieb:
> Seine Text-Lib war genau darauf ausgelegt, diese Schattenkopie nicht
> zu brauchen, aber dann kann man eben nur Text darstellen.

Genau, das Hauptaugenmerk lag bei mir auf der Variante, die nur Text 
darstellt. Diese Lib verbraucht keinen RAM. Die Grafik-Lib kommt um den 
RAM nicht rum wenn man nicht überzeichnen will.

Willst du, Joachim, also nur Text darstellen dann benutze die 
lcd.c/lcd.h Lib, die ich weiter oben gepostet habe. Diese Lib alleine 
braucht keine 2k Flash-Speicher.

Und bzgl. der Arduino-Umgebung: Da hab ich leider absolut keine Ahnung 
wie gut sich meine Lib in diese Umgebung integrieren lässt. Das sind so 
Dinge, die auf meine immer länger werdende ToDo-Liste kommt.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

M. K. schrieb:
> Die Grafik-Lib kommt um den RAM nicht rum wenn man nicht überzeichnen
> will.

Das führt zu dem Paradoxon: wenn man einen kleinen Controller mit wenig
SRAM hat, kommt man am Ende besser, statt eines monochromen
OLED-Displays ein RGB-Display zu nehmen.  Dort beschreibt man mit einem
Byte immer ein Pixel auf einmal, braucht daher keinen Puffer und kann
trotzdem Grafik machen.

von Joachim B. (jar)


Lesenswert?

M. K. schrieb:
> Willst du, Joachim, also nur Text darstellen dann benutze die
> lcd.c/lcd.h Lib, die ich weiter oben gepostet habe. Diese Lib alleine
> braucht keine 2k Flash-Speicher.

wo weiter oben, du hattest viel gepostet, hast du bitte einen Link?

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Gleich im ersten Beitrag.

von Joachim B. (jar)


Lesenswert?

Jörg W. schrieb:
> Gleich im ersten Beitrag.

danach kamen aber noch updates wegen verschiedener Controller 13xx zu 
11xx wegen der Pixelgrenze und Bugs wurden später auch noch berichtigt, 
warum also zur ersten ZIP ?

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Joachim B. schrieb:
> danach kamen aber noch updates

Stimmt, ein Update sehe ich noch:

Beitrag "Re: SSD1306 Library zum Darstellen von Text auf OLED Displays"

@Michael: soll ich mal deinen ersten Threadbeitrag editieren und die
Links auf die jeweils aktuelle Version einfügen?

von Johannes R. (Gast)


Lesenswert?

Nico W. schrieb:
> Das Problem hatte ich auch mal. Das kann man aber mit der
> Initialisierungssequenz korrekt einstellen. Bin mir nicht ganz sicher
> mehr wo das war. Irgendwas mit addressing mode.

Ja, dachte ich auch. Die Lib nutzt den "horizontal addressing mode", 
also hatte ich in der Init-Sequenz den Befehl 0x21 ausprobiert um Start- 
sowie Endadresse der zu nutzenden Spalten im RAM zu setzen:
1
  0x21, 0x00, DISPLAY_WIDTH-1,

Leider zunächst erfolglos. Auf deinen Beitrag hin habe ich mir das eben 
aber nochmal angeschaut und festgestellt, dass die Funktion lcd_gotoxy() 
den gleichen Befehl nutzt und die Einstellung aus der Init-Sequenz 
überschrieben hat. Wenn man die betreffende Zeile abändert funktioniert 
es. Damit ist dann auch meine Funktion lcd_writeBuffer() von oben 
überflüssig.
1
  uint8_t commandSequence[] = {0xb0+y, 0x21, x, DISPLAY_WIDTH-1 };

von DraconiX (Gast)


Lesenswert?

Cool danke, schön gemacht. Nur bei der GotoXY hat es bei meinem Display 
nicht funktioniert, ich stelle heute Abend mal meine Source für die 
Funktion ein.

Das man um den 1K RAM nicht drumrum kommt liegt an der 
Speicheraddressierung des SSD1306.

Hätte er einen Framebuffer wäre das alles halb so wild :-D

von DraconiX (Gast)


Angehängte Dateien:

Lesenswert?

Hier mal auf einem STM32F1... Grafikbibliothek und 1Bit Bild.

von M. K. (sylaina)


Angehängte Dateien:

Lesenswert?

DraconiX schrieb:
> Das man um den 1K RAM nicht drumrum kommt liegt an der
> Speicheraddressierung des SSD1306.

Nö, das liegt an der Schnittstelle. Bei i2c und spi kann man nur 
schreibend auf das Display zugreifen. Geht man ans parallele Interface 
des SSD1306 ran kann man das Display auch auslesen, dann braucht man den 
RAM nicht.

Jörg W. schrieb:
> @Michael: soll ich mal deinen ersten Threadbeitrag editieren und die
> Links auf die jeweils aktuelle Version einfügen?

Gute Idee, versuche ich gleich umzusetzen. Ich hab auch überlegt bei 
github ein Repository  jeweils für die Text-Variante und für die 
Grafik-Variante zu erstellen.

Joachim B. schrieb:
> wo weiter oben, du hattest viel gepostet, hast du bitte einen Link?

Ich hab beide Varianten in der aktuellen Version diesem Beitrag 
angehangen, aus dem ersten Beitrag werde ich gleich noch hierauf 
verlinken lassen.

EDIT: Jörg, ich darf den ersten Post nicht mehr editieren. Das ist wohl 
eine Option, die nur Moderatoren/Administratoren zur Verfügung steht, 
nicht aber "normalen" Usern. Wärst du vielleicht so nett?

: Bearbeitet durch User
von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

M. K. schrieb:
> Wärst du vielleicht so nett?

Ja, natürlich, darum hatte ich dir das ja angeboten.

von DraconiX (Gast)


Lesenswert?

M. K. schrieb:
> Geht man ans parallele Interface des SSD1306 ran kann man das Display
> auch auslesen, dann braucht man den RAM nicht.

Ah okay, das wusste ich nicht! :-D Danke für die Info, über die 
parallele Kommunikation hab ich mir beim SSD1306 noch keine Gedanken 
gemacht / im DB gestöbert weil es kaum Displays gibt die dies so 
ausgeführt haben.

Theoretisch, gerade auf großen MCs, könnte man sich auch Gedanken machen 
darüber immer nur eine Page vorzuhalten - dies wiederum braucht aber 
mehr Flash und Rechenzeit, da ja alle 8 Pages nacheinander neu berechnet 
und geschrieben werden müssen. Irgendwie...

von Joachim B. (jar)


Lesenswert?

Jörg W. schrieb:
> M. K. schrieb:
>> Wärst du vielleicht so nett?
>
> Ja, natürlich, darum hatte ich dir das ja angeboten.

irgendwas ist da schiefgelaufen,

die SH1106 Wahl ist wieder nicht drin, ich bekomme verschobene Pixel und 
bei   lcd_clrscr(); habe ich Rauschen auf dem Screen!
1
// init OLED
2
  lcd_init(LCD_INIT_I2C);
3
  lcd_clrscr();
4
  lcd_puts("huhu");
5
  lcd_gotoxy(8, 8);
6
//  lcd_gotoxy(16, 16);
7
  lcd_puts("hallo");

sollte ja nicht so schwer werden :)

: Bearbeitet durch User
von Joachim B. (jar)


Lesenswert?

ach ich liebe debugging

lcd.ino: In function 'void lcd_clrscr()':
lcd:324: error: invalid conversion from 'int' to 'uint8_t*'
lcd:324: error: initializing argument 1 of 'void lcd_data(uint8_t*, 
uint16_t)'

von Joachim B. (jar)


Lesenswert?

hier klemmts irgendwo
1
#elif defined SH1106
2
    for (uint8_t j = 0; j <= DISPLAY_HEIGHT/8; j++){
3
        for (uint8_t i = 0; i < DISPLAY_WIDTH ; i++) {
4
//          vvvvvvvvvvvvvv  
5
6
            lcd_data(0x0f, 1);
7
//                   ^^^^
8
9
        }
10
        lcd_gotoxy(0,j);
11
    }
12
  
13
#endif

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Tja, manches, was bei C einfach noch so durchgeht, ist bei C++ nicht
mehr zulässig, da ist das Typkonzept pingeliger.

Aber: irgendwas passt da nicht.  Wenn lcd_data() als erstes einen
Zeiger haben will, dann hat das einen Grund, ihm einfach 0x0F zu
übergeben, kollidiert zu Recht.

Probier's mal damit:
1
void lcd_clrscr(void){
2
    lcd_home();
3
    uint8_t data = 0x0f;
4
#if defined SSD1306
5
    for (uint16_t i = 0; i < DISPLAYSIZE; i++) {
6
        lcd_data(&data, 1);
7
    }
8
#elif defined SH1106
9
    for (uint8_t j = 0; j <= DISPLAY_HEIGHT/8; j++){
10
        for (uint8_t i = 0; i < DISPLAY_WIDTH ; i++) {
11
            lcd_data(&data, 1);
12
        }
13
        lcd_gotoxy(0,j);
14
    }
15
        
16
#endif
17
        lcd_home();
18
}

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Mal was ganz anderes, Michael: GPL für Code, den man im
Embedded-Bereich benutzen können soll, finde ich persönlich nicht
sehr sinnvoll.  Das dürfte für so ziemlich jeden, der das kommerziell
verwenden möchte, schnell zum KO-Kriterium werden.  Selbst LGPL ist
bei so kleinen Prozessoren wie einem AVR nicht sinnvoll, denn dann
brauchst du auch keine security fuse mehr, wenn du den Leuten sowieso
disassemblierfähige Objektdateien mitliefern musst.

Musst du natürlich am Ende selbst wissen, aber falls die Entscheidung
eher nicht vorsätzlich so gefallen ist: es gibt einen Grund, warum
bspw. die avr-libc eine BSD-Lizenz hat, obwohl sie sich ansonsten in
eine GNU-dominierte Toolchain integriert.

von Joachim B. (jar)


Lesenswert?

Jörg W. schrieb:
> ihm einfach 0x0F zu
> übergeben, kollidiert zu Recht.

verstehe ich ja, ich bin nur nicht der richtige Ansprechpartner,

der TO nannte es LIB und die möchte ich nutzen ;)

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Joachim B. schrieb:
> verstehe ich ja, ich bin nur nicht der richtige Ansprechpartner,

Du bist aber derjenige, der es jetzt gerade nutzen will, insofern kannst
du den von mir vorgeschlagenen Ersatz ja zumindest mal testen.  Ich
denke, dass Michael da in der Hektik einen Bug eingesammelt hat, den
sollte er korrigieren – wenn du den Bugfix aber als „funktioniert“
bestätigst, ist das ganz sicher hilfreich für ihn.

von Joachim B. (jar)


Lesenswert?

Jörg W. schrieb:
> kollidiert zu Recht.
>
> Probier's mal damit:

hmmm, Fehler im lcd_clrscr ist weg,

Text auch nicht mehr sichtbar mit der 1306 Version ging wenigstens Text 
wenn auch buggy

nun muss es noch was mit der Initialisierung sein, Timing oder Bit oder 
?

von Joachim B. (jar)


Lesenswert?

Jörg W. schrieb:
> Du bist aber derjenige, der es jetzt gerade nutzen will, insofern kannst
> du den von mir vorgeschlagenen Ersatz ja zumindest mal testen.

äh ja ich bin doch dabei!

nochmal, vorher hatte ich mit der ersten LIB "hallo" und "huhu" zu 
Display 1106 gebracht noch mit 1306 Code!

hallo und huhu landete aber auf falsche Zeilen weil ich ein 1106 habe,
das Display war auch nicht clean nach clr(); sondern verrauscht mit 
Pixelmüll um den Text.

Dann die andere LIB eingespielt mit Compilerfehler

deine Korrektur eingebracht, Kompilerfehler weg aber auch nur ein leeres 
unverrauschtes Display, kein Text mehr sichtbar.

nun hänge ich.....

BTW

wäre hier ein #define nicht besser?

statt:
1
void lcd_home(void)
2
{ lcd_gotoxy(0, 0);
3
}

besser?:
1
#define LCD_HOME() lcd_gotoxy(0, 0);

ich hänge immer noch.....

: Bearbeitet durch User
von M. K. (sylaina)


Lesenswert?

Jörg W. schrieb:
> Aber: irgendwas passt da nicht.  Wenn lcd_data() als erstes einen
> Zeiger haben will, dann hat das einen Grund, ihm einfach 0x0F zu
> übergeben, kollidiert zu Recht.

In der Tat, wie ist mir denn das passiert? Vor die 0x0f hätte noch ein 
(uint8_t*) gehört (wenn ich das recht im Kopf hab)...bei mir hat das der 
Compiler zunächst nicht mal angemeckert, daher ist mir das wohl durch 
die Lappen gegangen...

Joachim B. schrieb:
> deine Korrektur eingebracht, Kompilerfehler weg aber auch nur ein leeres
> unverrauschtes Display, kein Text mehr sichtbar.

Gibt der Compiler noch ein Warning oder ähnliches bei dir aus? Ich habe 
beim SH1106 auch ein 128*64 Pixel großes Display, benutzt du auch so 
eines? Wenn nicht liegt es vielleicht auch an der Displaygröße und da 
muss noch was eingestellt werden, dass ich bisher übersehen habe.
Es tut mir echt leid, dass es bei dir solche Probleme macht, ich hoffen 
wir können das Problem schnell lösen.
Joachim B. schrieb:
> wäre hier ein #define nicht besser?

Hm, so tief bin ich bei weitem nicht drin. Ich habe hier eine Funktion 
gewählt da ich mit dem OLED-Display auch ein paar meiner alten 
LCD-Displays ersetzt habe (mit HD48780-Controller) und hierbei die Lib 
von Peter Fleury verwendet habe. Damit ich meinen alten Code nicht 
umschreiben muss sondern wirklich nur die lcd-Lib austauschen muss habe 
ich mich bzgl. der Funktionsnamen ein wenig an Peters Lib orientiert ;)

Jörg W. schrieb:
> Mal was ganz anderes, Michael: GPL für Code, den man im
> Embedded-Bereich benutzen können soll, finde ich persönlich nicht
> sehr sinnvoll.
> ...

Ich hab da wenig Ahnung von und hab daher mal in meinem Dunstkreis 
rumgefragt und da wurde mit GPL empfohlen. In Stein gemeißelt ist das 
aber nicht.

: Bearbeitet durch User
von DraconiX (Gast)


Angehängte Dateien:

Lesenswert?

Hier mal meine, angepasst für einen STM32F103 - mit StdPeriphLib - 
gleich dazu mit der I2C Initialiesrung - Quasi LCD an I2C1 (PB6 und 
PB7). Dann noch die Header einbinden und los gehts:


1
#include "stm32f10x.h"
2
#include "SSD1306_i2c.h"
3
4
int main(void)
5
{
6
7
   ssd1306_InitializeDisplay();
8
9
   while(1)
10
   {
11
12
     ssd1306_clrscr();
13
     ssd1306_puts("Das sind 22 Zeichen!");
14
     ssd1306_gotoxy(0,7);
15
     ssd1306_puts("Und sieben Zeilen");
16
17
     delay_ms(2000);
18
19
            
20
     // Könnte man sich auch sparen mit dem display_buffer
21
     // in diesem Fall! Man könnte es direkt raussenden.
22
     // Aber ich hab es mal mit dazugenommen
23
   
24
     for(int i=0;i<1024;i++)
25
     {
26
      display_buffer[i] = starwars[i];
27
     }
28
29
     ssd1306_TransferBuffer();
30
     delay_ms(2000);
31
32
   }
33
}

Ich erweitere meine auch noch so nach und nach, so das ich die Register 
direkt beschreibe und keine Lib brauche, und das ich noch Standard I2C2 
und I2C3 mit rein nehme.

von Joachim B. (jar)


Lesenswert?

M. K. schrieb:
> ich hoffen
> wir können das Problem schnell lösen.

hoffe ich auch

M. K. schrieb:
> Gibt der Compiler noch ein Warning oder ähnliches bei dir aus? Ich habe
> beim SH1106 auch ein 128*64 Pixel großes Display,

ja ist identisch

M. K. schrieb:
> und hierbei die Lib
> von Peter Fleury verwendet habe. Damit ich meinen alten Code nicht
> umschreiben muss sondern wirklich nur die lcd-Lib austauschen muss habe
> ich mich bzgl. der Funktionsnamen ein wenig an Peters Lib orientiert ;)

ist ja kein Problem, die hatte ich auch verwendet als ich noch auf pure 
AVR und lcd mit Studio 4.18 unterwegs war

deswegen kenne ich die ja ganz gut

momentan mache ich halt mit der "U8glib.h" weiter

vielleicht klappts ja mit deiner irgendwann, Testaufbau ist vorhanden 
und wenn du was findest probiere ich weiter.

wie gesagt mit 1306 init lief es auf 1106 mal nur mit Pixelmüll und 
falscher xy Adressierung

nun ist der Pixelmüll weg, aber Text kommt nicht, nicht mal falsch 
adressiert.

M. K. schrieb:
> Gibt der Compiler noch ein Warning oder ähnliches bei dir aus?

nein

: Bearbeitet durch User
von DraconiX (Gast)


Lesenswert?

M. K. schrieb:
> DraconiX schrieb:
>> Das man um den 1K RAM nicht drumrum kommt liegt an der
>> Speicheraddressierung des SSD1306.
>
> Nö, das liegt an der Schnittstelle. Bei i2c und spi kann man nur
> schreibend auf das Display zugreifen. Geht man ans parallele Interface
> des SSD1306 ran kann man das Display auch auslesen, dann braucht man den
> RAM nicht.
>
> Jörg W. schrieb:
>> @Michael: soll ich mal deinen ersten Threadbeitrag editieren und die
>> Links auf die jeweils aktuelle Version einfügen?
>
> Gute Idee, versuche ich gleich umzusetzen. Ich hab auch überlegt bei
> github ein Repository  jeweils für die Text-Variante und für die
> Grafik-Variante zu erstellen.
>
> Joachim B. schrieb:
>> wo weiter oben, du hattest viel gepostet, hast du bitte einen Link?
>
> Ich hab beide Varianten in der aktuellen Version diesem Beitrag
> angehangen, aus dem ersten Beitrag werde ich gleich noch hierauf
> verlinken lassen.
>
> EDIT: Jörg, ich darf den ersten Post nicht mehr editieren. Das ist wohl
> eine Option, die nur Moderatoren/Administratoren zur Verfügung steht,
> nicht aber "normalen" Usern. Wärst du vielleicht so nett?

Ich habe einen Fehler in deiner Lib gefunden - schau mal bitte danach - 
bei mir hat der Compiler immer eine Warnung rausgeworfen aber ich kam 
selber nicht dahiner.

Bei deiner DrawRect, DrawLine etc... überall wo die Überprüfung des 
Displaybereiches ist.

von:
1
void lcd_drawRect(uint8_t px1, uint8_t py1, uint8_t px2, uint8_t py2, uint8_t color){
2
    if( ((px1 || px2) > DISPLAY_WIDTH-1) ||
3
       ((py1 || py2) > DISPLAY_HEIGHT-1) ) return;
4
    lcd_drawLine(px1, py1, px2, py1, color);
5
    lcd_drawLine(px2, py1, px2, py2, color);
6
    lcd_drawLine(px2, py2, px1, py2, color);
7
    lcd_drawLine(px1, py2, px1, py1, color);
8
}

zu:
1
void lcd_drawRect(uint8_t px1, uint8_t py1, uint8_t px2, uint8_t py2, uint8_t color){
2
    if( (px1 > DISPLAY_WIDTH-1) ||
3
        (px2 > DISPLAY_WIDTH-1) ||
4
        (py1 > DISPLAY_HEIGHT-1)||
5
        (py2 > DISPLAY_HEIGHT-1)) return;
6
7
    lcd_drawLine(px1, py1, px2, py1, color);
8
    lcd_drawLine(px2, py1, px2, py2, color);
9
    lcd_drawLine(px2, py2, px1, py2, color);
10
    lcd_drawLine(px1, py2, px1, py1, color);
11
}


Sie dazu auch hier: Beitrag "C Fehler: Vergleich von Const mit bool immer falsch"

von Joachim B. (jar)


Lesenswert?

DraconiX schrieb:
> Ich habe einen Fehler in deiner Lib gefunden - schau mal bitte danach -
> bei mir hat der Compiler immer eine Warnung rausgeworfen aber ich kam
> selber nicht dahiner.
>
> Bei deiner DrawRect, DrawLine etc... überall wo die Überprüfung des
> Displaybereiches ist.


betrifft das nicht nur die Grafik Version?
Momentan gehts um Text 1306 zu 1106, jedenfalls für mich, nur um mal 
wieder Ordnung in die Postings zu bekommen.

von DraconiX (Gast)


Lesenswert?

Joachim B. schrieb:
> betrifft das nicht nur die Grafik Version?
> Momentan gehts um Text 1306 zu 1106, jedenfalls für mich, nur um mal
> wieder Ordnung in die Postings zu bekommen.

Ja das betrifft nur die Grafik Version. Zum Thema 1106 kann ich leider 
nix sagen da ich hier keinen habe, sonst hätte ich mich auch darauf 
geworfen.

von M. K. (sylaina)


Lesenswert?

Joachim B. schrieb:
> wie gesagt mit 1306 init lief es auf 1106 mal nur mit Pixelmüll und
> falscher xy Adressierung
>
> nun ist der Pixelmüll weg, aber Text kommt nicht, nicht mal falsch
> adressiert.

Ja, das ist "normales" Verhalten, dass beim "falschen" Controller die 
Adressierung nicht passt und man Pixel-Salat bekommt.

Aber dass da gar nix kommt ist auch ungewöhnlich soweit ich das jetzt 
übersehen konnte. Ich könnte mir vorstellen, dass da irgendwo ein 
OutOfBounds auftritt.

Ich hab mir mal Gedanken um die lcd_clrscr()-Funktion gemacht und sie 
"vereinfacht". Es gibt da jetzt keinen Unterschied mehr zwischen SSD1306 
und SH1106:
1
void lcd_clrscr(void){
2
    uint8_t clearLine[DISPLAY_WIDTH];
3
    for (uint8_t i=0; i<DISPLAY_WIDTH; i++) {
4
        clearLine[i]=0x00;
5
    }
6
    for (uint8_t j = 0; j <= DISPLAY_HEIGHT/8-1; j++){
7
        lcd_gotoxy(0,j);
8
        lcd_data(clearLine, sizeof(clearLine));
9
        
10
    }
11
  lcd_home();
12
}
Vorteil: Das Löschen geht jetzt etwas schneller.
Nachteil: Man braucht jetzt min. 129 Byte SRAM (bei 128 Pixel Breite: 
128 für clearLine, 1 Byte für die Laufvariable i).
Ich glaubs zwar nicht, bei mir hat das am Display-Verhalten selbst 
nichts geändert, aber vielleicht ändert das ja was bei dir.
Wie sieht denn deine Main dazu aus? Ich glaube zwar nicht, dass es daran 
liegt, aber man weiß ja nie.
Weißt du eigentlich, dass das mich ein wenig fuchsig macht, dass es bei 
dir nicht laufen will? ;)

DraconiX schrieb:
> Bei deiner DrawRect, DrawLine etc... überall wo die Überprüfung des
> Displaybereiches ist.

In der Tat, da hast du recht. Es ist aber nur die DrawRect und die 
DrawLine, in der die Prüfung praktisch wirkungslos ist. Hab ich hier 
schon geändert, kommt also mit dem nächsten Upload...sobald wir den 
Fehler bei Johannes raus haben ;).

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

M. K. schrieb:

> for (uint8_t i=0; i<DISPLAY_WIDTH; i++) {
>         clearLine[i]=0x00;
>     }

Das würde ich als
1
memset(clearLine, 0, DISPLAY_WIDTH);
 schreiben.

von Joachim B. (jar)


Lesenswert?

Jörg W. schrieb:
> M. K. schrieb:
>
>> for (uint8_t i=0; i<DISPLAY_WIDTH; i++) {
>>         clearLine[i]=0x00;
>>     }
>
> Das würde ich als
1
memset(clearLine, 0, DISPLAY_WIDTH);
 schreiben.

ganz genau, memset nutze ich gerne ist schliesslich integriert und man 
bekommt es ja kaum besser hin!

M. K. schrieb:
> Weißt du eigentlich, dass das mich ein wenig fuchsig macht, dass es bei
> dir nicht laufen will? ;)

das freut mich, ich möchte ja auch das es läuft :)

: Bearbeitet durch User
von Rüdiger S. (ruediger9)


Angehängte Dateien:

Lesenswert?

Hier mal eine Erweiterung zur Anzeige von Bildern:

Dazu einfach den Code aus der angehängten Txt-Datei in die lcd_gfx.h und 
lcd_gfx.c einfügen.

Bilder mit Gimp etc. vorbereiten und skalieren. Dabei die maximale Größe 
beachten, es darf nicht größer als die Displaygröße sein.
Die Höhe muss glatt durch 8 teilbar sein.
Bei einem 128x64 Display wäre also z.B. eine Größe von 60x48 gültig.

Mit OledBm.exe in Programmcode umwandeln.
Es gibt hier noch die Möglichkeit, die Schwellwerte für RGB zu ändern, 
um z.B. schnell aus farbigen Bildern eine Monochrom-Bitmap zu 
generieren.
Bessere Ergebnisse ergeben sich, wenn das schon mit dem 
Bildverarbeitungsprogramm gemacht wird.
"Code erstellen" und "Copy Clipboard", dann in main.c oder wo immer es 
von der Funktion sichtbar ist, einfügen.

Funktionsaufruf sieht dann so aus:
lcd_drawBitmap(34, 5, wcfrei);

Es können natürlich soviele Bitmaps eingefügt werden, wie der 
Code-Speicher zulässt.

Damit konnte ich dann meine WC-Besetzt-Anzeige mit Bewegungsmelder 
realisieren. :-)
(Zuhause schließen wir keine Türen ab, weil im Notfall erschwerte 
Rettungsmöglichkeit.)

von Joachim B. (jar)


Lesenswert?

Rüdiger S. schrieb:
> Hier mal eine Erweiterung zur Anzeige von Bildern:
> Damit konnte ich dann meine WC-Besetzt-Anzeige mit Bewegungsmelder
> realisieren. :-)
> (Zuhause schließen wir keine Türen ab, weil im Notfall erschwerte
> Rettungsmöglichkeit.)

cool, trotzdem meine WC Tür hat aussen einen Schlitz der sofort mit 
Spachtel, Schlüsselanhänger, Messer, Tortenheber geöffnet werden kann!

von DraconiX (Gast)


Angehängte Dateien:

Lesenswert?

Coole Sache mit dem Bild-C-Dings-Bums! Schreibt er das Array anhand der 
Bildgröße raus?!

 Ich hab nun noch ein SIN Generator hinzugefügt und nun bin ich vollends 
zufrieden.

Kann es sein das der SSD1306 ab ca. 700khz bei I2C schlapp macht? Höher 
schafft er es nimmer.

von Johannes R. (Gast)


Lesenswert?

M. K. schrieb:
> In der Tat, da hast du recht. Es ist aber nur die DrawRect und die
> DrawLine, in der die Prüfung praktisch wirkungslos ist. Hab ich hier
> schon geändert, kommt also mit dem nächsten Upload...sobald wir den
> Fehler bei Johannes raus haben ;).

Das ging in der Flut überflüssiger Posts von Joachim B. vielleicht 
unter, aber die von mir beobachteten Probleme konnte ich durch die 
weiter oben beschriebenen Anpassungen in lcd_drawPixel() und 
lcd_gotoxy() erfolgreich beheben. Meiner Einschätzung nach sind die 
allgemeingültig und können von dir in die Bibliothek übernommen werden.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

DraconiX schrieb:
> 700khz bei I2C

I²C ist ja normal auch nur für 400 kHz spezifiziert.

von Klaus (Gast)


Lesenswert?

Jörg W. schrieb:
> DraconiX schrieb:
>> 700khz bei I2C
>
> I²C ist ja normal auch nur für 400 kHz spezifiziert.

Das ist ein typisches i2c Problem. Wenn ein Device nur 399 kHz schafft, 
fällt es in die Klasse Standard, 100kHz, genau wie eins, das bei 101 kHz 
nicht mehr kann. Schafft es keine 3,4 MHz, ist es nur Fast, also 400kHz. 
Zwischenwerte gibt es nicht.

MfG Klaus

von Rüdiger S. (ruediger9)


Lesenswert?

DraconiX schrieb:
> Coole Sache mit dem Bild-C-Dings-Bums! Schreibt er das Array anhand der
> Bildgröße raus?!

Ja, je nach Bildgröße enthält das Array auch mehr oder weniger Daten.
Die ersten beiden Bytes im Array beschreiben die Bildgröße.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Rüdiger S. schrieb:
> Mit OledBm.exe in Programmcode umwandeln.

Quellcode dafür wäre natürlich nicht schlecht.

Alternative: mit Gimp als XBM abspeichern. Das ist C-Quzelltext. :)

Für den AVR sollte man dann aber das XBM damit nachbearbeiten:
1
.SUFFIXES: .xbm
2
3
.xbm.h:
4
        sed -e 's/^.* \([a-zA-Z0-9_]*_bits\).*$$/static const uint8_t \1[] __attribute__((progmem)) = {/' $< > $@.tmp && mv $@.tmp $@

(Makefile-Schnipsel, Kommandos bitte mit <TAB> einrücken)

Damit wird ein progmem-Objekt draus gemacht.

von DraconiX (Gast)


Lesenswert?

Jörg W. schrieb:
> DraconiX schrieb:
> 700khz bei I2C
>
> I²C ist ja normal auch nur für 400 kHz spezifiziert.

Naaaa... Es gibt ja auch den I2C High-Speed-Mode mit Clockstretching bis 
3,4MHz.

von Rüdiger S. (ruediger9)


Lesenswert?

Jörg W. schrieb:
>> Mit OledBm.exe in Programmcode umwandeln.
>
> Quellcode dafür wäre natürlich nicht schlecht.

Kein Problem, werde das nach dem Aufräumen veröffentlichen. Ist C#, kann 
also mit der frei verfügbaren Visual Studio Community Edition kompiliert 
werden.

>
> Alternative: mit Gimp als XBM abspeichern. Das ist C-Quzelltext. :)
>

Klasse, man lernt immer was dazu. :)

von Stromtuner (Gast)


Lesenswert?

.SUFFIXES: .xbm

.xbm.h:
        sed -e 's/^.* \([a-zA-Z0-9_]*_bits\).*$$/static const uint8_t 
\1[] __attribute__((progmem)) = {/' $< > $@.tmp && mv $@.tmp $@

Schräg !!! :)

von Walter J. (oberallgeier)


Angehängte Dateien:

Lesenswert?

oberallgeier schrieb:
> Hallo Michael,
> ...
> Als Gegenleistung .. Bildchen .. vom Oskar .. I²C-Flanken bei den 400 kHz.

So Manfred, am 11.03.2017 hatte ich Dir versprochen die Bildchen vom 
I²C-Bus zu zeigen, der mit 400 kHz betrieben wird. Ich habe nun eine 
(selbst ge-copy´n´paste-e) Version aus den Tiefen des WWW 
(*.cpp-Version) adaptiert und das Display 1306 zum Laufen bekommen.

Hier die Bilder, einmal mit 400 kHz, einmal mit 200 kHz. Man sieht bei 
den 400 kHz-Flanken deutlich, dass der Pegel bei 5V eindeutig nicht mehr 
erreicht wird - vergleiche dazu die 200-kHz-Flanken. Dieser Bustakt 
dürfte also schon grenzwertig sein.

Sonstige Daten: nano-Clone mit 20 (!) Mhz, 5V-Pegel, je 1x 4k7 auf SDA 
und SCL, Datenleitung von den Steckleisten eines nanoclones bis 
zumSteckbrett ca. 20 cm, Display ohne Kondensator von der 
Nano-Steckerleiste (GND, 5V) versorgt.

DraconiX schrieb:
> Kann es sein das der SSD1306 ab ca. 700khz bei I2C schlapp macht?

Es gilt ja:
TWBR = ((F_CPU/SCL_CLOCK)-16)/2
bei (meinem Clone mit) 20 MHz ergibt sich also ein TWBR von 17, bei 
16MHz UND 700 kHz ist TWBR gleich 3 (3,4..). Soweit ich die 
I²C-Spezifikation kenne, ist bei TWBR von etwa 10 Schluss, dann wird 
sowieso clock gestretcht (KANN gestretcht werden gg).

: Bearbeitet durch User
von Walter J. (oberallgeier)


Lesenswert?

Nachtrag zu den Bildern: Gould DSO1602, 20 MHz.

von M. K. (sylaina)


Lesenswert?

Walter J. schrieb:
> Hier die Bilder, einmal mit 400 kHz, einmal mit 200 kHz. Man sieht bei
> den 400 kHz-Flanken deutlich, dass der Pegel bei 5V eindeutig nicht mehr
> erreicht wird - vergleiche dazu die 200-kHz-Flanken. Dieser Bustakt
> dürfte also schon grenzwertig sein.

So aus der Hüfte geschossen würde ich da aber sagen, dass deine Pull-Ups 
für 400 kHz schlicht schon zu groß sind. Schau dir mal das hier von TI 
dazu an:
http://www.ti.com/lit/an/slva689/slva689.pdf

;)

von Walter J. (oberallgeier)


Lesenswert?

M. K. schrieb ..
> .. aus der Hüfte geschossen .. Pull-Ups für 400 kHz .. zu groß ..

Huiii, danke, was für eine praktische, gute Anleitung von TI; die kannte 
ich nicht.
Nun hab ich mal die Leitung vom nano-Pinn SCL zum/inclusive Steckbrett 
gemessen. Uuuuups, 33 µF (mit Billig-DMM), das sind >> 450 pF aus Fig. 
3, und laut Fig. 2 können <1,6kΩ passen.
Also je 1x1k6 Ω gegen Vcc an jede I²C-Leitung - am Steckbrett, 
Übertragungsrate auf 400 kHz (ERinnerung: nanoclone 20 MHz) gestellt und 
Oskar angeworfen.

Genau, jetzt sieht es auch bei 400 kHz nicht mehr (so) grenzwertig aus. 
Die Auflösung meines alten DSOs ist zwar leider nur bis 10 µs/DIV. Am 
5V-Pegel ist trotzdem bei jedem Zacken/Puls vom SCL noch eine eindeutige 
Linie zu erkennen ?~1µs?. Foto könnte ich nachreichen, aber vielleicht 
reicht meine Beschreibung.

Danke für die Hilfe(n).

: Bearbeitet durch User
von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Walter J. schrieb:
> Uuuuups, 33 µF

Dann solltest du entweder den Messwert deines Schätzeisens grundlegend
in Zweifel ziehen oder aber den 33-µF-Elko schnellstens von der
SCL-Leitung wieder ablöten. :-)

von Joachim B. (jar)


Lesenswert?

33µF aus einer Leitung, RESPEKT wo gibt es das Kabel oder wie lang ist 
es?

Direktleitung zur ISS?

von Walter J. (oberallgeier)


Lesenswert?

oberallgeier schrieb:
> .. Datenleitung .. nanoclones bis zumSteckbrett ca. 20 cm ..
Jörg W. schrieb:
> .. entweder den Messwert deines Schätzeisens .. in Zweifel ziehen ..
Na ich dachte "Uuuuups, 33 µF .." sei Kommentar genug, aber man sollte 
halt nie zuviel voraussetzen.

Gut, ne Nachmessung mit meinem selbstgebauten Transistortester nach 
Markus F. zeigt später "kein Bauteil" an; einen 100 pF misst der 
(Kontrollmessung) noch mit 0,14 nF.

von DraconiX (Gast)


Lesenswert?

Walter J. schrieb:
> Es gilt ja:
> TWBR = ((F_CPU/SCL_CLOCK)-16)/2
> bei (meinem Clone mit) 20 MHz ergibt sich also ein TWBR von 17, bei
> 16MHz UND 700 kHz ist TWBR gleich 3 (3,4..). Soweit ich die
> I²C-Spezifikation kenne, ist bei TWBR von etwa 10 Schluss, dann wird
> sowieso clock gestretcht (KANN gestretcht werden gg).

Ja bei mir läuft es über ein STM32 welcher auf 64Mhz läuft und das I²C 
mit DMA gefeuert wird. Der würde seine 4Mhz locker schaffen, aber mir 
ist bis dato auch noch kein HighSpeed-Slave untergekommen, nichteinmal 
Kollegen die die Clock gestrecht haben, wenn es ihnen zu schnell war.

von Rainer K. (zebra)


Lesenswert?

Hallo,

ich versuche die Lib auf einem Tiny85 zum Laufen zu bekommen. Das geht 
auf Anhieb gar nicht. Wie ich festgestellt habe, fehlt bei den i2c 
bit-bang Routinen die Slave Adresse, deshalb fühlt sich das OLED Display 
(SSD1306) gar nicht angesprochen.

Gruß

Rainer

von Walter J. (oberallgeier)


Lesenswert?

Rainer K. schrieb:
> .. Lib auf einem Tiny85 .. fehlt bei den i2c ..

Gibts beim Tiny überhaupt ein I²C - na ja, aber eben nur "handgestrickt" 
?

In "meiner" SSD1306.h steht die Adresse als
#define SSD1306_DEFAULT_ADDRESS 0x78
aber der Code ist eben für Hardware-TWI beim ATMEGA328p.

: Bearbeitet durch User
von zebra (Gast)


Lesenswert?

Walter J. schrieb:
> #define SSD1306_DEFAULT_ADDRESS 0x78
> aber der Code ist eben für Hardware-TWI beim ATMEGA328p

Ja, aber es wurde auch versucht zumindestens die Text-Lib mit bit-bang 
I2C für die Tinys zu implementieren. Scheinbar hat vor mir das niemand 
ausprobiert :-) Ohne slave-Adresse in den bit-bang I2C Funktionen geht 
es aber nicht...das Diplay bleibt einfach dunkel. Mir ist noch nicht 
ganz klar, wo man am Einfachsten das Schreiben der Slave-Adresse 
einfügt.

Gruß

Rainer

von Dietmar (Gast)


Lesenswert?

Hallo zusammen,
wie Schwierig ist es einen anderen Font zu integrieren ?
lg Dietmar

von M. K. (sylaina)


Lesenswert?

Dietmar schrieb:
> wie Schwierig ist es einen anderen Font zu integrieren ?

Kommt auf den Font an. Aktuell ists nur für 6x8-Fonts gemacht. Wenn du 
also einen anderen 6x8-Font möchtest sollte das kein Problem sein.

von Dietmar (Gast)


Angehängte Dateien:

Lesenswert?

Vielen Dank für die Antwort und das erstellen der Library !
Ich finde die Library ausgezeichnet und sie ist auch nicht so überladen
wie die U8G Lib. Ich verwende den 6x8 Font aber der ist für mich als 
älteres Semester nicht so gut lesbat ;-)
lg Dietmar

von Klaus (Gast)


Lesenswert?

Dietmar schrieb:
> Ich verwende den 6x8 Font aber der ist für mich als
> älteres Semester nicht so gut lesbat ;-)

Kenn ich. Es gibt auch Pin- und Funktionskompatible 1,3" Oleds. Da ist 
es ein wenig besser.

MfG Klaus

von Dietmar (Gast)


Lesenswert?

meine quick and dirty Variante :-)
1
void lcd_putc(char c,char xpos,char ypos)
2
{
3
   unsigned char x,y,w;
4
5
   for (y=0; y<FONT_Y_SIZE; y+=1)
6
   {
7
       w=pgm_read_byte(&font_8x12[(unsigned char)c][y]);
8
       
9
       for (x=0; x<FONT_X_SIZE; x++)
10
       {
11
         if (w&1)
12
         lcd_drawPixel(actualIndex+x+xpos, y+ypos,1);
13
         else
14
         lcd_drawPixel(actualIndex+x+xpos, y+ypos,0);
15
         w=w>>1;
16
       }
17
18
   }
19
 
20
 actualIndex += FONT_X_SIZE+1;
21
}

: Bearbeitet durch Moderator
von Daniel R. (jimminy)


Lesenswert?

Hallo,
ich bin hier auf die OLED Library gestoßen und wollte die ganz gerne 
verwenden. Leider Bekomme ich beim Compilieren immer den fehler:

"undefined reference to `lcd_gotoxy(unsigned char, unsigned char)"

Dieser Fehler tritt bei jeder Funktion auf.
Hat einer eine Idee woran das liegen könnte?
Ich benutze Atmel Studio 7.
Würde mich über ein Tipp sehr freuen, Danke!
Mfg

von Tippgeber (Gast)


Lesenswert?

Daniel R. schrieb:
> Leider Bekomme ich beim Compilieren immer den fehler:
>
> "undefined reference to `lcd_gotoxy(unsigned char, unsigned char)"
>
> Dieser Fehler tritt bei jeder Funktion auf.
> Hat einer eine Idee woran das liegen könnte?

#include "SSD1306_i2c.h" vergessen?

von Tippgeber (Gast)


Lesenswert?

Sorry, das Ding heißt ja: #include "lcd_ssd1306_gfx.h"

von Dieter F. (Gast)


Lesenswert?

Beitrag "Re: SSD1306 Library zum Darstellen von Text auf OLED Displays"

Sag mal bitte  - woher kommt denn der Font von der Mini-Schrift am 
unterenb Rand? Findet man den irgendwo?

von Daniel R. (jimminy)


Lesenswert?

Wo bekomme ich die "lcd_ssd1306_gfx.h"?
Dachte die lcd_gfx.h und lcd_gfx.c wäre das was ich brauche?
Danke!

von Joachim B. (jar)


Lesenswert?

Dieter F. schrieb:
> Beitrag "Re: SSD1306 Library zum Darstellen von Text auf OLED Displays"
>
> Sag mal bitte  - woher kommt denn der Font von der Mini-Schrift am
> unterenb Rand? Findet man den irgendwo?

ach DU MEINST mich?

da muss man erst mal drauf kommen ohne Zitat, was du siehst ist die 
eingebundene originale UG8LIB, da kann man size wählen

beim Nokia bekomme ich 6 Zeilen a 14 Zeichen und in derselben lesbaren 
Größe nur 5 Zeilen a 16 Zeichen und deswegen habe ich die 6te Zeile 
verkleinert.

: Bearbeitet durch User
von Dieter F. (Gast)


Lesenswert?

Joachim B. schrieb:
> ach DU MEINST mich?

Ja, der Link ist eigentlich deutlich - oder?

Danke für den Hinweis auf die Skalierung.

von Joachim B. (jar)


Lesenswert?

Dieter F. schrieb:
> Joachim B. schrieb:
>> ach DU MEINST mich?
>
> Ja, der Link ist eigentlich deutlich - oder?

dazu müsste man jedem Link folgen was ich nur selten mache, wozu auch 
wenns mich nicht betrifft?

Deswgen die Zitatfunktion nutzen dann wird es eher gesehen wen es 
betrifft!

von Dieter F. (Gast)


Lesenswert?

Joachim B. schrieb:
> dazu müsste man jedem Link folgen was ich nur selten mache, wozu auch
> wenns mich nicht betrifft?
>
Aufwändig - 1 Klick

> Deswgen die Zitatfunktion nutzen dann wird es eher gesehen wen es
> betrifft!

O.K. - werde ich künftig berücksichtigen

von Joachim B. (jar)


Lesenswert?

Dieter F. schrieb:
> Joachim B. schrieb:
>> dazu müsste man jedem Link folgen was ich nur selten mache, wozu auch
>> wenns mich nicht betrifft?
>>
> Aufwändig - 1 Klick

ja bei begrenzter Restlebenszeit :)
(PS. Mein Nachbar klickt auch immer ALLES und wundert sich wenn sein 
Computer wieder mal spinnt)

>> Deswgen die Zitatfunktion nutzen dann wird es eher gesehen wen es
>> betrifft!
>
> O.K. - werde ich künftig berücksichtigen

danke dafür!

: Bearbeitet durch User
von Dieter F. (Gast)


Lesenswert?

Joachim B. schrieb:
> ja bei begrenzter Restlebenszeit :)
> (PS. Mein Nachbar klickt auch immer ALLES und wundert sich wenn sein
> Computer wieder mal spinnt)

Hier im Forum ... ja, wird wohl so sein ...
(Wer hat keine begrenzte Restlebenszeit?)

von Joachim B. (jar)


Lesenswert?

Dieter F. schrieb:
> Joachim B. schrieb:
>> ja bei begrenzter Restlebenszeit :)
>> (PS. Mein Nachbar klickt auch immer ALLES und wundert sich wenn sein
>> Computer wieder mal spinnt)
>
> Hier im Forum ... ja, wird wohl so sein ...

natürlich nicht, sollte nur mal aufzeigen das es (überall) keine gute 
Idee ist auf ALLES zu klicken!

> (Wer hat keine begrenzte Restlebenszeit?)

ja aber scheinbar stört es manche nicht oder sie haben Mutti Vati Frau 
Partner der das Leben organisiert und demzufolge genug Zeit übrig um 
alles zu klicken.

von Daniel R. (jimminy)


Lesenswert?

Hallo,
ich habe mein fehler gefunden. Mein Projekt habe ich in C++ geschrieben. 
Da die lcd_gfx.c ja in C geschrieben ist, hat das der Compiler nicht auf 
reihe bekommen. Hab dann die lcd_gfx.c in eine .cpp abgespeichert und 
läuft jetzt auch soweit.
Eine Frage habe ich allerdings noch. Kann man die Anzahl der Reihen oder 
die Schriftgröße verändern?
Danke!

von Julius (Gast)


Lesenswert?

Ich liebe diese Endlos Threads.

Anleitung zum Verbreiten von eigener Sofware:

1. Die finale/stable Version im ersten Post verlinken, am besten dort 
alle Versionen auflisten.

NIEMAND liesst alle Threads nur um die letzte Version zu finden.

2. Code Dokumentieren. Natürlich wissen die eingefuchsten Programmierer 
wie man diese Library benutzt. Aber für Anfänger gehören minimale 
Verwendungshinweise als Comment in den Code.

In der Art:

erst initialisieren,
dann bla,
dann zeichen senden

Ein Hello World Beispiel, am besten gleich am Anfang des Codes.

von M. K. (sylaina)


Lesenswert?

Daniel R. schrieb:
> Hallo,
> ich habe mein fehler gefunden. Mein Projekt habe ich in C++ geschrieben.
> Da die lcd_gfx.c ja in C geschrieben ist, hat das der Compiler nicht auf
> reihe bekommen. Hab dann die lcd_gfx.c in eine .cpp abgespeichert und
> läuft jetzt auch soweit.
> Eine Frage habe ich allerdings noch. Kann man die Anzahl der Reihen oder
> die Schriftgröße verändern?
> Danke!

Die Anzahl der Reihen (Pages) wird von der Displaygröße vorgegeben, eine 
Variation der Schriftgröße ist (noch) nicht implementiert, mir fehlt 
aktuell leider die Zeit weiter daran zu arbeiten, es darf sich aber 
jeder frei fühlen die Library um entsprechende Funktionen zu erweitern.

Julius schrieb:
> 1. Die finale/stable Version im ersten Post verlinken, am besten dort
> alle Versionen auflisten.

Die aktuelle Version ist im ersten Post verlinkt, ich kann ihn leider 
nicht editieren. Dazu muss ich dann immer einen Moderator/Admin fragen. 
;)

Julius schrieb:
> 2. Code Dokumentieren. Natürlich wissen die eingefuchsten Programmierer
> wie man diese Library benutzt. Aber für Anfänger gehören minimale
> Verwendungshinweise als Comment in den Code.
>
> In der Art:
>
> erst initialisieren,
> dann bla,
> dann zeichen senden
>
> Ein Hello World Beispiel, am besten gleich am Anfang des Codes.

Ja, einen Beispiel-Code hätte ich hier noch implementieren können. Fand 
ich jetzt hierbei überflüssig da man, wenn man sich wirklich mit 
Displays beschäftigt, sehr schnell dahinter kommt, dass man das Display 
erst initialisieren muss und erst dann drauf schreiben kann. Ich werde 
aber mal einen Beipsiel-Code als Comment mit reinpacken.

: Bearbeitet durch User
von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Daniel R. schrieb:
> Da die lcd_gfx.c ja in C geschrieben ist, hat das der Compiler nicht auf
> reihe bekommen.

Dafür hätte man im Headerfile die Funktionsdeklarationen in
1
#ifdef __cplusplus
2
extern "C" {
3
#endif
4
5
// hier kommen die Funktionsprototypen
6
int a(char b);
7
8
#ifdef __cplusplus
9
}
10
#endif

einschließen müssen.  Das sagt dem C++-Compiler, dass die entsprechenden
Funktionen in einer C-Datei stehen und daher eine andere 
Aufrufkonvention
zu benutzen ist.

von Joachim B. (jar)


Lesenswert?

Jörg W. schrieb:
> .......
> einschließen müssen.  Das sagt dem C++-Compiler, dass die entsprechenden
> Funktionen in einer C-Datei stehen und daher eine andere
> Aufrufkonvention
> zu benutzen ist.

das verstehe ich zwar nicht, aber in Arduino habe ich meinen alten 
C-Quellcode einfach zu s_tools.ino (aus s_tools.c) umbenannt das 
funktionierte, genauso wie in der *.ino #include "s_tools.c"

aber s_tools.ino kam mir praktischer vor als das include!

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Joachim B. schrieb:
> in Arduino habe ich meinen alten C-Quellcode einfach zu s_tools.ino (aus
> s_tools.c) umbenannt

Das mag für vielen C-Code funktionieren, aber nicht jedes gültige
C-Programm ist auch ein gültiges C++-Programm.  Das fängt bei
offensichtlichen Problemen an wie die Benutzung von Schlüsselwörtern,
die in C++ reserviert sind (class, new), aber es gibt subtilere
Unterschiede, bis hin zu C99-Features, die in C++ keinen Einzug
gefunden haben (named initializers).

> das verstehe ich zwar nicht

C++-Funktionen bekommen einen „verwürgten“ (engl.: mangled) Namen, in
dem Anzahl und Typ der Argumente codiert werden.  Dadurch hat man ein
typesafe linking und kann Funktionen gleichen Namens aber mit
unterschiedlichen Argumenten unterscheiden.

C kennt sowas nicht.  Durch die Deklaration als „extern "C"“ zeigt man
dem C++-Compiler an, das die entsprechenden Funktionen der C-Notation
folgen.

von Daniel R. (jimminy)


Lesenswert?

Hallo,
danke für die Antworten.
@sylaina
Du hattest mal ein Stück Beispielcode hier relativ am Anfang gepostet, 
daran hatte ich mich orientiert. Gut zu wissen das es noch nicht 
Implementiert ist, dann brauch ich da nicht weiter zu suchen. Vielleicht 
bekomme ich da auch eine Lösung hin.

Jörg W. schrieb:
> .......
> einschließen müssen.  Das sagt dem C++-Compiler, dass die entsprechenden
> Funktionen in einer C-Datei stehen und daher eine andere
> Aufrufkonvention
> zu benutzen ist.
Das werde ich bei Gelegenheit mal Testen. Kann man ja nur dazu lernen.
Vielen Dank!

von Markus (Gast)


Lesenswert?

Hallo ihr,

finde die Library prima. Nach ein paar Handgriffen konnte ich damit mein 
Display an einem ATmega32 betreiben. Danke auch für den Codeauszug. Ohne 
diesen wäre ich wohl nicht so schnell auf die unscheinbare Funktion 
lcd_display() aufmerksam geworden und daraufhin verzweifelt.

Was jedoch nicht funktioniert, ist die Ausgabe der Umlaute und 
Sonderzeichen. Diese werden von
1
 if((c > 127 ||
2
        c < 32) &&
3
       (c != 'ü' &&
4
...
5
        c != 'Ä' ) ) return;
einfach verschluckt, da die Anweisung sie nicht erkennt und die Funktion 
abbricht. Kommentiere ich die Überprüfung aus, wird mir an den 
entsprechenden Stellen des Displays nur Pixelsalat angezeigt. Ich 
schätze, da wird auf irgendwelche Speicherbereiche außerhalb des Arrays 
verwiesen.


Das AtmelStudio wirft mir weiterhin die Warnungen "Case label value is 
less than minimum value for type" und "Multi-character character 
constant [-Wmultichar]" aus. Diese beziehen sich auf den Bereich von 
lcd_putc(), in dem die Sonderzeichen vorkommen.

Die erste Meldung habe ich mit einem Cast in der switch-Anweisung 
beseitigen können
1
switch((uint16_t) c) {
2
      case 'ü':
3
      c = 95; // ü - 188
4
      break;

Die zweite Warnung rührt wohl daher, dass die switch-Anweisung die 
Unterscheidungen als Zeichenkette und nicht als einzelnes Zeichen 
interpretiert. Trage ich hier die vermeintlichen Zahlenwerte der 
Sonderzeichen ein, wie bspw.
1
      case 153:
2
        c = 100; // Ö
3
        break;
verschwindet zwar die Fehlermeldung, aber es bleibt beim Pixelsalat, da 
ich mit 153 über dem Wertebereich vom Datentyp char liege, den die 
gesamte Funktion ja ursprünglich als Variable erhält.
Auch ein ändern in unsigned char oder uint16_t brachte hier keine 
Verbesserung.

Irgendwie scheinen die Zeichen einfach nicht richtig erkannt zu werden. 
Weiß hier jemand Rat?

von DraconiX (Gast)


Lesenswert?

Die Sonderlaute müssen auch in deinem Font-Array vorhanden sein.

von Markus (Gast)


Lesenswert?

Vorhanden sind sie. Habe an den Fonts nicht verändert. Sie werden auch 
korrekt dargestellt, wenn ich sie händisch aufrufe
1
c = 100;  
2
for (uint8_t i = 0; i < 6; i++)
3
  {
4
    displayBuffer[actualIndex+i] = pgm_read_byte(&ssd1306oled_font6x8[c * 6 + i]);  // print font to ram, print 6 columns
5
  }
6
  
7
    actualIndex += 6;
Obiges Beispiel liefert beispielsweise das "Ö", welches sich an Position 
100 befindet.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Markus schrieb:
> "Multi-character character constant [-Wmultichar]"

Das deutet darauf hin, dass du mit UTF-8 als Sourcecode-Zeichensatz
arbeitest.  Damit funktioniert diese einfache switch/case-basierte
Implementierung nicht, die kommt nur mit 8-Bit-Zeichen zurecht.

von Markus (Gast)


Lesenswert?

Ja, das war ein guter Hinweis. Sobald ich im Atmel Studio die Option 
"Auto-detect UTF-8 encoding without signature" deaktiviere, wird jeder 
Umlaut durch zwei andere Zeichen ersetzt. Habe nun versucht, den 
Zeichensatz zu ändern, was aber nicht geglückt ist.

Jedoch habe ich während meiner Odyssey im Internet herausgefunden, dass 
sich die Zeichen durch den Zahlenwert des HTML-Unicode 
(https://de.wikipedia.org/wiki/Hilfe:Sonderzeichenreferenz) ersetzen 
lassen.
1
      case 246:
2
      c = 99; // ö
3
      break;
 funktioniert beispielsweise einwandfrei. Ist zwar etwas komisch zu 
lesen und es geht sicherlich eleganter, aber ich schätze, es wird dann 
wohl bei allen existierenden Sonderzeichen funktionieren, die man 
irgendwie verarbeiten möchte.

Jedenfalls ist es eine mögliche Lösung für Leute, die irgendwann mal ein 
ähnliches Problem haben.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Markus schrieb:
> Zahlenwert des HTML-Unicode

Genauer gesagt: Latin-1 encoding (ISO 8859-1).  Das ist ein
Ein-Byte-Encoding, bei dem die untere Hälfte ASCII ist und die obere
Hälfte allerlei mittel-, nord- und westeuropäische Schriftzeichen
enthält.

ISO 8859-1 ist das Standard-Encoding bei HTTP, sofern nichts anderes
vom Server angegeben ist.

von jps2000 (Gast)


Lesenswert?

Hi
Spiele mich gerade mit der Textversion herum
Blöde Frage:
Wie kann man eigentlich Zahlen mit Dezimalstelle (einfach) darstellen ? 
also zB zur Ausgabe einer Temperatur etc:  27.2 Grad ?

text geht ja einfach

lcd_gotoxy(0,0);
lcd_puts_p(PSTR("1234567890123456"));

Ich bräuchte sowas wie lcd.print (temp,1); zusätzlich zu text

any suggestions?

danke

von M. K. (sylaina)


Lesenswert?

jps2000 schrieb:
> Hi
> Spiele mich gerade mit der Textversion herum
> Blöde Frage:
> Wie kann man eigentlich Zahlen mit Dezimalstelle (einfach) darstellen ?
> also zB zur Ausgabe einer Temperatur etc:  27.2 Grad ?
>
> text geht ja einfach
>
> lcd_gotoxy(0,0);
> lcd_puts_p(PSTR("1234567890123456"));
>
> Ich bräuchte sowas wie lcd.print (temp,1); zusätzlich zu text
>
> any suggestions?
>
> danke

Aus der Standard-Lib (stdlib.h):

char * dtostrf(
  double __val,
  signed char __width,
  unsigned char __prec,
  char * __s)

Damit wandelst du Floats/Doubles in einen String um.
Für Integer gibts

char * itoa(
  int val,
  char * s,
  int radix)

Für dich vielleicht auch interessant: 
http://www.atmel.com/webdoc/avrlibcreferencemanual/

Ist ne recht gute Referenz

von jps2000 (Gast)


Lesenswert?

Danke für die Antwort.- Ich hab nicht so rasch mit einer Antwort 
gerechnet und was gebastelt

void lcd_print_var(uint8_t x, uint8_t y,float var){

// calculate digits
  uint16_t var1  =  abs(var) * 10;                //single decimal --> 
multiply by ten and convert to uint
  uint8_t tenth = 48 + var1 %10;                  // 48 is Ascii 0
  var1 /= 10;
  uint8_t single = 48 + var1 %10;
  var1 /= 10;
  uint8_t ten = 48 + var1 %10;
  var1 /= 10;
  uint8_t hundred = 48 + var1 %10;

// blank leading zeroes
  if (hundred == 48) hundred = 32;
  if (hundred == 32 && ten == 48) ten = 32;

// arrange characters
  char buf[6] = {32,hundred,ten,single,46,tenth}; // first sign is blank 
(32) 46 is decimal point
  if (var < 0) buf[0] = 45;                       // first sign is -

// write to display
  lcd_gotoxy(x-4,y);                              //sign position  x, y 
is decimal position
  lcd_puts(buf);         //write digit
  }


was du schreibst klingt interessant

kannst du bitte noch ergänzend für mein kleines Hirn
den syntax  aufschreiben
Nehmen wir an ich will -24.5 darstellen (float val = -24.5f)
was schreibe ich dann?

  lcd_puts(......);

mir helfen immer Beispiele

Danke

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

M. K. schrieb:
> Ist ne recht gute Referenz

„Das ist alles nur geklaut, das ist alles gar nicht meine!“ ;-)

Sie verletzen die avr-libc-Lizenz, da sie nicht erwähnen, dass das die
Doku der avr-libc ist, nur äußerlich ein bisschen auf Atmel getrimmt.

Aber irgendeinen Webmaster oder dergleichen, dem man sowas melden
könnte, sucht man bei Microchip vergeblich.  Wahrscheinlich muss man
wirklich der Rechtabteilung einen Drohbrief schreiben. :(

p.s.: Der Klassiker für sowas wäre natürlich sprintf().

: Bearbeitet durch Moderator
von M. K. (sylaina)


Lesenswert?

Jörg W. schrieb:
> Sie verletzen die avr-libc-Lizenz, da sie nicht erwähnen, dass das die
> Doku der avr-libc ist, nur äußerlich ein bisschen auf Atmel getrimmt.

Stimmt, da hast du völlig recht. Vielleicht kannst du das ja noch für 
mich ergänzen damit hier niemand Probleme bekommt. ;)

jps2000 schrieb:
> was du schreibst klingt interessant
>
> kannst du bitte noch ergänzend für mein kleines Hirn
> den syntax  aufschreiben
> Nehmen wir an ich will -24.5 darstellen (float val = -24.5f)
> was schreibe ich dann?
>
>   lcd_puts(......);
>
> mir helfen immer Beispiele

Kein Problem, hier ein kleines Beispiel dazu
1
...
2
#include <stdlib.h>
3
...
4
float myTestValue = -24.5;
5
char myValueToPrint[6];
6
...
7
lcd_gotoxy(1,0); // mal zu irgend einer Zeile gehen
8
lcd_puts_p(PSTR("Der Wert ist: "));
9
// dtostrf(): Variable die zu einem String umgewandelt werden soll, Stellen, die angezeigt werden sollen incl. Komma, Zahl der Nachkommastellen, Stringvariable(genauer: Zeiger auf die erste Speicherstelle der Stringvariablen) die den umgewandelten Wert aufnehmen soll
10
dtostrf(myTestValue, 
11
        6, 
12
        2, 
13
        myValueToPrint);
14
lcd_puts(myValueToPrint);
15
...

Jörg W. schrieb:
> p.s.: Der Klassiker für sowas wäre natürlich sprintf().

Post Scriptum kürzt man PS ab, nicht P.S. und auch nicht PS. oder 
ähnliches ;)
Und zu Sprint(): das hat ja u.U. den ein und anderen Haken.

von jps2000 (Gast)


Lesenswert?

Vielen Dank
jetzt habe ich es verstanden
damit schrumpft die Funktion zu

void lcd_print_var(uint8_t x, uint8_t y,float var, uint8_t digits, 
uint8_t resolution ){
  char buf[digits];
  dtostrf(var, digits, resolution, buf);
  lcd_gotoxy(x-resolution,y);      //sign position  x, y is decimal 
position
  lcd_puts(buf);                   //write digit
  }

Der einzige Pferdefuß ist dass dtostrf mehr Programmspeicher braucht

von Stefan F. (Gast)


Lesenswert?

Halo sylaina,
ist die Library aus dem Beitrag 
Beitrag "Re: SSD1306 Library zum Darstellen von Text auf OLED Displays" noch aktuell? Falls 
nicht, wo kann ich die aktuelle Version finden?

von Marco H. (damarco)


Lesenswert?

Da muss ich dich leider eines besseren belehren ;) Der RAM Verbrauch der 
u8g2 lib lässt sich beeinflussen. das mit der Memory Konfiguration, man 
kann auch nur eine ROW bzw. Page als Buffer benutzen.

Ein kleines Problem von einigen Controller ist leider das man nicht im 
RAM Zeichnen kann, da sie keinen Refresh Command besitzen. Heißt das 
dies sofort sichtbar wird und womit der Display Buffer nötig wird um 
Overlays etc. zu erzeugen.

Das schöne an der Lib ist wenn man es erst mal geschafft hat einen 
Displaytreiber zu schreiben es portierbar funktioniert. Bei vielen libs 
muss man oft die Display Konfiguration oder die Ausgabe anpassen.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Marco H. schrieb:
> Da muss ich dich leider eines besseren belehren

Wenn den eigentlich?  Der Thread ruht seit mehr als 2 Monaten in der
Kiste, und auf die Frage, die wirklich neu gestellt worden ist,
beziehst du dich ja ganz offensichtlich nicht.

Wenn man sich nicht auf den Beitrag direkt darüber bezieht, sollte man
besser den Beitrag zitieren, zu dem man etwas antworten möchte.  So
steht deine Wortmeldung ziemlich zusammenhanglos im Raum.

von Stefan P. (form)


Lesenswert?

Daniel R. schrieb:
> Leider Bekomme ich beim Compilieren immer den fehler:
>
> "undefined reference to `lcd_gotoxy(unsigned char, unsigned char)"
>
> Dieser Fehler tritt bei jeder Funktion auf.

Darüber bin ich auch gestolpert.
Hast Du auch einen anderen AVR verwendet? Dann bedarf es in der 
lcd_gfx.c einer Änderung:

Alt:
1
#if defined (__AVR_ATmega328P__)
2
void i2c_init(void){
3
...
4
#endif

Neu:
1
#if defined (__AVR_ATmega328__) || defined (__AVR_ATmega328P__) || defined (__AVR_ATmega324A__) || defined (__AVR_ATmega324P__) || defined (__AVR_ATmega324PA__) || defined (__AVR_ATmega644__) || defined (__AVR_ATmega644A__) || defined (__AVR_ATmega644P__) || defined (__AVR_ATmega644PA__) || defined (__AVR_ATmega1284P__)
2
3
void i2c_init(void){
4
...
5
6
#else
7
#error "Unsupported AVR!"
8
#endif

von M. K. (sylaina)


Lesenswert?

Ich habe die beiden Libraries zu einer Library zusammengefasst und ein 
github dazu erstellt. Die aktuelle Version ist jetzt zu finden unter:

https://github.com/Sylaina/oled-display.git

Ich werde auch noch einen freundlichen Moderator fragen, ob er mir den 
Link in den Startpost stellen kann.

von viking (Gast)


Angehängte Dateien:

Lesenswert?

Hallo Michael,
kann es sein, dass bevor der Buffer zum Display gesendet wird zuerst die 
Adresse zuvor mit lcd_gotoxy(0,0) auf die Startadresse gesetzt werden 
muss?

Bei meinem Display erschien der Text zu weit unten und die Linie wurde 
im oberen Bereich weiter gezeichnet. Im reinen Textmodus schie das 
Problem nicht zu geben.
1
int main(void){
2
  lcd_init(LCD_DISP_ON);    // init lcd and turn on
3
  lcd_gotoxy(0,0); 
4
  lcd_puts("Hello World");  // put string from RAM to display (TEXTMODE) or buffer (GRAPHICMODE)
5
  lcd_gotoxy(0,2);          // set cursor to first column at line 3
6
  lcd_puts_p(PSTR("String from flash"));  // puts string form flash to display (TEXTMODE) or buffer (GRAPHICMODE)7
7
  lcd_gotoxy(0,3);
8
  lcd_puts_p(PSTR("Test!!!"));
9
  
10
#if defined GRAPHICMODE
11
  lcd_drawCircle(64,32,7,WHITE); // draw circle to buffer white lines
12
  lcd_drawLine(0,0,127,63,WHITE); 
13
  lcd_display();                 // send buffer to display
14
  lcd_set_contrast(50);
15
#endif 
16
  for(;;){
17
    //main loop
18
  }
19
  return 0;
20
}

ich habe probeweise lcd_gotoxy(0,0); vor dem lcd_display() in main 
eingefügt und es hat funktioniert!
1
lcd.c...
2
void lcd_display() {
3
#if defined SSD1306
4
    lcd_gotoxy(0,0); //neu!
5
    lcd_data(displayBuffer, sizeof(displayBuffer));
6
#elif defined SH1106
7
    for (uint8_t i=0; i < DISPLAY_HEIGHT/8; i++) {
8
        lcd_gotoxy(0, i);
9
        uint8_t actualLine[DISPLAY_WIDTH];
10
        for (uint8_t j=0; j < DISPLAY_WIDTH; j++) {
11
            actualLine[j]=displayBuffer[i*DISPLAY_WIDTH+j];
12
        }
13
        lcd_data(actualLine, sizeof(actualLine));
14
    }
15
#endif

von M. K. (sylaina)


Lesenswert?

viking schrieb:
> Hallo Michael,
> kann es sein, dass bevor der Buffer zum Display gesendet wird zuerst die
> Adresse zuvor mit lcd_gotoxy(0,0) auf die Startadresse gesetzt werden
> muss?

Hast du die aktuelle Version von github geladen (siehe Eröffnungspost)?
Es wäre auf jeden Fall ein Fehler, das sollte nicht passieren. Ich werde 
mir das daheim anschaun, es kann durchaus sein, dass da noch Fehler drin 
sind. Die werde ich dann natürlich beheben. Danke für deine Rückmeldung.

Edit: Ich hab grad bei github geschaut und ja, du hast recht. Irgendwie 
ist das von dir eingefügte gotoxy bei der github-Version verloren 
gegangen. Das lcd_gotoxy(0,0) gehört da auf jeden Fall hin.

: Bearbeitet durch User
von M. K. (sylaina)


Lesenswert?

Problem ist behoben, danke nochmal für den Hinweis, viking

von viking (Gast)


Lesenswert?

M. K. schrieb:
> Hast du die aktuelle Version von github geladen (siehe Eröffnungspost)?
> Es wäre auf jeden Fall ein Fehler, das sollte nicht passieren.

Hallo Michael,

ja hab ich direkt von github heruntergeladen.

von viking (Gast)


Lesenswert?

da fehlt noch ein ";"
in
1
...
2
void lcd_display() {
3
#if defined SSD1306
4
lcd_gotoxy(0,0)
5
...

von M. K. (sylaina)


Lesenswert?

Das hab ich jetzt davon, dass ichs mit nem iPad editiert hatte...gefixt 
;)

von Welle 🧐 S. (w3llschmidt)


Lesenswert?

Blöde Frage, würde das auch auf einem ESP8266/32 laufen?

von Stefan F. (Gast)


Lesenswert?

> Blöde Frage, würde das auch auf einem ESP8266/32 laufen?

Das weiss ich nicht, aber auf dem ESP8266 kannst du auf jeden Fall die 
Libraries von Adafruit nutzen: 
https://github.com/adafruit/Adafruit_SSD1306 + 
https://github.com/adafruit/Adafruit-GFX-Library

Die sind mir persönlich aber zu Speicher-Hungrig, deswegen habe ich 
meine eigene Variante mit weniger Grafik-Schnickschnack geschrieben: 
http://stefanfrings.de/esp8266/WIFI-Kit-8-Test2.zip

Meine Variante benutzt digitalWrite() um die Pins "zu Fuß" als I²C Bus 
zu toggeln, deswegen müsste das theoretisch mit jedem Arduino Core 
klappen. Getestet habe ich es aber nur mit dem ESP8266.

von M. K. (sylaina)


Lesenswert?

W3ll S. schrieb:
> Blöde Frage, würde das auch auf einem ESP8266/32 laufen?

Wenn du die I2C-Routinen (siehe dazu die I2C-Lib, also i2c.c anpassen) 
für den ESP8266 entsprechend anpasst läuft die Library auch auf einem 
ESP8266. Die Grafik-Library an sich ist sehr allgemein gehalten.

von Dennis (Gast)


Lesenswert?

Hallo,
bin gerade über diese nette Library gestolpert.

Kann man mit dieser Library auch größere Buchstaben auf das Display 
zeichnen, oder nur in der Größe 6x8?


Gruß

von M. K. (sylaina)


Lesenswert?

Aktuell ist nur 6x8 implementiert. Ich bin dabei einen größeren Font 
(doppelte Größe) zum Implementieren, das ist aber noch in der 
Entwicklung und nicht vorzeigbar.

von Stefan F. (Gast)


Lesenswert?

Ich habe in meinem eigenen Code einfach die Pixel in Höhe und Breite 
verdoppelt, um Speicherplatz für den größeren Font zu sparen. Das sieht 
trotzdem nicht schlecht aus.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Größere Bitmap-Fonts sollte man doch problemlos bei X11 finden.  Die
dürften von der Lizenz her auch frei verwendbar sein, also entweder
public domain oder MIT-Lizenz oder dergleichen.

von Jan K. (madengineer)


Lesenswert?

Alternativ direkt hier im Forum schauen ;-)
Beitrag "LCD Schriftarten ( Fonts in veschiedenen Größen )"

von J. W. (skorpi08)


Lesenswert?

Ich bekomme die Lib nicht zu laufen.
Was ich geändert hab:
1
/* TODO: define displaycontroller */
2
#define SSD1306                              //SH1106 or SSD1306, check datasheet of your display
3
/* TODO: define displaymode */
4
#define TEXTMODE  
5
#define LCD_I2C_ADR     0x3C// 0x7A
1
#include <lcd.h>
2
void setup(){
3
  lcd_init(LCD_DISP_ON);    // init lcd and turn on
4
  lcd_puts("Hello World");  
5
  lcd_gotoxy(0,2);          // set cursor to first column at line 3
6
  lcd_puts_p(PSTR("String from flash"));
7
}
8
void loop(){}
Oder muss man da noch was ändern?

: Bearbeitet durch User
von M. K. (sylaina)


Lesenswert?

Die I2C-Adresse ist sicher richtig? Und hast du ein Oszi? Dann prüfe 
direkt an den Pins des Displays ob der Clock und auch Data richtig 
ankommt. Hab mir letztens einen Wolf gesucht...Clock und Data waren 
vertauscht.

: Bearbeitet durch User
von J. W. (skorpi08)


Lesenswert?

Oszi hab ich nicht.
Adresse stimmt, habs mit Wire.h mit dieser Lib halbwegs hinbekommen.
Frisst dann nur viel mehr Speicher.
Ich nutze den Atmega324PA.

Muss ich denn bei i2c.h und i2c.c was ändern?

von Stefan F. (Gast)


Lesenswert?

> Oszi hab ich nicht.

Dann kaufe Dir mal einen Logic Analyzer, das kann sehr hilfreich sein.
https://www.amazon.de/AZDelivery-Logic-Analyzer-kompatibel-Version/dp/B01MUFRHQ2/ref=sr_1_1?ie=UTF8&qid=1518864765&sr=8-1&keywords=logic+analyzer&dpID=51jjYdOKLLL&preST=_SY300_QL70_&dpSrc=srch

Die Software dazu kannst du bei der Firma Saleae herunterladen.

von M. K. (sylaina)


Lesenswert?

J. W. schrieb:
> Oszi hab ich nicht.
> Adresse stimmt, habs mit Wire.h mit dieser Lib halbwegs hinbekommen.
> Frisst dann nur viel mehr Speicher.
> Ich nutze den Atmega324PA.
>
> Muss ich denn bei i2c.h und i2c.c was ändern?

In der i2c.h werden die Einstellungen für I2C ansich gemacht, z.B. die 
Clock eingestellt.
Kann du eine serielle Kommunikation zum Computer aufbauen? Wenn ja dann 
lasse dir mal den I2C_ErrorCode übermitteln, daraus lassen sich ggf. 
Rückschlüsse ziehen wo es nicht klappt.

Falls du keine serielle Kommunikation aufbauen kannst: Hast du ein paar 
LEDs und Widerstände? Dann machen wir mal Debugging für Anfänger ;)

von J. W. (skorpi08)


Lesenswert?

Oszi würde mir erstmal nichts bringen, damit kenn ich mich noch garnicht 
aus.

Am Serial hab ich nen MAX485 hängen, Serial1 wäre frei.
LEDs und Taster hab ich noch an dem Atmega angeschlossen.

Am Serial wird nichts angezeigt:

#include "lcd.h"

void setup(){
Serial.begin( 19200 );
  pinMode(23,OUTPUT);  digitalWrite(23,1);
  lcd_init(LCD_DISP_ON);    // init lcd and turn on
  lcd_puts("Hello World");  // put string from RAM to display (TEXTMODE) 
or buffer (GRAPHICMODE)
  lcd_gotoxy(0,2);          // set cursor to first column at line 3
  lcd_puts_p(PSTR("String from flash"));  // puts string form flash to 
display (TEXTMODE) or buffer (GRAPHICMODE)


}

void loop(){
  Serial.write(I2C_ErrorCode);
}

: Bearbeitet durch User
von M. K. (sylaina)


Lesenswert?

Der I2C_ErrorCode ist auch ein uint8_t. Ich schätze mal, dass 
Serial.write() aber einen String haben will bzw. den Parameter als 
String interpretieren wird. Versuche es mal mit folgenden Loop
1
#include <stdlib.h> // fuer itoa()
2
...
3
void setup(){
4
  ...
5
}
6
...
7
void loop(){
8
  char errorCode[4];
9
  itoa(I2C_ErrorCode, errorCode, 10); // wandelt den ErrorCode in einen String um
10
  Serial.write("ErrorCode: ");
11
  Serial.write(errorCode);  // der eigentliche Errorcode
12
  Serial.write("\r\n"); // Zeilenumbruch fuer die Anzeige
13
}

: Bearbeitet durch User
von J. W. (skorpi08)


Lesenswert?

Jup, Error 0

von Stefan F. (Gast)


Lesenswert?

Wenn du gar nicht klar kommst hilft vielleicht meine alternative Library 
http://stefanfrings.de/esp8266/WIFI-Kit-8-Test2.zip.

Ich habe das Programm nur auf einem ESP8266 Modul ausprobiert. 
Theoretisch müsste es aber auch mit deinem AVR funktionieren. Du musst 
nur die Pin Nummern ganz oben bei "OLED display=OLED(4,5,16);" anpassen. 
Eventuell musst du noch die I2C Adresse als weiteren Parameter 
hinzufügen. Siehe dazu meine Kommentare in der oled.h.

von M. K. (sylaina)


Lesenswert?

J. W. schrieb:
> Jup, Error 0

Hm, d.h. dass die i2c-Kommunikation funktioniert hat. Und du hast nicht 
noch irgendwo auf GRAPHICMODE umgestellt?
Versuche am Ende der setup() mal ein lcd_display();. Eigentlich sollte 
das ein Fehler werfen, wenn nicht hast du irgendwo auf den Grafikmode 
umgestellt.

von J. W. (skorpi08)


Lesenswert?

oled-display:11: error: 'lcd_display' was not declared in this scope
 lcd_display();
             ^
exit status 1
'lcd_display' was not declared in this scope

von M. K. (sylaina)


Lesenswert?

Hm, dann bist du im richtigen Mode (TEXTMODE). Eigentlich sollte das 
Display an gehen und den Text zeigen. Bist du sicher, dass die setup() 
auch ausgeführt wird? Setz am Ende mal den Errorcode manuell auf 18 
(oder nen anderen Wert von 1-255). Diesen Wert müsstest du dann auch 
über die Serielle Schnittstelle bekommen, wenn nicht wird dein setup() 
erst gar nicht ausgeführt.

von J. W. (skorpi08)


Lesenswert?

12 zeigt mir auch im SerialMonitor an.
Ich schick die Daten über RS485, nur so am rande.

#include "lcd.h"

void setup(){
Serial.begin( 19200 );
  pinMode(23,OUTPUT);  digitalWrite(23,1);
  lcd_init(LCD_DISP_ON);    // init lcd and turn on
  lcd_puts("Hello World");  // put string from RAM to display (TEXTMODE) 
or buffer (GRAPHICMODE)
  lcd_gotoxy(0,2);          // set cursor to first column at line 3
  lcd_puts_p(PSTR("String from flash"));  // puts string form flash to 
display (TEXTMODE) or buffer (GRAPHICMODE)

  I2C_ErrorCode=12;

  Serial.print(I2C_ErrorCode);
  Serial.write("\r\n"); // Zeilenumbruch fuer die Anzeige
}

void loop(){
  Serial.print(I2C_ErrorCode);
  Serial.write("\r\n"); // Zeilenumbruch fuer die Anzeige
  delay(5000);
}

von M. K. (sylaina)


Lesenswert?

Dann bin ich leider überfragt. Wenn der Errorcode 0 bleibt (ist bei dir 
ja anscheinend so) und der setup() auch ausgeführt wird (was ja durch 
die 12 bestätigt ist) dann hat die Kommunikation mit dem Display 
funktioniert und du müsstest eigentlich was angezeigt bekommen.

von M. K. (sylaina)


Lesenswert?

Ich nehme an, du verwendest einen Arduino. Ich werd heute Abend oder 
morgen Früh daheim mal was testen, hab hier grad keinen Arduino zur 
Hand.

von J. W. (skorpi08)


Angehängte Dateien:

Lesenswert?

Arduino hat kein Atmega324PA, ich verwende aber die Arduino IDE.
So sieht die i2c.h aus:

/* TODO: setup i2c/twi */
#define F_I2C      100000UL// clock i2c
#define PSC_I2C      1    // prescaler i2c
#define SET_TWBR    (F_CPU/F_I2C-16UL)/(PSC_I2C*2UL)

Im Anhang hab ich die ohne deiner i2c.h probiert, dafür dann mit Wire.h 
von Arduino. Allerdings sind da noch punkte rechts neben dem Text.

Fuses sollten ja passen, 16 Mhz Quarz.


EDIT:
Jetzt bekomme ich Error 5, keine ahnung was ich geändert hab.

: Bearbeitet durch User
von M. K. (sylaina)


Lesenswert?

ErrorCode 5 bedeutet schon mal, dass der Start fehlgeschlagen ist, 
sprich die Kommunikation mit dem I2C hat nicht geklappt (dafür steht das 
erste Bit im ErrorCode). Die 4 steht dafür, dass das Übertragen des 
Bytes nicht geklappt hat (ist das dritte Bit in ErrorCode, vgl. auch 
i2c.h).

Ich hab grade aus meinem github noch mal die Library herunter geladen 
weil ich dachte, ich hab vielleicht noch nen Fehler drin, und sie 
einfach Übersetzen lassen und hoch geladen auf einen Atmega328pn (make 
flash). Das hat sofort fehlerfrei geklappt. Umgestellt auf Textmode mit 
dem Ergebnis auch das klappt auf Anhieb. Die Library ist in C 
geschrieben, ich weis leider nicht ob man C++ noch irgendwie sagen muss, 
dass es eine C Library ist. Ich denke aber, der Fehler liegt nicht in 
der Library sondern wie sie eingebunden wird. Weis z.B. auch der Linker 
was er damit machen soll, welches Encoding er benutzen soll usw.?

von J. W. (skorpi08)


Lesenswert?

extern "C" {
#include "i2c.h"
}

Ich denke mal irgendwie so wirds eingebunden.
Gibts aber immer noch Fehlermeldungen mit den ich nix anfangen kann.

von J. W. (skorpi08)


Lesenswert?

Stefan U. schrieb:
> Theoretisch müsste es aber auch mit deinem AVR funktionieren.

Es funktioniert auch, auf den Pins D4 und D5.
Also ist es eine SoftI2C-OLED-Lib

von Stefan F. (Gast)


Lesenswert?

Ja, ich habe mich für das soft-I²C entschieden, um beliebige Pins 
verwenden zu können. Beim ESP8266 (für den ich das geschrieben hatte) 
gibt es ohnehin keinen freien I²C in Hardware.

von M. K. (sylaina)


Lesenswert?

So, ich bin nun noch mal dazu gekommen das Ganze mit Arduino zu testen 
und es funktioniert problemlos. Die Libraries (aus dem Github geladen) 
für das LCD und I2C habe ich in den Projektordner kopiert.
1
extern "C" {
2
  #include "lcd.h"
3
}
4
5
void setup() {
6
  // put your setup code here, to run once:
7
  lcd_init(LCD_DISP_ON);    // init lcd and turn on
8
  
9
  lcd_puts("Hello World");  // put string from RAM to display (TEXTMODE) or buffer (GRAPHICMODE)
10
  lcd_gotoxy(0,2);          // set cursor to first column at line 3
11
  lcd_puts_p(PSTR("String from flash"));  // puts string form flash to display (TEXTMODE) or buffer (GRAPHICMODE)
12
#if defined GRAPHICMODE
13
  lcd_drawCircle(64,32,7,WHITE); // draw circle to buffer white lines
14
  lcd_display();                 // send buffer to display
15
#endif
16
}
17
18
void loop() {
19
  // put your main code here, to run repeatedly:
20
21
}

Der Sketch belegt 2344 Bytes (GRAPHICMODE, als Vergleich: der gleiche 
Code nur in C wie im github-Beispiel belegt lediglich 1884 Bytes).

Wichtig ist, dass man
1
extern "C" {
2
  #include "lcd.h"
3
}
schreibt. Schreibt man
1
#include "lcd.h"
meckert u.a. der Linker, dass er die jeweiligen Referenzen auf die 
einzelnen Funktionen (z.B. lcd_init()) nicht auflösen kann.

Ein weiteres Manko ist, dass man dem Compiler/Linker auch noch irgendwie 
beibringen muss, welchen Charset er für die Quellcode-Dateien verwenden 
soll. Es wird nämlich beim ersten Compilieren u.a. vor den Umlauten 
(ä,ö,ü usw.) gewarnt, diese sind auch nicht verarbeitet, d.h. versucht 
man z.B. ein ä aufs Display zu bringen erscheint schlicht nichts. In 
meinem Makefile steht deshalb
1
CFLAGS += -finput-charset=utf-8 -fexec-charset=iso-8859-15
drin, wo und wie man das bei Arduino angibt weis ich allerdings nicht 
aber dazu findet sich sicher auch hier im Forum Hilfe ;)

: Bearbeitet durch User
von J. W. (skorpi08)


Lesenswert?

Ich hab noch einige andere Librarys getestet, bei den wird maximal 4% 
RAM belegt.
Bei deiner werden 50% fürs Hello World benötigt, das ist ein Grund warum 
ich mich noch nicht für deine Lib sicher entscheiden kann.
Kannst du da noch was machen?

main.c funktioniert in der Arduino IDE natürlich auch.

von M. K. (sylaina)


Lesenswert?

J. W. schrieb:
> Ich hab noch einige andere Librarys getestet, bei den wird maximal 4%
> RAM belegt.
> Bei deiner werden 50% fürs Hello World benötigt, das ist ein Grund warum
> ich mich noch nicht für deine Lib sicher entscheiden kann.

Du kannst meine Libary auch auf Textmodus umstellen (siehe lcd.h) wenn 
du nur Text ausgeben möchtest aber nicht Zeichnen willst. Dann benötigt 
sie auch nicht so viel RAM (grade mal 2 Byte wenn ich das noch recht in 
Erinnerung habe). Im Grafik-Modus benötigt sie die Display-Größe als 
Speicher im RAM da ja via I2C der SSD1306/SH1106 nicht ausgelesen werden 
kann was dann aber schon beim Zeichnen eines Diagrams recht schwierig 
bis unmöglich wird.
Ich nehme mal an die Library, die du jetzt benutzt, läuft auch nur im 
Textmodus. Zumindest ist mir kein Lib bekannt, die bei diesen 
Controllern im Grafikmodus keinen RAM in Größe des Displays als Puffer 
vorhalten. Daher hatte ich diese Lib ja geschrieben da ich so ein 
Display an einem Atmega 8 einsetzen wollte zur Textanzeige aber das mit 
den Libs, die ich damals fand, nicht ging wegen des Puffers. ;)

von Stefan F. (Gast)


Lesenswert?

Prinzipiell kann man Grafik auch ohne Pufferspeicher ausgeben. Aber man 
muss immer 8 Bits (vertikal untereinander) gleichzeitig schreiben.

Wenn ich nun z.B. ganz oben eine horizontale Linie zeichnen will, und 
dann 4 Pixel Tiefer noch eine, wird es kompliziert. Beim Zeichnen der 
zweiten Linie muss ich zwangsläufig die Bits der ersten Linie 
überschreiben.

Damit dabei die erste Linie nicht verloren geht, müsste ich den Speicher 
lesen können, das geht bei I²C aber nicht.

Unterm Strich bedeutet das, man kann immer nur 8 Pixel-Reihen am Stück 
beschreiben. Text und Bitmaps kann man auf diese Weise problemlos im 
8-Linien Raster ausgeben, aber das Zeichnen von geometrischen Figuren 
wird ohne Pufferspeicher extrem kompliziert.

von M. K. (sylaina)


Lesenswert?

Stefan U. schrieb:
> Text und Bitmaps kann man auf diese Weise problemlos im
> 8-Linien Raster ausgeben, aber das Zeichnen von geometrischen Figuren
> wird ohne Pufferspeicher extrem kompliziert.

Deswegen schrieb ich oben schwierig bis unmöglich: Text& Bitmaps gehen 
noch ohne Pufferspeicher (wobei ich grade die Bitmap-Funktion mit 
Pufferspeicher implementiert habe ;)) aber beliebige, geometrische 
Figuren bzw. beliebige Graphen gehen ohne Pufferspeicher schlicht nicht.

: Bearbeitet durch User
von J. W. (skorpi08)


Lesenswert?

Habe so ein OLED, in weiß. Damals gabs da keine Auswahl und die waren 
ohne Versandkosten.
https://de.aliexpress.com/item/-/32717936245.html

Die Lib grad neu geladen.
I2C Scanner sagt dass es die 3C Adresse ist, mit anderen Libs läufts 
auch, Verkabelung muss dann ja auch passen.
1
/* TODO: define displaycontroller */
2
#define SSD1306                              // or SSD1306, check datasheet of your display
3
/* TODO: define displaymode */
4
#define GRAPHICMODE                         // TEXTMODE for only text to display,
5
                                            // GRAPHICMODE for text and graphic
6
7
#define LCD_I2C_ADR    0x3C
1
extern "C"{
2
  #include "lcd.h"
3
}
4
5
void setup() {
6
  lcd_init(LCD_DISP_ON);    // init lcd and turn on
7
  lcd_puts("Hello Wuüorld");  // put string from RAM to display (TEXTMODE)
8
  lcd_gotoxy(0, 2);         // set cursor to first column at line 3
9
  lcd_puts_p(PSTR("String from flash"));  // puts string form flash to
10
}
11
void loop() {}

Und das Display bleibt immer noch schwarz.
Hab jetzt den Arduino UNO, mit USBasp programmiert.

von M. K. (sylaina)


Lesenswert?

Hast du das Display umkonfiguriert? Das wird default-mäßig als 
SPI-Display ausgeliefert, so les ich das oben nämlich, sie Anleitung 
dazu.

Wenn du es als I2C schon umgelötet hast: Kannst du mal dein Arduino 
Projektordner für das Display mit dem kompletten Code zippen und hier 
einem Beitrag anhängen? Ich kann hier nämlich absolut keinen Fehler 
feststellen, auch mit der Arduino IDE. Ich habs jetzt mit verschiedenen 
SSD1306 und SH1106 Display getestet, die laufen alle perfekt an.

von J. W. (skorpi08)


Angehängte Dateien:

Lesenswert?

Wo wie was konfigurieren? Das Display ist ein I2C, wie auf den Bildern 
mit SDA, SCL, VCC und GND. Da muss man nix mehr löten.
Läuft ja mit anderen I2C Libs.

von M. K. (sylaina)


Lesenswert?

Habs mir runtergeladen und compiliert bzw. versucht, Arduino IDE meldet 
sofort beim Übersetzen den folgenden Fehler:

/Users/michael/Downloads/oled-display-master-2/examples/oled-display/ole 
d-display.ino:2:19:  fatal error: lcd.h: No such file or directory
   #include "lcd.h"

Das liegt daran, dass die Library einige Dateiebenen höher liegt, durch 
das
1
extern "C" {
2
  #include "lcd.h"
3
}
wird aber erwartet, dass die Library in der selben Dateiebenen liegt wie 
die .ino. Ich hab die Library (lcd.h, lcd.c, i2c.h und i2c.c) einfach 
mal ins Verzeichnis der .ino kopiert und schon wirds fehlerfrei 
übersetzt und das Display zeigt auch was an ;)

: Bearbeitet durch User
von J. W. (skorpi08)


Angehängte Dateien:

Lesenswert?

auch so läuft es nicht.

Man kann es auch so einbinden, dann wirds in dem ganzem Library Ordner 
nach lcd21.h gesucht.
1
extern "C" {
2
  #include <lcd21.h>
3
}

: Bearbeitet durch User
von M. K. (sylaina)


Angehängte Dateien:

Lesenswert?

Wie gesagt, ich kann den Fehler hier nicht reproduzieren. Weder als 
lokale Library (vgl. Dateianhang) noch als globale Library, bei mir 
läuft das stets problemlos an. OK, ich hab noch nicht geschaut wie man 
in der Arduino IDE dem Compiler sagen kann, dass er das charset 
iso-8859-15 bei den Dateien verwenden soll (ist für all die tollen, 
deutschen, Sonderzeichen wie ä,ö,ü usw.) aber sonst: fehlerfrei.

von J. W. (skorpi08)


Lesenswert?

Bei mir ist GND links (aussen), bei deinem ist VCC aussen.
Ist also schon mal ein anderes Display.
Ist mir nur aufgefallen, vielleicht hats ja nichts zu bedeuten.
Alle anderen Libs funktionieren, hab einige getestet
https://forum.arduino.cc/index.php?topic=529600.msg3610291#msg3610291

von M. K. (sylaina)


Lesenswert?

Das Bild ist von einem SH1106 (1.3"), bei meinem SSD1306 (0.96") ist 
auch GND außen ;)

von Johannes S. (Gast)


Lesenswert?

J. W. schrieb:
> Habe so ein OLED, in weiß. Damals gabs da keine Auswahl und die
> waren ohne Versandkosten.
> https://de.aliexpress.com/item/-/32717936245.html


Auf dem Bild sieht man R3/4 als 0R Widerstände, damit kann man eventuell 
SPI/I2C oder die I2C Adresse umstellen.

von M. K. (sylaina)


Lesenswert?

Das hatte ich ja weiter oben schon mal angefragt ob das Display in I2C 
konfiguriert ist oder auf SPI. Anscheinend ist es auf die I2C 
konfiguriert wenn die anderen Libraries funktionieren. Daher denke ich 
auch das ist kein Problem mit dem Wirering ist.

von J. W. (skorpi08)


Lesenswert?

Ich denke eher das ist für die I2C Adresse, nicht für SPI. Ist nur ne 
Vermutung, nicht weiter damit befasst.

von M. K. (sylaina)


Lesenswert?

Du denkst? Bist aber nicht sicher?

: Bearbeitet durch User
von J. W. (skorpi08)


Lesenswert?

Ich hab 2 Displays bestellt, 1 SPI und 1 I2C.
Beim SPI sind mehr Pins, deshalb dachte ich es ist schon richtig mit dem 
I2C.

von M. K. (sylaina)


Lesenswert?

Naja, bei mir lässt sich der Code problemlos übersetzen und das Display 
läuft problemlos. Vielleicht versuchst du mal als Adresse die 0x78 oder 
die 0x7A ggf. ist deine ermittelte Adresse nicht richtig.

von J. W. (skorpi08)


Lesenswert?

Unfassbar. Problem gelöst. Wieso kommst auch nicht früher mit der 
Adresse 0x78? :D

Die Frage bleibt jetzt aber, warum es bei anderen mit 0x3C läuft und mit 
deiner mit 0x78.

Jetzt weiß ich auch was ihr mit konfigurieren meint.
Hab das SPI Display ausgepackt und die Widerstände angeschaut, R3 und R4 
sind gelötet. Bei dem I2C Display sind R1, R4 und R8 gelötet.
Mal davon abgesehen dass die Platinen verschieden sind und bei SPI 
Version noch RES, DC und CS Pins vorhanden sind.
Habs mal auf I2C umgelötet, also R1, R4 und R8 gebrückt, I2C Scanner 
erkennt den nicht.

von Johannes S. (Gast)


Lesenswert?

Das Problem ist so alt wie I2C selbst, schiebe mal 0x78 um ein Bit nach 
rechts.
Beitrag "Re: Kann mir bitte wer beim USI-TWI helfen?"

Beitrag #5322585 wurde vom Autor gelöscht.
von M. K. (sylaina)


Lesenswert?

Johannes S. schrieb:
> Das Problem ist so alt wie I2C selbst, schiebe mal 0x78 um ein Bit nach
> rechts.
> Beitrag "Re: Kann mir bitte wer beim USI-TWI helfen?"

Das ist ein interessanter Beitrag, das war mir so auch nicht bewusst. 
Ich hab die lcd.h an der Stelle, an der die Adresse angegeben wird, 
entsprechend mit einem Kommentar versehen.
Die Displays, die ich hier hab, haben halt alle die Adresse nach dem 
Slave-Mode angegeben.

von Nico W. (nico_w)


Lesenswert?

J. W. schrieb:
> #define LCD_I2C_ADR     0x3C// 0x7A

Ich glaube nicht das 0x3C richtig ist.
Versuch es mal mit 0x78.
1
(0x3C << 1)

von J. W. (skorpi08)


Lesenswert?

Ich glaub auch nicht dass es richtig ist, bei dieser Lib.

von Nico W. (nico_w)


Lesenswert?

Je nach Lib ist das halt ein wenig unterschiedlich.

Die Adresse wird um 1 nach links geschoben. Im ersten Bit steht dann bei 
der Übermittlung der Adresse, ob gelesen oder geschrieben werden soll.

von M. K. (sylaina)


Lesenswert?

Richtig, bei der Adresse erwartet meine Library die 8-Bit Adresse. Da 
das SSD1306 bzw das SH1106 bei I2C nicht gelesen werden kann macht es 
keinen Sinn hier die 7-Bit Adresse anzugeben sodass die Library selbst 
zwischen Lesen und Schreiben wählen könnte. Wie gesagt, diese 
Information habe ich heute Morgen dem Quellcode als Comment hinzugefügt 
;)

von Sebastian (Gast)


Lesenswert?

Hallo und vorab eine echt gute Library!

Eine Frage. Gibt es eine Option das man den Text z.b. Zentrieren kann?

Ich muss mich nun erstmal damit auseinander setzen :) vielen Dank für 
eine Info schon mal ob es schon vielleicht möglich ist.

Verwende im übrigen ein SD1306


Gruß Sebastian

von M. K. (sylaina)


Lesenswert?

Hallo Sebastian,

ein Funktion zum Zentrieren ist nicht enthalten. Da könnte man mit der 
strlen-Funktion aus der string.h arbeiten.

von Fabian G. (fabian_g)


Angehängte Dateien:

Lesenswert?

Hi M. Köhler

Erstmal danke für die Library.
Leider funktioniert bei mir gar nichts.

Ich verwende ein 128x32 OLED mit SSD1306. Dieses steuere ich mit einem 
ATmega 644p mit 20MHz an.

Ich habe deinen Code von GitHub heruntergeladen und die nötigen 
Anpassungen vorgenommen(angehängt) und eine Codezeile hinzugefügt:
1
#if defined(__AVR_ATmega328P__) || defined(__AVR_ATmega168P__) || defined(__AVR_ATmega88P__) || defined(__AVR_ATmega48P__) || defined(__AVR_ATmega1284P__) || defined(__AVR_ATmega644P__)

Es zeigt mir nichts am OLED an. Ich nehme an ich habe die Hardware 
richtig verdrahtet.

SDL von Atmega->SCK des OLED mit 4.7kOhm Pull-Up
SDA von Atmega->SDA des OLED mit 4.7kOhm Pull-Up
VCC->5V

Kannst du mit weiterhlefen?

EDIT: habe ausversehen zweimal das gleiche Bild angehängt

Mit freundlichen Grüssen
Fabian

: Bearbeitet durch User
von M. K. (sylaina)


Lesenswert?

Packe mal dein Projekt in ein ZIP-File und lade es hier hoch, dann schau 
ich es mir heute Abend an, vorher komme ich leider nicht dazu da ich 
grade unterwegs bin.

von Stefan F. (Gast)


Lesenswert?

Schließe mal LEDs (mit 2,2k oder 4,7k) Vorwiderstand parallel zu den 
Pull-up Widerständen an und schaue, ob sie beide flackern.

Am besten kann man was sehen, wenn man die Übertragung erheblich 
verlangsamt.

Hast du einen Logic Analyzer? Falls nicht wäre jetzt der richtige 
Moment, sich einen anzuschaffen. Zur Analyse von I²C Problemen sind die 
Dinger Top und kosten nicht mehr als 15 Euro.

von Fabian G. (fabian_g)


Angehängte Dateien:

Lesenswert?

Vielen Dank für die schnellen Antworten.

Ich habe mein Programm angehängt.
Wir haben, glaube ich, irgendwo noch so ein Logic Analyzer. Mal schauen, 
ob ich mit diesem etwas herausfinde.
Aber ich glaube das Problem ist, dass er gar nicht zum senden kommt.

Mit freundlichen Grüssen
Fabian

von Dieter F. (Gast)


Lesenswert?

Möglicherweise ein "déjà vu" ? (Hatten wir heute schon mal)

JTAG-Fuse aktiv?

von Stefan F. (Gast)


Lesenswert?

> Aber ich glaube das Problem ist, dass er gar nicht zum senden kommt.

Glauben ist nicht Wissen. Die Aussage ist nicht dumm, aber sie sollte 
überprüft werden. Deswegen ja mein Vorschlag mit den LEDs.

Mit einem Debugger kannst du herausfinden, ob und wo das Programm hängt. 
Hast du das wenigstens gemacht?

von M. K. (sylaina)


Lesenswert?

Fabian G. schrieb:
> Vielen Dank für die schnellen Antworten.
>
> Ich habe mein Programm angehängt.
> Wir haben, glaube ich, irgendwo noch so ein Logic Analyzer. Mal schauen,
> ob ich mit diesem etwas herausfinde.
> Aber ich glaube das Problem ist, dass er gar nicht zum senden kommt.
>
> Mit freundlichen Grüssen
> Fabian

Ich hab mir den Code angeschaut und das sieht alles soweit OK aus.

Es fällt zunächst mal auf, dass du noch eine ältere Version der Lib 
benutzt. Dennoch sollte auch diese laufen.

Die Adresse des Displays ist im 7-Bit-Mode angegeben, hast du auch mal 
versucht die Adresse im 8-Bit-Mode anzugeben (also statt 0x3c 0x78 
angeben? Und ist die Adresse auch sicher die richtige?

Und zu guter letzt: Läuft dein uC auch wirklich mit 20 MHz? Fuses alle 
richtig gesetzt? In meiner Anfangszeit hab ich z.B. gerne vergessen die 
DIV8-Fuse auszumachen => Hello World der uCs mal programmieren und 
Zeiten kontrollieren
1
//Hello World der uCs
2
#include <avr/io.h>
3
#include <util/delay.h>
4
void main void {
5
  DDRB |= (1 << PB1);
6
  for(;;) {
7
    PORTB ^= (1 << PB1); //toggel PB1
8
    delay_ms(500);
9
  }
10
}
11
//aus dem Kopf getippt, Fehler ggf. inclusive ;)

von Fabian G. (fabian_g)


Lesenswert?

So habe nun die Fehler gefunden.

Einerseits musste ich die com Ports anpassen und die Adresse, wie du 
geschrieben hast, im 8-Bit modus angeben.

Kann ich mit deiner Bibliothek die Schriftgrösse ändern? Wenn ja, wie?

Mit freundlichen Grüssen und ein schönes Wochenende
Fabian

von M. K. (sylaina)


Lesenswert?

Nein, die Schriftgröße ist damit nicht anpassbar. Die aktuelle Version 
ist in der Lage Bitmaps zu zeichnen, damit könnte man sich auch andere 
Schriftgrößen generieren.

von Fabian G. (fabian_g)


Lesenswert?

Und diese Bitmaps benötigen viel Speicherplatz/Arbeitsspeicher?
Wie viele kann ich davon zeichnen?
Ist es möglich diese Bitmaps in schneller Abfolge nacheinander 
auszugeben?

EDIT: Habe noch eine zusätzliche Frage
Du verwendest einen TIMER für den Serial Clock, sehe ich das richtig? 
Für was brauchst du den TIMER_COUNTER?
1
ISR(TIMER_INT_vec){
2
  TIMER_COUNTER = 0;
3
  LCD_PORT ^= (1 << SDC_Pin);
4
}

Kommt in der Regel ein I2C-Programm nicht ohne zusätzliches Timer aus? 
Dachte der Mikrocontroller generiert diesen Serial Clock selber, ohne 
Timer.

: Bearbeitet durch User
von M. K. (sylaina)


Lesenswert?

Nein, ich verwende keinen Timer. Wie schon gesagt, du benutzt noch eine 
sehr alte Version der Library. Der Timer war einst gedacht für 
Software-I2C, das hab ich aber nie weiter entwickelt, war eine Spinnerei 
aus den Anfangstagen der Lib.

Zu den Bitmaps: Meine Library kann Bitmaps zeichnen, sie beinhaltet aber 
keine, die musst du selbst erstellen oder dir entsprechend besorgen aus 
dem Internet. Wie schnell sie Bitmaps hintereinander zeichnen kann hängt 
von der Größe der Bitmaps ab und der eingestellten 
Kommunikationsgeschwindigkeit. 10 Pixel sind halt schneller gezeichnet 
als 100 Pixel bei gleicher Kommunikationsgeschwindigkeit.

von Fabian G. (fabian_g)


Lesenswert?

Vielen Dank für die schnelle Antwort.
Wo finde ich die aktuellste Version deiner Library? Auf Github?

von M. K. (sylaina)


Lesenswert?

Ja, auf Github, Link ist im Eröffnungspost ;)

Da gibts einige Änderungen inzwischen, z.B. sind die I2C-Funktionen in 
einer eigenen Lib ausgelagert worden sodass man auch eigenen 
I2C-Funktionen nutzen kann ;)

: Bearbeitet durch User
von Marius K. (zephram)


Lesenswert?

Guten Abend!

Eine schöne Lib, wo hast du die nötigen Informationen her ? Die 
Informationslage zu den SSD13XX Chips ist ja recht dünn gesäht...

Ist irgendwas zum Aufbau des SSD1315 im Vergleich zum SSD1306 bekannt ? 
Kann man den mit der 1306er Lib ansteuern ? Zum SSD1315er gibts leider 
iwie gar nichts zu finden...

Viele Grüße

von Stefan F. (Gast)


Lesenswert?

> Die Informationslage zu den SSD13XX Chips ist ja recht dünn gesäht...

Eigentlich steht im Datenblatt des SSD1306 alles drin, was man für 
diesen Chip wissen muss. Funktionierende Code-Beispiele helfen dabei, es 
zu verstehen.

Bezüglich des SSD1315 würde ich also ebenfalls zuerst mal das Datenblatt 
suchen, wenn ich Fragen dazu hätte.

von M. K. (sylaina)


Lesenswert?

Marius K. schrieb:
> Eine schöne Lib, wo hast du die nötigen Informationen her ?

Aus dem Datenblatt. Da stehen neben den elektrischen/mechnischen Daten 
auch alle Befehle drin und, je nach Datenblatt, auch die ganzen Routinen 
zum Initialisieren usw.

von Marius K. (zephram)


Lesenswert?

"Bezüglich des SSD1315 würde ich also ebenfalls zuerst mal das 
Datenblatt
suchen, wenn..."

Ich meinte mit dünner Informationslage, dass Google kein Datenblatt des 
SSD1315 bekannt zu sein scheint...

Ich hab das Teil mal probehalber an einen Pi angeschlossen und die 
Adafruit Bib für SSD1306 getestet. Es scheint zu funktionieren, das 
würde bedeuten ein 1315 ist softwareseitig kompatibel zu einem 1306...

Viele Grüße

von Dieter F. (Gast)


Lesenswert?

Marius K. schrieb:
> Ich meinte mit dünner Informationslage, dass Google kein Datenblatt des
> SSD1315 bekannt zu sein scheint...

https://www.google.com/search?q=SSD1315+datasheet

von Stefan F. (Gast)


Lesenswert?

Ich habe auf den Link geklickt und kein passendes Ergebnis erhalten.

von Dieter F. (Gast)


Lesenswert?

Stefanus F. schrieb:
> Ich habe auf den Link geklickt und kein passendes Ergebnis erhalten.

Da war ich wohl zu nachlässig ...

https://www.mouser.com/ds/2/131/LPCXpresso_Experiment_Kit_Users_Guide-908526.pdf

Die arbeiten damit.

Da gibt es auch Anregungen

https://github.com/twchad/Adafruit_Python_SSD1351

Aber ja, scheint dünn zu sein - mea culpa.

von Stefan F. (Gast)


Lesenswert?

SSD1315 und nicht SSD1351 !

von Dieter F. (Gast)


Lesenswert?

Stefanus F. schrieb:
> SSD1315 und nicht SSD1351 !

Wie recht Du doch hast. Hast Du mal die Befehle mit 1306 etc. 
verglichen?

von Stefan F. (Gast)


Lesenswert?

> Hast Du mal die Befehle mit 1306 etc. verglichen?

Nein. Da ich weder ein SSD1315 noch ein SSD1551 besitze, ist das für 
mich nicht wichtig.

von Dieter F. (Gast)


Lesenswert?

Stefanus F. schrieb:
> Nein. Da ich weder ein SSD1315 noch ein SSD1551 besitze, ist das für
> mich nicht wichtig.

SSD1306 hast Du gelesen?

von Stefan F. (Gast)


Lesenswert?

> SSD1306 hast Du gelesen?

Ja, und eine Implementierung danach veröffentlicht. Aber ich will sie 
niemandem aufdrängen, danach hat ja auch gerade keiner gefragt.

von Dieter F. (Gast)


Lesenswert?

Stefanus F. schrieb:
> Aber ich will sie
> niemandem aufdrängen, danach hat ja auch gerade keiner gefragt.

Ich habe nach dem Vergleich zum 1315 gefragt ...

von Stefan F. (Gast)


Lesenswert?

> Ich habe nach dem Vergleich zum 1315 gefragt ...

Nein, du hast gefragt, ob ich das Datenblatt von SSD1306 gelesen habe.

Abgesehen davon, wie soll ich die Datenblätter miteinander vergleichen? 
Wir sich doch immer noch auf der Suche nach dem Datenblatt des SSD1315!

Das ist doch gerade das Thema dieses Threads. Jemand sucht das 
Datenblatt vom SSD1315 weil er es mit dem SSD1306 vergleichen will. Du 
hast ein paar nicht hilfreiche Links gepostet und forderst nun mich (ich 
war übrigens nicht der suchende) auf, die Datenblätter zu vergleichen.

Wo ist da die Logik?

von Dieter F. (Gast)


Lesenswert?

Stefanus F. schrieb:
> Wo ist da die Logik?

Frag dazu bitte den Marius K. (zephram).

Auch ich habe keine Lust irgendetwas für ihn zu Suchen oder zu 
Vergleichen.

von Marius K. (zephram)


Lesenswert?

Jungs, immer mit der Ruhe, war doch nur die Frage ob wer das Datenblatt 
für den 1315er rumfliegen hat, dann hätte ich mal versucht die 1306er 
Lib anzupassen, was aber ja eh, wie gesagt, unnötig erscheint, weil der 
1315 funzt ja mit der 1306er Lib ^^\

Viele Grüße

von Dieter F. (Gast)


Lesenswert?

Marius K. schrieb:
> unnötig erscheint, weil der
> 1315 funzt ja mit der 1306er Lib ^^

Ja, scheint mir auch so. Es gibt einige Varianten 13xx lt. 
Datenblättern, welche aber wohl nur "Ausstattungsvarianten" sind. Ich 
habe noch etwas rumgeschaut, bin aber auch nicht schlauer geworden. 
Würde es mit dem 1306-Code versuchen - falls nicht O.K.den "Pseudo 
1351-Code" (ohne den verglichen zu haben, da für mich nicht relevant - 
bisher).

Ich vermute, das es sich sowieso nur um Ausstattungsvarianten handelt - 
weiß es aber ehrlich gesagt nicht.

von Marius K. (zephram)


Angehängte Dateien:

Lesenswert?

"Ich vermute, das es sich sowieso nur um Ausstattungsvarianten handelt"

Seh ich auch so ^^ Auf dem Foto wird das Teil von einer kleinen App auf 
node.js mittels dem Paket oled-js-pi angesteuert die auf nem Pi Zero W 
läuft. Diese Lib ist ebenfalls für 1306er...

Viele Grüße

von John Doe (Gast)



Lesenswert?

siehe Anhang

von Nils E. (yetanotheruser)


Lesenswert?

Ich würde die Library gerne in einem GPLv2-only-Projekt verwenden. Der 
Code auf github ist jedoch als GPLv3 ausgewiesen, so dass hier 
inkompatible Lizenzen zusammen kommen.

Ist es vielleicht möglich, diese Library auch unter GPL2 zu 
veröffentlichen?

von Max (Gast)


Lesenswert?

Hallo zusammen,
ich hoffe einer von denjenigen bei denen das Display SSD1306 schon läuft 
ist so nett und hilft mir ein wenig auf die Sprünge.

Ich würde das Display auch gerne in mein Projekt einbauen.
Mir ist klar, wie ich die Displaymatrix berechne. Nur wie ich dem 
Display das mitteile (Befehle/Daten) ist mir nicht ganz ersichtlich aus 
dem Datenblatt.
Da steht viel drinnen. Aber wo nur steht was ich brauche? ;)

I2C Grundaufbau ist eigentlich klar.
Hier mal meine Ansätze wie ich folgende Grundfunktionen aufbauen würde.
So gehts wohl nicht, das hab ich gemerkt :(

Display einschalten:
1
start condition //I2C starten
2
0x78 // Display addresse + last bit (0) is write mode /(1) is read mode
3
ACK
4
0x40 // Befehl folgt
5
ACK
6
0xAF // Display einschalten
7
ACK
8
stop condition // I2C stop

Display ausschalten:
1
start condition //I2C starten
2
0x78 // Display addresse + last bit (0) is write mode /(1) is read mode
3
ACK
4
0x40 // Befehl folgt
5
ACK
6
0xAE // Display ausschalten
7
ACK
8
stop condition // I2C stop

Display alles löschen (alle Bytes auf 0x00):
1
start condition //I2C starten
2
0x78 // Display addresse // last bit (0) is write mode //(1) is read mode
3
ACK
4
0x40 // Befehl folgt
5
ACK
6
0x?? // Display clear
7
ACK
8
stop condition // I2C stop

Display page (Daten) setzen:
1
start condition //I2C starten
2
0x78 // Display addresse // last bit (0) is write mode //(1) is read mode
3
ACK
4
0x40 // Befehl folgt
5
ACK
6
0xB0 // Setze Page 0 0xB0-B7 für page 0-7
7
ACK
8
0xD3 // Setze Display offset
9
ACK
10
0x05 // 0x00 - 0x7F Für Spaltenoffset 0-127
11
ACK
12
0x00 // Sende folgende Daten
13
ACK
14
0xFF // Daten 0xFF zum ersten Byte
15
ACK
16
0xFF // Daten 0xFF zum zweiten Byte
17
ACK
18
... Wiederholung der Datenbytes bis alle Informationen übertragen sind
19
ACK
20
stop condition // I2C stop

Wo hab ich da Fehler eingebaut?
Wie müsste man diese Grundfunktionen richtig implementieren?

Wäre super wenn mir jemand weiterhelfen würde.

Vielen lieben Dank im Vorraus

Liebe Grüße
Max

von Stefan F. (Gast)


Lesenswert?

Bei mir sind die Sequenzen etwas länger, kannst du gerne hier abgucken: 
http://stefanfrings.de/esp8266/WIFI-Kit-8-Test2.zip

Ich habe das aus mehreren Libraries und Infos aus dem Datenblatt 
zusammen gewürfelt, weil es bei mir zuerst auch nicht richtig 
funktionierte. Mit dem jetzigen Stand habe ich allerdings nun ein gutes 
Gefühl.

Du darfst meinen Code frei ohne Lizenz-Beschränkungen nutzen. Das 
Einzige, was darin wirklich (fast*) 1:1 kopiert wurde, ist der 
Zeichensatz. Und der war vom ursprünglichen Autor als "Freeware" 
freigegeben.

*) ich habe deutsche Umlaute hinzugefügt.

von Max (Gast)


Lesenswert?

Hi,
wow die Antwort kam ja fix.

OK ich hab gesehen da sind viele Unterschiede
command bei dir 0x00; bei mir 0x40
write byte 0, bei mir 1....
alleine in der init schon

und viele andere Dinge gesetzt die ich nicht berücksichtigt habe.
wie: Multiplex ratio etc hab ich gar nicht vorgesehen gehabt.

Vielen Dank dafür.
Ich werd mal versuchen deine .cpp in .c umzubauen.
Ich brauche das in klasischem c.

Hoffe dann klappt das.

Braucht man wirklich all diese zusätzlichen Infos?
Oder kennt da jemand nocht nen einfachen Basis Ansteuerungssatz?

Gruß

Max

von Stefan F. (Gast)


Lesenswert?

> Ich werd mal versuchen deine .cpp in .c umzubauen.
> Ich brauche das in klasischem c.
> Hoffe dann klappt das.

Das wird Dir ganz sicher problemlos gelingen. Mein Code enthält keine 
komplizierte Tricks. Von C++ habe ich auch nur einen Bruchteil der 
möglichen Sprache-Konstrukte genutzt.

von Max (Gast)


Lesenswert?

Hallo Stefanus,
ja ich bin es gerade durchgegangen.
Das sieht alles logisch aufgebaut aus.
Und auch schön Kommentiert. Daumen hoch

Danke nochmal für die schnelle Hilfe.
Die Bytefolgen kann man da schön rausziehen.
Auch hast du Commands und Daten immer getrennt in I2C gesendet, nicht in 
ein ewig Telegramm vermischt. Hätte mir dann wohl auch Probleme dabei 
gegeben wenn ich alles auf einmal gesendet hätte.
Gruß
Max

von Stefan F. (Gast)


Lesenswert?

Man kann Kommandos und Daten auch an einem Stück hintereinander senden. 
Ich wollte den Code aber lieber übersichtlich halten, anstatt die 
letzten Mikrosekunden Performance heraus zu quetschen.

von Reinhard O. (Firma: privat) (flug52)


Lesenswert?

Welches ist denn nun die letzte gültige Lib? Für Text und Grafik. 
Benutze Atmel Studio 7.
Evtl. könnte ein Datum ganz vorn/oben eingefügt werden?

: Bearbeitet durch User
von Stefan P. (form)


Lesenswert?

Reinhard O. schrieb:
> Welches ist denn nun die letzte gültige Lib?

Im 1. Post ist ein Github Repository verlinkt:
https://github.com/Sylaina/oled-display

von Reinhard O. (Firma: privat) (flug52)


Lesenswert?

Danke, funktioniert!

von Reinhard O. (Firma: privat) (flug52)


Lesenswert?

Wenn der Grafikmodus  (lcd.h) eingestellt ist, muß zwingend eine Grafik 
dargestellt werden. Auch wenn es nur ein winziger Kreis in einer Ecke 
ist. Ansonsten wird bei mir kein Text dargestellt. Ist das so gewollt?

von M. K. (sylaina)


Lesenswert?

Reinhard O. schrieb:
> Wenn der Grafikmodus  (lcd.h) eingestellt ist, muß zwingend eine Grafik
> dargestellt werden. Auch wenn es nur ein winziger Kreis in einer Ecke
> ist. Ansonsten wird bei mir kein Text dargestellt. Ist das so gewollt?

Öhm, das kann sein. Im Grafikmode ist auch der Text einfach nur Grafik. 
Egal ob es Grafik oder Text ist, ein lcd_display() muss im Grafikmode 
immer gesendet werden um die Anzeige zu aktualisieren. Schau mal ob du 
nicht zufällig das lcd_display(); gelöscht hast als du im Grafikmode nur 
Text anzeigen wolltest.

von Reinhard O. (Firma: privat) (flug52)


Lesenswert?

lcd_display() hatte ich rausgelöscht!
Danke!

: Bearbeitet durch User
von Bessa Wissa (Gast)


Lesenswert?

Bei der Gelegenheit sei einmal angemerkt dass es einem
nativ Englischsprechenden die Haare und Zehennägel zu
Berge stehen lässt wenn er manche englischen Ausdrücke
in den Sourcen sieht.

z.B. LCD_display:

Ja, das ist es wieder, das Liquid Crystal Display Display.

Das Display "displayed". Aber die benannte Funktion displayed
nicht sondern sie schiebt den Inhalt des Buffers in das Display-
Array. Also dürfte sie besser display_update() heissen.

z.B. actual (kommt mehrmals vor).

Das Wort steht nicht - wie der Verfasser vermutet - für
"aktuell" sondern für "tatsächlich".

Wenn ich also übersetze:  displayBuffer[actualIndex+i]
wie würde ich dann "tatsächlicher Index" verstehen sollen?
Gäbe es dann auch einen "nicht so tatsächlichen Index"?

Mir ist es ein Graus, es lebe das Kauderwelsch Englisch.

SCNR

von Welscher (Gast)


Lesenswert?

Bessa Wissa schrieb:
> Bei der Gelegenheit sei einmal angemerkt dass es einem
> nativ Englischsprechenden die Haare und Zehennägel zu
> Berge stehen lässt wenn er manche englischen Ausdrücke
> in den Sourcen sieht.

Bessa Wissa schrieb:
> Mir ist es ein Graus, es lebe das Kauderwelsch Englisch.

Dann geh doch zum Duden - Verlag und verschone uns hier mit deinem 
Gesülze.
So einen Haarspalter wie dich muss man erstmal suchen :-(

LCD-Display oder LED-Display hat sich umgangsprachlich längst etabliert.
Das kennen sogar die Kleinkinder.

von M. K. (sylaina)


Lesenswert?

Welscher schrieb:
> LCD-Display oder LED-Display hat sich umgangsprachlich längst etabliert.
> Das kennen sogar die Kleinkinder.

Genau so sieht es aus. Zudem könnte man auch noch erkennen, dass es 
später dem geneigte Leser helfen könnte. Sobald er lcd_* im Code liest 
könnte man erahnen, dass es eine Funktion für das Display ist und dass 
lcd_display eventuell bedeuten könnte, am LCD etwas zur Anzeige ("to 
display") zu bringen und genau das macht ja die Funktion.
Und zum Thema "actual"...naja, hätte sich Bessa Wissa den Code 
angeschaut wüsste er/sie, dass actualIndex sich auf die tatsächliche 
Cursor-Position bezieht, also eigentlich auch nicht soo verkehrt ist. 
Und ja, es gibt ja auch eine nicht tatsächliche Cursor-Position.

von Reinhard O. (Firma: privat) (flug52)


Lesenswert?

Da könnten wir gleich bei der deutschen Sprache weitermachen, ohne lange 
zu forschen. Und wenn man einmal mit nativ englisch sprechenden Bürgern 
in einer Gaststätte war, bäumen sich einem zu entsprechende später 
Stunde nicht nur die Zehennägel auf.
Da lobe ich mir doch das doppelt gemoppelte LCD-Display.

von 900ss (900ss)


Lesenswert?

Reinhard O. schrieb:
> rausgelöscht

Kann man auch reinlöschen? ;)

von Harry L. (mysth)


Angehängte Dateien:

Lesenswert?

Erstmal ein Danke an Michael Köhler für den Code!

Ich hab das Library um Unterstützung für STM32/HAL erweitert, und paar 
kleinere Fehler beseitigt.

Gegenüber der Original-Version ergeben sich folgende Äderungen:

* lcd_init wird jetzt ohne Parameter aufgerufen.
Ursprünglich wurde versucht, LCD_DISP_ON an die originale init_sequence 
anzuhängen, was aber fehlschlagen muß, da die sich im PROGMEM befindet 
(warum der Compiler da nicht meckert ist mir ein Rätsel)

* i2c.h und i2c.c wurden in i2c_master.h und i2c_master.c umbenannt, um 
Konflikte mit anderen i2c-Librarys zu vermeiden.
Wenn der Code mit einem ARM-gcc übersetzt wird, werden die nicht 
genutzt.

* die Definitionen von YES und NO wurden durch die korrekten 
Definituionen von TRUE und FALSE ersetzt.

* ein Fehler in lcd_invert wurde korigiert.

* Wenn man das Library auf einem STM32 nutzt, muß bei lcd_init() als 
einziger Parameter die Adresse des Handles der I²C-Schnittstelle 
übergeben werden.
Bsp.:
1
  lcd_init(&hi2c1);

*Der Aufruf von lcd_display() ist mit STM32 nicht mehr erforderlich, da 
das Display-Update im Hintergrund mit DMA und Interrupt erfolgt.
Aus Gründen der Kompatibilität ist die Funktion auch bei STM32 weiter 
enthalten, tut aber nichts.

* Bei Nutzung mit STM32 läuft das Lbrary IMMER im Graphic-Mode.

* Auf AVRs sollte sich das Library unverändert nutzen lassen, lediglich 
lcd_init() braucht keine LCD_DISP_ON als Parameter.
Bitte testen und Rückmeldung geben, da ich das nicht testen konnte!

* Der Code "erkennt" selbst, mit welchem Compiler er übersetzt wird, und 
es müssen keine zusätzlichen Defines gesetzt werden

* Es könnte/wird vermutlich noch Probleme mit den SH1106-Displays auf 
STM32 geben, was ich mangels Hardware nicht testen kann.

Freue mich über Rückmeldung.

Harry

: Bearbeitet durch User
Beitrag #5522868 wurde vom Autor gelöscht.
von Dieter F. (Gast)


Lesenswert?

Harry L. schrieb:
> * lcd_init wird jetzt ohne Parameter aufgerufen.

Harry L. schrieb:
> * Wenn man das Library auf einem STM32 nutzt, muß bei lcd_init() als
> einziger Parameter die Adresse des Handles der I²C-Schnittstelle
> übergeben werden.
> Bsp.:  lcd_init(&hi2c1);

Konsistenz ist Wahrheit :-) sagte mein Ex-Chef-Chef-Chef ...

von M. K. (sylaina)


Lesenswert?

Harry L. schrieb:
> ...
> Freue mich über Rückmeldung.
> ...

Danke für deine Mühe. Bei Gelegenheit werde ich mir das mal anschaun und 
ggf. übernehmen wenn ich darf ;).

Harry L. schrieb:
> * lcd_init wird jetzt ohne Parameter aufgerufen.
> Ursprünglich wurde versucht, LCD_DISP_ON an die originale init_sequence
> anzuhängen, was aber fehlschlagen muß, da die sich im PROGMEM befindet
> (warum der Compiler da nicht meckert ist mir ein Rätsel)

Das hast du nicht richtig gesehen. Richtig ist, dass die Init-Sequence 
im PROGMEM liegt. Bei der lcd_init wird aber die Init-Sequence aus dem 
PROGMEM in eine Array, das im SRAM liegt, geladen, dann wird der 
Parameter LCD_DISP_ON dem Array noch hinten angehangen und anschließend 
das Array zum Display übertragen ;)

Den Parameter bei lcd_init() werde ich aber lassen, eine Idee der 
Library war ja u.a. dass man ein HD44780-Display (Library von Peter 
Fleury) durch ein OLED-Display ersetzen kann und lediglich die Library 
im entsprechenden Projekt austauschen muss ohne den Code sonst zu 
ändern. Ich muss nur mal schaun dass ich noch die Cursor-Funktionen 
implementiere.

von Harry L. (mysth)


Lesenswert?

M. K. schrieb:
> ggf. übernehmen wenn ich darf

Du darfst nicht nur, du sollst sogar! ;)

M. K. schrieb:
> Den Parameter bei lcd_init() werde ich aber lassen, eine Idee der
> Library war ja u.a. dass man ein HD44780-Display (Library von Peter
> Fleury) durch ein OLED-Display ersetzen kann und lediglich die Library
> im entsprechenden Projekt austauschen muss ohne den Code sonst zu
> ändern.

Ok, hab ich wieder eingebaut.

Ich hab jetzt doch noch grössere Änderungen am Code vorgenommen:

* zahlreiche "MagicNumbers" durch sinnvolle Defines ersetzt
* Kommentare hinzugefügt
* Die putc()-Funktion hat mir gar nicht gefallen.

Ich hab die neu gebaut, und das jetzt so gelöst:
1
/*
2
 * maps char to index of font-table
3
 * if char not found, 0xff is returned
4
 */
5
static inline uint8_t
6
map_char2fnt (char c)
7
{
8
  uint8_t i, idx;
9
  if ((c >= 0x20) && (c <= 0x7f))
10
    idx = (uint8_t) c - 0x20;
11
  else
12
    {
13
      for (i = 0;(pgm_read_byte(&fnt_map[i].idx) != 0xff)
14
               && (pgm_read_byte(&fnt_map[i].c) != c); i++);
15
      idx = pgm_read_byte(&fnt_map[i].idx);
16
    }
17
  return idx;
18
}
19
20
21
/*
22
 * print a single character on display and advance cursor
23
 *
24
 */
25
void
26
lcd_putc (char c)
27
{
28
  uint8_t fnt_idx;
29
  fnt_idx = map_char2fnt (c);
30
  cursorPosition++;
31
  if (fnt_idx != 0xff)
32
    {
33
#ifdef TEXTMODE
34
      i2c_start(OLED_I2C_ADR);
35
      i2c_byte(OLED_DTA_PREFIX);  // 0x00 for command, 0x40 for data
36
#endif
37
      for (uint8_t i = 0; i < 6; i++)
38
  {
39
#ifdef GRAPHICMODE
40
    displayBuffer.buf[actualIndex + i] = pgm_read_byte(
41
        &oled_font6x8[fnt_idx][i]);      // print font to ram, print 6 columns
42
#else
43
    i2c_byte(pgm_read_byte(&oled_font6x8[fnt_idx][i]));  // print font to ram, print 6 columns
44
#endif
45
  }
46
#ifdef TEXTMODE
47
      i2c_stop();
48
#endif
49
    }
50
#ifdef GRAPHICMODE
51
  actualIndex += 6;
52
#endif
53
}

Die fnt_map sieht so aus und mapped nur die Sonderzeichen:
1
typedef struct
2
{
3
  char c;    // char-code
4
  uint8_t idx;    // index in font-table
5
} fnt_map_t;
6
7
// font-map for extra-chars
8
const fnt_map_t fnt_map[] PROGMEM =
9
  {
10
    { 132, 97 },    // ä
11
    { 148, 99 },    // ö
12
    { 129, 95 },    // ü
13
    { 142, 98 },    // Ä
14
    { 153, 100 },    // Ö
15
    { 154, 96 },    // Ü
16
    { 248, 101 },    // °
17
    { 225, 102 },    // ß
18
//    { 230, 103 },    // µ    * not yet implemented *
19
//    { 234, 104 },    // Omega (Ohm)  * not yet implemented *
20
    { 0, 0xff }      // end of table
21
  };

Im Lauf des Tages, sobald ich den Code mit AVR getestet hab, werde ich 
den neuen Code hochladen.

Insgesamt ist der Code (und auch das Compilat) dadurch kürzer geworden.

Harry

: Bearbeitet durch User
Beitrag #5524800 wurde vom Autor gelöscht.
von Harry L. (mysth)


Angehängte Dateien:

Lesenswert?

So, hier nun die neue Version.

Alle Dinge, die vom User einstellbar sind befinden sich jetzt in
oled_config.h.

Den Code hab ich teilweise ziemlich stark umgebaut und kommentiert.
Getestet hab ich mit einem SSD1306 auf AVR im Text- und Graphicmode,
sowie mit STM32.

Was noch offen ist, ist die Unterstützung für SH1106.
Ich werd mir mal so ein Display bestellen, damit ich das auch
vervollständigen und testen kann, aber vielleicht hat ja auch jemand von
euch Lust dazu.
Viel ist da nicht mehr zu tun.

Wie üblich:
Bitte um Rückmeldungen!


Harry

von Harry L. (mysth)


Angehängte Dateien:

Lesenswert?

Und noch eine neue Version

* kleinere Bugs beseitigt
* Code weiter aufgeräumt
* Redundanzen im Code beseitigt
* neue Funktion:
1
void lcd_on(uint8_t onoff);
Damit kann man das Display abschalten und in den Stromspar-Mode 
versetzen.
Der Bildschirminhalt bleibt dabei erhalten.
* Bei der Ausgabe von Strings wird am Ende einer Zeile automatisch ein 
Zeilenumbruch eingefügt und in der folgenden Zeile weiter geschrieben. 
In der letzten Zeile wird zurück auf die erste Zeile gesprungen.
* SH1106 fehlt nach wie vor
* Im Zeichensatz sollten noch 2 Zeichen eingepflegt werden:
µ -> Bsp: µV, µA, µF etc.
Omega -> das Zeichen für Ohm

Die sind derzeit nur als Dummys im Zeichensatz.(die letzten 2 Zeichen)

Details siehe Code.


Harry

: Bearbeitet durch User
von Fabian F. (fabian_f55)


Lesenswert?

Du kennst den Font Generator für das Display?
http://oleddisplay.squix.ch/#/home

Generiert sehr Speicher-effizient auch größere Fonts. Ist nur etwas 
kmplizierter zu prozessieren.

von Harry L. (mysth)


Lesenswert?

Fabian F. schrieb:
> Du kennst den Font Generator für das Display?
> http://oleddisplay.squix.ch/#/home

Danke!
Schau ich mir an.

von Harry L. (mysth)


Angehängte Dateien:

Lesenswert?

Die Änderungen an dem originalen Code von Michael Köhler sind inzwischen 
so umfangreich geworden, daß kein Stein mehr auf dem Anderen geblieben 
ist.

Hinzu gekommen ist u.A. ein 6- und 4-Zeilen Modus
Besonders der 6-Zeilen Mode sieht wirklich schick aus (siehe Anhang)
Der läuft allerdings leider nur im Grafik-Mode.

Was geblieben ist, ist die Möglichkeit, weiter den Text-Mode mit einem 
Speicherbedarf von <2k Flash und 21 Byte RAM zu nutzen. (nur auf 
8bit-AVR)

Zusätzlich steht im Text-Mode jetzt auch ein 4-zeiliger Mode zur 
Verfügung, der die Portierung von einem klassischen HD44780-Display 
erleichtern sollte.
Der funktioniert zwar im Textmode, sieht aber auch erst im Grafik-Modus 
wirklich schick aus, da ich da das gesamte Bild auf dem Screen 
zentrieren kann.

Zusätzlich wurden \n, \r und \b in der putc()-Funktion implementiert.

Aktuell muß ich noch einen Bug in der STM32-Umsetzung beseitigen, und 
sobald das auch läuft, werde ich einen neuen Thread eröffnen, da mein 
Fork mit dem Original ohnehin nicht mehr viel zu tun hat.

Der neue Code wird dann auch via GitHub zur Verfügung stehen.

Harry

: Bearbeitet durch User
von Frank D. (Firma: Spezialeinheit) (feuerstein7)


Lesenswert?

Ich hasse ja eigentlich meckerrei in der Codeecke. Aber hättest du das 
Display nicht mal abwischen können? Sieht ja aus wie 10 Jahre 
Industrieeinsatz.
Ansonsten, danke für deine Arbeit, ich habe ein wenig in asm mit dem 
Display gespielt, wenn mal mehr Zeit ist geht es da hoffentlich weiter.

von Harry L. (mysth)


Lesenswert?


: Bearbeitet durch User
von M. K. (sylaina)


Lesenswert?

Hallo Harry,

ich hab mir mal deine Lib angeschaut und mir ist der ein und andere 
Schnitzer aufgefallen. Ich fang mal mit was einfachem an:
1
void lcd_command(uint8_t cmd[], uint8_t size, uint8_t fromFlash)
2
{
3
  i2c_start(OLED_I2C_ADR);
4
  i2c_byte(OLED_CMD_PREFIX);  // 0x80 for command
5
  for (uint8_t i = 0; i < size; i++)
6
  {
7
    if (fromFlash == TRUE)
8
      i2c_byte(pgm_read_byte(&cmd[i]));
9
    else
10
      i2c_byte((uint8_t)cmd[i]);
11
  }
12
  i2c_stop();
13
}
Hier schon mal eine Frage: Warum hast du die Unterscheidung, ob die 
Daten im RAM oder im FLASH liegen in die Command-Funktion verschoben? Du 
(und auch ich) laden nur ein einziges Mal Daten aus dem Flash: Bei der 
Initialisierung. Da so eine if-Schleife für einen µC eigentlich immer 
doof ist, die Command-Funktion aber öfter aufgerufen wird, ist das 
eigentlich nicht sehr sinnvoll. Und bei lcd_data() hast du das auch 
gemacht und auch da ist es genauso wenig sinnvoll.

Dann musst du noch mal überprüfen, ob wirklich alles so geht wie du dir 
das vorgestellt hast. Willst zu z.B. wirklich niemals auf einem ARM 
einen String aus dem Flash laden? Mir fielen nämlich folgende Zeilen 
auf:
1
...
2
#ifndef __ARM_ARCH
3
void lcd_puts_p(const char* progmem_s)
4
...
Beim ARM solls also wirklich nötig sein, dass alle Strings im RAM liegen 
müssen?

von Johannes S. (Gast)


Lesenswert?

M. K. schrieb:
> Beim ARM solls also wirklich nötig sein, dass alle Strings im RAM liegen
> müssen?

Der ARM hat einen linearen Adressraum für RAM und Flash, da ist die 
unterschiedliche Behandlung wie beim AVR nicht nötig. Der (kopierte?) 
Kommentar in dem STM32 Beispiel ist da irreführend.

Die paar Zyklen für die if-Abfrage dürften kaum wehtun, dafür ist der 
Code sicher wenn die Daten im Ram liegen. Wenn man das 'fromFlash' Flag 
beim Aufruf richtig setzt.

von Stefan F. (Gast)


Lesenswert?

Ich mische mich da mal ein:

M. K. schrieb:
> Warum hast du die Unterscheidung, ob die
> Daten im RAM oder im FLASH liegen in die Command-Funktion verschoben?

Vielleicht, weil es nur eine kleine if Anweisung kostet. Ich vermute, 
dass der Compiler sie heraus optimiert, wenn die Funktion mit einer 
Konstante aufgerufen wird. Aber selbst wenn nicht: Ein if mehr oder 
weniger macht den Kohl nicht fett.

> Willst zu z.B. wirklich niemals auf einem ARM
> einen String aus dem Flash laden?
> Beim ARM solls also wirklich nötig sein, dass alle Strings im RAM liegen
> müssen?

Die mir bekannten ARM Controller haben einen gemeinsamen Adressraum für 
Flash und RAM. Die ganze _P Funktionen sind dort schlicht unnötig.

Nachtrag: Jetzt merke ich gerade, dass Johannes S. schon das selbe 
schrieb. Egal, kommt mein Senf halt noch oben drauf :-)

von M. K. (sylaina)


Lesenswert?

Johannes S. schrieb:
> Der ARM hat einen linearen Adressraum für RAM und Flash, da ist die
> unterschiedliche Behandlung wie beim AVR nicht nötig.

Ah, OK. Mit ARMs hatte ich bisher wenig bis gar nichts zu tun.

Johannes S. schrieb:
> Die paar Zyklen für die if-Abfrage dürften kaum wehtun, dafür ist der
> Code sicher wenn die Daten im Ram liegen.

Naja, die Unterscheidung gibts bei mir ja auch, allerdings nur da, wo 
sie gebraucht wird. Die Frage war ja, warum er (Harry) es verschoben 
hat. Bei einem ARM würde ich wahrscheinlich eh zur u8g-lib oder 
ähnliches greifen.

von 900ss (900ss)


Lesenswert?

M. K. schrieb:
> if-Schleife

Aua......

von Harry L. (mysth)


Lesenswert?

Wie oben schon erklärt:
Die einzelne if-Bedingung tut nicht weh.
Auf die Art hab ich aber eine Funktion um Daten auf den I²C-Bus zu 
schreiben und nicht unübersichtlich viele Einzelabfragen quer über den 
Code verstreut.


M. K. schrieb:
> Du
> (und auch ich) laden nur ein einziges Mal Daten aus dem Flash
Ich schreibe im Textmode auch die Fonts diekt aus dem Flash.
Das spart mehr CPU-Zyklen als ich schlimmstenfalls durch die 
if.Bedingung verliere.

Alles, was mit AVR-PROGMEM zu tun hat, wird via Makro unwirksam gemacht, 
sobald für ARM compiliert wird (bei ARM reicht const um das ins Flash zu 
legen):
1
#ifdef __ARM_ARCH
2
/*
3
 * ARM-speciffic macros and functions
4
 */
5
#define PROGMEM
6
#define pgm_read_byte(a)  (*(a))
7
#define PSTR(a)      (a)
8
#define lcd_puts_p(a)    lcd_puts(a)
9
#define memcpy_P(a,b,c)    memcpy(a,b,c)

: Bearbeitet durch User
von M. K. (sylaina)


Lesenswert?

Harry L. schrieb:
> Die einzelne if-Bedingung tut nicht weh.
Aber sie unnötig oft aufrufen muss ja auch nicht sein ;)

Harry L. schrieb:
> Auf die Art hab ich aber eine Funktion um Daten auf den I²C-Bus zu
> schreiben und nicht unübersichtlich viele Einzelabfragen quer über den
> Code verstreut.

Nun, die waren vorher auch nicht da ;)

900ss D. schrieb:
> M. K. schrieb:
>> if-Schleife
>
> Aua......

Oh, ein Genauer. Ich denke jeder weiß, was gemeint war, auch du. ;)

von Harry L. (mysth)


Lesenswert?

M. K. schrieb:
> Bei einem ARM würde ich wahrscheinlich eh zur u8g-lib oder
> ähnliches greifen.

Weshalb?

Genau DAS wolltest du ja mit deinem Library vermeiden, und warum sollte 
man das auf einem ARM brauchen?
Dem Display ist es herzlich egal, welcher Controller die (korrekten) 
Daten liefert.

Auch ARM hat nur eine endliche Menge Speicher, und bei der 
µC-Programmierung sollte man immer den Speicherverbrauch im Auge 
behalten.

von Harry L. (mysth)


Lesenswert?

M. K. schrieb:
> Nun, die waren vorher auch nicht da ;)

Jede Art von Redundanz reduziert die Wartbarkeit eines Code.
Ausserdem lese ich (s.o.) im Textmode die Font-Daten direkt aus dem 
Flash ohne die im RAM zwischen zu speichern.
1
#ifdef GRAPHICMODE
2
#if (OLED_LINES == 8)
3
      memcpy_P(&displayBuffer.buf[cursor.y][(cursor.x * OLED_FONT_WIDTH) + OLED_HSHIFT],
4
          &oled_font6x8[fnt_idx], OLED_FONT_WIDTH);
5
#else

Mir ist ein sauberer Programmierstil wichtiger, als irgendwo einzelne 
Takt-Zyklen einzusparen.

: Bearbeitet durch User
von M. K. (sylaina)


Lesenswert?

Harry L. schrieb:
> Weshalb?
>
> Genau DAS wolltest du ja mit deinem Library vermeiden

Und genau da beißt sich die Katze in den Schwanz. Ich hab die Lib 
erstellt weil u.a. die u8g-lib einfach zu groß für einen Atmega48/88 
ist.

Harry L. schrieb:
> Jede Art von Redundanz reduziert die Wartbarkeit eines Code.
> Mir ist ein sauberer Programmierstil wichtiger, als irgendwo einzelne
> Takt-Zyklen einzusparen.

Ja, aber viele kleine, gesparte Taktzyklen, können zu unschönen 
Nebeneffekten führen. Ist ja auch so ein netter Nebeneffekt, dass meine 
Lib auch noch schneller ist als die u8g-lib ;)

von Harry L. (mysth)


Lesenswert?

Vergleich doch einfach mal die Codegrösse der ursprünglichen mit meiner 
Library!

Da ist kein grosser Unterschied, und wenn du die Geschwindigkeit im 
8Zeilen-Mode vergleichst, ist meine Version theoretisch sogar schneller, 
da ich mir das Zwischenspeichern der Font-Daten im RAM erspare.

"Theoretisch" deshalb, da der wirklich limitierende Faktor die 
Geschwindigkeit des I²C-Bus ist.

Die erstmal auf 400 kHz hoch zu drehen bringt erheblich mehr, als der 
Versuch irgendwo einzelne Taktzyklen zu sparen.

: Bearbeitet durch User
von M. K. (sylaina)


Lesenswert?

Harry L. schrieb:
> Vergleich doch einfach mal die Codegrösse der ursprünglichen mit meiner
> Library!

Hab ich, meine Code braucht weniger Flash-Speicher.

Harry L. schrieb:
> Da ist kein grosser Unterschied, und wenn du die Geschwindigkeit im
> Text-Mode vergleichst, ist meine Version sogar schneller, da ich mir das
> Zwischenspeichern der Font-Daten im RAM erspare.

Nö, da irrst du da du mit deinem Umstricken sehr viel öfters ein 
i2c_start und i2c_stop aufrufst. Meine Lib braucht bei 400 kHz Taktrate 
rund 5 ms zum Beschreiben einer Zeile, deine Lib braucht rund 10 ms

von Harry L. (mysth)


Lesenswert?

M. K. schrieb:
> Meine Lib braucht bei 400 kHz Taktrate
> rund 5 ms zum Beschreiben einer Zeile, deine Lib braucht rund 10 ms

Dann würde ich aber gern mal sehen, wie du auf diese Werte kommst...

Btw. erreich ich auf einem STM32F1xx >40fps
Schnell genug?

von Harry L. (mysth)


Lesenswert?

J. W. schrieb:
> oled-display:11: error: 'lcd_display' was not declared in this scope
>  lcd_display();
>              ^
> exit status 1
> 'lcd_display' was not declared in this scope

Dann zeig mal deinen Code!

im Verz. AVR-sample befindet sich ein Beispiel.
1
/*
2
 * main.c
3
 *
4
 *  Created on: 16.08.2018
5
 *      Author: harry
6
 */
7
8
#include <avr/io.h>
9
#include <stdio.h>
10
#include "lcd.h"
11
12
int main()
13
{
14
char s[21];
15
    // put your setup code here, to run once:
16
  lcd_init(OLED_DISPLAYON);    // init lcd and turn on
17
18
#if defined GRAPHICMODE
19
  sprintf(s, "%d-Line graphic-mode\r\n", OLED_LINES);
20
#else
21
  sprintf(s, "%d-Line text-mode\r\n", OLED_LINES);
22
#endif
23
    lcd_puts(s);  // put string from RAM to display (TEXTMODE) or buffer (GRAPHICMODE)
24
    lcd_puts("20 chars per line\r\n");
25
    lcd_puts_p(PSTR("special chars:\r\n\x84\x94\x81\x8e\x99\x9a\xf8\xe1\r\n"));
26
    for (uint8_t i=4;i < (OLED_LINES - 1);i++)
27
    {
28
        sprintf(s, "Line %2d\r\n", i+1);
29
        lcd_puts(s);  // put string from RAM to display (TEXTMODE) or buffer (GRAPHICMODE)
30
    } /**/
31
#if defined GRAPHICMODE
32
    lcd_puts ("Isn't it nice?");
33
#else
34
    lcd_puts ("Isn't it ugly?");
35
#endif
36
37
//    lcd_gotoxy(0,2);          // set cursor to first column at line 3
38
//    lcd_puts_p(PSTR("String from flash"));  // puts string form flash to display (TEXTMODE) or buffer (GRAPHICMODE)
39
  #if defined GRAPHICMODE
40
    lcd_drawRect(0,0,127,63,WHITE);
41
    lcd_drawCircle(96,42,7,WHITE); // draw circle to buffer white lines
42
    lcd_display();                 // send buffer to display
43
  #endif
44
45
    while(1)
46
    {
47
48
    }
49
50
}

von M. K. (sylaina)


Lesenswert?

Harry L. schrieb:
> Btw. erreich ich auf einem STM32F1xx >40fps
> Schnell genug?

Aber sicher nicht bei 400 kHz Taktrate.

von Harry L. (mysth)


Lesenswert?

M. K. schrieb:
> Harry L. schrieb:
>> Btw. erreich ich auf einem STM32F1xx >40fps
>> Schnell genug?
>
> Aber sicher nicht bei 400 kHz Taktrate.

Aber Ja!

Rechne mal nach! ;)

von M. K. (sylaina)


Lesenswert?

Harry L. schrieb:
> M. K. schrieb:
>> Harry L. schrieb:
>>> Btw. erreich ich auf einem STM32F1xx >40fps
>>> Schnell genug?
>>
>> Aber sicher nicht bei 400 kHz Taktrate.
>
> Aber Ja!
>
> Rechne mal nach! ;)

Hab ich. Das Display besteht aus 128*64 Pixel, macht also 12288 Bits zum 
übertragen. Bei 40 fps musst du 327680 Bits übertragen. Wird eng bei 400 
kHz. Und der Overhead ist da nicht mit drin.

Harry L. schrieb:
> Dann zeig mal deinen Code!

Öhm, der steht doch oben.

: Bearbeitet durch User
von Harry L. (mysth)


Lesenswert?

M. K. schrieb:
> Das Display besteht aus 128*96 Pixel

128 * 64 Pixel = 8192 Bit = 1024 Byte = 1kB

Ich sende via DMA den kompletten Buffer in einem Rutsch an den 
Controller, und sobald der fertig ist, geht das Spielchen von Vorne los.
Die Präambel (1 Byte) muss dabei nur 1mal pro Buffer-Write gesendet 
werden.

Das Programm läuft während dessen ungebremst weiter.

: Bearbeitet durch User
von M. K. (sylaina)


Lesenswert?

Harry L. schrieb:
> M. K. schrieb:
>> Das Display besteht aus 128*96 Pixel
>
> 128 * 64 Pixel = 1024 Byte = 1kB

Ja, hatte mich oben vertan mit der größe. Eng wirds dennoch.

Dass es auf dem STM besser/schneller geht als auf nem AVR glaub ich dir 
ja gern. Ich habs halt hier auf nem Atmega328p verglichen und da zeigt 
sich, dass mein Code schneller unterwegs ist.

von Harry L. (mysth)


Lesenswert?

M. K. schrieb:
> Ich habs halt hier auf nem Atmega328p verglichen und da zeigt
> sich, dass mein Code schneller unterwegs ist.

Den Beweis bist du bisher aber schuldig geblieben.
Und ich meine nicht die Anzahl der Taktzyklen, sondern die tatsächliche
Geschwindigkeit der Ausgabe auf dem Display.

von M. K. (sylaina)


Lesenswert?

Harry L. schrieb:
> Den Beweis bist du bisher aber schuldig geblieben.
> Und ich meine nicht die Anzahl der Taktzyklen, sondern die tatsächliche
> Geschwindigkeit der Ausgabe auf dem Display.

Welchen Beweis denn bitte schön? Was genau erwartest du? Verstehe ich 
nicht.

von Harry L. (mysth)


Lesenswert?

M. K. schrieb:
> Welchen Beweis denn bitte schön? Was genau erwartest du? Verstehe ich
> nicht.

Eine nachvollziehbare Erklärung/Beweis, daß deine Funktionen so viel 
schneller sind wie du behauptest (5ms vs. 10ms)

Zeig mir ein Code-Beispiel an dem das erkennbar ist!

von M. K. (sylaina)


Lesenswert?

Ach das meinst du, da hab ich meinen Code von damals genommen:
1
#include "main.h"
2
3
#include <stdlib.h>
4
#include <avr/io.h>
5
#include <avr/interrupt.h>
6
#include "i2c_master.h"
7
#include "lcd.h"
8
9
volatile uint16_t overflows=0;
10
11
int main(void)
12
{
13
    
14
    i2c_init();
15
    
16
    lcd_init(OLED_DISPLAYON);
17
    lcd_clrscr();
18
    
19
    sei();
20
    
21
    TCCR1B |= (1 << CS00);
22
    lcd_puts("M. Koehler 2016/2017");
23
    TCCR1B &= ~(1 << CS00);
24
    
25
    
26
    char time[6];
27
    
28
    dtostrf((overflows*65536.0+TCNT1)/F_CPU*1e3,
29
            6,
30
            3,
31
            time);
32
    lcd_gotoxy(0,6);
33
    lcd_puts("Time to print Line 1:");
34
    lcd_gotoxy(0,7);
35
    lcd_puts(time);
36
    lcd_puts("ms");
37
    
38
    lcd_display();
39
    for(;;){
40
        /* insert your main loop code here */
41
    }
42
    return 0;   /* never reached */
43
}
44
ISR(TIMER1_OVF_vect){
45
    overflows++;
46
}

Und wie gesagt, bei meinem Code bekomme ich knapp 5ms angezeigt, bei 
deinem knapp 10ms.

von Harry L. (mysth)


Lesenswert?

M. K. schrieb:
> Und wie gesagt, bei meinem Code bekomme ich knapp 5ms angezeigt, bei
> deinem knapp 10ms.

Text- oder GraphicMode?
Für den Text-Mode kann ich mir das kaum vorstellen.

Mein Graphic-Mode ist allerdings deutlich aufwendiger als deiner, da ich 
die Ausgabe vertikal wie horizontal zentriere was einiges an Bit-Shifts 
erfordert, aber auch das erklärt nicht so einen Unterschied.

Allerdings stört mich das bei reiner Textausgabe sowieso wenig,da das 
immer noch mehr als schnell genug für unsere Augen ist.

Am meisten Zeit und Platz vergeudest du übrigens hiermit:
1
dtostrf((overflows*65536.0+TCNT1)/F_CPU*1e3,
2
            6,
3
            3,
4
            time);

Wozu du da float brauchst, ist mir vollkommen schleierhaft.

: Bearbeitet durch User
von M. K. (sylaina)


Lesenswert?

Harry L. schrieb:
> Am meisten Zeit und Platz vergeudest du übrigens
> hiermit:dtostrf((overflows*65536.0+TCNT1)/F_CPU*1e3,
>             6,
>             3,
>             time);
>
> Wozu du da float brauchst, ist mir vollkommen schleierhaft.

Das ist in der Zeitmessung nicht mehr mit drin und wenn es dir 
vollkommen schleierhaft ist wozu ich da float benutze kann ich da auch 
nicht weiter helfen. Das war die einfachste/schnellste Variante x,yz ms 
anzuzeigen.

von Harry L. (mysth)


Lesenswert?

M. K. schrieb:
> Das war die einfachste/schnellste Variante x,yz ms
> anzuzeigen.

Die einfachste vielleicht, aber ganz sicher nicht die schnellste..

von Harry L. (mysth)


Lesenswert?

Sei mir bitte  nicht böse, aber ich gewinne zunehmend den Eindruck, daß 
du angepisst bist, weil jemand es gewagt hat, deinen Code einem 
kompletten Redesign zu unterziehen, und du darum so lange mit dem Kopf 
schüttelst, bis du das Haar in der Suppe findest.

Glaub mir einfach, daß unsere Design-Goals die Selben sind:
Größe und Geschwindigkeit

Es macht aber imho wenig Sinn, einige gesparte Taktzyklen mit schlecht 
les-/wartbarem Code zu erkaufen, und erst Recht dann nicht, wenn diese 
Einsparungen nur minimalen Einfluss auf das Gesamt-Ergebnis haben.

Das Ziel meines Redesign war nicht, deine Programmier-Fähigkeiten in 
Frage zu stellen, sondern die Usability dieses Library zu verbessern.

Du hängst dich an Kleinigkeiten auf, aber die wirklich relevanten 
Unterschiede hast du bisher mit keinem Wort erwähnt:

* die deutlich verbesserte putc-Routine
* die leichte Erweiterbarkeit des Font um individuelle Sonderzeichen.
* Die Möglichkeit bei den Graphic-Funktionen nicht nur s/w sondern auch 
invertierend zu zeichnen.

Sowas ist mir die paar Bytes mehr an Code wert, und selbst wenn meine 
Funktionen in einzel-Aspekten vielleicht sogar etwas langsamer als deine 
laufen, so sind das bezogen auf den gesamten Bildaufbau ganz sicher 
keine 100% Unterschied, und ich behaupte, daß das ein normaler Mensch 
auf dem Display ganz sicher nicht wahrnehmen wird.

: Bearbeitet durch User
von M. K. (sylaina)


Lesenswert?

Harry L. schrieb:
> Sei mir bitte  nicht böse, aber ich gewinne zunehmend den Eindruck, daß
> du angepisst bist, weil jemand es gewagt hat, deinen Code einem
> kompletten Redesign zu unterziehen, und du darum so lange mit dem Kopf
> schüttelst, bis du das Haar in der Suppe findest.

Nö, das ist überhaupt nicht der Fall, es ist gar das Gegenteil. Ich 
finde toll was du gemacht hast, das ist keine Frage. Mir sind halt 
gestern nur zwei, ich sag mal, Merkwürdigkeiten aufgefallen und die hab 
ich angesprochen da sie aus meiner Sicht keinen Sinn machten.

von Harry L. (mysth)


Lesenswert?

M. K. schrieb:
> Nö, das ist überhaupt nicht der Fall, es ist gar das Gegenteil. Ich
> finde toll was du gemacht hast, das ist keine Frage. Mir sind halt
> gestern nur zwei, ich sag mal, Merkwürdigkeiten aufgefallen und die hab
> ich angesprochen da sie aus meiner Sicht keinen Sinn machten.

Ok, dann hab ich das wohl falsch interprettiert.
Sorry!

Du beziehst dich auf den aktuellen Code im Github?
Der Link wurde in diesem Thread ja noch gar nicht genannt.

https://github.com/HarryLipphaus/OledLib

von M. K. (sylaina)


Lesenswert?

Sodele, hab ein wenig an meiner Lib rumgeschnitzt.

- lcd_putc()

Habe ich vereinfacht wodurch sie übersichtlicher (und noch mal 
schneller) wurde.

- Sonder-/Extrazeichen

und deren Auswertung sind nun, wie auch der Font, in eine eigenen 
Header-Datei gewandert.

- einige Steuerzeichen wurde ergänzt

die Lib erkennt nun die Steuerzeichen tab, linefeed und carrige-return.

- lcd-invert()

wurde gefixt, hier war noch ein Fehler drin denn unabhängig vom Argument 
wurde das Display da immer auf Not-Inverted gesetzt, da ist mir ein 
Tippfehler unterlaufen gewesen.

Der Referenzstring aus meinem Eröffnungpost benötigt nun im Fastmode 
(400 kHz I2C-Taktrate) ca. 2.6 ms bis er geschrieben ist im Textmode.

https://github.com/Sylaina/oled-display

von Harry L. (mysth)


Lesenswert?

M. K. schrieb:
> Sodele, hab ein wenig an meiner Lib rumgeschnitzt.
>
> - lcd_putc()
>
> Habe ich vereinfacht wodurch sie übersichtlicher (und noch mal
> schneller) wurde.

Und es gibt immer noch 2 komplett unabhängige lcd_put() (Text- und 
Graphic-Mode), die sich nur in wenigen Zeilen unterscheiden.

Wozu?

Wartbarer Code sieht anders aus!

M. K. schrieb:
> - einige Steuerzeichen wurde ergänzt

Und gleich ne ganze switch-Kaskade um das Sonderzeichen auszuwählen...
Mag vielleicht paar ns sparen, ist aber hässlicher Stil und dazu 
unflexibel.

Was stört dich an meiner Variante?
* Die 22 Byte Flash für die Tabelle?
* Die paar ns, die er bei dem selten auftretenden Sonderzeichen zum 
Durchsuchen der Tabelle benötigt?

Meine Version ist flexibler/generischer bei Erweiterungen um einzelne 
Zeichen, funktioiert mit allen Zeichen und belegt weniger Flash
1
// font-map for extra-chars
2
const fnt_map_t fnt_map[] PROGMEM =
3
{
4
    { 132, 97 },    // ä
5
    { 148, 99 },    // ö
6
    { 129, 95 },    // ü
7
    { 142, 98 },    // Ä
8
    { 153, 100 },    // Ö
9
    { 154, 96 },    // Ü
10
    { 248, 101 },    // °
11
    { 225, 102 },    // ß
12
    { 230, 103 },    // µ      * only dummy in font *
13
    { 234, 104 },    // Omega (Ohm)  * only dummy in font *
14
    { 0, 0xff }      // end of table
15
};
16
17
18
19
/*
20
 * maps char to index of font-table
21
 * if char not found, 0xff is returned
22
 */
23
static uint8_t map_char2fnt(char c)
24
{
25
  uint8_t i, idx;
26
  if ((c >= 0x20) && (c <= 0x7f))
27
    idx = (uint8_t) c - 0x20;
28
  else
29
  {
30
    for (i = 0;
31
        (pgm_read_byte(&fnt_map[i].idx) != 0Xff)
32
            && (pgm_read_byte(&fnt_map[i].c) != c); i++)
33
      ;
34
    idx = pgm_read_byte(&fnt_map[i].idx);
35
  }
36
  return idx;
37
}

M. K. schrieb:
> Der Referenzstring aus meinem Eröffnungpost benötigt nun im Fastmode
> (400 kHz I2C-Taktrate) ca. 2.6 ms bis er geschrieben ist im Textmode.

Und du glaubst wirklich, daß ein Mensch bei einer Textausgabe den 
Unterschied zw. 2,6ms und 12,5ms "sieht"?

Genau die Punkte, die mich zum Redesign bewogen haben sind in dieser 
Version genauso enthalten - nur teilweise "verschlimmbessert"

Das sind genau die Optimierungen, die in der Praxis genau gar nichts 
bringen, aber den Code alles Andere als schöner machen.

von Stefan F. (Gast)


Lesenswert?

Harry L. schrieb:
> Und du glaubst wirklich, daß ein Mensch bei einer Textausgabe den
> Unterschied zw. 2,6ms und 12,5ms "sieht"?

Ob der Rest des Programms 9,9ms mehr oder Weniger zur Verfügung hat, 
kann schon einen erheblichen Unterschied machen.

von Harry L. (mysth)


Lesenswert?

Stefanus F. schrieb:
> Harry L. schrieb:
>> Und du glaubst wirklich, daß ein Mensch bei einer Textausgabe den
>> Unterschied zw. 2,6ms und 12,5ms "sieht"?
>
> Ob der Rest des Programms 9,9ms mehr oder Weniger zur Verfügung hat,
> kann schon einen erheblichen Unterschied machen.

Jaja....weil man natürlich die zeitkritischen Dinge in der main() 
erledigt....

Wenn man programmieren kann, ist es vollkommen unerheblich, wie lange 
die Ausgabe eines String auf einem Display dauert.
Die Display-Ausgabe hat sowieso die niedrigste Priorität von Allen.
Da zählt nur, daß es für den Bediener (Mensch) schnell genug ist damit 
der nicht ungeduldig wird.

von Harry L. (mysth)


Lesenswert?

Ich hab jetzt auch mal nachgemessen:

Meine Ausgabe (Textmode, 20 Zeichen/Zeile) dauert 4,4ms pro volle Zeile 
(20 Zeichen schreiben)

So gemessen:
MyTimer wird im ms-Takt von einem HW-Timer incrementiert.
1
uint16_t *MyTimer;
2
3
uint32_t uptime;
4
5
#define MYTIMER (*(MyTimer))
6
7
#define TIMETEST
8
9
int main()
10
{
11
char s[21];
12
uint32_t fulltime, linetime;
13
14
    // put your setup code here, to run once:
15
  lcd_init(OLED_DISPLAYON);    // init lcd and turn on
16
  lcd_clrscr();
17
  uint8_t teststring[]="01234567890123456789";
18
19
#ifdef TIMETEST
20
  init_SysTimer(&uptime);
21
  MyTimer = request_SysTimer();
22
23
  MYTIMER = 0;
24
  for (uint8_t i=0; i<7;i++)
25
  {
26
    lcd_gotoxy(0,i);
27
    lcd_puts(teststring);
28
  }
29
  fulltime = (uint32_t)MYTIMER;
30
  linetime = (fulltime * 10) / 7;
31
  sprintf(s, "%ld,%ld ms/line", linetime / 10, linetime % 10);
32
  lcd_gotoxy(0,7);
33
  lcd_puts(s);
34
#endif

: Bearbeitet durch User
von Harry L. (mysth)


Lesenswert?

Noch mehr Timing:

Das Schreiben 1 kompl. Zeile (20 Zeichen) im aufwendigen 6-Zeilen-Mode 
in den Framebuffer: 1,0ms

Das Übertragen des Framebuffer auf das Display: 25,4ms

Für das Beschreiben des vollst. Display im 6-Zeilen-Mode macht das dann:

((6 * 1ms) + 25,4ms) / 6 = 5,23ms pro Zeile.


Da beim Überragen einer Zeile des Framebuffe auf das Display 25,4 ms / 8 
= 3,18 ms/Zeile benötigt werden, erscheinen mir die von Michael 
gemessenen 2,6ms unglaubwürdig.

Entweder war das keine vollst. Zeile mit 20 Zeichen, oder da ist 
irgendwo ein Messfehler.

: Bearbeitet durch User
von M. K. (sylaina)


Lesenswert?

Harry L. schrieb:
> Und es gibt immer noch 2 komplett unabhängige lcd_put() (Text- und
> Graphic-Mode), die sich nur in wenigen Zeilen unterscheiden.
>
> Wozu?

Das steht weiter oben warum das so ist. Das werde ich mit Sicherheit 
nicht noch einmal erklären.

Harry L. schrieb:
> Wartbarer Code sieht anders aus!

Was willst du daran warten, was soll daran unübersichtlich sein?

Harry L. schrieb:
> M. K. schrieb:
>> - einige Steuerzeichen wurde ergänzt
>
> Und gleich ne ganze switch-Kaskade um das Sonderzeichen auszuwählen...
> Mag vielleicht paar ns sparen, ist aber hässlicher Stil und dazu
> unflexibel.

In wiefern soll das unflexibel sein? Und was daran ist hässlicher Stil? 
Ich mein, die Steuerzeichen wählst auch du über ne Switch aus, warum ist 
das bei dir kein hässlicher Stil aber bei mir? Den check ich nicht.

Harry L. schrieb:
> Meine Version ist flexibler/generischer bei Erweiterungen um einzelne
> Zeichen, funktioiert mit allen Zeichen und belegt weniger Flash

Ob meine Variante weniger Flash belegt muss ich mal gleich schaun aber 
weniger flexibel ist sie definitiv nicht. Wie kommst du darauf?

Harry L. schrieb:
> Und du glaubst wirklich, daß ein Mensch bei einer Textausgabe den
> Unterschied zw. 2,6ms und 12,5ms "sieht"?

Nö, aber je schneller das Display abgefrühstückt ist desto eher hat man 
Zeit in der Main andere Dinge zu tun. Es wäre ja schon irgendwie, 
überspitzt formuliert, blöd wenn man in der Main nur Zeit hätte das 
Display zu beschreiben.

Harry L. schrieb:
> Genau die Punkte, die mich zum Redesign bewogen haben sind in dieser
> Version genauso enthalten - nur teilweise "verschlimmbessert"

Das ist natürlich Unsinn.

Harry L. schrieb:
> Das sind genau die Optimierungen, die in der Praxis genau gar nichts
> bringen, aber den Code alles Andere als schöner machen.

Du findest es jetzt also unschöner, dass die Suche&Auswahl des 
Sonderzeichens nicht mehr in der putc() geschieht sondern 
übersichtlicher in der Headerdatei, die auch den Font beinhaltet? 
Interessant.

Harry L. schrieb:
> Meine Ausgabe (Textmode, 20 Zeichen/Zeile) dauert 4,4ms pro volle Zeile
> (20 Zeichen schreiben)

Das ist bei mir ebenso ;)

Harry L. schrieb:
> Das Übertragen des Framebuffer auf das Display: 25,4ms

Das dauert bei mir im Grafikmode 26,858ms. Übrigens: 25,4ms entsprechen 
nicht > 40fps sondern < 40fps ;)

Harry L. schrieb:
> Da beim Überragen einer Zeile des Framebuffe auf das Display 25,4 ms / 8
> = 3,18 ms/Zeile benötigt werden, erscheinen mir die von Michael
> gemessenen 2,6ms unglaubwürdig.
>
> Entweder war das keine vollst. Zeile mit 20 Zeichen, oder da ist
> irgendwo ein Messfehler.

War ein Messfehler. Ich hatte doch in der Tat die falsche Taktquelle für 
den Atmega ausgewählt sodass der Atmega nicht mit 8 MHz lief. Blöder 
Fehler.

Am Besten finde ich deine Kritik an der Wartbarkeit des Codes, und dann 
lese ich z.B. bei dir solche Dinge:
1
...
2
#ifdef __ARM_ARCH
3
...
4
#endif
5
...
6
#ifdef __ARM_ARCH
7
...
8
#endif
9
...

Also wirklich übersichtlicher/besser Wartbar ist das ja nicht. Am besten 
gefällt mir das:
1
...
2
// line 153
3
#ifndef __ARM_ARCH
4
...
5
#endif
6
//line 187
7
#ifdef __ARM_ARCH
8
...
9
#endif
10
...

Warum du bei sowas kein #elif benutzt versteh ich nicht.
Aber, bzgl. Wartbarkeit, wirklich übersichtlich durch diese ganzen, ich 
sag mal, Spagetti-#if's ist dein Code nicht wirklich. Warum hast du hier 
nicht mal richtig nach Architektur sortiert wie etwa so:
1
...
2
#ifdef __ARM_ARCH
3
// alles was zum ARM gehört hier rein
4
#elif
5
// hier alles was zum AVR gehört
6
#endif
7
// hier (oder vor das ifdef) hin alles, was für ARM und AVR benutzt werden soll
8
...

Das wäre erheblich übersichtlicher als so, wie du es jetzt hast.

EDIT:

Ich habe nun auch noch mal verglichen. Mikrocontroller ist ein AVR 
Atmega328p mit internen RC, auf 8 MHz eingestellt (Standardfuse mit 
CLKDIV8 ausgeschaltet)

Im TEXTMODE belegt deine Library mit der nachfolgenden Main 5118 Bytes 
im Flash und es dauert 4.903ms bis die Zeile auf dem Display steht (kein 
Overflow vom Timer und der Count steht bei 39227).
Meine Library belegt 4936 Bytes und sie braucht grade mal 4.399ms bis 
der Text im Display steht (kein Overflow vom Timer und der Count steht 
bei 35195)

Im GRAPHICMODE belegt deine Library mit der nachfolgenden Main 6426 
Bytes im Flash und es dauert 28.177ms bis die Zeile auf dem Display 
steht (3 Overflows vom Timer und der Count steht bei 28810).
Meine Library belegt 6138 Bytes und sie braucht grade mal 27.766ms bis 
der Text im Display steht (3 Overflows vom Timer und der Count steht bei 
25517).

Mit deiner Library braucht der Atmega 1. länger bis die Anzeige da ist 
und 2. belegt sie mehr Flash-Speicher
1
//Testcode
2
#include <stdlib.h>
3
#include <avr/io.h>
4
#include <avr/interrupt.h>
5
#include "i2c_master.h"
6
#include "lcd.h"
7
#include <util/delay.h>
8
volatile uint32_t overflows=0;
9
10
int main(void)
11
{
12
    TIMSK1 |= (1 << TOIE1);
13
    i2c_init();
14
    
15
    lcd_init(OLED_DISPLAYON);
16
    lcd_clrscr();
17
  
18
    sei();
19
    lcd_gotoxy(0, 0);
20
    TCCR1B |= (1 << CS10);
21
    lcd_puts(("M. Koehler 2016/2017"));
22
#ifdef GRAPHICMODE
23
  lcd_display();
24
#endif
25
  TCCR1B &= ~(1 << CS10);
26
  
27
  char time[6];
28
  lcd_gotoxy(0, 2);
29
  lcd_puts_p(PSTR("OVF: "));
30
  ltoa(overflows,
31
     time,
32
     10);
33
  lcd_puts(time);
34
  
35
  lcd_gotoxy(0, 3);
36
  lcd_puts_p(PSTR("TCNT1: "));
37
  ltoa(TCNT1,
38
     time,
39
     10);
40
  lcd_puts(time);
41
  
42
    dtostrf((overflows*65536.0+TCNT1)/(float)F_CPU*1e3,
43
            6,
44
            3,
45
            time);
46
  
47
    lcd_gotoxy(0,5);
48
    lcd_puts_p(PSTR("Time to print line 1:\r\n"));
49
    lcd_puts(time);
50
    lcd_puts_p(PSTR("ms"));
51
#ifdef GRAPHICMODE
52
  lcd_display();
53
#endif
54
    for(;;){
55
        /* insert your main loop code here */
56
    }
57
    return 0;   /* never reached */
58
}
59
ISR(TIMER1_OVF_vect){
60
    overflows++;
61
}

EDIT2: Ich hab natürlich die Library von Harry auf 8-Zeilen-Modus 
gesetzt und den I2C-Bus auf 400 kHz eingestellt (I2C_HIGHSPEED definiert 
in der i2c_master.h).

: Bearbeitet durch User
von Harry L. (mysth)


Lesenswert?

M. K. schrieb:
> Du findest es jetzt also unschöner, dass die Suche&Auswahl des
> Sonderzeichens nicht mehr in der putc() geschieht sondern
> übersichtlicher in der Headerdatei, die auch den Font beinhaltet?
> Interessant.

Die Aussage ist schlicht und einfach falsch!
In der .fnt-Datei befindet sich nur die Tabelle mit der Zuordnung.
Die Funktion um den Index eines Zeichen innerhalb des Font zu ermitteln 
steht in lcd.c.

M. K. schrieb:
> Am Besten finde ich deine Kritik an der Wartbarkeit des Codes, und dann
> lese ich z.B. bei dir solche Dinge:
> ...
> #ifdef __ARM_ARCH
> ...
> #endif
> ...
> #ifdef __ARM_ARCH
> ...
> #endif
> ...

Das ist geradezu lächerlich!
Hättest du dir die Mühe gemacht, den Code zu verstehen würdst du hier 
nicht solche Pseudo-Argumente auffahren.

M. K. schrieb:
> Im TEXTMODE belegt deine Library mit der nachfolgenden Main 5118 Bytes
> im Flash und es dauert 4.903ms bis die Zeile auf dem Display steht (kein
> Overflow vom Timer und der Count steht bei 39227).
> Meine Library belegt 4936 Bytes und sie braucht grade mal 4.399ms bis
> der Text im Display steht (kein Overflow vom Timer und der Count steht
> bei 35195)
>
> Im GRAPHICMODE belegt deine Library mit der nachfolgenden Main 6426
> Bytes im Flash und es dauert 28.177ms bis die Zeile auf dem Display
> steht (3 Overflows vom Timer und der Count steht bei 28810).
> Meine Library belegt 6138 Bytes und sie braucht grade mal 27.766ms bis
> der Text im Display steht (3 Overflows vom Timer und der Count steht bei
> 25517).
>
> Mit deiner Library braucht der Atmega 1. länger bis die Anzeige da ist
> und 2. belegt sie mehr Flash-Speicher

Jaja, wer misst, misst Mist!
Das ganze inkl. main, startup und deinem Timer-Zeugs (für die Messung 
selbst) als Summe ist völlig nichts-sagend.

Für meine Version hab ich valide Werte ermittelt:
Beitrag "Re: Universelles Oled-Libary (SSD1306) für AVR(8bit) und STM32/HAL"

Demnach brauch ich in der kleinsten Variante 1853 Byte Flash und 9 Byte 
RAM.

Wenn du unbedingt vergleichen willst, dann bitte auch mit belastbaren 
Zahlen.

: Bearbeitet durch User
von Stefan F. (Gast)


Lesenswert?

Leute, streitet euch doch nicht um solche Nichtigkeiten!

Jeder Programmierer hat seinen eigenen Stil. Ich arbeite seit vielen 
Jahren in Teams und hätte es nicht vom ungelernten Anfänger zum Senior 
mit Führungsverantwortung gebracht, wenn ich mich an solchen 
Kleinigkeiten aufgezogen hätte.

Ihr solltet beide akzeptieren, dass andere Lösung auch OK sind. Im 
echten Leben ist es völlig egal, welche Lösung die Beste ist, solange 
man damit das Ziel erreicht.

Schau euch doch nur mal Microsoft an. Jeder Dummkopf sieht, das deren 
Produkte bei weitem nicht optimal sind, und doch ist es eines der 
erfolgreichsten Softwarehäuser. Ein Grund ist ganz sicher der, dass die 
Manager sich nicht auf der Suche nach Perfektion festbeißen.

Lasst es gut sein und freut eich statt dessen darüber, dass eure 
Software tut, was sie soll. Es gibt genug Menschen, die sich mit nicht 
funktionierendem Schrott auseinandersetzen müssen.

Ihr habt hier echt ein Luxusproblem. Lernt bitte, andere Lösungen und 
Meinungen zu akzeptieren. Es verlangt doch niemand, dass ihr euch auf 
die eine einzig wahre Wahrheit einigt. Die gibt es ohnehin nur bei 
religiösen Fanatikern. Über dieses Stadium sollten wir Techniker doch 
erhaben sein, oder nicht?

von Harry L. (mysth)


Lesenswert?

So funktioniert Open-Source aber nicht!

Da setzt sich nämlich die bessere Lösung durch, und die übernimmt man 
dann in seinem Code.

Ich gewinne hier zunehmend den Eindruck, daß es eben doch primär um 
Eitelkeiten geht.

von Stefan F. (Gast)


Lesenswert?

Harry L. schrieb:
> So funktioniert Open-Source aber nicht!
> Da setzt sich nämlich die bessere Lösung durch

Nein, das ist die Theorie des Herrn Darwin.

Die Philosophie von Open-Source ist, dass jeder den Code nach seinem 
Gusto ändern kann und dadurch eine große Vielfalt entsteht.

> Ich gewinne hier zunehmend den Eindruck, daß es eben doch primär um
> Eitelkeiten geht.

Wenn schon, dann geht es um deine Eitelkeiten.

Nachtrag: Dein -1 kommt von woanders her. Ich finde deine Beiträge 
lesenswert weil du deine Meinung nachvollziehbar kund getan hast. Es 
sagt ja niemand, dass ich gleicher Meinung sein muss. Aber du hast das 
sicher schon bemerkt, dass die Bewertung von "lesenswert/nicht 
lesenswert" oft einfach als "stimme zu/stimme nicht zu" missbraucht 
wird.

von Harry L. (mysth)


Lesenswert?

Stefanus F. schrieb:
> Die Philosophie von Open-Source ist, dass jeder den Code nach seinem
> Gusto ändern kann und dadurch eine große Vielfalt entsteht.

Und genau aus dieser Vielfalt setzt sich das Bessere durch.
Wäre es anders, wäre ein Linux wie wir es heute kennen niemals 
entstanden.

Stefanus F. schrieb:
>> Ich gewinne hier zunehmend den Eindruck, daß es eben doch primär um
>> Eitelkeiten geht.
>
> Wenn schon, dann geht es um deine Eitelkeiten.

Wir sind doch hier nicht im Kindergarten, wo der Sandhaufen von Kevin 
eine genau so tolle Sandburg ist wie der Sandhaufen von Jaqueline.

Wir reden doch über Fakten.

ich hätte/habe jedenfalls kein Problem damit, fremden Code zu 
übernehmen, "wenn" er tatsächlich nach Fakten-Lage besser/effektiver als 
meine Lösung ist.

von M. K. (sylaina)


Lesenswert?

Harry L. schrieb:
> Das ganze inkl. main, startup und deinem Timer-Zeugs (für die Messung
> selbst) als Summe ist völlig nichts-sagend.

Sorry, aber das zeigt eindeutig, dass du anscheinend absolut keine 
Ahnung hast, wie man Zeiten mit einem AVR misst.

Harry L. schrieb:
> Wenn du unbedingt vergleichen willst, dann bitte auch mit belastbaren
> Zahlen.

Ich habe meinen Test-Code gepostet, auf Github gib es die entsprechende 
Library zum herunter laden und das kann so nun jeder selber gegenprüfen.

Damit ich meine Library (i2c + lcd) mit deiner (ebenfalls i2c + lcd) 
Vergleichen kann habe ich den selben Testcode verwendet, der Controller 
war/ist exakt gleich eingestellt und dabei habe ich obige Werte schlicht 
mit gemessen. Ich habe sogar zuvor mittels Portpin auch noch einen Puls 
erzeugt (Pin setzen vor dem Beschreiben und löschen nach dem 
Beschreiben) um sicher sein zu können, dass ich diesmal auch richtig 
messe und der Puls hatte stets auch die Zeit, die ich gemessen habe. 
Mein Test ist damit mehr als nur belastbar, er ist verifizierbar.

Stefanus F. schrieb:
> Die Philosophie von Open-Source ist, dass jeder den Code nach seinem
> Gusto ändern kann und dadurch eine große Vielfalt entsteht.

Und genau das war auch meine Intention und es freut mich sehr, dass 
Harry meine Lib als Ausgangsbasis benutzt hat um sie auf den ARM zu 
bringen. Sowas finde ich toll und ich bin diesbezüglich auch riesig 
Stolz darauf.

Harry L. schrieb:
> ich hätte/habe jedenfalls kein Problem damit, fremden Code zu
> übernehmen, "wenn" er tatsächlich nach Fakten-Lage besser/effektiver als
> meine Lösung ist.

Anscheinend schon ;)

: Bearbeitet durch User
von Harry L. (mysth)


Lesenswert?

M. K. schrieb:
> Harry L. schrieb:
>> Das ganze inkl. main, startup und deinem Timer-Zeugs (für die Messung
>> selbst) als Summe ist völlig nichts-sagend.
>
> Sorry, aber das zeigt eindeutig, dass du anscheinend absolut keine hast,
> wie man Zeiten mit einem AVR misst.

Und was hat das mit Zeiten zu tun?
Dabei ging es um Code/RAM-Grösse.

Wie ich meine Zeiten ermittelt hab, hab ich hier beschrieben:
Beitrag "Re: Universelles Oled-Libary (SSD1306) für AVR(8bit) und STM32/HAL"

M. K. schrieb:
> Damit ich meine Library (i2c + lcd) mit deiner (ebenfalls i2c + lcd)
> Vergleichen kann habe ich den selben Testcode verwendet, der Controller
> war/ist exakt gleich eingestellt und dabei habe ich obige Werte schlicht
> mit gemessen. Ich habe sogar zuvor mittels Portpin auch noch einen Puls
> erzeugt (Pin setzen vor dem Beschreiben und löschen nach dem
> Beschreiben) um sicher sein zu können, dass ich diesmal auch richtig
> messe und der Puls hatte stets auch die Zeit, die ich gemessen habe.
> Mein Test ist damit mehr als nur belastbar, er ist verifizierbar.

Du wirfst wahllos Performace und Grösse durcheinander.
Zur Laufzeit-Ermittlung: s.o.

belastbar und valide ist anders.

Tip: die tatsächliche Code-Grösse eines Object-File ermittelt man mit 
"size"
https://linux.die.net/man/1/size

: Bearbeitet durch User
von M. K. (sylaina)


Lesenswert?

Harry L. schrieb:
> Und was hat das mit Zeiten zu tun?
> Dabei ging es um Code/RAM-Grösse.

1. Wenn du nicht weißt wie man mit einem Timer auf dem AVR Zeiten misst 
halte ich es für sehr anmaßend, dass du die Ergebnisse anzweifelst
2. Es ging nicht nur um die Code-Größe sondern auch um die Zeiten. Um 
die RAM-Größe ging es bisher noch gar nicht.

Harry L. schrieb:
> Du wirfst wahllos Performace und Grösse durcheinander.
> Zur Laufzeit-Ermittlung: s.o.
>
> belastbar und valide ist anders.

Wo? Wo würfel ich das durcheinander? Nur weil dir das nicht passt? Dein 
Code kann gar nicht schneller sein als meiner. Und zwar ganz einfach 
weil ich ein Zeichen so übermittele
1
i2c_start(LCD_ADRESSE);
2
i2c_byte(LCD_DATA_PREFIX);
3
for(uint8_t i; i<CHAR_FONT_SIZE;i++){
4
  i2c_byte(CHAR[pos_in_FONT][i]);
5
}

und du machst das so
1
for(uint8_t i; i<CHAR_FONT_SIZE;i++){
2
  lcd_data(CHAR[pos_in_FONT][i]);
3
}
mit
1
void lcd_data(uint8_t data){
2
i2c_start(LCD_ADRESSE);
3
i2c_byte(LCD_DATA_PREFIX);
4
i2c_byte(data);

Ich habs vereinfacht nur um was zu verdeutlichen: Ich sende die 
LCD-Adresse mit jedem Zeichen, die bei dir und mir aus 8 Bytes bestehen, 
lediglich ein mal.
Das Gleiche gilt für das Kommando, dass dem LCD nun Daten übermittelt 
werden.

Du sendest aber mit jedem Byte eines Zeichens die LCD-Adresse und das 
Kommando für Daten. Damit musst du 7*2 Bytes = 14 Bytes mehr als ich dem 
Display schicken mit jedem Zeichen, dass du darstellen willst.

Und wenn wir beide das Display mit gleicher Geschwindigkeit betreiben 
musst du länger brauchen da du viel mehr Daten ans Display übermittelst 
als ich.

Übrigens: Du hast immer noch nicht erklärt was du überhaupt an der 
lcd_putc-Funktion warten willst.

Harry L. schrieb:
> Tip: die tatsächliche Code-Grösse eines Object-File ermittelt man mit
> "size"

Beim avr-gcc Toolchain heist es avr-size. Und was meinst du wie ich die 
Größe ermittelt hatte? Kannst du in meinem Github nachlesen ;)

: Bearbeitet durch User
von Harry L. (mysth)


Lesenswert?

M. K. schrieb:
> Ich habs vereinfacht nur um was zu verdeutlichen: Ich sende die
> LCD-Adresse mit jedem Zeichen, die bei dir und mir aus 8 Bytes bestehen,
> lediglich ein mal.
> Das Gleiche gilt für das Kommando, dass dem LCD nun Daten übermittelt
> werden.
>
> Du sendest aber mit jedem Byte eines Zeichens die LCD-Adresse und das
> Kommando für Daten. Damit musst du 7*2 Bytes = 14 Bytes mehr als ich dem
> Display schicken mit jedem Zeichen, dass du darstellen willst.

Du vergisst dabei, daß bei mir die 20 Zeichen (im Text-Mode) zentriert 
werden.
D.h.: ich muß mindestens am Anfang jeder Zeile einmal den RAM-Cursor neu 
initialisieren.
Das könnte man darauf beschränken, aber bläht imho den Code nur unnötig 
auf.
Die paar µs durch das zusätzliche gotoxy kratzen mich nicht wirklich.
4,4ms/Zeile sind für mich ok, und weitere Optimierungen stehen imho in 
keinem sinnvollen Verhältnis zum Aufwand.

M. K. schrieb:
> Übrigens: Du hast immer noch nicht erklärt was du überhaupt an der
> lcd_putc-Funktion warten willst.

2 nahezu identische Funktionen für putc für die Text- bzw. 
Graphic-Ausgabe ist alles Andere als wartungsfreundlich.

Und solche Konstruktionen:
1
uint8_t getCharPosition(char value){
2
  // getting chars position at font-array
3
  switch (value) {
4
        case 'ü':
5
            value = 95; // ü
6
            break;
7
        case 'Ü':
8
            value = 96; // Ü
9
            break;
10
        case 'ä':
11
            value = 97; // ä
12
            break;
13
        case 'Ä':
14
            value = 98; // Ä
15
            break;
16
...
17
...
18
...

sind einfach nur übel!

von Dieter F. (Gast)


Lesenswert?

Harry L. schrieb:
> Kindergarten

Scheint so.

von M. K. (sylaina)


Lesenswert?

Harry L. schrieb:
> 2 nahezu identische Funktionen für putc für die Text- bzw.
> Graphic-Ausgabe ist alles Andere als wartungsfreundlich.

Nochmal: Es hat seinen Grund warum sie nahezu identisch sind und was 
willst du daran warten?

Harry L. schrieb:
> 4,4ms/Zeile sind für mich ok, und weitere Optimierungen stehen imho in
> keinem sinnvollen Verhältnis zum Aufwand.

Mein Testcode hat gezeigt, dass meine Lib, dein Ausgang also, rund 10% 
schneller ist. Eigentlich hast du Aufwand reingesteckt um es langsamer 
zu machen. Dass dir das aber dennoch genügt ist auch völlig OK.

Harry L. schrieb:
> Und solche Konstruktionen:
> ...
> sind einfach nur übel!

Was ist daran übel? Das ist genauso übersichtlich wie deine Tabelle. Ich 
hab das Mapping nur auf anderem Wege gelöst, das ist aber deshalb nicht 
schlechter wie ich oben auch gezeigt habe. Weder von der Codegröße noch 
von der Performance

von Harry L. (mysth)


Lesenswert?

Ich bin raus aus dieser Diskussion.
Hab keine lust mehr, gegen Wände zu reden.

Du mußt noch viel lernen!

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Harry L. schrieb:
> Und genau aus dieser Vielfalt setzt sich das Bessere durch.

Auch das passiert nicht immer … davon abgesehen: was „das Bessere“ 
ist, legen die Nutzer fest, nicht die Autoren.

von Johannes S. (Gast)


Lesenswert?

Jörg W. schrieb:
> Auch das passiert nicht immer … davon abgesehen: was „das Bessere“ ist,
> legen die Nutzer fest, nicht die Autoren.

Und danach gibt es nichts besseres als Arduino :  (weiß gerade nicht ob 
und welchen Smiley ich anbringen soll).

von M. K. (sylaina)


Lesenswert?

Harry L. schrieb:
> Ich bin raus aus dieser Diskussion.
> Hab keine lust mehr, gegen Wände zu reden.
>
> Du mußt noch viel lernen!

Das Problem ist ja nur, dass du gegen die Wand redest, die du selbst 
erbaut hast.

Ich gehe ja auf deine Vorschläge ein, so habe ich ja z.B. die 
lcd_putc()-Funktion umgebaut. Da war deine Kritik auch völlig 
berechtigt.

Dann habe ich, weil ich eben der Meinung war, dass dein Code länger 
brauchen müsste als meiner (das hatte ich ja an deiner Library 
kritisiert), einen Performance-Test durchgeführt.
Es stellte sich stets heraus, dass meine Vermutung zu traf.

Das hast du nicht geglaubt: Post #5552007

Ich habe dann meinen Code mit dem ich das getestet hatte, gepostet: Post 
#5552108

Hier hast du z.b. bemängelt, dass ich mit float gerechnet habe, wie ich 
die Zeit bestimmt habe, war die trotz Code und Angabe, wie der 
Mikrocontroller eingestellt ist, überhaupt nicht klar.
Wirklich gegengemessen hast du zu diesem Zeitpunkt nicht.

Ich habe zwischenzeitlich aufgrund deiner berechtigten Kritik am Umgang 
mit Sonderzeichen in der putc-Funktion meine Library umgebaut.

Auch hier führte ich den obigen Performance-Test durch und kam auf eine 
neue, noch schnellere, Zeit.
Auch das hast du bemängelt: Post #5557315
Du hattest es als unglaubwürdig bezeichnet, darauf hin hab ich meine 
Code nochmal überprüft und festgestellt, dass der Mikrocontroller falsch 
eingestellt war: Post #5557816
Auch dafür danke ich dir denn du hast mir so einen Fehler gezeigt.

Hier habe ich dann den Mikrocontroller richtig eingestellt und deine und 
meine Library miteinander verglichen. Das Ergebnis davon war, dass meine 
Library immer noch kleiner und auch schneller ist als deine Library.

Und an diesem Punkt hast du meine Testmethode als nicht geeignet 
bezeichnet du hattest ja zwischenzeitlich einen eigenen Test ins Feld 
geführt.
Mein Test soll ja nicht valide und belastbar sein. Und das obwohl der 
Code zum Test oben für jeden, sogar für Gäste, zugänglich und nachlesbar 
ist. Ich weis hier ehrlich nicht wie man mehr valide sein will, sein 
kann, wenn man schon alles für jederman sichtbar veröffentlicht hat. 
Mehr valide&belastbar geht dabei gar nicht.

Nachfragen, was du z.B. an der putc() warten willst oder warum das 
Handhaben von Sonderzeichen schlecht sein soll hast du bisher nicht 
beantwortet.

Ich bin jetzt aber dennoch darauf eingegangen und habe meine Library nun 
noch einmal umstrukturiert.

- Es gibt jetzt keine gleichnamigen Funktionen mehr, die sich bzgl. 
Textmode und Graphicmode nur minimal unterscheiden. Die Unterscheidung, 
ob das Display im Graphicmode oder Textmode ist, ist nun direkt in den 
Funktionen untergebracht (das gilt auch für die lcd_gotoxy() und 
lcd_clrscr()).
- Sonderzeichen werden nun durch ein zweidimensionales Array zugeordnet 
wo sie im Font-Satz stehen, die lcd_putc()-Funktion durchsucht dieses 
Array.

Die Performance meiner Library hat sich dadurch im Graphicmode noch 
einmal minimal gesteigert (knapp eine Millisekunde), beim Textmode ist 
die Performance gleich geblieben.
Die Code-Größe hat sich nicht nennenswert verändert.

Unterm Strich: Meine Library ist immer noch schneller als deine Variante 
und benötigt weniger Flash/RAM. Um es mal in deiner Darstellung zu 
visualisieren (meine war ja anscheinend nicht ausreichend):

Speicherbedarf
1
Modul       | Code (Flash) | Stat. RAM
2
------------+--------------+------------
3
I2C-Core    | 120 Byte     |    0
4
Oled (TXT)  | 1569 Byte    |    2 Byte
5
Oled (GFX)  | 2789 Byte    | 1026 Byte

Ich finde es schade, dass du dich so aus der Diskussion verabschiedest.

: Bearbeitet durch User
von Otto (Gast)


Lesenswert?

Ich hätte da einen Vorschlag:
jetzt, wo das Wetter wieder besser wird, stellt Ihr euch gegenüber, 
jeder mit einem Wasserschlauch bewaffnet, und tragt den Streit aus!

von 900ss (900ss)


Lesenswert?

M. K. schrieb:
> Ich finde es schade, dass du dich so aus der Diskussion verabschiedest.

Nein es ist gut damit der Kindergarten-Zank aufhört. Echt albern.

von OLEDer (Gast)


Lesenswert?

Hi sylaina,

vielen Dank zunächst für die ganze Arbeit!

Ich bräuchte allerdings einmal Hilfe, da ich die Lib nicht lauffähig 
bekomme.

Als Display benutze ich das 0,96" Display von 42project (mit SSD1306 
Treiber), als uC den ATMega164PA.

Mit einem Arduino Uno und der U8glib funktioniert es problemlos, 
allerdings ist mit diese Lib zu groß und unübersichtlich für persönliche 
Erweiterungen.

SDA und SCL sind direkt an dem uC angeschlossen, da das Display soweit 
ich weiß über interne Pull-Ups verfügt.

Zum Test habe ich dein Beispiel aus der Lib (Git) genommen, das dort in 
der Main hinterlegt ist.
Muss ich selbst an dem uC noch Einstellungen vornehmen, die dort nicht 
vermerkt sind?
Den mit diesem simplen Code bleibt das Display leider schwarz.

Danke für deine Hilfe.

von OLEDer (Gast)


Lesenswert?

Treiber habe ich in der "lcd.h" auf SSD1306 geändert und von "Graphic" 
in "textmode" gewechselt.

Hab grade noch mal mit meinem ATMega328P probiert, auch hier 
funktioniert es nicht.

Mit meinem Messgerät messe ich auf der "SCL" Leitung einen Takt von 
50kHz, in der "lcd.h" sind 100.000 eingetragen. Ist dem so richtig?

von Harry L. (mysth)


Lesenswert?

Ohne PullUps wird das nix...

Wer misst, misst Mist

von Stefan F. (Gast)


Lesenswert?

> SDA und SCL sind direkt an dem uC angeschlossen, da das Display soweit
> ich weiß über interne Pull-Ups verfügt.

Du kannst das ganz einfach nachmessen: Im Ruhezustand muss der Pegel 
HIGH sein und ein Amperemeter (von SDA nach GND bzw. SCL nach GND) 
müsste ca. 1mA anzeigen.

von Dieter F. (Gast)


Lesenswert?

Harry L. schrieb:
> Ohne PullUps wird das nix..

Sind auf dem OLED.

von Harry L. (mysth)


Lesenswert?

Dieter F. schrieb:
> Harry L. schrieb:
>> Ohne PullUps wird das nix..
>
> Sind auf dem OLED.

Auf Deinem vielleicht...auf meinem nicht.
Und die gehören da auch nicht hin!

von Dieter F. (Gast)


Lesenswert?

Harry L. schrieb:
> Und die gehören da auch nicht hin!

Habe es mal auf chinesich übersetzt - für die Zielgruppe:

他们也不属于那里!

von OLEDer (Gast)


Lesenswert?

Stefanus F. schrieb:
> Du kannst das ganz einfach nachmessen: Im Ruhezustand muss der Pegel
> HIGH sein und ein Amperemeter (von SDA nach GND bzw. SCL nach GND)
> müsste ca. 1mA anzeigen.

Habe ich grade mal gemacht. Es fließen jeweils 0.33mA.

von Stefan F. (Gast)


Lesenswert?

Dann hast du 10k Ohm. Fuer die maximale Bitrate ist das zu viel.

von Harry L. (mysth)


Lesenswert?

Stefanus F. schrieb:
> Dann hast du 10k Ohm. Fuer die maximale Bitrate ist das zu viel.

Bei 3,3V...

Bei 5V wären das sogar 15k....

https://www.nxp.com/docs/en/user-guide/UM10204.pdf

von Stefan F. (Gast)


Lesenswert?

Die I²C Spezifikation alleine reicht so nicht. Man muss die Kapazitäten 
der Leitungen und Bauteile berücksichtigen.

von M. K. (sylaina)


Lesenswert?

OLEDer schrieb:
> Muss ich selbst an dem uC noch Einstellungen vornehmen, die dort nicht
> vermerkt sind?
> Den mit diesem simplen Code bleibt das Display leider schwarz.

Ja, in der lcd.h musst du z.B. einstellen, dass es ein SSD1306-Display 
ist, das Github ist auf SH1106 eingestellt.
Die Adresse musst du auch korrekt einstellen. Auf den Displays, so meine 
Erfahrung, ist meist die Adresse im 8-Bit-Format angegeben. Daher ist da 
in meiner Lib diese merkwürdige Shift-Option. Willst du die Adresse 
direkt im 7-bit-Format angeben (statt z.B. 0x78 gleich 0x3c angeben) 
dann darfst du natürlich nicht shiften.

Zudem viel mir grade beim Github auf, dass ich vergessen hatte, die 
font.c dem Linker hinzuwerfen, das habe ich grade noch korrigiert (das 
wirft aber typischerweise Fehler da er dann den Font nicht linken kann).

von Harry L. (mysth)


Lesenswert?

Stefanus F. schrieb:
> Die I²C Spezifikation alleine reicht so nicht. Man muss die Kapazitäten
> der Leitungen und Bauteile berücksichtigen.
Kann man bei Kabellängen unter ~50cm komplett ignorieren...

So, wie es in o.g. DB steht funktioniert das auch.

: Bearbeitet durch User
von OLEDer (Gast)


Lesenswert?

Stefanus F. schrieb:
> Dann hast du 10k Ohm. Fuer die maximale Bitrate ist das zu viel.

Ja es sind 3.3 V für das Display.
Aber da es mit der normalen U8glib funktioniert, dürfte es eigentlich 
kein Problem darstellen.

von OLEDer (Gast)


Lesenswert?

M. K. schrieb:
> Ja, in der lcd.h musst du z.B. einstellen, dass es ein SSD1306-Display
> ist, das Github ist auf SH1106 eingestellt.

Hatte ich oben noch beigefügt, Treiber ist entsprechend eingestellt. Die 
F_CPU muss ich auch noch manuell einfügen, ist das richtig? Das habe ich 
auch bereits gemacht.

> Die Adresse musst du auch korrekt einstellen. Auf den Displays, so meine
> Erfahrung, ist meist die Adresse im 8-Bit-Format angegeben. Daher ist da
> in meiner Lib diese merkwürdige Shift-Option. Willst du die Adresse
> direkt im 7-bit-Format angeben (statt z.B. 0x78 gleich 0x3c angeben)
> dann darfst du natürlich nicht shiften.

Das hatte ich auch noch nicht so ganz verstanden. Die Adresse meines 
Displays (I2C-Scanner) ist 0x3C, ich habe jetzt vermutet das es sich um 
die Adresse handelt, die Bereits in der lcd.h angegeben ist, jedoch in 
einem anderen Format. Diese habe ich soweit nicht verändert.

Allerdings steht in der "lcd.h" 0x7A nicht 0x78, kann das der Fehler 
sein?
Gleich mal ausprobieren.

von OLEDer (Gast)


Lesenswert?

OLEDer schrieb:
> Allerdings steht in der "lcd.h" 0x7A nicht 0x78, kann das der Fehler
> sein?
> Gleich mal ausprobieren.

Auch mit 0x78 bleibt es dunkel.

von Harry L. (mysth)


Lesenswert?

OLEDer schrieb:
> Allerdings steht in der "lcd.h" 0x7A nicht 0x78, kann das der Fehler
> sein?
> Gleich mal ausprobieren.

Für unmodifizierte Displays muß die Adresse 0x78 sein

0x78 = 0x3c << 1

Bit 0 ist für R/W zuständig.
Die I²C-Adresse steht in den oberen 7bit.

: Bearbeitet durch User
von OLEDer (Gast)


Lesenswert?

Harry L. schrieb:
> 0x78 = 0x3c << 1
>
> Bit 0 ist für R/W zuständig.
> Die I²C-Adresse steht in den oberen 7bit.

Danke für den Hinweis, das macht es etwas verständlicher.

von Ralph S. (jjflash)


Lesenswert?

... in einem Buch (vor Jahren, welches weiß ich nicht mehr), wurde 
behauptet, ein I2C Device besitze 2 Adressen, eine Adresse zum Lesen, 
eine zum Schreiben.

Wenn man dieses so betrachtet hat ein Display die Adresse 0x78 und 0x79 
und das R/W Flag ist somit Bestandteil der Adresse (und nicht wirklich 
ein Flag).

Wenn man es als Flag und nicht als Bestandteil der Adresse sieht, dann 
besteht die Adresse aus 7 Bits deren niederwertiges Bit in D1 im Byte 
(und nicht D0) ist.

Ist das nirgendwo festgelegt, wie das zu betrachten ist ?

von M. K. (sylaina)


Lesenswert?

OLEDer schrieb:
> Hatte ich oben noch beigefügt, Treiber ist entsprechend eingestellt. Die
> F_CPU muss ich auch noch manuell einfügen, ist das richtig? Das habe ich
> auch bereits gemacht.

Ich schau mal was du so geschrieben hattest, hab mir nicht alles genau 
durchgelesen.

OLEDer schrieb:
> Mit meinem Messgerät messe ich auf der "SCL" Leitung einen Takt von
> 50kHz, in der "lcd.h" sind 100.000 eingetragen. Ist dem so richtig?

Öhm...das ist nicht richtig, wenn du 100 kHz einstellst soll es auch mit 
100 kHz laufen. Entweder stimmt das F_CPU nicht oder was anderes. Was 
direkt aber auffällt: Die I2C-Settings werden in der i2c.h eingestellt, 
nicht in der lcd.h.

Bevor wir weiter lang rumraten: Zippe doch mal dein Projekt und lade es 
hier hoch, dann könnten wir es runter laden und mal schaun. Benutzt du 
z.B. einen Arduino Nano/Uno mit der Arduino-IDE? Da sind besondere 
Einstellungen dann noch nötig die im Github in der Readme ganz unten 
beschrieben sind.

Ralph S. schrieb:
> ... in einem Buch (vor Jahren, welches weiß ich nicht mehr), wurde
> behauptet, ein I2C Device besitze 2 Adressen, eine Adresse zum Lesen,
> eine zum Schreiben.

Hm, das kann man so sehen, dann muss man aber sagen, dass jeder 
I2C-Baustein aus mindestens 2 I2C-Geräten besteht. Ne, diese 
Betrachtungsweise ist im Prinzip unsinn.
Man kann sagen, dass ein I2C-Device eine 8-bit Adresse hat bei der das 
LSB dem Device schlicht nur mitteilt, ob das Device gelesen oder 
beschrieben werden soll.
Die OLED-Displays mit SSD1306 bzw. SH1106 können jedoch mit dem 
I2C-Interface nicht quatschen, deshalb muss man bei diesen Displays mit 
einem Puffer arbeiten wenn man darauf zeichnen will und dabei den 
aktuellen Inhalt nicht löschen möchte. Und deshalb werte ich auch das 
Ack/NAck bei den Displays nicht aus (das ist das Einzige, dass sie einem 
zurück liefern), es ist mir wurscht wie sie Antworten wenn ich ihnen 
Daten schicke. Wenn was schief geht könnten sie mir eh nicht sagen, was 
schief gegangen ist.

von Ralph S. (jjflash)


Lesenswert?

M. K. schrieb:
> Wenn was schief geht könnten sie mir eh nicht sagen, was
> schief gegangen ist

Wenn sie nicht antworten weißt du aber, DASS etwas schief gegangen 
ist...

von OLEDer (Gast)


Angehängte Dateien:

Lesenswert?

M. K. schrieb:
> Bevor wir weiter lang rumraten: Zippe doch mal dein Projekt und lade es
> hier hoch, dann könnten wir es runter laden und mal schaun. Benutzt du
> z.B. einen Arduino Nano/Uno mit der Arduino-IDE? Da sind besondere
> Einstellungen dann noch nötig die im Github in der Readme ganz unten
> beschrieben sind.

Wie gesagt nutze ich einen ATMega164PA, den Code erstelle ich in Atmel 
Studio 7 und nutze einen ISP zum übertragen, da der chip45 Bootloader 
nicht für den PA funktioniert.

von Dieter F. (Gast)


Lesenswert?

Setze den
1
#define PSC_I2C      1    // prescaler i2c

mal auf 2.

So wird der Wert für TWBR zu groß - bzw. nach Zuweisung unpassend (das 
sollte im Header mit einer Meldung bedacht werden ... - nur so, als 
Anregung :-) )

von M. K. (sylaina)


Lesenswert?

Dieter F. schrieb:
> So wird der Wert für TWBR zu groß

Dann hätte er nicht weiter compilieren können, der gcc wäre mit Fehler 
stehen geblieben. Kann man sich auch selbst ausrechnen: Bei 16 MHz und 
100 kHz I2C Taktrate kommt da 72 bei raus. Das ist bei weitem nicht zu 
groß für TWBR.

OLEDer schrieb:
> Wie gesagt nutze ich einen ATMega164PA, den Code erstelle ich in Atmel
> Studio 7 und nutze einen ISP zum übertragen, da der chip45 Bootloader
> nicht für den PA funktioniert.

Ich glaube auch nicht, dass es am ISP liegt.

Ich hab mal rein geschaut, mit dem Atmel Studio kenn ich mich aber nicht 
aus. Das nutze ich idR nur wenn ich einen Attiny4 oder ähnliches 
(TPI-Schnittstelle) programmieren/flashen will.

1. Frage: Das Projekt kompiliert absolut ohne Fehlermeldung, ja? Ich 
erhalte beim Build die Meldung "recipe for target "Display_test.elf" 
failed.". Ich kann das aber auf die Schnelle nicht interpretieren, mir 
scheint aber, dass er irgend etwas nicht findet. Beim zweiten 
Build-Versuch wird dann fehlerfrei übersetzt. Es sollte aber auch schon 
beim 1. Build funktionieren.
2. Hinweis: F_CPU kann man auch als Projektvariable anlegen, dann ist 
sie jedem File bekannt. Ich mein das ging irgendwie über 
Properties-Symbols. Google weis hier sicher mehr.

von Stefan F. (Gast)


Lesenswert?

Ralph S. schrieb:
> Ist das nirgendwo festgelegt, wie das zu betrachten ist ?

In der I²C Spezifikation 
(https://www.nxp.com/docs/en/user-guide/UM10204.pdf) steht:

> After the START condition (S), a slave address is sent. This address
> is seven bits long followed by an eighth bit which is a data direction
> bit (R/W).

Für mich ist damit klar, dass die Slave Adresse 7bit groß ist. Dieses 
R/W Bit ist nicht Bestandteil der Adresse. Das wird auch in sämtlichen 
folgenden Diagrammen und Tabellen so dargestellt.

Deswegen halte ich es für falsch, dass viele Libraries als Input 8bit 
Werte inclusive R/W Bit erwarten und dass dann "address" nennen.

Richtig verwirrend wird es bei dieser kruden 8bit Variante, wenn man 
einen I²C Slave ansprechen will, der nur Write Operationen kennt. Dann 
muss man nämlich immer noch die 8bit Adresse mit bit0=Low konfigurieren, 
obwohl tatsächlich immer bit0=High gesendet wird.

von Dieter F. (Gast)


Lesenswert?

M. K. schrieb:
> Dann hätte er nicht weiter compilieren können, der gcc wäre mit Fehler
> stehen geblieben. Kann man sich auch selbst ausrechnen: Bei 16 MHz und
> 100 kHz I2C Taktrate kommt da 72 bei raus. Das ist bei weitem nicht zu
> groß für TWBR.

Hast Recht - schlechter Morgen ...

von OLEDer (Gast)


Lesenswert?

M. K. schrieb:
> 1. Frage: Das Projekt kompiliert absolut ohne Fehlermeldung, ja? Ich
> erhalte beim Build die Meldung "recipe for target "Display_test.elf"
> failed.". Ich kann das aber auf die Schnelle nicht interpretieren, mir
> scheint aber, dass er irgend etwas nicht findet. Beim zweiten
> Build-Versuch wird dann fehlerfrei übersetzt. Es sollte aber auch schon
> beim 1. Build funktionieren.

Beim ersten mal bekomme ich nur eine Warnung für die Umlaute.

"case lable value less than minimum value for type"
"multi-character character constant [-Wmultichar]"

Ansonsten läuft es problemlos durch.

Auch eine Änderung am prescaler hat nichts bewirkt.

von OLEDer (Gast)


Lesenswert?

Ich hab nochmal etwas rum probiert, jetzt funktioniert es.
Zum einen lag es wohl an der falschen Adresse in der "lcd.h", da dort 
standardmäßig 0x7A steht und zum anderen das ich im Projekt selbst noch 
328P stehen hatte, beim flaschen aber 164PA ausgewählt habe.

Vielen dank für eure Hilfe und ganz besondern nochmal an sylaina für die 
tolle Lib, wirklich hervorragende Arbeit!!

von M. K. (sylaina)


Lesenswert?

OLEDer schrieb:
> Beim ersten mal bekomme ich nur eine Warnung für die Umlaute.
>
> "case lable value less than minimum value for type"
> "multi-character character constant [-Wmultichar]"

Da wird das Encoding des Quellcodes nicht richtig erkannt, schau dir 
noch mal die Readme an, da steht drin welches Flag man wie setzen muss 
damit der Compiler die Quellcode-Dateien auch richtig dekodiert mit dem 
richtigen Encoding.

Zudem hab ich gesehen, dass du noch eine alte Version meiner Lib 
benutzt. Geh mal auf:

https://www.github.com/Sylaina/oled-display/

da findest du die aktuelle Version. Die braucht zum einem noch etwas 
weniger Flash und ist noch schneller als die alte Version.

von OLEDer (Gast)


Lesenswert?

M. K. schrieb:
> Da wird das Encoding des Quellcodes nicht richtig erkannt, schau dir
> noch mal die Readme an, da steht drin welches Flag man wie setzen muss
> damit der Compiler die Quellcode-Dateien auch richtig dekodiert mit dem
> richtigen Encoding.

Da steht nur drin, was ich ändern muss, aber nicht der Befehl dafür. 
Wenn ich den Befehl "-finput-charset=utf-8 -fexec-charset=iso-8859-15" 
aus dem Makefile nehme, bekomme ich den Fehler:

"no iconv implementation, cannot convert from UTF - 8 to iso..."

Den oben genannten befehl füge ich bei

Toolchain -> AVR/GNU C Compiler -> Miscellanneous

ein.

> Zudem hab ich gesehen, dass du noch eine alte Version meiner Lib
> benutzt.

Dann müsste der Link im ersten Post korrigiert werden, denn der verweißt 
noch auf die ältere Version.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

OLEDer schrieb:
> "no iconv implementation, cannot convert from UTF - 8 to iso..."

Ohne ein erreichbares iconv bleibt dir nur übrig, den Quelltext selbst 
gleich als ISO-8859-1[5] abzuspeichern.  Wie das geht (und ob es 
überhaupt geht), hängt vom jeweils benutzten Editor ab.

von Harry L. (mysth)


Lesenswert?

Die Lösung ist, statt der Umlaute im Source die numerischen Konstanten 
zu nutzen.
Also z.B. statt 'ä' '\x84'

: Bearbeitet durch User
von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Harry L. schrieb:
> Also z.B. statt 'ä' '\x84'

Das wäre allerdings nicht ISO8859-1[5].

Dort liegen die Umlaute wie folgt:
1
$ echo -n 'äöüÄÖÜß' | iconv -f utf-8 -t iso8859-1 | hd
2
00000000  e4 f6 fc c4 d6 dc df                              |.......|
3
00000007

: Bearbeitet durch Moderator
von Harry L. (mysth)


Lesenswert?

Jörg W. schrieb:
> Harry L. schrieb:
>> Also z.B. statt 'ä' '\x84'
>
> Das wäre allerdings nicht ISO8859-1[5].
>
> Dort liegen die Umlaute wie folgt:
>
>
1
> $ echo -n 'äöüÄÖÜß' | iconv -f utf-8 -t iso8859-1 | hd
2
> 00000000  e4 f6 fc c4 d6 dc df                              |.......|
3
> 00000007
4
>

"welchen" 8Bit-Zeichensatz man nutzt, ist dabei doch vollkommen egal.
So lange man im Source numerische Konstanten für die Sonderzeichen nutzt 
ist das eindeutig, und der Compiler hat nix zu meckern.
.

: Bearbeitet durch User
von M. K. (sylaina)


Lesenswert?

OLEDer schrieb:
> Da steht nur drin, was ich ändern muss, aber nicht der Befehl dafür.

Richtig, aber ich dachte auch, dass das eindeutig ist. So wie z.B. ein 
"make all" das entsprechende Programm samt EEPROM-File und Co erzeugt.

OLEDer schrieb:
> Dann müsste der Link im ersten Post korrigiert werden, denn der verweißt
> noch auf die ältere Version.

Öhm, nö. Nicht den Dateianhang laden sondern dem Link im ersten Post 
folgen, der führt dich zur aktuellen Version der Lib

M. K. schrieb:
>> Edit: Github link https://github.com/Sylaina/oled-display.git

Harry L. schrieb:
> So lange man im Source numerische Konstanten für die Sonderzeichen nutzt
> ist das eindeutig, und der Compiler hat nix zu meckern.

Das ist zwar richtig aber später in der main wird wohl kaum einer auf 
die Idee kommen, statt z.B. 'ä' ein '0x84' zu schreiben und schon wirds 
wieder wichtig, was der Editor/Compiler benutzt. Wenn der nämlich ein 
Charset benutzt, bei dem ein 'ä' z.B. nicht bei '0x84' steht sondern bei 
z.B. '0xe4' (da stehts bei ISO 8859-1, unserem typischen Latin-1) 
bekommt man wieder nicht das, was man eigentlich will.

von Harry L. (mysth)


Lesenswert?

M. K. schrieb:
> Harry L. schrieb:
>> So lange man im Source numerische Konstanten für die Sonderzeichen nutzt
>> ist das eindeutig, und der Compiler hat nix zu meckern.
>
> Das ist zwar richtig aber später in der main wird wohl kaum einer auf
> die Idee kommen, statt z.B. 'ä' ein '0x84' zu schreiben und schon wirds
> wieder wichtig, was der Editor/Compiler benutzt. Wenn der nämlich ein
> Charset benutzt, bei dem ein 'ä' z.B. nicht bei '0x84' steht sondern bei
> z.B. '0xe4' (da stehts bei ISO 8859-1, unserem typischen Latin-1)
> bekommt man wieder nicht das, was man eigentlich will.

Das Kunststück,das für alle denkbaren IDE/Editoren/OS hinzubekommen will 
ich sehen!

: Bearbeitet durch User
von OLEDer (Gast)


Lesenswert?

M. K. schrieb:
> Richtig, aber ich dachte auch, dass das eindeutig ist. So wie z.B. ein
> "make all" das entsprechende Programm samt EEPROM-File und Co erzeugt.

Das stimmt, aber dafür müsste man sich dann mit Compiler Befehlen und 
deren Implementierung auskennen.

> Öhm, nö. Nicht den Dateianhang laden sondern dem Link im ersten Post
> folgen, der führt dich zur aktuellen Version der Lib

Ich hab den Thred anfangs erst einmal durchgelesen und dann wie weiter 
unten geschrieben im ersten Post den github Link benutzt. Da bin ich auf 
die Lib gekommen die ich bisher benutzt habe.
Wie auch immer, jetzt habe ihc ja die aktuelle Version.

Zu den Umlauten:

Ich hätte jetzt gedacht, das Atmel Studio so etwas hin bekommt. Naja, so 
kann man sich täuschen. Aber ich denke, ich kann auf die Umlaute gut 
verzichten, dann spare ich mir den switch vergleich und der code wird 
noch etwas schneller ^^

von M. K. (sylaina)


Angehängte Dateien:

Lesenswert?

Harry L. schrieb:
> Das Kunststück,das für alle denkbaren IDE/Editoren/OS hinzubekommen will
> ich sehen!

Ist doch einfach:

Mein Beispielcode von oben.
Font von meiner Library, 'ä' gegen 0x84 ersetzt, die 
Charset-Konfiguration aus dem Makefile entfernt.
Im main meines Beispielcodes folgende beide Zeilen direkt nach dem Code 
zum print von Zeile 1 eingefügt:
1
lcd_gotoxy(0,1);
2
lcd_puts("Test: ä");

Ergebnis ist das angehangene Bild. Ich mag was mit dem Auge habe aber 
ich sehe kein "ä", du etwa? Sowie ich aber den Charset wieder einfüge 
gibts auch ein "ä".
Ich kann alternativ auch im Font 'ä' durch 0xe4 ersetzen, dann steht da 
auch ein ä auf dem Display.
Das zeigt: Es kommt drauf an, welches Textencoding der Compiler benutzt 
um ein 0x84 (oder 0xe4) als 'ä' zu erkennen.

: Bearbeitet durch User
von M. K. (sylaina)


Lesenswert?

OLEDer schrieb:
> Ich hätte jetzt gedacht, das Atmel Studio so etwas hin bekommt. Naja, so
> kann man sich täuschen. Aber ich denke, ich kann auf die Umlaute gut
> verzichten, dann spare ich mir den switch vergleich und der code wird
> noch etwas schneller ^^

Nimm doch die aktuelle Lib, da ist auch kein Switch-Vergleich mehr drin 
;)

von Harry L. (mysth)


Lesenswert?

M. K. schrieb:
> Das zeigt: Es kommt drauf an, welches Textencoding der Compiler benutzt
> um ein 0x84 (oder 0xe4) als 'ä' zu erkennen.

So ein Blödsinn!
Es kommt bei solchen Anwendungen (das ist kein PC-Programm bei dem es so 
hübsche Dinge wie i18n gibt!!) darauf an, was du als "ä" definierst!

Außerdem nutzt nicht jeder Makefiles, und IDEs haben z.T. sehr 
unterschiedliche Vorstellungen von der Zeichencodierung.

Bei Displays, die einen integrierten Char-Generator haben, kommt es 
zusätzlich darauf an, an welcher Position das "ä" steht.

So, wie du das gelöst hast, funktioniert das bei dir - eine allgemein 
gültige Lösung ist das jedenfalls nicht.

Aber, wenn du meinst, daß du das alles so richtig verstanden 
hast....bitte sehr!

Hab keinerlei Lust, hier ein weiteres Faß auf zu machen.

: Bearbeitet durch User
von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

M. K. schrieb:
> Das ist zwar richtig aber später in der main wird wohl kaum einer auf
> die Idee kommen, statt z.B. 'ä' ein '0x84' zu schreiben

Ich habe mir dann immer mit sowas beholfen:
1
#define sz "\xdf"
2
#define ae "\xe4"
3
4
...
5
   printf("Damit geht das verl"ae sz"lich");

Harry L. schrieb:
> Hab keinerlei Lust, hier ein weiteres Faß auf zu machen.

Fein, wir haben vom letzten noch genug. :/

OLEDer schrieb:
> Zu den Umlauten:
>
> Ich hätte jetzt gedacht, das Atmel Studio so etwas hin bekommt.

Offensichtlich haben sie bei Atmel/Microchip nicht dran gedacht, ein 
iconv-Binary mitzuliefern.

Mach doch bei ihnen einfach mal einen Bugreport auf.

: Bearbeitet durch Moderator
von M. K. (sylaina)


Lesenswert?

Harry L. schrieb:
> So ein Blödsinn!
> Es kommt bei solchen Anwendungen (das ist kein PC-Programm bei dem es so
> hübsche Dinge wie i18n gibt!!) darauf an, was du als "ä" definierst!

Das ist völlig richtig aber: Der Compiler ist doch ein PC-Programm und 
der muss doch den Kram 1. erstmal einlesen (Quellcode usw.) und 2. 
daraus was für den Mikrocontroller Ausführbares machen (Hex-Files, 
EEPRom-Files usw.). Deswegen heißt das eine ja auch input und das andere 
exec.

Harry L. schrieb:
> So, wie du das gelöst hast, funktioniert das bei dir - eine allgemein
> gültige Lösung ist das jedenfalls nicht.

Wenn man die Randbedingungen beachtet, die ich in der Readme angegeben 
habe, dann funktioniert das nicht nur bei mir so sondern bei jedem.

Harry L. schrieb:
> Hab keinerlei Lust, hier ein weiteres Faß auf zu machen.

Gute Idee.

von Harry L. (mysth)


Lesenswert?

Jörg W. schrieb:
> Ich habe mir dann immer mit sowas beholfen:
> #define sz "\xdf"
> #define ae "\xe4"
>
> ...
>    printf("Damit geht das verl"ae sz"lich");

Ein der wenigen sinnvollen Lösungen!

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Harry L. schrieb:
> Jörg W. schrieb:
>> Ich habe mir dann immer mit sowas beholfen:
>> #define sz "\xdf"
>> #define ae "\xe4"
>>
>> ...
>>    printf("Damit geht das verl"ae sz"lich");
>
> Ein der wenigen sinnvollen Lösungen!

Sinnvoll ist es natürlich auch, wenn man den Text flüssig schreiben 
kann. Bei dieser Variante ist man halt komplett unabhängig vom host und 
execution charset.

von M. K. (sylaina)


Lesenswert?

Harry L. schrieb:
> Jörg W. schrieb:
>> Ich habe mir dann immer mit sowas beholfen:
>> #define sz "\xdf"
>> #define ae "\xe4"
>>
>> ...
>>    printf("Damit geht das verl"ae sz"lich");
>
> Ein der wenigen sinnvollen Lösungen!

Würde nur mit deinem Font nicht funktionieren da da ä als 0x84 definiert 
ist und ß mit 0xe1. 0xdf (223) und 0xe4 (228) kennt dein Font nicht. 
Wenn die Codes nicht zum geplanten Charset passen kannst du dich auf den 
Kopf stellen und mit den Füßen wackeln und es wird nicht fnuktionieren.

von Harry L. (mysth)


Lesenswert?

Jörg W. schrieb:
> innvoll ist es natürlich auch, wenn man den Text flüssig schreiben
> kann. Bei dieser Variante ist man halt komplett unabhängig vom host und
> execution charset.

Einen Tod musst du sterben....

Mich mit dem Compiler über den verwendeten Zeichensatz herum zu streiten 
wiederstrebt mir zu tiefst.
Der Code sollte auf jedem System mit jeder Codepage zum selben Ergebnis 
führen.

von M. K. (sylaina)


Lesenswert?

Harry L. schrieb:
> Einen Tod musst du sterben....

Ja, und bevor ich den Tod sterbe mit irgendwelchen kryptischen 
Hex-Zahlen geh ich lieber her und sage konkret, welches Charset zu 
verwenden ist. Ich finde nämlich ein
1
#define sz "\xdf"
2
#define ae "\xe4"
3
4
...
5
   printf("Damit geht das verl"ae sz"lich");

ist bei weitem nicht so leicht zu lesen wie ein
1
printf("Damit geht das verläßlich");


Harry L. schrieb:
> Mich mit dem Compiler über den verwendeten Zeichensatz herum zu streiten
> wiederstrebt mir zu tiefst.

Was hat das mit herumstreiten zu tun. Das sind stink normale 
Einstellparameter. Wenn man so Sachen wie delay_ms verwendet muss man 
dem Compiler ja auch die korrekte Taktfrequenz des µCs mitteilen. Da 
kann man im makefile, das man ja eigentlich auch beim Code mitliefert, 
auch direkt die flags für die entsprechenden Charsets setzen.

Harry L. schrieb:
> Der Code sollte auf jedem System mit jeder Codepage zum selben Ergebnis
> führen.

Das kann schon per Definition nicht funktionieren da es unterschiedliche 
Charsets ad absurdum führen würde. Latin-1 und DOS-Latin-1 z.B. klingen 
ähnlich und haben Umlaute und Co doch nicht an den gleichen Stellen 
stehen. Zwei Charsets, die insbesondere beim extenden Set definitiv zu 
unterschiedlichen Ergebnissen kommen.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Harry L. schrieb:
> Der Code sollte auf jedem System mit jeder Codepage zum selben Ergebnis
> führen.

Die Zeit von „Codepages“ ist (zumindest in meiner Welt) vorbei. Der 
einzige Nachteil von UTF-8 an dieser Stelle ist es eben, dass dort die 
Umlaute dann Multibyte-Zeichen werden, sodass man sie nicht mehr in 
einem einfachen "char" abspeichern und verarbeiten kann. Für ein kleines 
Werkzeug auf einem Controller ist sowas natürlich lästig, da hätte man 
gern alle Zeichen in 8 Bit passend.

Wenn der Compiler UTF-8 als host character set akzeptiert, dann geht 
allerdings obiges auch so zu schreiben:
1
#define ä "\xe4"
2
#define ß "\xdf"
3
4
   ...
5
   printf("Verl"ä ß"lich");

Bekomme ich mit dem GCC aber gerade nicht akzeptiert, während der Clang 
es klaglos schluckt. Vorgeblich sollte GCC es zumindest mit -std=c99 
(oder höher) auch akzeptieren.

M. K. schrieb:
> Würde nur mit deinem Font nicht funktionieren da da ä als 0x84 definiert
> ist und ß mit 0xe1.

Dass diese Definitionen mit dem Font zusammenpassen müssen, sollte 
sonnenklar sein.

von M. K. (sylaina)


Lesenswert?

Jörg W. schrieb:
> Bei dieser Variante ist man halt komplett unabhängig vom host und
> execution charset.

Nö, ist man nicht. Ist das charset so eingestellt dass ein ä als 0x84 
dargestellt wird, wie das beim verwendeten Font von Harry der Fall ist, 
führt das zu einer fehlerhaften Ausgabe da sein Font kein Zeichen mit 
dem Code 0xe4 kennt ;)
Man kann natürlich Glück haben, dass die Defaulteinstellungen vom input 
so sind, dass ein ä ein 0xe4 ist und vom exec so, dass ein ä ein 0x84 
ist aber das wäre schlicht purer Zufall. Aber hat man Pech wird aus 
einem 0xe4 ein 0xe4 und dann sagt der Mikrocontroller nur "Das Zeichen 
ist im Font nicht enthalten."
Jörg W. schrieb:
> Dass diese Definitionen mit dem Font zusammenpassen müssen, sollte
> sonnenklar sein.

Eben das ist aber dem Harry nicht klar. Deshalb diskutieren wir ja 
darüber. Er meint ja, dass es besser wäre dem Compiler im Font besser 
den Hexcode zu geben als das Zeichen. In der main aber, so meine 
Meinung, wird man weniger mit hexcode den Font schreiben wollen als mit 
Zeichen. Daher ist es IMO sinniger im Font auch die Zeichen anzugeben 
und dem Compiler eben das korrekte Charset mitzuteilen. Dafür gibts ja 
extra flags beim gcc. Warum also sie nicht nutzen und sich somit das 
Leben leichter machen?

: Bearbeitet durch User
von Harry L. (mysth)


Lesenswert?

M. K. schrieb:
> Eben das ist aber dem Harry nicht klar. Deshalb diskutieren wir ja
> darüber. Er meint ja, dass es besser wäre dem Compiler im Font besser
> den Hexcode zu geben als das Zeichen. In der main aber, so meine
> Meinung, wird man weniger mit hexcode den Font schreiben wollen als mit
> Zeichen. Daher ist es IMO sinniger im Font auch die Zeichen anzugeben
> und dem Compiler eben das korrekte Charset mitzuteilen. Dafür gibts ja
> extra flags beim gcc. Warum also sie nicht nutzen und sich somit das
> Leben leichter machen?

Natürlich ist mir der Zusammenhang klar, aber meine IDE verwendet UTF-8 
- und jetzt?

: Bearbeitet durch User
von M. K. (sylaina)


Lesenswert?

Harry L. schrieb:
> Natürlich ist mir der Zusammenhang klar, aber meine IDE verwendet UTF-8
> - und jetzt?

Ja, deine IDE. Und wenn sich nun jemand dein Projekt im Github runter 
läd und seine IDE benutzt nicht UTF-8 sondern z.B. Ansi (Windows 
Standard-Charset) oder Latin-1? Wie gesagt, der GCC kennt ja Flags zur 
Vorgabe der Charsets, warum also sie nicht benutzen wenn sie schon da 
sind? ;)

: Bearbeitet durch User
von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Ihr beiden dreht euch schon wieder im Kreise.  Lasst's doch mal gut 
sein.  Dass die Optionen für die Umwandlung der Zeichen offenbar nicht 
in jeder Umgebung funktionieren, ist ja nun auch klar geworden, damit 
sind auch die Kommandozeilenoptionen kein „Allheilmittel“. Wichtig ist 
daher, dass sich jeder dessen gewahr ist, um sich mit seinem Sourcecode 
passend drauf einstellen zu können.

von Simon X. (simon1720)


Lesenswert?

M. K. schrieb:
> Joachim B. schrieb:
>> freut mich, ich habe auch noch 2 nachbestellt
>
> So, ich hab meine SH1106er nun auch endlich bekommen und konnte heute
> experimentieren. Library ist angepasst, Fehler möglich ;).
> Es werden nun OLED-Displays mit SSD1306 und SH1106 Controller
> unterstützt, entsprechend einzustellen in der jeweiligen Header-Datei.

Funktioniert diese Library auch mit einem Atmega2560 ohne Arduino mit 
Atmelstudio 7 ? oder was für Anpassungen müsste man vornehmen, damit es 
funktionieren würde?

Danke im Voraus

von M. K. (sylaina)


Lesenswert?

Simon X. schrieb:
> Funktioniert diese Library auch mit einem Atmega2560 ohne Arduino mit
> Atmelstudio 7 ? oder was für Anpassungen müsste man vornehmen, damit es
> funktionieren würde?

Es müsste auch auf einem Atmega2560 funktionieren. Dazu muss lediglich 
in der i2c.h die Prozessorinformation ergänzt werden (gehört also ein 
(_defined_ATmega2560_) zum entsprechenden #if dazu). Das habe ich 
grade mal bei der Library ergänzt und sollte nun gehen.
Die Library kannst du mit der Arduino IDE, dem Atmel Studio oder auch 
jeder anderen IDE benutzen. Denke nur daran, dass es eine C-Library ist. 
Willst du sie in einem C++ Projekt verwenden musst du sie mit

[c]extern "C" {
    #include "lcd.h"
}

includieren ;)

von M. K. (sylaina)


Lesenswert?

Habe heute ein kleines Update aufgespielt.
Man kann nun in der Header-Datei (lcd.h) ein #define BIGCHAR setzen 
wodurch die Schriftgröße verdoppelt wird.
Bisher funktioniert das fehlerfrei auf SSD1306 und SH1106 Displays im 
Grafik- und Textmode. Lediglich die Displaygröße wird noch nicht bei 
Verwendung der BIGCHARs mit berücksichtigt (man kann also quasi über den 
Displayrand schreiben...mit allen Konsequenzen, die das jeweilige 
Display dabei bedingt).

von M. K. (sylaina)


Angehängte Dateien:

Lesenswert?

Noch eine kleine Änderung eingefügt, es lässt sich nun der Font in 
normaler Größe und doppelter Größe gleichzeitig nutzen.

Lib liegt unter

https://github.com/Sylaina/oled-display

zum Download bereit.

von privat (Gast)


Lesenswert?

Sehr schön lesbare Zeichen. Jetzt wird es eine Anzeige für das E-Bike 
werden.

von Tillmaier (Gast)


Lesenswert?

Sehr gute Arbeit  M. K., ich danke dafür.
Hab noch eine Frage dazu, da ich noch nicht so gut programmieren kann:

Köntest Du eine Beispielzeile für die Verwendung von Sonderzeichen wie 
Ä, Ü
geben?

Was mir noch aufgefallen ist:
Auf Github in der readme.md sind zwei Beispiele. Im zweiten Beispiel 
liegt die Ausgabe in der main loop. Im ersten Beispiel vor der main 
loop?
Das erste Beispiel ist richtig, oder?

von M. K. (sylaina)


Lesenswert?

Es sind beide Beispiele richtig wenn auch der Code im zweite Beispiel 
nicht zwingend im Mainloop liegen muss.
Ob Code für das Display im Mainloop liegen muss oder nicht hängt 
letztendlich vom konkreten Programm ab. Als Regel kann man aber sagen: 
Text des Displays, der sich zur Programmlaufzeit nicht ändert, muss 
nicht im Mainloop liegen.

Ich hab den Code mal aus dem Mainloop raus genommen damit es nicht 
weiter zu Verwirrung führt.

Tillmaier schrieb:
> Köntest Du eine Beispielzeile für die Verwendung von Sonderzeichen wie
> Ä, Ü
> geben?

Einfach im Code benutzen und beachten, dass der Compiler entsprechend 
eingestellt ist (vergleiche Makefile Line 114, angegebene Compiler-Flags 
setzen).
1
...
2
  // irgendwo im Code, bei dem Text gedruckt werden soll
3
  lcd_puts_p(PSTR("Wäre doch alles so\r\n"));
4
  lcd_puts_p(PSTR("einfach."));
5
...

von Tillmaier (Gast)


Lesenswert?

Hallo M. K., danke für Deine Erleuterung.
Jetzt läuft alles wie es soll.

von Simon (Gast)


Angehängte Dateien:

Lesenswert?

M. K. schrieb:


Ich habe den code mal hinein kopiert. Jedoch beim compilieren auf 
(ATMega2560) kommen mehrere gleiche Fehler wie auf dem Bild (F_CPU 
undeclared) obwohl definiert oder fehlt da noch was?

von M. K. (sylaina)


Lesenswert?

Wie lautet deine Fehlermeldung genau? Auf den ersten Blick würde ich 
sagen 1 MHz System-Clock und 100 kHz I2C-Clock passen nicht zusammen, da 
müsste das TWBR out of Range gehen.
Vom Atmel Studio hab ich zudem wenig Ahnung, es könnte auch sein, dass 
F_CPU an dieser Stelle noch unbekannt ist, wird da aber gebraucht.

von Simon (Gast)


Angehängte Dateien:

Lesenswert?

M. K. schrieb:
> Wie lautet deine Fehlermeldung genau? Auf den ersten Blick würde
> ich
> sagen 1 MHz System-Clock und 100 kHz I2C-Clock passen nicht zusammen, da
> müsste das TWBR out of Range gehen.
> Vom Atmel Studio hab ich zudem wenig Ahnung, es könnte auch sein, dass
> F_CPU an dieser Stelle noch unbekannt ist, wird da aber gebraucht.

Hier die genaue Fehlermeldung: in jedem File sozusagen

von Simon (Gast)


Lesenswert?

Es kommt mir vor, wie wen file Verknüpfungen nicht existieren jedoch 
vorhanden sind.

von M. K. (sylaina)


Lesenswert?

Wie ich mir schon dachte, TWBR ist außerhalb des zulässigen Bereiches. 
Du musst die erste Fehlermeldung erst mal bearbeiten. Dass F_CPU nicht 
definiert ist, ist ein Folgefehler.

Reduziere einmal F_I2C auf z.B. 40000

von Simon (Gast)


Lesenswert?

M. K. schrieb:
> 40000

Die Frequenz zu verändern auf 40000 hat nichts gebracht. Fehlermeldung 
erscheint immer noch.

von M. K. (sylaina)


Lesenswert?

Dann liegt es wohl doch daran, dass er F_CPU an dieser Stelle nicht 
kennt. Ich kenne mich mit dem Studio leider zu wenig aus, ich arbeite 
mit einem Macintosh.
Was sagt den Google dazu wie man im Studio ein Symbol dem gesamten 
Projekt bekannt machen kann?

EDIT: Schau mal hier, vielleicht hilft es:
Beitrag "define F_CPU in AVR Studio 5, nur wo?"

: Bearbeitet durch User
von Dieter F. (Gast)


Lesenswert?

M. K. schrieb:
> Dann liegt es wohl doch daran, dass er F_CPU an dieser Stelle nicht
> kennt.

Projekt - Properties - AVR/GNU C Compiler - Symbols - "F_CPU=16000000UL"

von Simon (Gast)


Lesenswert?

Das habe ich versucht die Fehler sind nicht mehr da compiliert auch so 
wie sollte. Jedoch bleibt das Display schwarz (Prozessor ATMeaga2560 
16Mhz)
SDA und SCL Pins richtig angeschlossen mit Pull up.

von Dieter F. (Gast)


Lesenswert?

Simon schrieb:
> Das habe ich versucht die Fehler sind nicht mehr da compiliert auch so
> wie sollte. Jedoch bleibt das Display schwarz (Prozessor ATMeaga2560
> 16Mhz)

Stell mal bitte Dein Projekt (komplett) ein.

von Simon (Gast)


Lesenswert?

Dieter F. schrieb:
> Simon schrieb:
>> Das habe ich versucht die Fehler sind nicht mehr da compiliert auch so
>> wie sollte. Jedoch bleibt das Display schwarz (Prozessor ATMeaga2560
>> 16Mhz)
>
> Stell mal bitte Dein Projekt (komplett) ein.

Ich konnte das Problem mit einem neuen Display losen. Weiss nicht wie 
dies so gekommen ist, dass es nicht mehr geht. Sieht super aus und lässt 
sich einiges darstellen. Doch wie schreibt man einen Parameter auf das 
Display z.B. eine sich hochzählende Zahl oder eine Temperatur.

von Stefan F. (Gast)


Lesenswert?

Simon schrieb:
> Doch wie schreibt man einen Parameter auf das
> Display z.B. eine sich hochzählende Zahl oder eine Temperatur.

itoa
ltoa
utoa
ultoa
sprintf

oder etwas selbst gebautes. Man muss dabei nur den ASCII Zeichensatz 
anwenden.
1
int i=5;
2
char c='0'+i;  // ergibt "5"

Auf alles Weitere müsstest du mit Nachdenken, Divisionen und Modulus 
Operator kommen.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Stefanus F. schrieb:
> Divisionen und Modulus Operator

Da Division und Modulus eigentlich immer gemeinsam berechnet werden, 
spart man sich eine zusätzliche Operation, wenn man gleich die 
(Standard-)Funktion div() benutzt.

Aber wenn mich nicht Platzgründe dazu zwingen, würde ich nicht ohne Not 
etwas anderes als sprintf() benutzen … das ist schlicht die bequemste 
(und flexibelste) Variante.

von M. K. (sylaina)


Lesenswert?

Simon schrieb:
> Doch wie schreibt man einen Parameter auf das
> Display z.B. eine sich hochzählende Zahl oder eine Temperatur.

Du musst dir im vorfeld überlegen, wieviele Stellen wird die Zahl wohl 
maximal haben. Um einen Wert auf dem Display auszugeben musst du die 
Zahl in eine Zeichenfolge umwandeln, dafür musst du ein char-Array zur 
Verfügung stellen. Je nachdem ob du einen Integer darstellen möchtest 
oder einen Float-Wert gibt es zur Umwandlung unterschiedliche 
Funktionen. Hier mal ein Beispiel wie das in C aussehen kann:
1
#include <stdlib.h>
2
#include "lcd.h"
3
4
int main(void){
5
  char valueToPrint[5]; // char-Array das später die darzustellende Zahl enthalten soll, es muss mindestens so lang sein wie die darzustellenden Stellen plus dem String-Ende-Zeichen \0
6
  uint8_t myInteger = 123;
7
  float myFloat = 1.23;
8
  
9
  lcd_init(LCD_DISP_ON);
10
  lcd_clrscr();
11
  itoa(myInterger,   // Zahl, die umgewandelt werden soll
12
       valueToPrint, // char-Array, dass die Umwandlung aufnehmen soll
13
       10);          // Zahlenbasis, die zur Darstellung benutzt werden soll, hier dezimales System, oktal (8) und hexadezimal (16) ginge auch wenn ich mich recht entsinne
14
  lcd_puts_p(PSTR("Integer: "));
15
  lcd_puts(valueToPrint);
16
  lcd_puts_p(PSTR("\r\n"));
17
  dtostrf(myFloat, // Zahl, die umgewandelt werden soll, kann auch ein Interger sein
18
          4,       // Anzahl der darzustellenden Stellen incl. Komma, Komma ist auch eine Stelle ;)
19
          2,       // Anzahl der Nachkommastellen
20
          valueToPrint); // char-Array, der die Umwandlung aufnehmen soll
21
  
22
  lcd_puts_p(PSTR("Float: "));
23
  lcd_puts(valueToPrint);
24
  for(;;){
25
    // main-loop
26
  }
27
  return 0;
28
}
Hoffe, ich hab in dem Code jetzt keinen Fehler drin, schreib das grade 
vom iPad aus von unterwegs.
Auf dem Diplay sollte dann stehen:

Integer: 123
Float: 1.23

: Bearbeitet durch User
von Peter (Gast)


Lesenswert?

Also ich finde möglichst schnellen und kleinen Code optimal, da ich 
meistens auf einem Controller auch noch andere Dinge tute, als nur das 
Display zu bespaßen...aber das beisst sich mit der Bequemlichkeit, 
welche eine flexible und voller Funktionen steckende Libray bietet. Hier 
einen Kompromiss zu finden ist sicherlich schwer. Ich orientiere mich 
meistens nur daran, was ich konkret an Funktionalität benötige, um die 
Komplexität zu reduzieren, und werfe überflässigen Overhead raus!

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Peter schrieb:
> Also ich finde möglichst schnellen und kleinen Code optimal, da ich
> meistens auf einem Controller auch noch andere Dinge tute, als nur das
> Display zu bespaßen

Das macht ja wohl so ziemlich jeder, wer baut schon ein reines serielles 
Terminal oder sowas?

Meist bringen aber ohnehin andere Randbedingungen (nötige Peripherie 
etc.) einen Controller mit sich, bei dem es gar auf das letzte Kilobyte 
an Flashverbrauch ankommt, weil am Ende noch genügend frei bleibt. Für 
nicht benutzten Flash bekommt man ja kein Geld zurück. ;-)

Allerdings habe ich die genannten OLED-Displays bislang immer (zumindest 
teilweise) grafisch benutzt, da braucht man dann ohnehin die im 
Eingangspost genannten 1 KiB an Display-Puffer (shadow buffer) und damit 
mindestens sowas wie einen ATmega328. Flashnutzung ist dann oft nur bei 
10 oder 20 %.

Wenn man mit einem ATtiny2313 auskommen möchte, sieht das anders aus. 
Andererseits ist der Preisunterschied zwischen einem ATtiny2313 und 
einem ATmega328 so verschwindend gering, dass man schon ziemliche 
Stückzahlen braucht, damit sich der höhere Aufwand lohnt im Vergleich zu 
„Komfort-Funktionen“ mit etwas mehr Flashverbrauch …

von Bernd (Gast)


Lesenswert?

Hallo M. K.

Ich hab mal ne Frage wegen Bitmaps.

Hatte vor ein paar Monaten diese Library ausprobiert, welche nebenbei 
gesagt mal richtig gut ist, und hatte auch ein paar Bitmaps mit dem 
weiter oben geposteten Programm Oledbm.exe generiert und das 
funktionierte ganz gut, auch für dieses Progi ein herzlichen Dank.

Jetzt habe ich die neueste Version der Library compiliert und musste 
feststellen, das sich die draw_bitmaps Funktion um 3 weitere Variablen 
erweitert hat und meine Bitmaps nun nicht mehr korrekt angezeigt werden.

Hab hier ein Bitmap mit 64x64 Pixeln und wenn ich bei Width und Height 
64, 64 angebe gibts nur ein komplett verpixeltes Bild mit der Grösse.

Für einen guten Tip wäre ich sehr dankbar.
Bernd

von Max M. (maxmicr)


Lesenswert?

Besitzt jemand das Font-Array für die längere Version des SSD1306-OLEDs 
(das 128x32 Pixel misst)?
Auf dem 128x64 funktioniert das aktuelle einwandfrei, nur bei dem 
längeren ist die Schrift nicht gut erkennbar.

: Bearbeitet durch User
von Stefan F. (Gast)


Lesenswert?

Was hat der Font mit der Display-Breite zu tun?

von Max M. (maxmicr)


Angehängte Dateien:

Lesenswert?

Ich dachte, der Font wäre an das Seitenverhältnis des 128x64-Displays 
angepasst.

Welche Gründe könnte es noch haben, dass der Font abgeschnitten 
aussieht?
Das soll "HALLO" heißen.

von Stefan F. (Gast)


Lesenswert?

Ich schätze dass du hier versuchst, Text zwischen zwei Zeilen auszugeben 
und das kann diese Library wohl nicht.

Schreibe den Text mal ganz oben in die äusserste Ecke (ab Position 0,0). 
Wenn das auch nicht geht, wurde der Display Controller wohl falsch 
initialisiert. Da gleiche Problem müsste dann auch mit Linien erkennbar 
sein. Zeichne mal einfach ein großes X quer über das gesamte Display. 
Wird das auch Lückenhaft dargestellt?

Die richtige Initialisierungs-Sequenz kannst du meinem (anderen) 
Quelltext entnehmen: http://stefanfrings.de/esp8266/WIFI-Kit-8-OLED.zip

von Daniel B. (daniel_3d)


Angehängte Dateien:

Lesenswert?

Max M. schrieb:
> Welche Gründe könnte es noch haben, dass der Font abgeschnitten
> aussieht?

Mir sind schon mal Displays mit gebrochenen Ecken geliefert worden. Dort 
sah die Schrift dann ähnlich aus wie bei dir.

von Max M. (maxmicr)


Angehängte Dateien:

Lesenswert?

Stefanus F. schrieb:
> Da gleiche Problem müsste dann auch mit Linien erkennbar
> sein. Zeichne mal einfach ein großes X quer über das gesamte Display.
> Wird das auch Lückenhaft dargestellt?

Ich weiß nicht?

Daniel B. schrieb:
> Mir sind schon mal Displays mit gebrochenen Ecken geliefert worden.

Also die Ecken sind nicht gebrochen, aber im angehängten Foto erkennt 
man, dass das silber Reflektierende im Display gebrochen aussieht. Keine 
Ahnung, ob das so etwas verursachen kann.

: Bearbeitet durch User
von M. K. (sylaina)


Lesenswert?

Bernd schrieb:
> Hallo M. K.
>
> Ich hab mal ne Frage wegen Bitmaps.
>
> Hatte vor ein paar Monaten diese Library ausprobiert, welche nebenbei
> gesagt mal richtig gut ist, und hatte auch ein paar Bitmaps mit dem
> weiter oben geposteten Programm Oledbm.exe generiert und das
> funktionierte ganz gut, auch für dieses Progi ein herzlichen Dank.
>
> Jetzt habe ich die neueste Version der Library compiliert und musste
> feststellen, das sich die draw_bitmaps Funktion um 3 weitere Variablen
> erweitert hat und meine Bitmaps nun nicht mehr korrekt angezeigt werden.
>
> Hab hier ein Bitmap mit 64x64 Pixeln und wenn ich bei Width und Height
> 64, 64 angebe gibts nur ein komplett verpixeltes Bild mit der Grösse.
>
> Für einen guten Tip wäre ich sehr dankbar.
> Bernd

Hm, das muss ich mir mal anschaun, da schau ich morgen mal. Eigentlich 
müsste es funktionieren. Hast du vielleicht etwas Beispielcode?

Max M. schrieb:
> Besitzt jemand das Font-Array für die längere Version des SSD1306-OLEDs
> (das 128x32 Pixel misst)?
> Auf dem 128x64 funktioniert das aktuelle einwandfrei, nur bei dem
> längeren ist die Schrift nicht gut erkennbar.

Hm, wie schon gesagt wurde ist der Font nicht vom Display abhängig. Es 
sieht in der Tat so aus als stimmt irgend etwas mit deinem Display 
nicht. Bei dem "Hallo-Beispiel" sieht es so aus als würde die ein und 
andere Zeile fehlen, bei dem "X-Beispiel" sieht es so aus als würde jede 
zweite Spalte fehlen.

: Bearbeitet durch User
von M. K. (sylaina)


Lesenswert?

Bernd schrieb:
> Hab hier ein Bitmap mit 64x64 Pixeln und wenn ich bei Width und Height
> 64, 64 angebe gibts nur ein komplett verpixeltes Bild mit der Grösse.

Ich habs mir nun mal angeschaut und habe eine Vermutung:

Hast du deinem Bitmap auch das Attribut mitgegeben, dass es im Flash 
liegen bleiben soll? Über den "Fehler" bin ich grad bei mir gestolpert, 
viel mir aber sofort auf weil sich der Pixelsalat unabhängig vom Bild 
nicht änderte ;)
Die lcd_drawBitmap() erwartet das Bitmap nämlich im Flash ;)

Folgender Code sollte mit der aktuellen Library einen Pacmen aufs 
Display malen:
1
//****main.c****//
2
#include "lcd.h"
3
#include <util/delay.h>
4
5
6
const uint8_t PacMen[] PROGMEM=
7
{
8
//127x64  
9
  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff
10
    ,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff
11
    ,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff
12
    ,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff
13
    ,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff
14
    ,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff
15
    ,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff
16
    ,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff
17
    ,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff
18
    ,0xff,0xff,0xff,0xff,0xe0,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff
19
    ,0xff,0xff,0xff,0xf0,0x00,0x01,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff
20
    ,0xff,0xff,0xff,0xe0,0x00,0x00,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff
21
    ,0xff,0xff,0xff,0xc0,0x00,0x00,0x3f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff
22
    ,0xff,0xff,0xff,0x00,0x00,0x00,0x0f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff
23
    ,0xff,0xff,0xfe,0x00,0x00,0x00,0x07,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff
24
    ,0xff,0xff,0xf8,0x00,0x00,0x00,0x03,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff
25
    ,0xff,0xff,0xf8,0x00,0x00,0x00,0x01,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff
26
    ,0xff,0xff,0xe0,0x00,0x00,0x00,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff
27
    ,0xff,0xff,0xe0,0x00,0x00,0x00,0x00,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff
28
    ,0xff,0xff,0xe0,0x00,0x00,0x00,0x00,0x3f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff
29
    ,0xff,0xff,0xc0,0x00,0x00,0x00,0x00,0x3f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff
30
    ,0xff,0xff,0x80,0x00,0x00,0x00,0x00,0x1f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff
31
    ,0xff,0xff,0x00,0x00,0x00,0x00,0x00,0x0f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff
32
    ,0xff,0xff,0x00,0x00,0x00,0x00,0x00,0x0f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff
33
    ,0xff,0xfe,0x00,0x00,0x00,0x00,0x00,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff
34
    ,0xff,0xfc,0x00,0x00,0x00,0x00,0x01,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff
35
    ,0xff,0xfc,0x00,0x00,0x00,0x00,0x07,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff
36
    ,0xff,0xfc,0x00,0x00,0x00,0x00,0x0f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff
37
    ,0xff,0xfc,0x00,0x00,0x00,0x00,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff
38
    ,0xff,0xfc,0x00,0x00,0x00,0x01,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff
39
    ,0xff,0xfc,0x00,0x00,0x00,0x07,0xff,0xf0,0xff,0x83,0xfc,0x1f,0xf8,0x3f,0xe0,0xff
40
    ,0xff,0xfc,0x00,0x00,0x00,0x0f,0xff,0xf0,0x7f,0x03,0xf8,0x1f,0xf0,0x3f,0xc0,0xff
41
    ,0xff,0xf8,0x00,0x00,0x00,0xff,0xff,0xe0,0x3e,0x03,0xf0,0x1f,0xe0,0x1f,0x80,0xff
42
    ,0xff,0xf8,0x00,0x00,0x01,0xff,0xff,0xe0,0x3e,0x01,0xf0,0x0f,0xe0,0x1f,0x80,0x7f
43
    ,0xff,0xf8,0x00,0x00,0x03,0xff,0xff,0xc0,0x3e,0x03,0xf0,0x1f,0xe0,0x3f,0x80,0xff
44
    ,0xff,0xf8,0x00,0x00,0x03,0xff,0xff,0xe0,0x3e,0x03,0xf0,0x1f,0xe0,0x3f,0x80,0xff
45
    ,0xff,0xf8,0x00,0x00,0x00,0xff,0xff,0xe0,0x7f,0x07,0xf8,0x3f,0xf0,0x7f,0xc1,0xff
46
    ,0xff,0xfc,0x00,0x00,0x00,0x1f,0xff,0xf9,0xff,0xcf,0xfe,0x7f,0xfc,0xff,0xf3,0xff
47
    ,0xff,0xfc,0x00,0x00,0x00,0x07,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff
48
    ,0xff,0xfc,0x00,0x00,0x00,0x03,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff
49
    ,0xff,0xfc,0x00,0x00,0x00,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff
50
    ,0xff,0xfc,0x00,0x00,0x00,0x00,0x1f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff
51
    ,0xff,0xfc,0x00,0x00,0x00,0x00,0x07,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff
52
    ,0xff,0xfc,0x00,0x00,0x00,0x00,0x03,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff
53
    ,0xff,0xfe,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff
54
    ,0xff,0xff,0x00,0x00,0x00,0x00,0x00,0x0f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff
55
    ,0xff,0xff,0x00,0x00,0x00,0x00,0x00,0x1f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff
56
    ,0xff,0xff,0x80,0x00,0x00,0x00,0x00,0x1f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff
57
    ,0xff,0xff,0x80,0x00,0x00,0x00,0x00,0x3f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff
58
    ,0xff,0xff,0xe0,0x00,0x00,0x00,0x00,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff
59
    ,0xff,0xff,0xe0,0x00,0x00,0x00,0x00,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff
60
    ,0xff,0xff,0xf0,0x00,0x00,0x00,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff
61
    ,0xff,0xff,0xf8,0x00,0x00,0x00,0x01,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff
62
    ,0xff,0xff,0xfc,0x00,0x00,0x00,0x03,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff
63
    ,0xff,0xff,0xfe,0x00,0x00,0x00,0x0f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff
64
    ,0xff,0xff,0xff,0x80,0x00,0x00,0x1f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff
65
    ,0xff,0xff,0xff,0xe0,0x00,0x00,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff
66
    ,0xff,0xff,0xff,0xf0,0x00,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff
67
    ,0xff,0xff,0xff,0xff,0x80,0x1f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff
68
    ,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff
69
    ,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff
70
    ,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff
71
    ,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff
72
    ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
73
};
74
75
int main(void){
76
  lcd_init(LCD_DISP_ON);    // init lcd and turn on
77
  
78
lcd_puts_p(PSTR("BMP-Test"));
79
    lcd_display();
80
    _delay_ms(2000);
81
    lcd_clrscr();
82
#if defined GRAPHICMODE
83
  lcd_drawBitmap(0,0,PacMen, 127, 64,WHITE); // draw bitmap to buffer
84
  lcd_display();                       // send buffer to display
85
#endif
86
  for(;;){
87
    //main loop
88
  }
89
  return 0;
90
}
Einzige Änderung, die ich heute an der lcd_drawBitmap() gemacht habe 
ist, dass nun Bitmaps auch invertiert gezeichnet werden wenn als Color 
nicht WHITE sondern BLACK angegeben wird.

: Bearbeitet durch User
von Adrian E. (ahsd)


Lesenswert?

Bei mir spuckt der Compiler immer folgende Fehlermeldungen aus. Im 
TEXTMODE funktioniert die Ansteuerung trotzdem. Im GRAPHICMODE nicht. 
Was hat das zu bedeuten?
1
lcd.c:91:0: warning: ignoring #pragma mark LCD [-Wunknown-pragmas]
2
 #pragma mark LCD COMMUNICATION
3
 ^
4
Makefile:405: die Regel für Ziel „lcd.o“ scheiterte
5
lcd.c:108:0: warning: ignoring #pragma mark  [-Wunknown-pragmas]
6
 #pragma mark -
7
 ^
8
lcd.c:109:0: warning: ignoring #pragma mark GENERAL [-Wunknown-pragmas]
9
 #pragma mark GENERAL FUNCTIONS
10
 ^
11
lcd.c:252:0: warning: ignoring #pragma mark  [-Wunknown-pragmas]
12
 #pragma mark -
13
 ^
14
lcd.c:253:0: warning: ignoring #pragma mark GRAPHIC [-Wunknown-pragmas]
15
 #pragma mark GRAPHIC FUNCTIONS
16
 ^
17
lcd.c: In function ‘lcd_display’:
18
lcd.c:356:5: error: expected declaration or statement at end of input
19
     lcd_data(&displayBuffer[0][0], DISPLAY_WIDTH*DISPLAY_HEIGHT/8);
20
     ^
21
make: *** [lcd.o] Fehler 1
22
Kompilierung fehlgeschlagen.

von M. K. (sylaina)


Lesenswert?

Die
1
#pragma mark...

Zeilen dienen der Strukturierung in Xcode, sie erleichtern mir ein wenig 
das Navigieren.

Die Fehlermeldung ist merkwürdig, hast die die Library 
verändert/modifiziert? Ein Beispiel wäre sicher gut. Ich hab grade die 
aktuelle Library herunter geladen und in allen Variationen kompiliert 
(nur Graikmode, für SSD1306 und SH1106) und es wird bei mir immer 
fehlerfrei kompiliert. Der AVR-GCC 4.8.1 warnt bei mir nur wegen der 
#pragma marks.

von Adrian E. (ahsd)


Lesenswert?

Ich habe die Library noch mal frisch heruntergeladen, nur das minimalste 
konfiguriert und jetzt kompiliert sie ohne Probleme.

Ich muss nochmal schauen was ich beim letzten Mal falsch gemacht habe..

Danke trotzdem :)

: Bearbeitet durch User
von Adrian E. (ahsd)


Lesenswert?

Moin,

ich habe in der i2c.c heute den Atmega16 hinzugefügt. Im Textmode hat 
das ohne Probleme funktioniert. (Von 1 - 16 MHz) Der Graphicmode spuckt 
allerdings nur einen Block gequirlte Zeichen aus.

Hat jemand eine Idee, wo man da ansetzen müsste?

Liebe Grüße,
Adrian

: Bearbeitet durch User
von Stefan F. (Gast)


Lesenswert?

Adrian E. schrieb:
> Hat jemand eine Idee, wo man da ansetzen müsste?

Signalqualität messen.

von Adrian E. (ahsd)



Lesenswert?

Stefanus F. schrieb:
> Signalqualität messen.

Alle Einstellungen bis auf F_CPU = 16 MHz und die Erlaubnis, für 
Atmega16 zu kompilieren unverändert zum original Code

: Bearbeitet durch User
von Stefan F. (Gast)


Lesenswert?

Die Signale steigen im Graphic Mode wesentlich langsamer an, als im Text 
Mode. Man beachte die Form der oberen Spitzen vom SCL Signal. Das ist 
aber komisch.

Normalerwesie hängt das von den Pull-Up Widerständen ab, nicht vom 
Programm. Welche Werte haben deine Pull-Up Widerstände? Ich würde 
ungefähr 2,2k Ohm Empfehlen.

von Adrian E. (ahsd)


Lesenswert?

Stefanus F. schrieb:
> Die Signale steigen im Graphic Mode wesentlich langsamer an, als im Text
> Mode. Man beachte die Form der oberen Spitzen vom SCL Signal. Das ist
> aber komisch.


SORRY! Ich habe einen Flüchtigkeitsfehler gemacht. Ich wollte kürzere 
Kabel verwenden, habe dabei so umgesteckt dass es keine Pull-Ups mehr 
gab.
Ich verwende 10k Pull-Ups. Screenshots tausche ich in einer Minute aus. 
Jetzt sehen die Signale qualitativ gleich aus.

von Stefan F. (Gast)


Lesenswert?

Adrian E. schrieb:
> Jetzt sehen die Signale qualitativ gleich aus.

Ok, dann ist der Fehler wohl doch in der Software zu suchen.

von Adrian E. (ahsd)


Angehängte Dateien:

Lesenswert?

Im Textmode wird ein einziges mal der Bildschirminhalt gesendet, im 
Graphicmode resettet er sich kontinuierlich..

: Bearbeitet durch User
von M. K. (sylaina)


Lesenswert?

Adrian E. schrieb:
> Im Textmode wird ein einziges mal der Bildschirminhalt gesendet, im
> Graphicmode resettet er sich kontinuierlich..

Öhm...das liegt dann aber an deinem Aufbau/Programm. Im Textmode wird 
jedes Zeichen direkt an das Display gesendet, im Graphicmode wird der 
komplette Displayinhalt nur bei Aufruf von lcd_display(); ans Display 
gesendet (dann die kompletten 1024 Bytes).

von RAM Prüfer (Gast)


Lesenswert?

Adrian E. schrieb:
> Im Textmode wird ein einziges mal der Bildschirminhalt gesendet, im
> Graphicmode resettet er sich kontinuierlich..

Reicht denn die RAM-Grösse des Atmega16 aus?
Einfach mal nach dem Kompilieren die Grösse kontrollieren.

von M. K. (sylaina)


Lesenswert?

RAM Prüfer schrieb:
> Reicht denn die RAM-Grösse des Atmega16 aus?
> Einfach mal nach dem Kompilieren die Grösse kontrollieren.

Nur wenn getrickst wird. Ich bin jetzt davon ausgegangen, dass er die 
Lib ein wenig geändert hat. Ist natürlich auch denkbar, dass er gar nix 
an der Lib verändert hat, dann passt das mit dem Graphicmode aber gar 
nicht da man mindestens 1027 Bytes RAM braucht, der Atmega16 aber nur 
1024 Bytes besitzt. Ich muss das mal ändern bei Zeiten sodass man 
zumindest ein Warning erhält.

von RAM Prüfer (Gast)


Lesenswert?

M. K. schrieb:
> Nur wenn getrickst wird.

Ist sowieso Schwachsinn auf so einem kleinen Controller
graphische Dinge zu machen. Was soll das Sinnvolles bringen?

Mir fällt da nix ein ....

von M. K. (sylaina)


Lesenswert?

RAM Prüfer schrieb:
> Ist sowieso Schwachsinn auf so einem kleinen Controller
> graphische Dinge zu machen. Was soll das Sinnvolles bringen?

Wenn er genügend RAM hat, warum denn nicht? Zur Visualisierung? Fiktives 
Beispiel: Multimeter. Man kann eine Digitalanzeige machen, klar. Manch 
einem gefällt aber eine Zeigeranzeige besser. Schwachsinn würde ich das 
also nicht nennen wollen. Da kann es schon ganz schicke Projekte für 
geben.

von RAM Prüfer (Gast)


Angehängte Dateien:

Lesenswert?

M. K. schrieb:
> Da kann es schon ganz schicke Projekte für geben.

Ja, is doch schick wenn der Stack in den Framebuffer reinschreibt.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

RAM Prüfer schrieb:
> M. K. schrieb:
>> Da kann es schon ganz schicke Projekte für geben.
>
> Ja, is doch schick wenn der Stack in den Framebuffer reinschreibt.

Ist noch ausbaufähig: welche Stackbelegung liefert einen schönen 
QR-Code? :.)

von Adrian E. (ahsd)


Lesenswert?

M. K. schrieb:
> RAM Prüfer schrieb:
>> Reicht denn die RAM-Grösse des Atmega16 aus?
>> Einfach mal nach dem Kompilieren die Grösse kontrollieren.
>
> Nur wenn getrickst wird. Ich bin jetzt davon ausgegangen, dass er die
> Lib ein wenig geändert hat. Ist natürlich auch denkbar, dass er gar nix
> an der Lib verändert hat, dann passt das mit dem Graphicmode aber gar
> nicht da man mindestens 1027 Bytes RAM braucht, der Atmega16 aber nur
> 1024 Bytes besitzt. Ich muss das mal ändern bei Zeiten sodass man
> zumindest ein Warning erhält.

Danke für die Antworten! Nein ich gebe zu, ich habe erst mal gar nichts 
an der Library geändert. Mir war nicht bewusst dass der ATMega16 
aufgrund des zu kleinen RAM gar nicht dafür geeignet ist. Dann werde ich 
auf diesem Controller nur den Textmode verwenden.

von M. K. (sylaina)


Lesenswert?

Adrian E. schrieb:
> Danke für die Antworten! Nein ich gebe zu, ich habe erst mal gar nichts
> an der Library geändert. Mir war nicht bewusst dass der ATMega16
> aufgrund des zu kleinen RAM gar nicht dafür geeignet ist. Dann werde ich
> auf diesem Controller nur den Textmode verwenden.

Der Atmega32 hätte wieder genug RAM auch für den Graphicmode und ist IMO 
pinkompatibel zum Atmega16 ;)

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

M. K. schrieb:
> Der Atmega32 hätte wieder genug RAM auch für den Graphicmode und ist IMO
> pinkompatibel zum Atmega16 ;)

ATmega644 und 1284 sind auch pinkompatibel, allerdings nicht mehr 
Code-kompatibel (nicht einmal auf Sourcecodeebene komplett).

von oberallgeier (Gast)


Lesenswert?

M. K. schrieb:
> Noch eine kleine Änderung eingefügt ..
> normaler Größe und doppelter Größe gleichzeitig ...
> .. Lib .. zum Download bereit.

Perfekt, prima, vielen Danke, vor allem für die saubere Bereitstellung 
des Codes. Es klappte bei mir auf Anhieb auf nem 1306 (NEIN :-/ - erst 
nachdem ich die richtige Adresse eingefügt hatte), siehe unten. Ich bin 
begeistert.  Bisher hatte ich das als lausiger C(äh)Programmierer nur 
sehr bescheiden mit veröffentlichten Codes in cpp hinbekommen. Aber nun 
:
https://dl.dropbox.com/s/igqyyhpnnvajayz/oled_4217-50%25.jpg?dl=0

Nun war ich zwei Tage dran den Code von DoubleSize auf 4fachSize zu 
bemühen - wegen drei, vier Zahlen irgendwo mittendrin in meinem archie. 
Aber da finde ich mich nicht wirklich zurecht. Gibts so etwas, jetzt 
oder zukünftig?

Nochmal herzlichen Dank für Dein Projekt

grüßt der
oberallgeier
(aus dem obern Allgäu)

von Walter J. (oberallgeier)


Lesenswert?

Sorry, war nicht angemeldet.
Beste Grüße

von M. K. (sylaina)


Lesenswert?

Zukünftig gibts sowas vielleicht mal, derzeit mangelt es mir aber ein 
wenig an der Zeit. Ich hab einfach zu viele andere Projekte noch am 
laufen die erst mal fertig werden müssen ;)

von oberallgeier (Gast)


Lesenswert?

M. K. schrieb:
> .. vielleicht mal .. zu viele andere Projekte ..
> .. die erst mal fertig werden müssen ;)
Ach ja, kenne ich. Sowas gibt sich wohl nie (nicht mal bei mir als 
Rentner).

Danke für die schnelle Antwort.

von Jan H. (janiiix3)


Lesenswert?

Moin,

ich klinke mich hier mal mit ein..
Hat jemand schon mal den "Effekt" gehabt das sich der Bildschirminhalt 
nach unbestimmter Zeit einfach mal um 180° dreht? Oder das die oberste 
Zeile einfach mal ein Stück weit unten wieder raus kommt?

von M. K. (sylaina)


Lesenswert?

Wahrscheinlich ist der Text, den du auf das Display ausgeben willst, zu 
groß so dass der Speicher quasi überläuft. Diesbezüglich sind in der 
Library nur wenig Überprüfungen implementiert.

Hast du vielleicht Beispiel-Code der die Fehler zeigt? Dann kann ich mal 
schauen ob ich das raus gefixt bekomme.

von Jan H. (janiiix3)


Angehängte Dateien:

Lesenswert?

M. K. schrieb:
> Wahrscheinlich ist der Text, den du auf das Display ausgeben willst, zu
> groß so dass der Speicher quasi überläuft. Diesbezüglich sind in der
> Library nur wenig Überprüfungen implementiert.
>
> Hast du vielleicht Beispiel-Code der die Fehler zeigt? Dann kann ich mal
> schauen ob ich das raus gefixt bekomme.

Also der Fehler ist nach wie vor noch da.. :(
Anbei mal meine Lib für den "SSD1306"..
Vielleicht findest Du ja was.

von M. K. (sylaina)


Lesenswert?

Ach, das ist ja gar nicht meine Lib. Ich dachte du benutzt meine Lib.

Was mir bei deiner verwendeten Lib auffällt ist z.B. dass es egal ist wo 
x und y liegt, so ein Display hat ja idR 128*64 Pixel Größe, bei der Lib 
hindert mich aber nichts daran auch bei x > 128 und y > 64 was zu 
zeichnen.

Ist hier im Thread etwas OT aber wie schon gesagt, es kommt einfach auch 
drauf an wohin du im RAM des Displays was reinschreibst und wie sich 
dann die Displays verhalten. Genaueres steht im Datenblatt, das ist echt 
etwas umfangreich, z.B. kennt das SSD1306 einen automatischen 
Zeilenumbruch, man muss also nichts dazu tun um einen Zeilenumbruch zu 
erwirken. Meine Lib ist allerdings so aufgebaut dass man hierbei nicht 
vom automatischen Zeilenumbruch des SSD1306 profitieren kann. Sinn 
dahinter war/ist dass die Befehle dann für das SH1106, dass keinen 
automatischen Zeilenumbruch kennt, die selben sind. ;)

von Paul (Gast)


Lesenswert?

Hallo Gemeinde
habe den Artikel gelesen, tolle Sachen dabei. Habe aber ein Problem 
damit. Ihr geht vom SSD1306 und einem Display von 0,96`` aus. Moderne 
bzw. andere Displays haben den SSD1309 drin. Der kling ähnlich. Wie weit 
ist er ähnlich? Kann ich die Libs einfach für ein grösseres Display 
nutzen? Sicher muss ich was dazu anpassen. Die Displays haben 128x64.
LG Paul

von Stefan F. (Gast)


Lesenswert?

Vergleiche die Datenblätter der beiden Chips. Da steht drin, wie sie 
funktionieren und initialisiert werden sollen.

von Paul (Gast)


Lesenswert?

Das sieht nicht so gut aus mit deinem Hinweis. Da ich alles in C mache 
konnte ich keinerlei Info dazu finden

von Au Weia (Gast)


Lesenswert?

Paul schrieb:
> Das sieht nicht so gut aus mit deinem Hinweis.

Das sieht nicht so gut aus mit deinem Vorhaben. Du bist
zu faul zum Lesen des Datenblatts.

von Stefan F. (Gast)



Lesenswert?

Das hat doch mit der Programmiersprache nicht zu tun. Zur 
Initialisierung muss eine Folge von Kommandos (das sind einfache Zahlen, 
teils mit Pausen dazwischen) an den Controller gesendet werden.

Diese Sequenzen sind im Datenblatt des Displays in Form von 
Flussdiagrammen dargestellt. Jedes einzelne Kommando ist im Datenblatt 
des Controllers beschrieben.

Zu prüfen wäre aber auch, ob der Bildspeicher anders organisiert ist.

Ich habe mal die Doku von einem 0,96" SSD1306 Display angehängt.

von Heinzi(Gast) (Gast)


Lesenswert?

Der gute Paul(Gast) will eine mundgerechte Lösung in C und hat keine 
Lust, sich durch den Datenblattwust zu kämpfen ;-)

von Stefan F. (Gast)


Lesenswert?

Wenn ich das kann, dann er das auch. Denn bin schon ziemlich faul.

von M. K. (sylaina)


Lesenswert?

Heinzi(Gast) schrieb:
> Der gute Paul(Gast) will eine mundgerechte Lösung in C und hat
> keine
> Lust, sich durch den Datenblattwust zu kämpfen ;-)

Wer hat schon Lust sich durch den Datenblattwust zu kämpfen. Ich würde 
auch erstmal schaun obs nicht was Mundgerechtes gibt ;)

von Paul (Gast)


Lesenswert?

Mit der Faulheit kann man geteilter Meinung sein. Habe das Datenblatt 
angeschaut und versucht es zu verstehen. Ab einem Punkt bin ich 
gescheitert, war zu viel für mich.
Das mit Flussdiagramm habe ich gesehen. Habe auch schon versucht etwas 
umzusetzen. Es gibt einige Anfänge dazu. Sind zu kaotisch um sie zu 
zeigen. Leider ohne Erfolg. Im Datenblatt des Herstellers ist auch eine 
Routine dazu drin. Bin am entschlüsseln was wozu ist.
Beim SSD1306 ist ja auf eine andere Grösse bezogen. Wollte es eigentlich 
als Grundstein für des SDD1309 nehmen. Einiges scheint zu passen anderes 
nicht.

von Jan L. (ranzcopter)


Lesenswert?

Paul schrieb:
> Mit der Faulheit kann man geteilter Meinung sein. Habe das Datenblatt

In der Tat; wenn ein Display nur Mittel zum Zweck sein soll, täte ich 
mich „sogar“ nach was Vorhandenem umschauen, z.B. die Uglib2, oder 
Sparkfun 
https://github.com/sparkfun/HyperDisplay_SSD1309_ArduinoLibrary.

Würde  ich eine Lib erweitern oder ergänzen wollen, würde ich mir 
sicherlich zuerst die Init-Routinen vorhandener Libs (s.o.) anschauen...


> angeschaut und versucht es zu verstehen. Ab einem Punkt bin ich
> gescheitert, war zu viel für mich.
> Das mit Flussdiagramm habe ich gesehen. Habe auch schon versucht etwas
> umzusetzen. Es gibt einige Anfänge dazu. Sind zu kaotisch um sie zu
> zeigen. Leider ohne Erfolg. Im Datenblatt des Herstellers ist auch eine
> Routine dazu drin. Bin am entschlüsseln was wozu ist.
> Beim SSD1306 ist ja auf eine andere Grösse bezogen. Wollte es eigentlich
> als Grundstein für des SDD1309 nehmen. Einiges scheint zu passen anderes
> nicht.

von Paul (Gast)


Lesenswert?

Jan L. schrieb:
> Sparkfun
> https://github.com/sparkfun/HyperDisplay_SSD1309_ArduinoLibrary.

Danke, hat schon was gebracht. Die Stelle kannte ich noch nicht

von Reinhard O. (Firma: privat) (flug52)


Lesenswert?

Wer hat schon Lust sich durch den Datenblattwust zu kämpfen. Ich würde
auch erstmal schaun obs nicht was Mundgerechtes gibt ;)

Niemand muß doch einen Beitrag schreiben, wenn er es nicht möchte, lässt 
er es eben. Wenn er etwas anfängt, wäere es schön, es zu vollenden (ohne 
dass das in Stress ausartet, natürlich). Nicht jeder ist in der Lage, 
das Datenblatt umzusetzen. Die Lebenszeit ist endlich. Wenn jeder 
Erdenbürger bei Null, in der Urzeit anfangen wollte, alles dagewesene 
neu zu erfinden, wird nichts fertig oder besser wie das dagewesene. So 
eine Lib ist eben meist nur Teil eines Ganzen. Ein Baubetrieb setzt auch 
Fertigzement ein und brennt ihn nicht selber. Der Baumensch ist deshalb 
nicht faul. So geht eben Fortschritt.
Der Autor der Lib sollte natürlich immer genannt werden. Sein Lohn ist 
es, als Berühmtheit in die Geschichte einzugehen.
Gruß
Reinhard

: Bearbeitet durch User
von M. K. (sylaina)


Lesenswert?

Paul schrieb:
> Hallo Gemeinde
> habe den Artikel gelesen, tolle Sachen dabei. Habe aber ein Problem
> damit. Ihr geht vom SSD1306 und einem Display von 0,96`` aus. Moderne
> bzw. andere Displays haben den SSD1309 drin. Der kling ähnlich. Wie weit
> ist er ähnlich? Kann ich die Libs einfach für ein grösseres Display
> nutzen? Sicher muss ich was dazu anpassen. Die Displays haben 128x64.
> LG Paul

Ich hab mich jetzt ein wenig damit beschäftigt und mir auch mal ein 
SSD1309-Display beschafft. Das erste, dass mir auffiel ist, dass das 
Display standard-mäßig für SPI konfiguriert ist. Meine Library geht aber 
von einem I2C-Bus aus, an dem das Display klemmt.
Ich hab mal noch ein wenig aufgeräumt im Code, will nun mal schaun wie 
ich das Ganze umschreiben kann sodass es auch mit SPI läuft. Man kann 
die SSD1309-Displays anscheinend auch an I2C betreiben, ich bekomme 
meins da aber nicht an den Start. Das Suchen nach der I2C-Adresse 
schlägt bei mir immer wieder fehl. Und ja, ich hab auch die Widerstände 
umgelötet, das Reset-Signal geschickt und CS auf GND gepinnt.
Vom Programmaufruf/-ablauf an sich scheinen SSD1306 und SSD1309 
identisch zu sein, ich konnte beim Überfliegen der Datenblätter 
diesbezüglich keine Unterschiede feststellen, d.h. wenn man die 
Kommunikation auf SPI umschreibt müsste auch ein SSD1309-Display mit der 
Library funktionieren.

von M. K. (sylaina)


Lesenswert?

Ich bin dazu gekommen zu testen und hab meine Library mal von I2C auf 
SPI umgeschrieben (nur rudimentär zum testen). Damit lässt sich dann, 
wenn die Library auf SSD1306-Displays eingestellt ist, auch ein 
SSD1309-Display ansteuern. Das funktioniert. Mal schaun ob ich die Tage 
dazu komme, die Library ganz allgemein auf SPI umzuschreiben sodass man 
zwischen I2C und SPI wählen kann.

von M. K. (sylaina)


Lesenswert?

Die Github-Version ist nun erweitert und kann ab sofort die Displays 
auch via SPI ansprechen und unterstützt nun auch 
SSD1309-Displaycontroller ;)

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

M. K. schrieb:
> unterstützt nun auch SSD1309-Displaycontroller

Soll ich dir das mal in der Überschrift ergänzen?

von M. K. (sylaina)


Lesenswert?

Jörg W. schrieb:
> M. K. schrieb:
>> unterstützt nun auch SSD1309-Displaycontroller
>
> Soll ich dir das mal in der Überschrift ergänzen?

Oh, das wäre sehr gut. Danke dir, Jörg ;)

von Äd Franzis (Gast)


Lesenswert?

Hallo Sylaina,


herzlichen Dank, wirklich eine tolle Arbeit.

Ist die Lib auch für ESP32 verwendbar? Bzw., wird es eine Anpassung 
geben?
Aktuell verwende ich die U8g2lib.h, aber ich bekomme es nicht in den 
Griff, dass immer beim Überschreiben die Zeichen nicht komplett 
überschrieben werden  (z.b. wenn 0 mit 1 überschrieben wird, bleiben am 
linken Rand des Zeichens Punkte stehen). Dies tritt z.B. bei einer 
Uhrzeitausgabe auf.
Erhoffe mir, dass das Problem bei deinem Verfahren nicht auftritt.


MfG.
Äd

von M. K. (sylaina)


Lesenswert?

Hallo Äd Franzis,

die Library kann mit Anpassungen auch beim ESP verwendet werden. Hierzu 
musst du lediglich die Kommunikations-Funktionen in lcd_data, 
lcd_command und lcd_init anpassen.
Ich selbst habe noch keinen ESP und es wird bei mir dieses Jahr auch 
kein ESP mehr ins Haus kommen. Grund dafür ist, dass ich noch einige 
andere Baustellen habe und mir keine weitere aufmachen will. Es liegt 
also nicht daran, dass ich den ESP doof finde, mir fehlt es schlicht nur 
an Zeit. ;)

Zu deinem Problem:

Die U8G2lib ist eigentlich sehr gut (leider auch sehr umfangreich 
weshalb ich diese Lib nur für SSD1306/SSD1309/SH1106 schrieb). Ich denke 
also, dass dein beobachteter Fehler nicht von der Lib herrührt sondern 
von deinem Code. Ich kann dir daher empfehlen, dir deinen Code noch mal 
genau anzuschaun und auf einem Blatt Karo-Papier und Bleistift mal die 
Zeichenfunktionen gemäß dem Code durchzuspielen. Ich denke dann wirst du 
den Fehler entdecken ;)

Grüße

Michael

von Äd Franzis (Gast)


Lesenswert?

Vielen Dank, Michael, für deine Informationen.

Viel Code ist da ja nicht, da ich ausschließlich Text ausgeben. Habe 
mich an einem "Hallo Welt"-Beispiel orientiert.
Ich verwende das Board "WIFI_Kit_32  HTIT-WB32" von Heltec. Darauf 
enthalten ist ein 0.96'' 128*64 Display, das über I2C angeschlossen ist.

Hier mal die relevanten Code-Fagmente (alles, was mit dem OLED zu tun 
hat):
1
/*
2
 * BEGIN OF DECLARATIONS from 0.92'' OLED
3
*/
4
5
#include <Arduino.h>
6
#include <U8g2lib.h>
7
8
9
// the OLED used
10
U8G2_SSD1306_128X64_NONAME_F_SW_I2C u8g2(U8G2_R0, /* clock=*/ 15, /* data=*/ 4, /* reset=*/ 16);
11
12
/*
13
 * END  OF DECLARATIONS from 0.92'' OLED (128x64)
14
*/
15
16
const char *pSW_Version = "v1.0.0.01";
17
18
void DisplayTime() {
19
  //wird alle 500ms von loop() aufgerufen
20
  char buf[12];
21
22
23
  snprintf(buf, sizeof(buf), "%02d:%02d:%02d",
24
           hour(), minute(), second());
25
  u8g2.drawStr(6*9,43,buf);   
26
  u8g2.sendBuffer();                  
27
28
}  //END OF DisplayTime()
29
30
void DisplayDate() {
31
32
  //wird einmalig nach Setzen der Uhr und jew. um Mitternacht in loop() aufgerufen
33
34
  String sWeek_day[8] = {"Mon.,  ", "Dien., ", "Mitt., ", "Donn., ", 
35
                         "Frei., ", "Sams., ", "Sonn., ", "??tag, "};
36
37
  date_th    date;
38
  date_th*   p_date =&date;
39
40
41
  p_date->day      =(uint8_t)day();
42
  p_date->month    =(uint8_t)month();
43
  p_date->year     =(uint16_t)year();
44
  p_date->week_day =(uint8_t)weekday();
45
  Date_Calc_Calweek(p_date);  //calender week and leap year calculation
46
47
  char buf[50];
48
49
  snprintf(buf, sizeof(buf), "%s %02d.%02d.%04d",
50
           sWeek_day[(int)p_date->week_day], p_date->day, p_date->month, p_date->year);
51
52
  
53
  u8g2.drawStr(0,32,buf);   
54
  u8g2.sendBuffer();                  
55
56
  snprintf(buf, sizeof(buf), "WD: %1d CW: %2d LJ: %1d",
57
                                    p_date->week_day,
58
                                    p_date->calweek,
59
                                    p_date->leapjear);
60
61
 
62
 u8g2.drawStr(0,54,buf);   
63
 u8g2.sendBuffer();  
64
  
65
}  //END OF DisplayTime()
66
67
68
69
void setup() {
70
  
71
/*
72
 * BEGIN OF SETUP() from 0.92'' OLED
73
*/
74
  u8g2.begin();
75
  
76
  u8g2.clearBuffer();                 // clear the internal memory
77
  u8g2.setFont(u8g2_font_ncenB08_tr); // choose a suitable font  oder u8g2_font_helvB08_tr
78
  u8g2.setFontMode(0);
79
  u8g2.drawStr(0,10,pSW_Version);      // write something to the internal memory
80
  u8g2.sendBuffer();                  // transfer internal memory to the display
81
/*
82
 * END OF SETUP() from 0.92'' OLED
83
*/
84
85
86
//[... ... ... ...]
87
88
  String s0 =WiFi.localIP().toString();
89
  
90
  u8g2.drawStr(0,21,s0.c_str());   
91
  u8g2.sendBuffer(); 
92
93
//[... ... ... ...]
94
95
}

Problem: Wenn z.B. 1 auf 0 und 7 auf 6 folgt bleiben bei der 1 links 
Punkte von der 0 und bei der 7 rechts Punkte von der 6 über. Ganz wild 
sieht es aus, wenn die Wochentage überschrieben werden. Das ist dann gar 
nicht mehr lesbar.


Vielen Dank.
MfG.
Äd

von M. K. (sylaina)


Lesenswert?

Wenn ich das richtig sehe löschst du nie den Zeichenbuffer sondern 
überschreibst ihn einfach. Das ist dein Problem: Wenn im neuen String 
ein Pixel aus sein soll, im alten aber ein Pixel an ist dann wird dieser 
Pixel nicht ausgeschaltet. Am besten immer erst mal den Zeichenbuffer 
löschen und dann neu reinschreiben, so wie das im Setup ja auch gemacht 
wird ;)

von Äd Franzis (Gast)


Lesenswert?

Hallo Sylaina,


herzlichen Dank, das ist ein ganz wichtiger Hinweis.

Das heißt dann aber auch, ich kann immer nur den kompletten 
Display-Bereich schreiben, oder wie? Ich habe jezt SW-Version und IP in 
der initialisierung Datumsangaben nur um Mitternacht und die Uhrzeit 
halt alle 500ms geschrieben. Ich dachte, es ist effizienter, als immer 
alles zu beschreiben. So habe ich es immer beim LCD-Display gemacht.

Oder kann ich auch einen Teil des Buffers löschen, also immer die Zeile, 
die ich auch neu beschreibe will.

Oder anders gefragt: Wird eh jedesmal mit u8g2.sendBuffer() der gesamte 
Buffer geschickt, d.h. immer die gleiche Datenmenge. Dann würde ich 
natürlich  durch mein vorgehen eh nichts sparen.

MfG.
Äd

von M. K. (sylaina)


Lesenswert?

Äd Franzis schrieb:
> Wird eh jedesmal mit u8g2.sendBuffer() der gesamte
> Buffer geschickt, d.h. immer die gleiche Datenmenge.

Ja, wird es. u.a. deshalb habe ich die Library entwickelt, im Textmode 
ist meine Library erheblich schneller als die u8g-Library da ich im 
Textmode nur an der Stelle ins Display schreibe, in der ich Daten ändern 
will, und nicht den gesamten Displayinhalt neu beschreiben muss.

von Äd Franzis (Gast)


Lesenswert?

Hallo Sylaina,


vielen Dank. Dann schließt sich jetzt der Kreis und ich komme wieder zu 
der Frage:

Äd schrieb:
> Ist die Lib auch für ESP32 verwendbar? Bzw., wird es eine Anpassung geben?

und:
Äd schrieb:
> Erhoffe mir, dass das Problem bei deinem Verfahren nicht auftritt.

Ist denn bei deiner Lib auch das Problem, dass ich trotzdem den ganzen 
Buffer vor dem Überschreiben löschen muss? Oder kann ich auch 
zeilenweise löschen und nicht nur schreiben.


MfG.
Äd

von Hugo H. (hugohurtig1)


Lesenswert?

Äd Franzis schrieb:
> Oder kann ich auch
> zeilenweise löschen und nicht nur schreiben

Jein - Du kannst zeilenweise Leerzeichen reinschreiben und dann das, was 
Du dort sehen willst.

von M. K. (sylaina)


Lesenswert?

Äd Franzis schrieb:
> Dann schließt sich jetzt der Kreis und ich komme wieder zu
> der Frage:

Die hatte ich schon beantwortet: Ja, du musst nur die lcd_command, 
lcd_data und lcd_init bzgl. der Kommunikation für den ESP anpassen ;)

Äd Franzis schrieb:
> Ist denn bei deiner Lib auch das Problem, dass ich trotzdem den ganzen
> Buffer vor dem Überschreiben löschen muss?

Im Grafikmode: Jain (du müsstest mit meiner Lib den Bereich löschen, der 
neu beschrieben werden soll).
Im Textmode: Nein, da gibts keinen Buffer, da wird direkt ins Display 
geschrieben.

von Bob H. (bob3150)


Lesenswert?

Hallo,

ich hoffe hier kann mir jemand bei meinem Anliegen helfen, ich möchte 
ein OLED-Display als Statusanzeige (wie die serielle Console von 
Arduino) benutzen und würde immer gerne die letzen 7 Zeilen anzeigen. 
Mit folgendem Code werden die ersten 7-Zeilen angezeigt, aber der Rest 
wird nicht mehr angezeigt!
1
display.println("Statustext");
2
display.display();

Bitte um dringende Hilfe!

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Bob H. schrieb:
> Bitte um dringende Hilfe!

Bitte einen eigenen Thread in "Microcontroller + Elektronik" öffnen.

Bitte Netiquette beachten, insbesondere viel mehr Details zu deinem 
Problem schreiben.

von Äd Franzis (Gast)


Lesenswert?

Hallo M.K.


M. K. schrieb:
> Die hatte ich schon beantwortet: Ja, du musst nur die lcd_command, lcd_data und 
lcd_init bzgl. der Kommunikation für den ESP anpassen ;)
ups, stimmt, hattest du schon beantwortet. Vor lauter, lauter...
Werde mir das später mal anschauen, ob ich das anpassen kann. Bin auch 
erst Einsteiger. Wenn nur die digitalen Ausgänge anzupassen, wäre das ja 
schnell gemacht, aber I2C direkt ansteuern habe ich bisher noch nicht 
gemach. Würde dann schon gerne deine schlanke lib verwenden.


Hallo Hugo

Hugo H. schrieb:
> Jein - Du kannst zeilenweise Leerzeichen reinschreiben und dann das, was Du dort 
sehen willst.
Bei der U8g2lib genügt das leider nicht. Ich hab's probiert; Ergebnis 
ist unverändert. Es bleiben also immer noch einzelne Pixel stehen. 
Vermute, auch das Leerzeichen ist quasi transparent. Man müsste ein 
schwarzen Leerzeichen haben.
Habe nun auf die U8x8lib gewechselt, da funzt es genau so, wie du sagst. 
Aber dann passen immer nur 16 Zeichen in einer Zeile. Schade, aber OK.

Im Moment läuft die OLED-Ausgabe mal zufriedenstellend. Wäre schön, wenn 
ich die LIB aus diesem Thread hier für ESP umschreiben kann. Ansonsten 
werde ich später doch wieder zur U8g2lib  zurückkehren, und dann jeweils 
vor'm Schreiben einer Zeile die Pixel mit einem schwarzen Rechteck 
"löschen".
Ich lasse es euch wissen, wird aber etwas dauern.

Herzlichen Dank euch allen.


Liebe Grüße,
Äd.

von M. K. (sylaina)


Lesenswert?

Äd Franzis schrieb:
> lcd_init bzgl. der Kommunikation für den ESP anpassen ;)
> ups, stimmt, hattest du schon beantwortet. Vor lauter, lauter...
> Werde mir das später mal anschauen, ob ich das anpassen kann. Bin auch
> erst Einsteiger. Wenn nur die digitalen Ausgänge anzupassen, wäre das ja
> schnell gemacht, aber I2C direkt ansteuern habe ich bisher noch nicht
> gemach. Würde dann schon gerne deine schlanke lib verwenden.

Das muss man sich nur einmal an einem ruhigen Nachmittag anschaun, dann 
sieht man recht zügig, dass I2C doch eigentlich schon mega einfach ist 
was u.a. den Charme von dieser Schnittstelle aus macht. Also keine 
Furcht davor ;)

von Äd Franzis (Gast)


Lesenswert?

Hallo M. K.

M. K. schrieb:
> Also keine Furcht davor ;)
Danke für's Mutmachen. :)


Ja, schaue es mir gerne an. Habe vorher noch ein paar andere Steine aus 
dem Weg zu rollen (das OLED ist nicht die einzige Baustelle), aber dann 
wird dieser Nachmittag mal kommen. Vielleicht komme ich dann aber auch 
nochmal mit 'ner Frage hierher. Denke, dass dann dein LIB auch für 
andere ESP-User von Nutzen sein wird.


Liebe Grüße,
Äd.

von Rüdiger S. (ruediger9)


Angehängte Dateien:

Lesenswert?

Beitrag "Re: SSD1306 Library zum Darstellen von Text auf OLED Displays"

Wegen einer Nachfrage habe ich das OledBm-Tool zum Generieren des 
C-Codes noch erweitert. Es kann jetzt zusätzlich auch noch den Binärcode 
als Datei rausschreiben. Für eine 128x64 Bitmap wird also eine 1.024 
Byte große Datei erstellt.

Zudem noch der Sourcecode dazu, ist C# und z.B. mit VS 2019 
kompilierbar.

von Daniel I. (Gast)


Lesenswert?

Hallo Sylaina,
Diese Library ist der Hammer. Ich bin Anfänger und fand mich gut 
zurecht! Wirklich ausgezeichnete Arbeit. Was mich sehr freuen würde, 
wäre eine Funktion für das Ausgeben von einer Zahl und Zahlen mit 
Kommastellen. Ich dachte zuerst das ich einfach anstelle einen Text auch 
eine Variabel nehemen könnte. Aber dies funktionierte nur ein mal 
leider. Dan wird die Zahl nicht mehr aktualisiert. Dan habe ich ein 
wenig herumprobiert aber musste schlussendlich aufgebe. Mit meinen 
Kentnissen konnte ich das nicht bewältigen. Wäre somit der Hammer wen 
die Library um diese Funkton erweitert werden könnte.

Mit freundlichen Grüssen

Daniel

von Stefan F. (Gast)


Lesenswert?

Daniel I. schrieb:
> Was mich sehr freuen würde,
> wäre eine Funktion für das Ausgeben von einer Zahl und Zahlen mit
> Kommastellen.
1
char puffer[5];
2
sprintf(puffer, "%0.2f", 0.99);
3
lcd_puts(puffer);

https://www.tutorialspoint.com/c_standard_library/c_function_sprintf.htm

Achtung: Der Puffer muss mindestens ein Zeichen größer sein, als die 
längste erwartete Textausgabe. Das heisst in diesem Fall, dass die Zahl 
im Bereich 0.00 bis 9.99 liegen muss, sonst gibt es einen 
Speicher-Überlauf.

von M. K. (sylaina)


Lesenswert?

sprintf ist die eine Möglichkeit.

Für Integer gibt es z.B. itoa(), für Fließkomma benutze ich dtostrf():
1
...
2
#include <stdlib.h> // benoetigt fuer itoa() und dtostrf()
3
...
4
int main(void){
5
  ...
6
  char valueAsString[5];
7
  ...
8
  // einen Integer in einen String wandeln
9
  itoa(123,
10
       valueAsString,
11
       10);
12
  // einen float/double in einen String wandeln
13
  dtostrf(1.23,
14
          4,    // Anzahl der Stellen incl. Komma
15
          2,    // Anzahl der Nachkommastellen
16
          valueAsString);
17
   ...
18
   // und auf dem LCD ausgeben 
19
   lcd_prints(valueAsString);
20
   #ifdef GRAPHICMODE
21
   lcd_display();
22
   #endif
23
   ...

Um genauer sagen zu können, wo es bei dir klemmt, Daniel, müsste man den 
Code sehen.

: Bearbeitet durch User
von Begeisterter (Gast)


Lesenswert?

Hallo!

Frage zum Verwenden von 128 X 32 Oleds (also die Kleinen).

funktioniert das mit der gegebenen Library schon (Wenn ja einfach diesen 
Beitrag ignorieren)? Ansonsten habe ich da eine sehr einfache Lösung. Es 
muss lediglich in der Initalisierung was geändert werden, ansonsten 
bleibt alles gleich...

von Begeisterter (Gast)


Lesenswert?

Nachtrag: Ich meine die SSD1306 displays mit 128X32

von Begeisterter (Gast)


Lesenswert?

Hier kurz die Änderung:

In der Initialiserungssequenz muss folgendes abgeändert werden:

Von derzeit:
0xDA, 0x12,      // Set com pins hardware configuration

Auf:

0xDA, 0x02,      // Set com pins hardware configuration

zudem muss dann natürlich noch in den DEFINES der Wert für 
DISPLAY_HEIGHT entsprechend auf 32 geändert werden.

von M. K. (sylaina)


Lesenswert?

Begeisterter schrieb:
> Hier kurz die Änderung:
>
> In der Initialiserungssequenz muss folgendes abgeändert werden:
>
> Von derzeit:
> 0xDA, 0x12,      // Set com pins hardware configuration
>
> Auf:
>
> 0xDA, 0x02,      // Set com pins hardware configuration
>
> zudem muss dann natürlich noch in den DEFINES der Wert für
> DISPLAY_HEIGHT entsprechend auf 32 geändert werden.

So schaut es aus ;)

von Bernhard65 (bernhard65)



Lesenswert?

Hallo Sylaina,
ich möchte dir zuerst mal Danken für die tolle Lib und zweites noch eine 
Rückmeldung zur Verwendung mit einem OLED 0,91" 128x32 Display geben.

Angeschlossen habe ich das ganze an einem Arduino Nano zuerst mit der 
bekannten Adafruit_SSD1306 und der Adafruit-GFX-Library.
Das Display funktioniert da ja soweit ganz gut jedoch 'fressen' mir die 
beiden Lib's in meinem Projekt den restlichen Speicher auf.
Da ich aber eh nur Textausgaben machen will, würde mir deine Lib sehr 
helfen.
Jedoch ist die Darstellung so nicht zu gebrauchen (siehe Image1). Sieht 
alles irgendwie zu klein aus und in die untere Hälfte verschoben.
In der LCD.h habe ich folgende Werte angepasst:
1
  /* TODO: define bus */
2
#define I2C          // I2C or SPI  
3
#define SSD1306       // SH1106 or SSD1306, check datasheet of your display
4
#define TEXTMODE      // TEXTMODE for only text to display,
5
#define FONT     ssd1306oled_font  // set font here, refer font-name at font.h/font.c
6
#define LCD_I2C_ADR  (0x78 >> 1)   // 7 bit slave-adress without r/w-bit
Als kleines Testprogramm habe ich nur folgende Zeilen:
1
#include <font.h>
2
#include <i2c.h>
3
#include <lcd.h>
4
5
void setup() {
6
    
7
    lcd_init(LCD_DISP_ON);
8
    lcd_clrscr();
9
    lcd_set_contrast(0x00);
10
    lcd_charMode(NORMALSIZE);
11
    lcd_gotoxy(0,0);
12
    lcd_puts("Normal Size");
13
    lcd_charMode(DOUBLESIZE);
14
    lcd_gotoxy(0,1);
15
    lcd_puts("DoubleSize");       
16
}
17
18
void loop() {
19
  // put your main code here, to run repeatedly:
20
21
}
Da das Display und die Ausgaben in den Adafruit-Libs richtig 
funktioniert, hab ich mal auf die Suche gemacht, warum es mit deiner Lib 
nicht gehen soll.

Aufgefallen ist mir dabei ein Unterschied in der Init-Sequenz:
In der Adafruit_SSD1306.cpp steht beim Init u.A. folgendes:
1
if((WIDTH == 128) && (HEIGHT == 32)) {
2
    comPins = 0x02;
3
    contrast = 0x8F;
4
  } else if((WIDTH == 128) && (HEIGHT == 64)) {
5
    comPins = 0x12;
6
    contrast = (vccstate == SSD1306_EXTERNALVCC) ? 0x9F : 0xCF;
7
  } else if((WIDTH == 96) && (HEIGHT == 16)) {
8
    comPins = 0x2;    // ada x12
9
    contrast = (vccstate == SSD1306_EXTERNALVCC) ? 0x10 : 0xAF;
10
  } else {
11
    // Other screen varieties -- TBD
12
  }
 D.h.: Bei einem Display mit 32 Pixel Höhe wird comPins mit 0x02 
initalisiert und bei 64 Pixels mit 0x12.
 In deiner LCD.c hab ich dann die Init-Sequenz mal geändert
1
    0x02,      // Set com pins hardware configuration for Display 128x32
2
   //0x12,      // Set com pins hardware configuration for Display 128x64
Und siehe da, die Ausgabe passt jetzt (siehe Image 2).

Event. hilft die Info ja jemanden weiter bzw. kannst du in einem Update 
das mal einpflegen.

Danke und Gruß,
Bernardo

von Stefan F. (Gast)


Lesenswert?

Das scheint eine Besonderheit bei deinem Display zu sein.

Meine 128x32 Displays funktionieren richtig, wenn ich mit 0x12 
initialisieren.

Ich habe deinen Hinweis mal als Kommentar in meine (das ist eine andere) 
Bibliothek eingebaut, dann findet man es später schneller.

von Bernhard65 (bernhard65)


Lesenswert?

Ob das ein bessonderes Display ist kann ich nicht sagen, aber in der 
Library von Adadfruit SSD1306 (Adafruit_SSD1306.cpp  s.o.), ist das fest 
für 128x32 Displays eingestellt (wenn ich das richtig Überblicke).
Und diese Library wird von sehr vielen verwendet.

Event. geht dein Display ja auch mit der Einstellung comPins 0x02 ?

von Stefan F. (Gast)


Angehängte Dateien:

Lesenswert?

Ja, in der Adafruit Library ist der Wert 0x02.

von Stefan F. (Gast)


Lesenswert?

Stefan ⛄ F. schrieb:
> Meine 128x32 Displays funktionieren richtig, wenn ich mit 0x12
> initialisieren.

Sorry ich habe das etwas verwechselt. Ich habe auch mit 0x02 
initialisiert.

Beitrag #6181523 wurde vom Autor gelöscht.
Beitrag #6181524 wurde von einem Moderator gelöscht.
von M. K. (sylaina)


Lesenswert?

Hallo Bernhard,

ich muss mich unbedingt noch mal hinsetzen und meine Lib überarbeiten. 
Sie ist, wie schon einigen aufgefallen ist, für die 128x64er Displays 
geschrieben, für Displays mit anderer Auflösung muss die Library 
angepasst werden und das fängt schon in der Init-Routine an aber auch in 
den Zeichenroutinen und Co muss z.B. die Abfragen der Art
1
...
2
if((WIDTH == 128) && (HEIGHT == 64)) {
3
...

angepasst werden. Ich danke dir für deine Rückmeldung, ich werde mal 
schaun dieser Tage die Ergänzung für die Init-Sequence einfließen zu 
lassen.

von Jörg F. (jopelabln)


Lesenswert?

Für den Fall, dass jemand die Anzeige um 180° verdreht eingebaut hat:
1
void lcd_flip(uint8_t flip){
2
    uint8_t commandSequence[2];
3
    if (flip != YES) {
4
        commandSequence[0] = 0xA1;      // normal
5
        commandSequence[1] = 0xC8;
6
    } else {
7
        commandSequence[0] = 0xA0;      // gedreht
8
        commandSequence[1] = 0xC0;
9
    }
10
    lcd_command(commandSequence, 2);

von M. K. (sylaina)


Lesenswert?

Oh, das muss ich mal ausprobieren. Passt das dann immer noch mit den 
Zeilen und Spalten Abfragen (also diese Teile: if( x > DISPLAY_WIDTH-1 
|| y > (DISPLAY_HEIGHT-1)) return; // out of Display)? Ich denke nicht, 
oder? Ich schätze mal WIDTH und HEIGHT muss man dann auch tauschen.

von Jörg F. (jopelabln)


Lesenswert?

Nö, die Drehung ist doch 180°.
DISPLAY_WIDTH und DISPLAY_HEIGHT werden nur bei 90° bzw. 270° 
vertauscht.
Das ist dann aber komplizierter.
Edit:
Ist nicht auf meinem Mist gewachsen, sondern stammt aus der 
u8g2/u8x8-Lib.
Ich konnte auf dieser Weise mein Layout retten.
Edit2:
Ich habe nur den TEXTMODE benutzt

: Bearbeitet durch User
von M. K. (sylaina)


Lesenswert?

Jörg F. schrieb:
> Nö, die Drehung ist doch 180°.

Achja, stimmt ja, ist ja Flip...war schon zu spät gestern für mich.

Jörg F. schrieb:
> Ich habe nur den TEXTMODE benutzt

Sollte im Graphicsmode auch gehen denn die Funktion dreht am RAM-Inhalt 
des Displays ;)

von Jörg F. (jopelabln)


Lesenswert?

Der Text steht nach dem Flip zwar auf dem Kopf ist aber in 
Spiegelschrift.
Nach einem lcd_clear und der neuen Ausgabe des Textes ist aber wieder 
alles OK. Ich denke den Flip benutzt man ähnlich den init nur ein 
einziges Mal im Programm, da das Display ja nicht auf einem 
Rotationteller ist.

von Benedikt M. (bmuessig)


Lesenswert?

M. K. schrieb:
> Wie soll das funktionieren also ohne Puffer funktionieren?

Ich könnte mir einen FIFO mit Zeichenbefehlen vorstellen. Hierbei könnte 
eine Scanline gepuffert werden und alle Zeichenkommandos dann Scanline 
für Scanline abgearbeitet und zeilenweise an's Display übertragen 
werden. Hierfür muss man nur die übliche y-Schleife der Zeichenbefehle 
in eine finale Zeichnen & Senden-Funktion auslagern.
Da hier im Flash gespeicherte Bitmaps und Fonts einfach per Adresse 
referenziert werden können und für Linien und Formen einfach die 
Eckkoordinaten gespeichert werden können, kann solch eine Vorgehensweise 
recht effizient sein. Hier muss jedoch bei jeder Änderung eines 
Bildschirmbereiches dieser Teil neu gezeichnet werden. Die Erzeugung des 
Zeichenbefehlspuffers muss also in jedem Frame passieren. Die 
Übertragungssoftware könnte dann immer den kleinstmöglichen Bereich 
rendern und zeilenweise übertragen.

von M. K. (sylaina)


Lesenswert?

Benedikt M. schrieb:
> Hier muss jedoch bei jeder Änderung eines
> Bildschirmbereiches dieser Teil neu gezeichnet werden.

Und genau das ist ja der Knackpunkt. Wenn man den Displayinhalt nicht 
löschen will ist man gezwungen mit dem Puffer zu arbeiten da man die 
Displays typischerweise nicht auslesen kann (könnte man sie auslesen 
wäre es einfach ;)).

von Benedikt M. (bmuessig)


Lesenswert?

M. K. schrieb:
> Und genau das ist ja der Knackpunkt. Wenn man den Displayinhalt nicht
> löschen will ist man gezwungen mit dem Puffer zu arbeiten

Doch, das Problem ist damit ja auch adressiert. Wenn man den 
Bildschirminhalt nur teilweise verändert, kann man die (nach 
Einschätzung des Entwicklers) gleich geliebenen Bildschirmteile nicht 
aktualisieren, dafür aber die veränderten Regionen. Wenn die Elemente im 
Puffer in den zu aktualisierenden Bereichen gleich bleiben, kann man die 
Updates problemlos in den aktuellen Bildschirminhalt einfügen.

Beispiel: Bitmap mit Textoverlay. Der Text soll geändert werden.
Hier reicht es, nur den Teil mit dem Text erneut an das Display zu 
senden.
Im Puffer ist dasselbe Bitmap weiterhin an derselben Stelle vorhanden.
Ändert man nun den Text, können exklusiv die Scanlinien, die Bitmap und 
Text enthalten haben, einfach neu berechnet und an den Framebuffer im 
Display gesendet werden. Da der Output deterministisch ist, funktioniert 
das auch ohne Update des gesamten Bildschirms, oder Lesen des 
Framebuffers.

> (könnte man sie auslesen wäre es einfach ;))
Einfach ist doch langweilig ;-)

: Bearbeitet durch User
von M. K. (sylaina)


Lesenswert?

Benedikt M. schrieb:
> Beispiel: Bitmap mit Textoverlay. Der Text soll geändert werden.
> Hier reicht es, nur den Teil mit dem Text erneut an das Display zu
> senden.

Und hier jetzt der Gedankenanstoß: Man will nicht den Text, der da schon 
im Display steht, löschen sondern einfach einen weiteren Text drüber 
schreiben. Schon hast du ein Problem wenn du nicht weißt, welcher Text 
da schon drin steht.
OK, bei Text ist das nicht unbedingt sinnvoll aber wenn man irgend etwas 
x-beliebiges zeichnet kann ich mir schon vorstellen, dass man das schon 
Gezeichnete nicht löschen will sondern einfach drüber zeichnen will, 
Beispiel Koordinatensystem mit verschiedenen Kurvenverläufen und Gitter 
usw. (bedenke: Diese Displays können auch nicht ein einzelnes Pixel 
ändern, es sind immer mindestens 8 Pixel)

Natürlich kann man vom Puffer bei speziellen Anwendungen weg kommen, die 
Textversion ist ja sowas quasi, aber allgemein kommst du nicht um den 
Puffer rum wenn du keine Informationen verlieren willst.

von Viking (Gast)


Lesenswert?

Hallo Michael,

ich habe schon vor einiger Zeit benutzt und fand die shon richtig 
klasse!
Nun habe ich ein kleines Problem mit der Initialisierung des kleineren 
Displays (64x48).
Ich habe die entspr. Befehle 0x21 - Set column address und 0x22 - Set 
page address gefunden. Ich weiß allerdings nicht wo ich das einbauen 
muss.

Ich habe bereits an folgender Stelle ausprobiert und gesehen, dass die 
anzeige sich auch verschiebt. Sobald ich auch die Displaygröße von 
128x64 auf 64x48 einstelle sehe ich meine gezeichnete Linie nicht mehr.
Wie ich sehen konnte ist das nicht die richtige stelle, da du in 
weiteren Funktionen den Pointer (im Display) veränderst.
1
void lcd_data(uint8_t data[], uint16_t size) {
2
#if defined I2C
3
//Test set memory area
4
    const uint8_t def_mem_area [] = {    // Adressbereich für kleiner Displays als 128x64
5
        0x21,   //Set column address
6
        32,     //Start column
7
        95,     //End column
8
        0x22,   //Set page address
9
        2,      //Start page
10
        7       //End page
11
    };
12
    lcd_command(def_mem_area, sizeof(def_mem_area));
13
// Test Ende
14
15
    i2c_start((LCD_I2C_ADR << 1) | 0);
16
    i2c_byte(0x40);    // 0x00 for command, 0x40 for data
17
    for (uint16_t i = 0; i<size; i++) {
18
        i2c_byte(data[i]);
19
    }
20
    i2c_stop();

Ich habe deine Lib (nicht die aktuellste) auf diesem (64x48) und auf 
einem noch kleineren (48x32)Display ausprobiert. Buffer war dabei auf 
128x64 gesetzt. Dabei habe ich gesehen, dass die sichtbaren Zellen des 
Displays immer horizontal zentriert und vertikal am unteren Rand des 
RAMs des Kontrollers ausgerichtet sind. Somit kann den ganzen Display 
RAM ansprechen, sehe dann aber nur den 'sichtbaren' Teil der Ausgabe.

Was kann ich ich machen, an welchen Stellen müsste ich ansetzen?

von M. K. (sylaina)


Lesenswert?

Viking schrieb:
> Was kann ich ich machen, an welchen Stellen müsste ich ansetzen?

Viking schrieb:
> Ich habe deine Lib (nicht die aktuellste)

Erstelle eine Sicherung deines Projektes und verwende dann mal die 
aktuelle Version der Lib. In der alten Version gab es in der Tat 
Probleme bei anderen Displaygrößen, dass aber inzwischen bearbeitet 
wurde. Ggf. funktionieren deine Displays aus mit der aktuellen Lib 
fehlerfrei.

von Viktor (Gast)


Lesenswert?

HalloMichael,

danke für deine schnelle Antwort. Ich habe es vielleicht 
missverständlich geschrieben. Ich habe schon die aktuelle Version von 
github verwendet.

Ich werde nochmals ausprobieren und mit einem Foto dokumentieren.

Einen interessanten Ansatz habe ich hier gefunden.
http://www.technoblogy.com/show?WNM

Ein Teil deiner Init. scheint keine Auswirkung zu haben. Laut Datenblatt 
sind die Befehle welche die Start page und column festlegen nur bei der 
page Adressierung wirksam.

Ich schreibe gerade von meinem Handy, daher mit spärlichen Infos. Ich 
werde mich die Tage melden sobald ich es getestet habe.

Danke und bis dahin...

von Viking (Gast)


Angehängte Dateien:

Lesenswert?

Hallo Michael,

ich habe nochmals die aktuelle Lib (github) passend für das Display 
konfiguriert. Für die Ausgabe habe habe ich dein Beispiel aus der Main.c 
verwendet. (s. Bild - Aktuelle_Lib.jpg)
1
 
2
int main(void)
3
{
4
  lcd_init(LCD_DISP_ON);    // init lcd and turn on
5
  
6
  lcd_puts("Hello World");  // put string from RAM to display (TEXTMODE) or buffer (GRAPHICMODE)
7
  lcd_gotoxy(0,2);          // set cursor to first column at line 3
8
  lcd_puts_p(PSTR("String from flash"));  // puts string form flash to display (TEXTMODE) or buffer (GRAPHICMODE)
9
  #if defined GRAPHICMODE
10
  lcd_drawCircle(64,32,7,WHITE); // draw circle to buffer white lines
11
  lcd_display();                 // send buffer to display
12
  #endif
13
    /* Replace with your application code */
14
    while (1) 
15
    {
16
    }
17
}

Die Konfiguration für das Display sieht so aus:
#define DISPLAY_WIDTH        64
#define DISPLAY_HEIGHT       48

Im zweiten Bild (alte_Lib.jpg) habe ich die frühere version der Lib 
verwendet. Die Ausgabe auf dem Display täuscht allerdings. Ich musste 
Buffer mit 128x64 pix initialisieren. Mit folgendem Code habe ich auch 
rausgefunden wie die kleineren Displays an den Kontroller angebunden 
sind.
ACHTUNG!: Der Codeschnipsel ist jedoch auf die Ausgabe auf dem noch 
kleineren Display (64x32) angepasst. Im Bild ist eine 64x48 Display zu 
sehen.
1
#if defined GRAPHICMODE
2
  lcd_drawPixel(32,32,WHITE);   //quasi 0.0 (x.y)
3
  lcd_drawPixel(95,32,WHITE);   // x-ende
4
  lcd_drawPixel(32,63,WHITE);   // x-ende, y-start 
5
  lcd_drawPixel(95,63,WHITE);   // x,y-ende
6
  lcd_gotoxy(6,4);
7
  lcd_puts_p(PSTR("1. Zeile")); //start ab dem 2. Zeichen
8
  lcd_gotoxy(6,5);
9
  lcd_puts_p(PSTR("2. Zeile"));
10
  lcd_gotoxy(6,6);
11
  lcd_puts_p(PSTR("3. Zeile"));
12
  lcd_display();                // send buffer to display
13
#endif

Zusammenfassung:
Atmel Studio 7.0.1645
Atmega328P (20MHz)

von M. K. (sylaina)


Lesenswert?

Hab jetzt schon ein paar Tage hier nicht reingeschaut, ich muss mal bei 
Gelegenheit ein Testaufbau mit dem Display umsetzen. Was mir aber hier 
jetzt auf Anhieb auffiel war, dass du z.B. schriebst:

Viking schrieb:
>
1
lcd_gotoxy(6,6);

Da dein Display 48 Pixel hoch ist und jede Zeile 8 Pixel hoch ist hat 
man zwar 6 Zeilen aber die 6. Zeile hat den Index 5, es müsste also 
heißen
1
...
2
lcd_gotoxy(6,5);
3
...
um in die 6. Zeile zu schreiben. Ich weiß grad nicht, ob das eigentlich 
von der Lib aufgefangen werden sollte.

Auch nicht so gut ist

Viking schrieb:
>
1
lcd_drawPixel(95,32,WHITE);   // x-ende

da du ja selbst schriebst, dass dein Display nur 64 Pixel breit ist. Da 
als X 95 nun anzugeben kann auch "knallen" (das müsste abgefangen sein 
und dürfte nicht zu Ausführung kommen).

Zudem muss die Initialisierung angepasst werden, ich hab ja nur eine 
Initialisierung für 64 Pixel Displayhöhe und für 32 Pixel Displayhöhe. 
Das könnte sich auch beißen wenn man als Displayhöhe 48 angibt.

von Arduino (Gast)


Lesenswert?

M. K. schrieb:
> Hab jetzt schon ein paar Tage hier nicht reingeschaut,

Gibt es eine fertige .ino, die unter Arduino Hello World in 
unterschiedlichen Größen darstellt?

von Stefan F. (Gast)


Lesenswert?

Arduino schrieb:
> Gibt es eine fertige .ino, die unter Arduino Hello World in
> unterschiedlichen Größen darstellt?

Worauf willst du den Text darstellen?

Meine Gegenfrage soll klar machen, dass es nicht nur eine ino für 
diesen Zweck geben kann.

von Arduino (Gast)


Lesenswert?

Stefan ⛄ F. schrieb:
> Worauf willst du den Text darstellen?

Auf dem OLED, wie lautet der Titel vom Thread?
(Library zum Darstellen von Text auf OLED Displays)

> Meine Gegenfrage soll klar machen, dass es nicht nur eine ino für
> diesen Zweck geben kann.

Deine Gegenfrage ergibt für mich keinen Sinn.

von Stefan F. (Gast)


Lesenswert?

Arduino schrieb:
> Deine Gegenfrage ergibt für mich keinen Sinn.

Es gibt viele unterschiedliche Displaygrößen, die man mit der Library 
ansteuern kann. Ein Testprogramm würde nur Sinn ergeben, wenn es an den 
Display-Typ und die Display-Größe angepasst ist.

von Arduino (Gast)


Lesenswert?

Stefan ⛄ F. schrieb:
> Es gibt viele unterschiedliche Displaygrößen,
> die man mit der Library ansteuern kann.

M. K. schrieb:
> Ich habe eine kleine Library für den Displaycontroller SSD1306
> geschrieben, wie er häufig bei den 0.96" OLED-Displays eingesetzt wird.

Genau dieses, Standard-Chinese in Schwarz-Weiß.

von M. K. (sylaina)


Lesenswert?

Arduino schrieb:
> Gibt es eine fertige .ino, die unter Arduino Hello World in
> unterschiedlichen Größen darstellt?

Ne INO dafür habe ich nicht aber du kannst den Code so eins-zu-eins in 
die INO schreiben, die Lib muss dann im selben Ordner liegen, und das 
ganze Kompilieren. Die Arduino IDE kann nämlich auch C ;)

Alternativ kannst du auch weiterhin der typischen Syntax der Arduino-IDE 
folgen, die Library ist inzwischen angepasst, dass sie ohne Änderung in 
der Arduino-IDE benutzt werden kann.

Ich rate dir dich mal damit zu beschäftigen wie man das genau macht. Es 
ist nicht schwer, sogar sehr einfach und du wirst es wohl noch öfter 
benötigen wenn du Libs von anderen Quellen als Arduino benutzen 
möchtest. Gehört IMO zu den Grundlagen die man beherrschen sollte bei 
der Programmierung von Mikrocontrollern.

von Viking (Gast)


Lesenswert?

Hallo Michael,
ich komme in letzter Zeit auch nur sporadisch dazu und auch ich habe 
lange hier nicht reingeschaut.

Ich habe einwenig experementiert und folgendes ist dabei herausgekommen.

Ich habe die Initialiesierung etwas entschlackt, soweit ich mich 
errinere waren da noch Befehle enthalten welche nur für page addressing 
gedacht sind. Mit "TODO" habe ich bei mir noch die stelle markiert wo 
man die Grenzen des sichtbaren Bereichs im RAM setzen muss, hier 64x48.

Initialisierung:
- einiges ist noch auskommentiert, da ich mich damit noch nicht 
beschäftigt habe.
1
const uint8_t init_sequence [] PROGMEM = {    // Initialization Sequence
2
    0xAE,           // --Display OFF (sleep mode)
3
    0x8D,           // --Charge pump enable
4
    0x14,
5
    0x20,           // --Set Memory Addressing Mode
6
    0b00,           // 00=Horizontal Addressing Mode; 01=Vertical Addressing Mode;
7
                    // 10=Page Addressing Mode (RESET); 11=Invalid
8
9
    //TODO: automatisch anhand des Displays berechnen 
10
    0x21,           // --Set column address
11
    32,             //Start column
12
    95,             //End column
13
    0x22,           // --Set page address
14
    2,              //Start page
15
    7,              //End page                
16
    //^^^^^
17
                
18
    0xA1,           // --Set Segment Re-map. (0xA0/0xA1 flip horizontally)
19
    0xC8,           // --Set COM Output Scan Direction (0xC0/0xC8 flip vertically)
20
    0xD9,           // --Set pre-charge period
21
    0xF1,           // (orig. 0x22)
22
    0x81,           //--Set contrast control register
23
    0x3F,
24
    0xDB,           // --Set vcomh
25
    0x20,           // 0x20,0.77xVcc
26
27
    0xAF            // --Display On
28
    
29
    /* //Origanle init
30
    0x81, 0x3F,      // Set contrast control register
31
    0xA6,            // Set display mode. A6=Normal; A7=Inverse
32
    0xA8, DISPLAY_HEIGHT-1, // Set multiplex ratio(1 to 64)
33
    0xA4,            // Output RAM to Display
34
           // 0xA4=Output follows RAM content; 0xA5,Output ignores RAM content
35
    0xD3, 0x00,      // Set display offset. 00 = no offset
36
    0xD5,            // --set display clock divide ratio/oscillator frequency
37
    0xF0,            // --set divide ratio
38
    // Set com pins hardware configuration
39
#if DISPLAY_HEIGHT==64
40
    0xDA, 0x12,      
41
#elif DISPLAY_HEIGHT==32
42
    0xDA, 0x02,
43
#endif
44
*/
45
};

Da ich nur die Grafikfunktionen verwende habe ich was eigenes gebaut 
bzw. zusammenkopiert. Da die Grenzen des Displays bereits bei der Init 
eingestellt werden und die Größe des Buffer da rein passt funktioniert 
das wunderbar! Ich aktualieseiere dabei immer die gesammte Anzeige.

Ausgabe Buffer:
1
#define BUFFER_SIZE (DISPLAY_HEIGHT * DISPLAY_WIDTH)/8
2
unit8_t buffer[BUFFER_SIZE];
3
4
// Display buffer
5
void lcd_display_buffer(void){
6
    i2c_start((LCD_I2C_ADR << 1) | 0);
7
    i2c_byte(0x40);    // 0x00 for command, 0x40 for data
8
    for (uint16_t i = 0; i < BUFFER_SIZE; i++){
9
        i2c_byte(buffer[i]);
10
    }
11
    i2c_stop();
12
}

von Rolf L. (dj7th)


Lesenswert?

Suche eine solche Library für den Bascom Compiler. Bin für jeden Hinweis 
dankbar.

von R. F. (inet_surfer88)


Lesenswert?

Hallo,

ich habe auf der oben verlinkten Github-Seite die Library 
heruntergeladen. Ich steuere damit ein 0.96" Display mit 128x64 Pixel.

Ich schreibe mit
1
lcd_init(LCD_DISP_ON);
2
lcd_gotoxy(0,0);
3
lcd_puts("123");

Daten zum Testen auf das Display. Ich habe mittlerweile auch ein 
umfangreiches Programm mit dem noch viel mehr Daten auf das Display 
geschrieben werden. Es funktioniert alles ohne Probleme.

Jetzt habe ich mir folgendes Display mit 0.49" und 64x32 Pixel gekauft.
https://www.amazon.de/gp/product/B07QGZ4SRF/ref=ppx_yo_dt_b_asin_title_o00_s00?ie=UTF8&psc=1

Ich bekomme mit dem oben stehenden Testcode keine Anzeige auf das kleine 
Display. Da ich schon einen defekt oder falsche I2C-Adresse vermutet 
habe habe ich extra die Arduino-IDE gestartet (zum Programmieren nehm 
ich Atmel Studio). In Arduino gibt es einen I2C-Sniffer. Der gibt mir 
die Adresse 0x3c zurück, die gleiche wie das große Display.
In der lcd.h habe ich folgendes angepasst:
1
#define LCD_I2C_ADR         0x3c
2
#define DISPLAY_WIDTH         64
3
#define DISPLAY_HEIGHT        32

Ich bekomme einfach keine Anzeige auf das Display.
Controller ist bei beiden Displays ssd1306.

Hat jemand noch eine Idee was man noch überprüfen könnte???

: Bearbeitet durch User
von Joachim B. (jar)


Lesenswert?

arduino nutzt nur rechtsshift Adressen 0-127
Mit AVR Studio habe ich angefangen und das write Bit selber behandelt!

http://www.peterfleury.epizy.com/avr-software.html?i=1

Du musst schon wissen wie du die I2C Adressen behandelst.
In den Datenblättern von I2C devices ist immer 8 Bit genannt, die 
obersten 7 Bit sind die Adresse, Bit 0 ist das WR Bit.

Arduino 0-127 AVR 0-255 und Bit0 ausklammern

#if (ARDUINO>0)
  DEBUG_PRINTLN(F(" -> Scanning..."));
  char _i2c_key=0;
  byte error, address;
  int nDevices=0;
  for(address = 1; address < 127; address++ ) { // The i2c_scanner uses 
the return value of
    // the Write.endTransmisstion to see if
    // a device did acknowledge to the address.
    Wire.beginTransmission(address);
    error = Wire.endTransmission();

    if (error == 0) {
      DEBUG_PRINT(F("I2C device found at address 0x"));
      if (address<16)
        DEBUG_PRINT(F("0"));
      DEBUG_PRINT_DEC_HEX(address,HEX);
      DEBUG_PRINT(F("; "));
      if (address<64)
        DEBUG_PRINT(F("0"));
      DEBUG_PRINT_DEC_HEX(address,BIN);
      DEBUG_PRINT(F("x; << 0x"));
      DEBUG_PRINT_DEC_HEX((address<<1),HEX);
      DEBUG_PRINT(F("; "));
      if ((address<<1)<128)
        DEBUG_PRINT(F("0"));
      DEBUG_PRINT_DEC_HEX((address<<1),BIN);
      DEBUG_PRINT(F("; "));

      switch(address<<1) {
        case 0x40:
          //i2c_test_flags|=(1<<I2C_TASTATUR);
          i2c_test_flags|=(1<<I2C_TASTATUR_8574);
          _i2c_key=' ';
          DEBUG_PRINTLN(F("PCF8574  Tastatur"));
          break;
        case 0x70:
          //i2c_test_flags|=(1<<I2C_TASTATUR);
          i2c_test_flags|=(1<<I2C_TASTATUR_8574A);
          _i2c_key='A';
          DEBUG_PRINTLN(F("PCF8574A Tastatur"));
          break;
        case 0x78:
          DEBUG_PRINTLN(F("I2C OLED"));
          break;
        case 0xA0:
        case 0xA1:
        case 0xA2:
        case 0xA3:
        case 0xA4:
        case 0xA5:
        case 0xA6:
        case 0xA7:
          DEBUG_PRINTLN(F("I2C_EEPROM"));
          i2c_test_flags|=(1<<I2C_EEPROM);
DEBUG_PRINT(F("VOR eep_address FIND: ")); 
DEBUG_PRINTLN_DEC_HEX(eep_address, HEX);
          eep_address=(address);
DEBUG_PRINT(F("NACH eep_address FIND: ")); 
DEBUG_PRINTLN_DEC_HEX(eep_address, HEX);
          break;
        case 0xD0:
          Wire.beginTransmission(DS1307_ID);
          Wire.write(0x3F);
          if(Wire.endTransmission())
            i2c_test_flags|=(1<<I2C_RTC_3231);
          if(i2c_test_flags&(1<<I2C_RTC_3231))
            DEBUG_PRINTLN(F("DS3231 RTC"));
          break;
        default:
          DEBUG_PRINTLN();
          break;
      }
      nDevices++;
    } // if (error == 0)
    else if (error==4) {
      DEBUG_PRINT(F("Unknow error at address 0x"));
      if (address<16)
        DEBUG_PRINT(F("0"));
      DEBUG_PRINTLN_DEC_HEX(address,HEX);
    } // ! if(error==4)
  } // for(address = 1; address < 127; address++ )
  if (nDevices == 0)
    DEBUG_PRINTLN(F("No I2C devices found"));
  else
    DEBUG_PRINTLN(F("done"));
  DEBUG_PRINTLN();
#else // kein Arduino hier andere Methode einbinden
#endif // #if (ARDUINO>0)

: Bearbeitet durch User
von R. F. (inet_surfer88)


Lesenswert?

0x3c ist ja die 0x78 um eine Stelle geschoben. Ich habe auch schon beide 
Varianten ausprobiert. Arduino erkennt das kleine und das große Display 
als 0x3c. Von daher müsste es ja ok sein wenn ich das kleine mit dem 
Atmel Studio auch mit 0x3c anspreche, beim großen funktioniert es ja 
auch mit 0x3c (wie gesagt, beide geben im Sniffer ja auch den 
identischen Wert zurück).

von Joachim B. (jar)


Lesenswert?

R. F. schrieb:
> 0x3c ist ja die 0x78 um eine Stelle geschoben. Ich habe auch schon beide
> Varianten ausprobiert.

na denn weisst du ja bescheid

Ich habe aber auch einige I2C OLEDs gehabt die sich ums verrecken nicht 
ansprechen liessen, entweder ich bin zu dusslig oder mir wurde Mist 
geliefert, ist aus China auch schon öfter vorgekommen, aber wegen <=10€ 
macht man keinen Aufriss.

von R. F. (inet_surfer88)


Lesenswert?

Ich bin ein klein wenig weiter gekommen.

Ich habe jetzt erst mal das AVR Studio beiseite gelegt und die 
ArduinoIDE genommen.

Mein 0.96 lässt sich mit dem HelloWorld Beispiel und folgender 
Displaydefinition zum Leben erwecken.
1
U8X8_SSD1306_128X64_NONAME_HW_I2C u8x8(/* reset=*/ U8X8_PIN_NONE);

Für das 0.49 habe ich dann das genommen - funktioniert nicht
1
U8X8_SSD1306_64X32_NONAME_HW_I2C u8x8(/* reset=*/ U8X8_PIN_NONE);

Nach ein wenig "rumspielen" hat folgende Zeile den Erfolg gebracht:
1
U8X8_SSD1306_64X32_1F_HW_I2C u8x8(/* reset=*/ U8X8_PIN_NONE);

Weis jemand was der Unterschied zwischen diesem NONAME und 1F ist?
Über die Doku zur Library auf https://github.com/olikraus/u8g2 bin ich 
bisher nicht weiter gekommen.

von Joachim B. (jar)


Lesenswert?

R. F. schrieb:
> Weis jemand was der Unterschied zwischen diesem NONAME und 1F ist?

schau doch in den Code!

von R. F. (inet_surfer88)


Lesenswert?

Joachim B. schrieb:
> schau doch in den Code!

Da werd ich bei meinen derzeitigen Programmierkenntnissen nicht schlau 
draus. Das einzige was mir bisher aufgefallen ist wäre eine 
unterschliedliche multiplex ratio.

Hier steht in
1
u8x8_d_ssd1306_64x32_noname_init_seq[] =
1
U8X8_CA(0x0a8, 0x02f), /* multiplex ratio: changed from 0x1f to 0x2f */

und in
1
u8x8_d_ssd1306_64x32_1f_init_seq[] =
1
U8X8_CA(0x0a8, 0x01f), /* multiplex ratio: changed from 0x1f to 0x2f, 23 Sep 17: changed back to 1f */

Laut dem müsste es also 1f sein.

In der c-Library die ich verwende steht:
1
0xA8, DISPLAY_HEIGHT-1, // Set multiplex ratio(1 to 64)

Da ich bei DISPLAY_HEIGHT den Wert 32 eingebe wäre das Ergebnis 31. Und 
das ergibt in HEX 1F. Demnach wäre das der richtige Wert welcher mit dem 
Display funktionieren sollte.

von Joachim B. (jar)


Lesenswert?

R. F. schrieb:
> Da werd ich bei meinen derzeitigen Programmierkenntnissen nicht schlau
> draus.
dann musst du tiefer schauen, hier ist nicht zu sehen,
dort ist gehts weiter:
R. F. schrieb:
> U8X8_CA(

von R. F. (inet_surfer88)


Lesenswert?

In der Arduino-Library habe ich noch folgendes gefunden.
1
U8X8_CA(0x0da, 0x012),    /* com pin HW config, sequential com pin config (bit 4), disable left/right remap (bit 5) */[c/]
2
3
In der Library von hier steht
4
[c]#if DISPLAY_HEIGHT==64
5
    0xDA, 0x12,      
6
#elif DISPLAY_HEIGHT==32
7
    0xDA, 0x02,

Da mein DISPLAY_HEIGHT den Wert 32 hat steht bei mir dann 0x02.
Das habe ich jetzt auf 0x12 geändert. Der Unterschied ist ja genau das 
5. Bit vom Kommentar (disable left/right remap). Jetzt habe ich die 
Hälfte vom Display sichtbar.

Bei der derzeitigen Schriftgröße bekomme ich 10 Zeichen in eine Zeile.
Wenn ich den Sting "1234567890" ausgebe, dann steht in der linken Hälfte 
vom Display "567890". Die rechte Hälfte ist leer.

von Stefan F. (Gast)


Lesenswert?

Suche mal das Datenblatt von dem Display, da müsste die korrekte 
Initialisierungssequenz drin stehen. Die hängt nämlich ganz stark davon 
ab, wie die Pixel mit dem Chip verbunden sind. Da gibt es mehrere 
Möglichkeiten, deswegen lässt das Datenblatt des Chips diesen Teil 
offen.

von R. F. (inet_surfer88)


Lesenswert?

Stefan ⛄ F. schrieb:
> Suche mal das Datenblatt von dem Display

Das ist das Problem. Ich habe nur die Angaben auf Amazon. Über den 
genannten Hersteller werde ich bei Google auch nicht weiter fündig. 
Deswegen bestelle ich meine Displays normalerweise bei AZ Delivery. Da 
gibt es eine vernünftige Doku. Und der Preisaufschlag ist bei meinen 
paar Displays jetzt auch nicht entscheident. Aber bei AZ Delivery gibt 
es keine so kleinen Displays. Selbst die I2C Adresse war schon 
"Rätselraten".

von Stefan F. (Gast)


Lesenswert?

Guck mal bei Vishay: 
https://www.vishay.com/docs/37971/oled064o032alpp3n00000.pdf

Irgendwo findest du bei diesem Hersteller vielleicht auch die passende 
Initialisierungssequenz. Leider nicht in diesem PDF.

von Stefan F. (Gast)


Lesenswert?


von R. F. (inet_surfer88)


Angehängte Dateien:

Lesenswert?

Ic

Stefan ⛄ F. schrieb:
> Habe was gefunden:
> https://www.buydisplay.com/download/manual/ER-OLED0.49-1_Series_Datasheet.pdf

Nach der Doku bin ich jetzt mal vorgegangen, gleiches Ergebnis. Irgend 
wie habe ich da wohl ein merkwürdiges Display mit etwas anderer 
Konfiguration erwischt als die "Standard-Teile".

Aktuell schreibe ich folgendes auf das Display. Von der Breite her 
müsste das exakt auf das Display passen.
1
lcd_gotoxy(0,0);
2
lcd_puts("HelloWorld");
3
4
lcd_gotoxy(0,2);
5
lcd_puts("1234567890");

Das Ergebnis sieht man auf dem Bild "64x32", WIDTH 64, HEIGHT 32

Dann habe ich einfach das Display getauscht, ohne die Definitionen 
anzupassen. Das Ergebnis auf dem Bild "128x64_falsch"

Der Text landet also korrekt auf dem Controller, nur ist der Inhalt beim 
kleinen Display irgend wie nach links verschoben.

Zuletzt noch das Bild mit den korrekten Einstallungen für das große 
Display "128x64_ok" WIDTH 128, HEIGHT 64

von Joachim B. (jar)


Lesenswert?

128x64_ok.jpg sieht doch gut aus, wie ist deine Frage?

versuche
R. F. schrieb:
> lcd_gotoxy(0,0);
> lcd_puts("HelloWorld, i am OK");
>
> lcd_gotoxy(0,2);
> lcd_puts("12345678901234567890");

von R. F. (inet_surfer88)


Lesenswert?

Joachim B. schrieb:
> 128x64_ok.jpg sieht doch gut aus, wie ist deine Frage?

128x64 ist auch nicht das Problem, wollte damit nur Zeigen das der Code 
generell funktioniert. Das Problem ist das der gleiche Code auf dem 
64x32 nicht läuft, bzw. die Anzeige verschoben ist. Ich muss auf dem 
kleinen Display alles ein Stück nach rechts rücken, aber ich finde 
einfach nicht die passende Stellschraube in der Library (auch mangels 
Datenblatt vom Display). Von den WIDTH und HEIGHT Definitionen mal 
abgesehen. Aber die habe ich ja angepasst.

von Joachim B. (jar)


Lesenswert?

R. F. schrieb:
> 128x64.....

ich versteh dich nicht und kann zu dem
Beitrag "Re: SSD1306/1309 Library zum Darstellen von Text auf OLED Displays"

nichts mehr hinzufügen

von Stefan F. (Gast)



Lesenswert?

Ich habe dir das Datenblatt vom SSD1306 angehängt. Da sind alle 
Initialisierungsparameter beschrieben.

von R. F. (inet_surfer88)


Angehängte Dateien:

Lesenswert?

Joachim B. schrieb:
> ich versteh dich nicht und kann zu dem
> Beitrag "Re: SSD1306/1309 Library zum Darstellen von Text auf OLED
> Displays"
>
> nichts mehr hinzufügen

Uppps, hatte übersehen das du in meinen zitierten Text etwas hinzugefügt 
hast.
1
lcd_gotoxy(0,0);
2
lcd_puts("HelloWorld, i am OK");
3
4
lcd_gotoxy(0,2);
5
lcd_puts("12345678901234567890");

Bei der Einstellung WIDHT 64, HEIGHT 32:
Bild "64x32" kleines Display
Bild "128x64_falsch" großes Display

Bei der Einstellung WIDHT 128, HEIGHT 32:
Bild "128x64_ok" großes Display

von R. F. (inet_surfer88)


Lesenswert?

Stefan ⛄ F. schrieb:
> Ich habe dir das Datenblatt vom SSD1306 angehängt. Da sind alle
> Initialisierungsparameter beschrieben.

Ich habe gedacht ich wär auf der Seite 24 bei Punkt 8.4 und 8.3 auf 
Seite 23 auf der richtigen Spur. Alles ohne Erfolg. Bei dem einen Punkt 
"FR synchronization" beginnt das Display nur zu flackern (bei 
nochmaligem, genauerem lesen wurde auch klar warum), bei dem Punkt 
"Oscillator Circuit and Display Time Generator" verschieben sich die 
Zeilen in ihrer vertikalen Position. Ich müsste aber Horizontal 
verschieben.

Das Datenblatt muss ich die nächsten Tage nochmals genauer anschauen.

von Joachim B. (jar)


Lesenswert?

R. F. schrieb:
> Bei der Einstellung WIDHT 128, HEIGHT 32:
> Bild "128x64_ok" großes Display

siehste, nun weisst du es wie es richtig geht!
und musst für das warum nicht mehr suchen!

: Bearbeitet durch User
von R. F. (inet_surfer88)


Lesenswert?

Joachim B. schrieb:
> siehste, nun weisst du es wie es richtig geht!
> und musst für das warum nicht mehr suchen!

Irgend wie reden wir glaube ich aneinander vorbei, oder stehe ich 
komplett auf der Leitung???
Wie schon geschrieben, mein großes Display läuft ohne Probleme, mein 
Problem ist das kleine Display, das 64x32. Und da bekomme ich trotz 
WIDTH 64 und HEIGHT 32 keine vernünftige Anzeige, siehe Bild "64x32"

von Joachim B. (jar)


Lesenswert?

R. F. schrieb:
> Irgend wie reden wir glaube ich aneinander vorbei

möglich denn besonders klar finde ich deine seltenen Aussagen nicht, man 
weiss nie worauf du dich beziehst, du hast es im Kopf, für dich ist 
alles klar und hier bleiben bei mir nur ?????? über.

R. F. schrieb:
> Da ich bei DISPLAY_HEIGHT den Wert 32 eingebe wäre das Ergebnis 31. Und
> das ergibt in HEX 1F. Demnach wäre das der richtige Wert welcher mit dem
> Display funktionieren sollte.

"welcher mit dem Display"

aha, wie war das in der Schule, einen vollständigen Satz mit
"Subjekt Prädikat Objekt"
Wie beim Notruf
www
Wer
Wo
Was

meldet!

hier brennts ist zwar richtig aber nicht zielführend.

Wo ist deine Systematik?
sich Stück für Stück einem Fehler zu nähern und dabei zu lernen.

vermutlich bekomme ich dafür wieder Dankespunkte.

von M. K. (sylaina)


Lesenswert?

R. F. schrieb:
> Wie schon geschrieben, mein großes Display läuft ohne Probleme, mein
> Problem ist das kleine Display, das 64x32. Und da bekomme ich trotz
> WIDTH 64 und HEIGHT 32 keine vernünftige Anzeige, siehe Bild "64x32"

Ich tippe auf die Initialisierungs-Routine. Die ist u.a. abhängig von 
der Dislay-Größe. Ich hab nur die 128*64er Displays hier und hab die Lib 
darauf angepasst, wahrscheinlich muss da in der Initialisierung noch 
etwas geändert werden damit es für ein 64*32 Display passt. Wenns klappt 
bau ich die Lösung gerne in die Lib mit ein.

von R. F. (inet_surfer88)


Lesenswert?

Ich bin an der Sache noch dran, werde da aber erst im Januar weiter 
machen. Mittlerweile habe ich auch eine "provisorische Lösung" gefunden, 
damit die Texte korrekt auf dem Display angezeigt werden. Allerdings als 
Bastel- und nicht als saubere Dauerlösung.

Ich werde im Januar mal alles ausführlich erklärt hier posten. Kann also 
noch ein paar Tage dauern, bis ich mich wieder melde.

von Jan (Gast)


Angehängte Dateien:

Lesenswert?

Hallo community,

ich versuche gerade ein SSD1306 Display welches ich bei Ebay gekauft 
habe in Betrieb zu nehmen, es klappt aber nicht ganz. Ich hoffe jemand 
kann mir helfen. Die hardware ist atmega328p mit 8MHz RC osc.

Die Library habe ich vom
https://github.com/Sylaina/oled-display

Folgende Zeilen habe ich modifiziert :

lcd.h zeile 61
1
//#define SH1106  
2
#define SSD1306

lcd.h zeile 72
1
//#define LCD_I2C_ADR         (0x7a >> 1)    // 7 bit slave-adress without r/w-bit
2
#define LCD_I2C_ADR         (0x78 >> 1)    // 7 bit slave-adress without r/w-bit

Ich hoffe die Slave-Adresse (0x78 >> 1) ist richtig.
Immerhin tut sich was mit dieser Adresse.
Wenn ich es mit (0x7a >> 1) ausprobiere tut sich nichts. Ich finde keine 
Dokumentation von meinem Display.

Beim compilieren bekomme ich den folgenden Fehler :
1
..
2
avr-gcc (GCC) 4.7.2
3
Copyright (C) 2012 Free Software Foundation, Inc.
4
This is free software; see the source for copying conditions.  There is NO
5
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
6
Compiling: main.c
7
avr-gcc -c -mmcu=atmega328p -I. -gdwarf-2   -Os -funsigned-char -funsigned-bitfields -fpack-struct -fshort-enums -Wall -Wstrict-prototypes -Wa,-adhlns=main.lst  -std=gnu99 -DF_CPU=16000000UL -finput-charset=utf-8 -fexec-charset=iso-8859-15 -MD -MP -MF .dep/main.o.d main.c -o main.o
8
cc1.exe: error: no iconv implementation, cannot convert from UTF-8 to iso-8859-15
9
make.exe: *** [main.o] Error 1

Was kann ich gegen diesen Fehler machen?

Nach dem ich die folgende Zeile im Makefile auskommentiere :

# CFLAGS += -finput-charset=utf-8 -fexec-charset=iso-8859-15

lässt es sich kompilieren, es gibt aber Warnungen :
1
-------------- Build: Debug in EmcExcelRelay (compiler: GNU GCC Compiler for AVR)---------------
2
3
Checking if target is up-to-date: make.exe -q -f makefile 
4
Running command: make.exe -f makefile 
5
-------- begin --------
6
avr-gcc (GCC) 4.7.2
7
Copyright (C) 2012 Free Software Foundation, Inc.
8
This is free software; see the source for copying conditions.  There is NO
9
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
10
Compiling: main.c
11
avr-gcc -c -mmcu=atmega328p -I. -gdwarf-2   -Os -funsigned-char -funsigned-bitfields -fpack-struct -fshort-enums -Wall -Wstrict-prototypes -Wa,-adhlns=main.lst  -std=gnu99 -DF_CPU=16000000UL -MD -MP -MF .dep/main.o.d main.c -o main.o
12
Compiling: i2c.c
13
avr-gcc -c -mmcu=atmega328p -I. -gdwarf-2   -Os -funsigned-char -funsigned-bitfields -fpack-struct -fshort-enums -Wall -Wstrict-prototypes -Wa,-adhlns=i2c.lst  -std=gnu99 -DF_CPU=16000000UL -MD -MP -MF .dep/i2c.o.d i2c.c -o i2c.o
14
lcd.c:102:0: warning: ignoring #pragma mark LCD [-Wunknown-pragmas]
15
lcd.c:139:0: warning: ignoring #pragma mark  [-Wunknown-pragmas]
16
lcd.c:140:0: warning: ignoring #pragma mark GENERAL [-Wunknown-pragmas]
17
Compiling: lcd.c
18
avr-gcc -c -mmcu=atmega328p -I. -gdwarf-2   -Os -funsigned-char -funsigned-bitfields -fpack-struct -fshort-enums -Wall -Wstrict-prototypes -Wa,-adhlns=lcd.lst  -std=gnu99 -DF_CPU=16000000UL -MD -MP -MF .dep/lcd.o.d lcd.c -o lcd.o
19
Compiling: font.c
20
avr-gcc -c -mmcu=atmega328p -I. -gdwarf-2   -Os -funsigned-char -funsigned-bitfields -fpack-struct -fshort-enums -Wall -Wstrict-prototypes -Wa,-adhlns=font.lst  -std=gnu99 -DF_CPU=16000000UL -MD -MP -MF .dep/font.o.d font.c -o font.o
21
font.c:126:6: warning: multi-character character constant [-Wmultichar]
22
font.c:126:5: warning: large integer implicitly truncated to unsigned type [-Woverflow]
23
font.c:127:6: warning: multi-character character constant [-Wmultichar]
24
font.c:127:5: warning: large integer implicitly truncated to unsigned type [-Woverflow]
25
font.c:128:6: warning: multi-character character constant [-Wmultichar]
26
font.c:128:5: warning: large integer implicitly truncated to unsigned type [-Woverflow]
27
font.c:129:6: warning: multi-character character constant [-Wmultichar]
28
font.c:129:5: warning: large integer implicitly truncated to unsigned type [-Woverflow]
29
font.c:130:6: warning: multi-character character constant [-Wmultichar]
30
font.c:130:5: warning: large integer implicitly truncated to unsigned type [-Woverflow]
31
font.c:131:6: warning: multi-character character constant [-Wmultichar]
32
font.c:131:5: warning: large integer implicitly truncated to unsigned type [-Woverflow]
33
font.c:132:6: warning: multi-character character constant [-Wmultichar]
34
font.c:132:5: warning: large integer implicitly truncated to unsigned type [-Woverflow]
35
font.c:133:6: warning: multi-character character constant [-Wmultichar]
36
font.c:133:5: warning: large integer implicitly truncated to unsigned type [-Woverflow]
37
font.c:134:6: warning: multi-character character constant [-Wmultichar]
38
font.c:134:5: warning: large integer implicitly truncated to unsigned type [-Woverflow]
39
Linking: main.elf
40
avr-gcc -mmcu=atmega328p -I. -gdwarf-2   -Os -funsigned-char -funsigned-bitfields -fpack-struct -fshort-enums -Wall -Wstrict-prototypes -Wa,-adhlns=main.o  -std=gnu99 -DF_CPU=16000000UL -MD -MP -MF .dep/main.elf.d main.o i2c.o lcd.o font.o  --output main.elf -Wl,-Map=main.map,--cref    -lm
41
Creating load file for Flash: main.hex
42
avr-objcopy -O ihex -R .eeprom main.elf main.hex
43
Creating load file for EEPROM: main.eep
44
avr-objcopy -j .eeprom --set-section-flags=.eeprom="alloc,load" \
45
  --change-section-lma .eeprom=0 -O ihex main.elf main.eep
46
c:\Elektrotechnik\avr-gcc-4.7.2-mingw32\bin\avr-objcopy.exe: --change-section-lma .eeprom=0x00000000 never used
47
Creating Extended Listing: main.lss
48
avr-objdump -h -S main.elf > main.lss
49
Creating Symbol Table: main.sym
50
avr-nm -n main.elf > main.sym
51
Size after:
52
main.elf  :
53
section           size      addr
54
.data               14   8388864
55
.text             2538         0
56
.bss                 3   8388878
57
.stab             1740         0
58
.stabstr           110         0
59
.comment            17         0
60
.debug_aranges     216         0
61
.debug_info       4051         0
62
.debug_abbrev     1218         0
63
.debug_line       1310         0
64
.debug_frame       732         0
65
.debug_str         566         0
66
.debug_loc        2847         0
67
.debug_ranges       96         0
68
Total            15458
69
Errors: none

Der Text auf dem Display ist aber verschoben und es gibt Artefakte.

(In dem Angehängten Bild wird nur der Textmodus getestet)
Im Graphik mode gibt es nur noch diese Artefakte zu sehen,
der Text ist nur ganz kurz im Einschaltaugenblick zu sehen, dann nur 
noch die Artefakte )

Ich habe auch mit der Compilerversion avr-gcc (GCC) 9.2.0 versucht.
Das Ergebnis war aber gleich.

Vielleicht hatte jemand ein ähnliches Problem ?


Danke im Voraus.
Jan

[Mod: C- und code-Tags ergänzt.]

: Bearbeitet durch Moderator
von R. F. (inet_surfer88)


Lesenswert?

Hallo Jan,

du schreibst das dein Controller mit 8MHz läuft.
In deiner Ausgabe welche du gepostet hast steht
1
-DF_CPU=16000000UL
Das heißt in deiner Entwicklungsumgebung sind 16MHz eingestellt.
Das solltest du auf jeden Fall anpassen (in der Entwicklungsumgebung 
korrekt eintragen).

Die Meldung
1
no iconv implementation, cannot convert from UTF-8 to 
2
iso-8859-15
hatte ich auch schon. Ich habe dann ebenfalls
1
-finput-charset=utf-8 -fexec-charset=iso-8859-15
wieder gelöscht, dann hat es funktionert. Allerdings kann ich dadurch 
ä,ö,ü,ß nicht darstellen. Hier wäre ich ebenfalls an einer Lösung 
interessiert.

Gruß Rüdiger

von Stefan F. (Gast)


Lesenswert?

Speichere deine Quelltexte entweder im ISO-8859-15 Zeichensatz oder 
ersetze die Umlaute durch Escape Sequenzen wie
1
"L\xFCffelbisquit"

FC = ü
DC = Ü
E4 = ä
C4 = Ä
F6 = o
D6 = O
B0 = °
DF = ß

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Stefan ⛄ F. schrieb:

>
1
> "L\xFCffelbisquit"
2
>
>
> FC = ü
> DC = Ü
> E4 = ä
> C4 = Ä
> F6 = o
> D6 = O
> B0 = °
> DF = ß

Geht etwas lesbarer:
1
#define ae "\xE4"
2
#define oe "\xF6"
3
// ...
4
5
   lcd_write(..., "L"oe"ffelbisquit");

von Stefan F. (Gast)


Lesenswert?

Stefan ⛄ F. schrieb:
> F6 = o
> D6 = O

Oh, ich sehe gerade, dass die Punkte vom ö und Ö fehlen. Die 
Hexadezimal-Codes stimmen aber.

von Jan (Gast)


Angehängte Dateien:

Lesenswert?

Danke für die Antworten und Erkläerungen.

das mit dem Zeichensatz werde ich später angehen. Erstmal wollte ich 
soweit kommen das es das Anzeigt was es anzeigen soll.

R. F. (inet_surfer88) schrieb :

>du schreibst das dein Controller mit 8MHz läuft.
>In deiner Ausgabe welche du gepostet hast steht
>-DF_CPU=16000000UL
>Das heißt in deiner Entwicklungsumgebung sind 16MHz eingestellt.
>Das solltest du auf jeden Fall anpassen (in der Entwicklungsumgebung
>korrekt eintragen).

Ich habe F_CPU = 8000000UL gesetzt.

Wie man im Anhang sieht läuft die Kommunikation mit 100KHz, das Display 
antwortet auch.
(Der erste Zugriff nach dem Reset ist im Bild zu sehen)

Ich überlege ob es nicht ein Hardware Probleme ist und Frage mich auch 
mit welcher Spannung das Display betrieben werden soll.
In der Beschreibung bei Ebay stand 3-5V.
Im Dattenblatt vom SSD1306 steht Power supply o VDD = 1.65V to 3.3V for 
IC logic.
Ich habe es erstmal mit 5V versucht, danach habe ich es mit 3.3V 
versucht.

Das Display zeigt immer diesen verschobenen Text und die Artefakte.

Schade das das hex file nicht im github dabeit ist. Das würde ich gerne 
flashen um es auszuprobieren.

Vielleicht ist jemand so freundlich und kann es hochladen.
(Also das hex file vom  Ausgangs Projekt 
https://github.com/Sylaina/oled-display  für den atmega328p )
(ob die F_CPU auf 16MHz oder 8MHz steht sollte erstmal keine Rolle 
spielen, es läuft dann halt mit der halben Geschwindigkeit)

Danke im Voraus,
Jan

von Joachim B. (jar)


Lesenswert?

Jan schrieb:
> Das Display zeigt immer diesen verschobenen Text

hatte ich mal bei falscher Controllerwahl
aber in welcher Lib? adafruit oder diese?

vergessen!

: Bearbeitet durch User
von Stefan F. (Gast)


Lesenswert?

Jan schrieb:
> Ich überlege ob es nicht ein Hardware Probleme

Die steigenden Flanken der Signale sind stark abgerundet. 400 kHz würden 
sicher gar nicht mehr funktionieren, obwohl das Display eigentlich sogar 
500 kHz schafft.

Vermutlich sind deine Pull-Up Widerstände and SCL und SDA zu hochohmig. 
Versuche mal 2,2kΩ oder 3,3kΩ.

> Frage mich auch mit welcher Spannung das Display betrieben werden soll.

Der Display-Controller braucht ungefähr 3,3V. Die meisten Module 
enthalten einen Spannungsregler, der aus einer höheren 
Versorgungsspannung bis 6V diese 3,3V bereit stellt.

Trotzdem ist es wichtig, dass die Signale am I²C Bus nicht mehr als 3,3V 
haben. Die Pull-Up Widerstände müssen daher auf 3,3V gehen, nicht auf 
5V!

von Jan (Gast)


Angehängte Dateien:

Lesenswert?

Vielen Dank für die Antworten.
Den Fehler habe ich gefunden. Ich habe es auf SH1106 umgestellt und es 
funktioniert.

Danke an Joachim B für den Tip mit mit der falschen Controllerwahl.
Ich bin davon ausgegangen das ich einen SSD1306 habe.

F. (stefanus) schrieb :
>Vermutlich sind deine Pull-Up Widerstände and SCL und SDA zu hochohmig.
>Versuche mal 2,2kΩ oder 3,3kΩ.

6.8KOhm habe ich drin, und sie sind auch an 5V angeschlossen.
Ich muss das noch ändern und sie an die VDD vom display anschliessen.
Vermutlich ist auf der Displayplatine ein Spannungsregler, ich muss mir 
das noch genau angucken.
Siehe Anhang

Danke nochmals.
Grüße,
Jan

von Joachim B. (jar)


Lesenswert?

Jan schrieb:
> Ich habe es auf SH1106 umgestellt und es
> funktioniert.
>
> Danke an Joachim B für den Tip mit mit der falschen Controllerwahl.
> Ich bin davon ausgegangen das ich einen SSD1306

ja jetzt fällt es mir wieder ein, der Unterschied war wie du schreibst!
SH1106 <-> SSD1306 :)))

von M. K. (sylaina)


Lesenswert?

Jan schrieb:
> Danke an Joachim B für den Tip mit mit der falschen Controllerwahl.
> Ich bin davon ausgegangen das ich einen SSD1306 habe.

Meiner Beobachtung bisher ist es übrigens so, dass die 0.96" Displays 
den SSD1306 drin haben während die 1.3" Displays den SH1106 Controller 
drin haben.

Jan schrieb:
> 6.8KOhm habe ich drin

Die sind für 400kHz und mehr definitiv zu hoch. Meiner einer hat 
üblicherweise 4k7 drin, für 1 MHz geh ich typischer Weise auf 2k2.

von M. K. (sylaina)


Lesenswert?

Jan schrieb:
> Schade das das hex file nicht im github dabeit ist. Das würde ich gerne
> flashen um es auszuprobieren.

Das Hex-File kann man sich ja selbst erstellen und "make all" ausführen, 
das Makefile liegt ja mit bei ;)

von Stefan F. (Gast)


Lesenswert?

M. K. schrieb:
> Meiner Beobachtung bisher ist es übrigens so, dass die 0.96" Displays
> den SSD1306 drin haben während die 1.3" Displays den SH1106 Controller
> drin haben.

Hmm, ich habe neulich ein paar 1.3" Displays bestellt und die laufen 
prima mit den Settings für den SSD1306. Allerdings habe ich das nur mit 
meiner eigenen OLED Klasse 
(http://stefanfrings.de/arduino_oled/index.html) ausprobiert.

Bei mir gibt es nur einen kleinen Unterschied bei der Datenübertragung 
vom RAM zum Display:
1
        // Set memory address to fill
2
        i2c.beginTransmission(i2c_address);
3
        i2c.write(0x00); // command
4
        if (isSH1106)
5
        {
6
            i2c.write(0xB0 + page); // set page
7
            i2c.write(0x00); // lower columns address =0
8
            i2c.write(0x10); // upper columns address =0
9
        }
10
        else
11
        {
12
            i2c.write(0xB0 + page); // set page
13
            i2c.write(0x21); // column address
14
            i2c.write(0x00); // first column =0
15
            i2c.write(width - 1); // last column
16
        }
17
        i2c.endTransmission();
18
19
        // send one page of buffer to the display
20
        ...

Ich habe irgendwo gelesen, dass beim SH1106 jede Page in einer eigenen 
I2C Transaktion übertragen werden muss, während man beim SSD1306 alles 
in einem Rutsch übertragen kann.

von Stefan F. (Gast)


Lesenswert?

Komisches Angebot, da hält sich der Händler beide Optionen offen:
https://www.ebay.de/itm/OLED-Display-1-3-weiss-blau-tuerkis-SH1106-SSD1306-128x64-I2C-Modul-Arduino-/272942171612

Und AZ-Delivery hat einen neuen Chip erfunden, den "SSH 1106":
https://www.az-delivery.de/products/1-3zoll-i2c-oled-display

Ich muss mal etwas loswerden. Bei den chinesischen Produkt nervt es mich 
kollosal, dass die Händler keine klaren Angaben dazu machen, was man da 
eigentlich kauft. Selbst auf die Fotos ist kein Verlass - die Ware 
weicht ob in Details davon ab.

Bei Boards mit STM32F1, ESP8266 und ESP32 wird auch wild gemischt.

von Joachim B. (jar)


Lesenswert?

Stefan ⛄ F. schrieb:
> Und AZ-Delivery hat einen neuen Chip erfunden

ruf doch mal an und frage....

kleiner Scherz am Rande, ne das habe ich alles durch, die wissen nicht 
mal was sie verkaufen, ist aber bei vielen deutschen Onlinehändlern auch 
nicht anders, die Leute am Telefon wissen nicht mal was in den Kisten im 
Lager ist.

von M. K. (sylaina)


Lesenswert?

Stefan ⛄ F. schrieb:
> Ich habe irgendwo gelesen, dass beim SH1106 jede Page in einer eigenen
> I2C Transaktion übertragen werden muss, während man beim SSD1306 alles
> in einem Rutsch übertragen kann.

Das ist u.a. einer der Unterschiede. Auch der ein und andere Spass mit 
dem Cursor muss man etwas anders behandeln wenn ich mich recht entsinne. 
Hat am Ende alles Auswirkung auf Bildwiederholrate und Co, da ist der 
SSD1306 gegenüber dem SH1106 im Vorteil.

von Bernhard S. (bernhard)


Angehängte Dateien:

Lesenswert?

Mal eine kleine Frage an die Spezialisten, wenn ich per TWI/I2C ein FFh 
sende, dann werden 8 vertikale Pixel dargestellt.

Kann man mit FFh auch 8 horizontale Pixel darstellen?

Wenn ja, wie?

Danke

Bernhard


Kleine Anmerkung:

TWI_BIT_RATE=0, TWI_PRESCALER=0

Display Clear, Takt 16MHz, SCL 444,444kHz, 1024Byte (128x64:8) in 11,6ms

mit Assembler

: Bearbeitet durch User
von Stefan F. (Gast)


Lesenswert?

Bernhard S. schrieb:
> Kann man mit FFh auch 8 horizontale Pixel darstellen?

Nein.

von Paul (Gast)


Lesenswert?

Hallo
hat jemand die Anpassung vom SSD1306 zum SSD1309 gemacht?

von John Doe (Gast)


Lesenswert?

Paul schrieb:
> Hallo
> hat jemand die Anpassung vom SSD1306 zum SSD1309 gemacht?

Was machen Deine eigenen Versuche nach den Hinweisen von gestern?

von Paul (Gast)


Lesenswert?

Bin nach euren Hinweisen und diesem Beispiel sehr viel weiter gekommen. 
Konnte meine Fehler von ca. 100 auf 7 reduzieren. Was ich nicht verstehe 
ist das:
1
void lcd_drawLine(uint8_t x1, uint8_t y1, uint8_t x2, uint8_t y2, uint8_t color)
2
  {
3
    if( ((x1 || x2) > DISPLAY_WIDTH-1) || ((y1 || y2) > DISPLAY_HEIGHT-1) ) return;
4
    int dx =  abs(x2-x1), sx = x1<x2 ? 1 : -1;
5
    int dy = -abs(y2-y1), sy = y1<y2 ? 1 : -1;
6
    int err = dx+dy, e2; /* error value e_xy */
7
    while(1)
8
    {
9
        lcd_drawPixel(x1, y1, color);
10
        if (x1==x2 && y1==y2) break;
11
        e2 = 2*err;
12
        if (e2 > dy) { err += dy; x1 += sx; } /* e_xy+e_x > 0 */
13
        if (e2 < dx) { err += dx; y1 += sy; } /* e_xy+e_y < 0 */
14
      }
15
  }
Dieser Teil bringt eine Fehlermeldung:
1
if( ((x1 || x2) > DISPLAY_WIDTH-1) || ((y1 || y2) > DISPLAY_HEIGHT-1) ) return;
Fehlermeldung:
Severity  Code  Description  Project  File  Line
Warning    comparison of constant '127' with boolean expression is 
always false [-Wbool-compare]  ATB_I2C_OLED_L128  D:\AAA 
Technik\Programme AVR 
Studio\ATB_I2C_OLED_L128\ATB_I2C_OLED_L128\oledl128.c  465
Warning    comparison of constant '63' with boolean expression is always 
false [-Wbool-compare]  ATB_I2C_OLED_L128  D:\AAA Technik\Programme AVR 
Studio\ATB_I2C_OLED_L128\ATB_I2C_OLED_L128\oledl128.c  465
[/c]
nicht klar warum das kommt.

von John Doe (Gast)


Lesenswert?

Paul schrieb:
> Dieser Teil bringt eine Fehlermeldung:
>
1
> if( ((x1 || x2) > DISPLAY_WIDTH-1) || ((y1 || y2) > DISPLAY_HEIGHT-1) ) 
2
> return;
3
>
> Fehlermeldung:
> Severity  Code  Description  Project  File  Line
> Warning    comparison of constant '127' with boolean expression is
> always false [-Wbool-compare]  ATB_I2C_OLED_L128  D:\AAA
> Technik\Programme AVR
> Studio\ATB_I2C_OLED_L128\ATB_I2C_OLED_L128\oledl128.c  465
> Warning    comparison of constant '63' with boolean expression is always
> false [-Wbool-compare]  ATB_I2C_OLED_L128  D:\AAA Technik\Programme AVR
> Studio\ATB_I2C_OLED_L128\ATB_I2C_OLED_L128\oledl128.c  465
> [/c]
> nicht klar warum das kommt.

Steht doch da (Tip: Besorg Dir ein C-Buch...):
Der Ausdruck (x1 || x2) liefert true oder false. Also 1 oder 0 und das 
ist immer < Deiner Display_Width oder Heigth.
Schreib das in vernünftigem C, dann geht das...

von Heini (Gast)


Lesenswert?

... und wieder die Empfehlung ein C Buch zu kaufen

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Paul schrieb:
> Dieser Teil bringt eine Fehlermeldung:

Dieser Teil sieht auch komplett sinnlos aus.

Es wird eine logische ODER-Verknüpfung gemacht (die kann nur 0 oder 1 
liefern, Wahrheitswerte halt), und deren Ergebnis wird dann mit Höhe 
oder Breite des Displays verglichen.

Was zum Geier™ wolltest du damit eigentlich ausdrücken?

von John Doe (Gast)


Lesenswert?

Jörg W. schrieb:
> Paul schrieb:
>> Dieser Teil bringt eine Fehlermeldung:
>
> Dieser Teil sieht auch komplett sinnlos aus.
>
> Es wird eine logische ODER-Verknüpfung gemacht (die kann nur 0 oder 1
> liefern, Wahrheitswerte halt), und deren Ergebnis wird dann mit Höhe
> oder Breite des Displays verglichen.
>
> Was zum Geier™ wolltest du damit eigentlich ausdrücken?

Ziemlich offensichtlich wollte er:
1
if( (x1 > (DISPLAY_WIDTH-1)) || (x2 > (DISPLAY_WIDTH-1))...
schreiben...

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

John Doe schrieb:
> Ziemlich offensichtlich wollte er:

OK, überzeugt. :-)

Gut'nacht!

von Paul (Gast)


Lesenswert?

Nicht ganz so schnell. Versuche die Sache zu begreiffen.

Paul schrieb:
> void lcd_drawLine(uint8_t x1, uint8_t y1, uint8_t x2, uint8_t y2,
> uint8_t color)
>   {
>     if( ((x1 || x2) > DISPLAY_WIDTH-1) || ((y1 || y2) >
> DISPLAY_HEIGHT-1) ) return;

Wenn ich das richtig verstehe erfolgt die Eimgabe für eine Linie als 
Anfangspunkt und Endpunkt in der Richtung x und y. Dabei wird 
kontrolliert das die eingebenen Punkte nicht ausserhalb der zulässigen 
angebenen Grösse liegen, ansonsten Begrenzung?

von John Doe (Gast)


Lesenswert?

Paul schrieb:
> Wenn ich das richtig verstehe erfolgt die Eimgabe für eine Linie als
> Anfangspunkt und Endpunkt in der Richtung x und y. Dabei wird
> kontrolliert das die eingebenen Punkte nicht ausserhalb der zulässigen
> angebenen Grösse liegen, ansonsten Begrenzung?

Nö, nix Begrenzung.

von Paul (Gast)


Lesenswert?

Es ist doch eine Begrenzung mit x und y drin. Wie wird das sonst 
gemacht?

von Dr. MCU (Gast)


Lesenswert?

Paul schrieb:
> Es ist doch eine Begrenzung mit x und y drin. Wie wird das sonst
> gemacht?

Mal abgesehen von Deinen falschen Statements springst Du mit return 
einfach zurück, wenn x- oder der y-Wert ausserhalb der 
Displaykoordinaten liegen.
Zudem hast Du eine void-Funktion und somit erkennt der Aufrufer auch 
nicht, ob da nun was gezeichnet wurde.
Besser wäre (je nach gewünschtem Effekt):
- Entweder bei Überschreiten der Max-Werte einfach den Max-Wert als 
Koordinate setzen
- Oder einen Boolean-Wert zurückgeben, der anzeigt, ob ein Fehler 
vorliegt oder nicht

von M. K. (sylaina)


Lesenswert?

Paul schrieb:
> void lcd_drawLine(uint8_t x1, uint8_t y1, uint8_t x2, uint8_t y2,
> uint8_t color)
> 2  {
> 3    if( ((x1 || x2) > DISPLAY_WIDTH-1) || ((y1 || y2) >
> DISPLAY_HEIGHT-1) ) return;

Das ist doch nicht meine aktuelle drawLine-Funktion. Schau doch noch mal 
ins github und lade dir die aktuelle Library. ;)

Dr. MCU schrieb:
> Mal abgesehen von Deinen falschen Statements springst Du mit return
> einfach zurück, wenn x- oder der y-Wert ausserhalb der
> Displaykoordinaten liegen.

Genau das war die Idee meines Gedankens: Ich wollte nur nicht außerhalb 
des Displays zeichnen. Auf Return-Werte hatte ich hier übrigens bewusst 
verzichtet getreu dem Motto keep it simple, natürlich wäre es sauberer 
wenn man zumindest einen Bool-Wert zurückgeben würde um zu sehen ob die 
Funktion zumindest fehlerfrei abgearbeitet wurde.

An die Bereichsüberprüfung wollte ich mich eh noch mal ran setzen da ich 
meine, dass sie in der drawPixel-Methode völlig ausreichen würde, die 
Überprüfungen in den anderen Zeichenfunktionen sind eigentlich 
überflüssig wenn ich das recht in Erinnerung habe.

von Paul (Gast)


Lesenswert?

M. K. schrieb:
> https://github.com/Sylaina/oled-display

Dann ist das neuste von dir. Da hab ich wohl was altes geholt.
Du verwendest auch die Datein zum I2C Bus. Das klappt bei mir nicht. Da 
ich noch andere Module im Bus anschliesse verwende ich eine andere 
Ansteuerung.
Wie kann man das am besten lösen?

LG Paul

von M. K. (sylaina)


Lesenswert?

Welche I2C-Library du verwendest bleibt dir überlassen. Du kannst meine 
Library benutzen um auch deine anderen Devices zu verwenden, du kannst 
auch deine Library benutzen, dann musst du nur in der lcd.c die 
Funktionen lcd_init (hier wird lediglich i2c initialisiert, 
initialisierst du den i2c woanders kannst du diesen Teil 
löschen/auskommentieren), lcd_command und lcd_data entsprechend 
anpassen.

von Paul (Gast)


Lesenswert?

Danke für deine Info, werde es testen. Betreibe mit dem I2C Bus noch 
eine ganze Reihe anderer Module, z.B. ein TFT Farbdisplay 3,2" mit 64000 
Farben. Teilweise sind recht anspruchsvolle Libs dabei.
Paul

von M. K. (sylaina)


Lesenswert?

I2C ist recht überschaubar bzgl Anspruch. ;)

von Stefan F. (Gast)


Lesenswert?

M. K. schrieb:
> I2C ist recht überschaubar bzgl Anspruch.

Ja. Wahrscheinlich meint er, dass die Bibliothek die er benutzen muss 
eine Menge Voraussetzungen hat, die erfüllt sein müssen.

von Paul (Gast)


Lesenswert?

Habe es ausprobiert. Ganz so einfach scheint es doch nicht zu sein. 
Kommen noch eine Reihe von Fehlermeldungen. z.B. Graphicmode, i2ccommand 
usw.
Versuche es durch auskommentieren erst mal zu einer Anzeige zu kommen.
Es klingt so, als ob die Datein von Peter Fleury nichts taugen, da ich 
diese verwende.
Paul

von M. K. (sylaina)


Lesenswert?

Paul schrieb:
> Es klingt so, als ob die Datein von Peter Fleury nichts taugen

Das klingt aber wirklich nur so. Was Peter gemacht hat ist richtig 
richtig gut finde ich.

Beginne bei der Fehlersuche immer beim ersten Fehler, der dir angezeigt 
wird. Viele der Fehler werden nämlich nur Folgefehler sein.

von Joachim B. (jar)


Lesenswert?

M. K. schrieb:
> Was Peter gemacht hat ist richtig
> richtig gut finde ich.

ganz genau, habe selber mit I2C von Fleury angefangen und viel gelernt 
dadurch.
Fehlerhaft, kann nicht sein, die LIB funktioniert perfekt seit 
mindestens 1 Jahrzehnt!

von Tuffi (Gast)


Lesenswert?

Hallo! Tolle Library, habe ich eingebunden funktioniert super. Ich nutze 
auch das 128x32 dank den HInweisen die Anpassung vorgenommen lief 
sofort. Auch die Bitmap-Funktion und die Exe klappt super.

ABER: 1 Problem habe ich. Ich habe nur die Schrift 6x8 von M. Köhler. 
Wie kann ich andere Schriftgrößen erhalten (oder erstellen)? Ich brauche 
am besten 2 weitere, eine die doppelt so groß ist und eine 4x so große.

von M. K. (sylaina)


Lesenswert?

Tuffi schrieb:
> Ich brauche
> am besten 2 weitere, eine die doppelt so groß ist und eine 4x so große.

Eine vier mal so große Schrift habe ich leider nicht. Aber es gibt eine 
Funktion, die die Schriftgröße verdoppelt. Die Funktion heißt 
lcd_charMode(uint8_t mode). Standard ist der Mode auf 1 eingestellt. 
Übergibst du der Funktion bei Aufruf eine 2 wird fortan die doppelte 
Schriftgröße verwendet. Hierzu gibt es zur Besseren Lesbarkeit auch zwei 
Makros, einmal NORMALSIZE (entspricht einer 1) und DOUBLESIZE 
(entspricht einer 2). Spiele damit ein wenig herum, nicht überall wird 
berücksichtigt welche Schriftgröße eingestellt ist, z.B. muss du bei 
einem Zeilenumbruch bei eingestellter doppelter Schriftgröße zwei Zeilen 
weiter springen statt nur eine.

Eigene Schriften lassen sich auch erstellen. Dafür gibts 
Schriftgeneratoren. Bedenke dabei aber, dass die Zeilengröße "nur" 8 
Pixel hoch ist, der Code berücksichtigt höhere Schriften nicht.

: Bearbeitet durch User
von Johannes S. (Gast)


Lesenswert?

Der Vorteil der Lib von M.K. ist die geringe Größe und wenig RAM Bedarf, 
aber die Fonts durch Pixel vervielfachen sehen dann entsprechend grob 
aus. Da gibt es schönere Fonts, die brauchen dann aber mehr Platz im 
Flash und es ist ein Framebuffer nötig, sonst flimmert es. Da hat die 
Adafruit Lib schöne Fonts drin und es gibt auch Generatoren um weitere 
zu erzeugen

https://youtu.be/Y0nxLMqq1Jk

von Tuffi (Gast)


Lesenswert?

Das mit der DOUBLESIZE wäre interessant, meine Lib hat die FUnktionen 
nicht? Wo bekomme ich die her?!

von M. K. (sylaina)


Lesenswert?

Zieh dir die Lib von github, da ist immer die aktuelle Version:

http://www.github.com/sylaina/oled-display/

: Bearbeitet durch User
von Was Costas (Gast)


Lesenswert?

Hat jemand eigentlich inzwischen mal ein zum restlichen Font passendes 
Omega-Zeichen designt und implementiert und würde es hier posten?

von M. K. (sylaina)


Lesenswert?

Was Costas schrieb:
> Hat jemand eigentlich inzwischen mal ein zum restlichen Font
> passendes
> Omega-Zeichen designt und implementiert und würde es hier posten?

Ich hab grad mal aus dem Stehgreif das Spezial-Char-Set erweitert um Ω 
und ω, meintest du das? Kannst du jetzt aus dem github herunterladen. 
Testen kann ich frühestens morgen.

von Was Costas (Gast)


Lesenswert?

Supi. Danke.

von M. K. (sylaina)


Angehängte Dateien:

Lesenswert?

So, konnte es mir jetzt auch noch mal anschauen und musste ein klein 
wenig nachbessern aber jetzt schauts gut aus (vgl. Anhang). Ich musste 
auch das Makefile anpassen da durch Ω und ω nun das charset UTF-8 nicht 
mehr funktioniert.

von Nano (Gast)


Lesenswert?

M. K. schrieb:
> konnte es mir jetzt auch noch mal anschauen

Hast Du dazu einen Beispielcode, den die Arduino-IDE verarbeiten mag?

von M. K. (sylaina)


Lesenswert?

Nano schrieb:
> M. K. schrieb:
>
>> konnte es mir jetzt auch noch mal anschauen
>
> Hast Du dazu einen Beispielcode, den die Arduino-IDE verarbeiten mag?

Die Library ist in C geschrieben aber auch zu C++ kompatibel, du kannst 
die Funktionen 1:1 auch in Arduino-Projekten verwenden. ;)

von Kinderschokolade (Gast)


Lesenswert?

ich hoffe es ist ok diesen Beitrag nach einigen Jahren wieder 
hervorzukramen. Eine super Bibliothek! Gibt es eine Möglichkeit die 
Anzeige um 180° zu drehen?

von Frank D. (Firma: Spezialeinheit) (feuerstein7)


Lesenswert?

Ich habe gerade keine Lust im Datenblatt zu suchen, aber ich glaube mich 
erinnern zu können, dass es dafür ein Befehl für das Display gibt. Also 
nur ein Bit setzen und fertig.

von Kinderschokolade (Gast)


Lesenswert?

Das dachte ich auch.
Im Datenblatt unter 10.1.14 Set COM Output Scan Direction müsste man es 
theoratisch mit (C0h/C8h) umschalten können. Habe diese Stelle 
angepasst.
Das Display zeigt nun tatsächlich um 180° gedreht, allerdings auch 
spiegelverkehrt :D
1
// Init Sequence of SSD Display
2
static const uint8_t init_sequence [] PROGMEM = {  // Initialization Sequence
3
LCD_DISP_OFF,      // Display OFF (sleep mode)
4
0x20, 0b00,    // Set Memory Addressing Mode
5
        // 00=Horizontal Addressing Mode; 01=Vertical Addressing Mode;
6
        // 10=Page Addressing Mode (RESET); 11=Invalid
7
0xB0,      // Set Page Start Address for Page Addressing Mode, 0-7
8
0xC0,                  // Set COM Output Scan Direction //Vorher: 0xC8 
9
0x00,      // --set low column address
10
0x10,      // --set high column address
11
0x40,      // --set start line address
12
0x81, 0x3F,    // Set contrast control register
13
0xA1,      // Set Segment Re-map. A0=address mapped; A1=address 127 mapped.
14
0xA6,      // Set display mode. A6=Normal; A7=Inverse
15
0xA8, DISPLAY_HEIGHT-1,    // Set multiplex ratio(1 to 64)
16
0xA4,      // Output RAM to Display
17
        // 0xA4=Output follows RAM content; 0xA5,Output ignores RAM content
18
0xD3, 0x00,    // Set display offset. 00 = no offset
19
0xD5,      // --set display clock divide ratio/oscillator frequency
20
0xF0,      // --set divide ratio
21
0xD9, 0x22,    // Set pre-charge period
22
0xDA, 0x12,    // Set com pins hardware configuration    
23
0xDB,      // --set vcomh
24
0x20,      // 0x20,0.77xVcc
25
0x8D, 0x14,    // Set DC-DC enable
26
};

von M. K. (sylaina)


Lesenswert?

Ja, man kann die Anzeige um 180° drehen. In meiner Library ist diese 
Funktionalität aber noch nicht implementiert da ich selbst diese 
Funktionalität noch nicht benötigt habe (ähnlich wie das Scrollen). Da 
werde ich mich am WE mal dran setzen und das integrieren.

von Kinderschokolade (Gast)


Lesenswert?

Das wäre ja super. Dafür vorab schonmal einen dicken Dank!

von J. S. (jojos)


Lesenswert?

ich habe das mal in eine ältere Version der Adafruit_GFX eingebaut, die 
codes waren:
1
void Adafruit_UC1601S::flipVertical(bool flip) {
2
  _flipVertical = flip;
3
  if (flip) {
4
    command(LCD_SET_MAPPING_CTRL | 0b000);// flip vertical / horizontal
5
    command(LCD_SET_RAM_ADDRESS_CTRL | 0b101);  //
6
    command(LCD_SET_COM_END);
7
    command(21);                // Rows - 1
8
  } else {
9
    command(LCD_SET_MAPPING_CTRL | 0b100);// flip vertical / horizontal
10
    command(LCD_SET_RAM_ADDRESS_CTRL | 0b001);  //
11
    command(LCD_SET_COM_END);
12
    command(21);                // Rows - 1
13
  }
14
}

von Stefan F. (Gast)


Lesenswert?

J. S. schrieb:
> UC1601S

Sind wir hier noch beim gleichen Display Controller? Nach meinem 
Kenntnisstand kann der SSD1306 das Bild nicht drehen.

von J. S. (jojos)


Lesenswert?

Stefan F. schrieb:
> Sind wir hier noch beim gleichen Display Controller?

du hast Recht, habe die Lib für beide Controller und bin im falschen 
gelandet.
1
    if (_flipVertical) {
2
        command(SSD1306_SEGREMAP | 0x0);
3
        command(SSD1306_COMSCANINC);
4
    } else {
5
        command(SSD1306_SEGREMAP | 0x1);
6
        command(SSD1306_COMSCANDEC);          // flip vertically
7
    }

ist schon länger her, aber müsste funktionieren.
ja, der Kommentar ist blöde, müsste eigentlich in den anderen Zweig. 
Lange her...

: Bearbeitet durch User
von Kinderschokolade (Gast)


Lesenswert?

habe mal einen Versuch gewagt und das hier direkt nach der Init-Sequenz 
aufgerufen:
1
void lcd_flip_vertical(){  //Neu hinzugefügte Funktion
2
   uint8_t SSD1306_SEGREMAP = 0xA0;
3
   uint8_t SSD1306_COMSCANINC = 0xC0;
4
   lcd_command(SSD1306_SEGREMAP | 0x0, sizeof(SSD1306_SEGREMAP));
5
   lcd_command(SSD1306_COMSCANINC, sizeof(SSD1306_COMSCANINC));
6
}
Das funktioniert leider nicht. Zeigt dann nur Müll an...

von J. S. (jojos)


Lesenswert?

Kann ich mir morgen nochmal ansehen, sitze ausnahmsweise mal nicht am 
PC.

von Kinderschokolade (Gast)


Lesenswert?

Danke euch für die schnellen Antworten.
Habe es nun dank der Tipps mit dieser Funktion hinbekommen:
1
void lcd_flip_vertical(){  //Neu hinzugefügte Funktion
2
   uint8_t SSD1306_SEGREMAP[2] = {0x80, 0xA0};
3
   uint8_t SSD1306_COMSCANINC[2] = {0x80, 0xC0};
4
   lcd_command(SSD1306_SEGREMAP, sizeof(SSD1306_SEGREMAP));
5
   lcd_command(SSD1306_COMSCANINC, sizeof(SSD1306_COMSCANINC));
6
}

von Stefan F. (Gast)


Lesenswert?

Kinderschokolade schrieb:
> abe es nun dank der Tipps mit dieser Funktion hinbekommen

Wird das Bild damit nun um 180° gedreht oder nur vertikal gespiegelt?

von Kinderschokolade (Gast)


Lesenswert?

>Wird das Bild damit nun um 180° gedreht oder nur vertikal gespiegelt?

oh du hast Recht ich habe meine Funktion falsch benannt. Also damit wird 
das Bild um 180° gedreht. Spiegeln geht auch. Dann muss man das Kommando 
SEGREMAP einfach weglassen....Schreit nach einer tollen Funktion oder? 
Der Author wollte ja noch drann. Er macht es dann vernünftig :D

von Stefan F. (Gast)


Lesenswert?

Läuft, danke.
Ich konnte das auch in meine (andere) Bibliothek einbauen:
1
void OLED::rotate_180(bool enable) 
2
{
3
    i2c.beginTransmission(i2c_address);
4
    i2c.write(0x00); // command
5
6
    if (enable) 
7
    {
8
        i2c.write(0xA0); // segment remapping mode
9
        i2c.write(0xC0); // COM output scan direction
10
    }
11
    else
12
    {
13
        i2c.write(0xA1); // segment remapping mode
14
        i2c.write(0xC8); // COM output scan direction
15
    }
16
    i2c.endTransmission();
17
}

von M. K. (sylaina)


Lesenswert?

Kinderschokolade schrieb:
> Er macht es dann vernünftig :D

Brauch ich nicht, hat Stefan schon gemacht ;)

Derzeit kämpfe ich noch mit der Funktion. Das Problem: Segment-Remap 
(horizontal flip) wirkt nicht auf den RAM-Inhalt des Displays, d.h. man 
muss die Daten neu zum Display schicken. COM Scan Direction (vertical 
flip) wirkt sofort auf den RAM-Inhalt. kniffelig.

von J. S. (jojos)


Lesenswert?

Ich hatte die Funktion im Konstruktor benutzt, also nur einmal die 
Ausrichtung beim Start gesetzt. Das wird sicher schon für viele 
Anwendungen reichen.

von Tobiasz Topyla (Gast)


Lesenswert?

Der TEXTMODE 6x8 Font sieht sehr gut aus. Vielen herzlichen Dank für 
diese Lösung.

von M. K. (sylaina)


Lesenswert?

So, ich hab die Möglichkeit, das Display bzw. den Inhalt entsprechend zu 
spiegeln, implementiert. Man hat die Wahl zwischen horizontal spiegeln, 
vertikal zu spiegeln oder horizontal & vertikal zu spiegeln.

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.