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"
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
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.
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.
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.
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.
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....
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:
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.
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 ;)
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?
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 ;)
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.
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.
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
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.
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.
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
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.
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.
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
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.
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.
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
;)
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.
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.
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
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.
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.
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?
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.
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
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:
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
voidlcd_command(uint8_tcmd){
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
voidlcd_data(uint8_tdata){
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.
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. :)
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. ;)
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.
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:
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.
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.
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)
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..).
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
volatileuint16_toverflows;
12
13
intmain(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
chartime[6];
21
// diverse Hilfsvariablen zum Zeichnen eines wachsenden/schrumpfenden Balkens
22
uint8_tmyVar=0;
23
uint8_tdir=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
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.
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) ;)
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)).
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.
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 ;))
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?
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.
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.
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.
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.
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.
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
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.
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 ?
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.
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.
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(inti=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
inti;
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.
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!
Joachim B. schrieb:> Habe gegoogelt wo man beim Arduino den C99 Schalter setzthttps://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.
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:
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)?
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
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
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.
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.
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
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.
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.
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.
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?
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 ?
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.
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
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?
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...
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!
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)'
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:
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.
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 ;)
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.
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
?
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:
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.
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
intmain(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(inti=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.
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
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:
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.
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.
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
voidlcd_clrscr(void){
2
uint8_tclearLine[DISPLAY_WIDTH];
3
for(uint8_ti=0;i<DISPLAY_WIDTH;i++){
4
clearLine[i]=0x00;
5
}
6
for(uint8_tj=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 ;).
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 :)
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.)
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!
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.
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.
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
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.
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:
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.
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. :)
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).
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
;)
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).
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. :-)
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.
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.
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
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.
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
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.
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
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
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
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?
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.
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!
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
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!
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?)
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.
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!
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.
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.
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
inta(charb);
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.
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!
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.
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!
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
case153:
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?
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.
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
case246:
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.
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.
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
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
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
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().
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
floatmyTestValue=-24.5;
5
charmyValueToPrint[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.
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
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.
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.
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__)
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.
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
intmain(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
return0;
20
}
ich habe probeweise lcd_gotoxy(0,0); vor dem lcd_display() in main
eingefügt und es hat funktioniert!
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.
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.
> 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.
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.
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ß
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.
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.
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.
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.
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?
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 ;)
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);
}
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
voidsetup(){
4
...
5
}
6
...
7
voidloop(){
8
charerrorCode[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
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.
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.
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.
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);
}
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.
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.
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.?
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
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.
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
voidsetup(){
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
voidloop(){
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
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.
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. ;)
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.
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.
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
voidsetup(){
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
voidloop(){}
Und das Display bleibt immer noch schwarz.
Hab jetzt den Arduino UNO, mit USBasp programmiert.
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.
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.
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 ;)
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.
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
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.
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.
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.
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.
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.
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.
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
;)
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
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:
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
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.
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.
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
> 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?
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
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
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.
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.
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.
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 ;)
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
> 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.
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.
"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
> 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.
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 ...
> 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?
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.
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
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.
"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
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?
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
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.
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
> 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.
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
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.
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?
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.
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
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.
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.
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.
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
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 ...
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.
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
staticinlineuint8_t
6
map_char2fnt(charc)
7
{
8
uint8_ti,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
returnidx;
18
}
19
20
21
/*
22
* print a single character on display and advance cursor
23
*
24
*/
25
void
26
lcd_putc(charc)
27
{
28
uint8_tfnt_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_ti=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:
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
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
Und noch eine neue Version
* kleinere Bugs beseitigt
* Code weiter aufgeräumt
* Redundanzen im Code beseitigt
* neue Funktion:
1
voidlcd_on(uint8_tonoff);
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
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.
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
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.
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
voidlcd_puts_p(constchar*progmem_s)
4
...
Beim ARM solls also wirklich nötig sein, dass alle Strings im RAM liegen
müssen?
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.
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 :-)
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.
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):
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. ;)
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.
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.
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 ;)
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.
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
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?
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
intmain()
13
{
14
chars[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)
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! ;)
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.
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.
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.
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.
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.
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!
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.
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.
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.
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.
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
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
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
constfnt_map_tfnt_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
staticuint8_tmap_char2fnt(charc)
24
{
25
uint8_ti,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
returnidx;
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.
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.
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.
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.
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.
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
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).
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.
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?
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.
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.
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.
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 ;)
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
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_ti;i<CHAR_FONT_SIZE;i++){
4
i2c_byte(CHAR[pos_in_FONT][i]);
5
}
und du machst das so
1
for(uint8_ti;i<CHAR_FONT_SIZE;i++){
2
lcd_data(CHAR[pos_in_FONT][i]);
3
}
mit
1
voidlcd_data(uint8_tdata){
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 ;)
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:
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
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.
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).
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.
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!
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.
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.
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?
> 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.
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!
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.
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).
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.
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.
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.
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.
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.
... 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 ?
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.
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...
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.
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 :-) )
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.
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.
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 ...
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.
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!!
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.
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.
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.
"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.
.
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.gitHarry 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.
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!
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 ^^
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.
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
;)
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.
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"aesz"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.
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.
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!
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.
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.
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.
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"aesz"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.
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.
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?
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?
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? ;)
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.
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
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 ;)
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).
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.
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?
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
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?
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.
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
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
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?"
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"
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.
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.
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.
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
inti=5;
2
charc='0'+i;// ergibt "5"
Auf alles Weitere müsstest du mit Nachdenken, Divisionen und Modulus
Operator kommen.
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.
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
intmain(void){
5
charvalueToPrint[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_tmyInteger=123;
7
floatmyFloat=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
return0;
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
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!
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 …
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
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.
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.
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
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.
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.
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.
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:
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
return0;
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.
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
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.
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 :)
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
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
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.
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.
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).
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.
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.
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 ....
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.
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? :.)
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.
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 ;)
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).
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)
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 ;)
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.
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?
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.
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.
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. ;)
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
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.
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.
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 ;)
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.
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.
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
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.
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.
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 ;)
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
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
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):
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
Strings0=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
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 ;)
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
Ä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.
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
Ä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.
Ä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.
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!
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.
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.
Ä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 ;)
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.
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.
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
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
charpuffer[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.
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...
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.
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 ;)
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
voidsetup(){
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
voidloop(){
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:
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
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.
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 ?
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.
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.
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.
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
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 ;)
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.
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.
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 ;)).
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 ;-)
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.
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
voidlcd_data(uint8_tdata[],uint16_tsize){
2
#if defined I2C
3
//Test set memory area
4
constuint8_tdef_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_ti=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?
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.
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...
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
intmain(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)
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.
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?
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.
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.
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.
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ß.
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.
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.
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:
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???
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)
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).
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.
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.
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.
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.
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(
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
InderLibraryvonhiersteht
4
[c]#ifDISPLAY_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.
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.
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".
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
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");
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.
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
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.
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!
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"
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.
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.
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.
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.
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.
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.]
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
noiconvimplementation,cannotconvertfromUTF-8to
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
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
Jan schrieb:> Das Display zeigt immer diesen verschobenen Text
hatte ich mal bei falscher Controllerwahl
aber in welcher Lib? adafruit oder diese?
vergessen!
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!
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
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 :)))
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.
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 ;)
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.
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.
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.
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
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:
> 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...
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?
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:
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?
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.
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
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.
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
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.
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
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.
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
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.
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!
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.
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.
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
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.
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.
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. ;)
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?
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.
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
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.
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...
Kinderschokolade schrieb:> abe es nun dank der Tipps mit dieser Funktion hinbekommen
Wird das Bild damit nun um 180° gedreht oder nur vertikal gespiegelt?
>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
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.
Ich hatte die Funktion im Konstruktor benutzt, also nur einmal die
Ausrichtung beim Start gesetzt. Das wird sicher schon für viele
Anwendungen reichen.
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.