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.