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.
Ich nehme an, du verwendest einen Arduino. Ich werd heute Abend oder morgen Früh daheim mal was testen, hab hier grad keinen Arduino zur Hand.
Arduino hat kein Atmega324PA, ich verwende aber die Arduino IDE. So sieht die i2c.h aus: /* TODO: setup i2c/twi */ #define F_I2C 100000UL// clock i2c #define PSC_I2C 1 // prescaler i2c #define SET_TWBR (F_CPU/F_I2C-16UL)/(PSC_I2C*2UL) Im Anhang hab ich die ohne deiner i2c.h probiert, dafür dann mit Wire.h von Arduino. Allerdings sind da noch punkte rechts neben dem Text. Fuses sollten ja passen, 16 Mhz Quarz. EDIT: Jetzt bekomme ich Error 5, keine ahnung was ich geändert hab.
:
Bearbeitet durch User
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.?
extern "C" { #include "i2c.h" } Ich denke mal irgendwie so wirds eingebunden. Gibts aber immer noch Fehlermeldungen mit den ich nix anfangen kann.
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 | void setup() { |
6 | // put your setup code here, to run once:
|
7 | lcd_init(LCD_DISP_ON); // init lcd and turn on |
8 | |
9 | lcd_puts("Hello World"); // put string from RAM to display (TEXTMODE) or buffer (GRAPHICMODE) |
10 | lcd_gotoxy(0,2); // set cursor to first column at line 3 |
11 | lcd_puts_p(PSTR("String from flash")); // puts string form flash to display (TEXTMODE) or buffer (GRAPHICMODE) |
12 | #if defined GRAPHICMODE
|
13 | lcd_drawCircle(64,32,7,WHITE); // draw circle to buffer white lines |
14 | lcd_display(); // send buffer to display |
15 | #endif
|
16 | }
|
17 | |
18 | void loop() { |
19 | // put your main code here, to run repeatedly:
|
20 | |
21 | }
|
Der Sketch belegt 2344 Bytes (GRAPHICMODE, als Vergleich: der gleiche Code nur in C wie im github-Beispiel belegt lediglich 1884 Bytes). Wichtig ist, dass man
1 | extern "C" { |
2 | #include "lcd.h" |
3 | }
|
schreibt. Schreibt man
1 | #include "lcd.h" |
meckert u.a. der Linker, dass er die jeweiligen Referenzen auf die einzelnen Funktionen (z.B. lcd_init()) nicht auflösen kann. Ein weiteres Manko ist, dass man dem Compiler/Linker auch noch irgendwie beibringen muss, welchen Charset er für die Quellcode-Dateien verwenden soll. Es wird nämlich beim ersten Compilieren u.a. vor den Umlauten (ä,ö,ü usw.) gewarnt, diese sind auch nicht verarbeitet, d.h. versucht man z.B. ein ä aufs Display zu bringen erscheint schlicht nichts. In meinem Makefile steht deshalb
1 | CFLAGS += -finput-charset=utf-8 -fexec-charset=iso-8859-15 |
drin, wo und wie man das bei Arduino angibt weis ich allerdings nicht aber dazu findet sich sicher auch hier im Forum Hilfe ;)
:
Bearbeitet durch User
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.
:
Bearbeitet durch User
Habe so ein OLED, in weiß. Damals gabs da keine Auswahl und die waren ohne Versandkosten. https://de.aliexpress.com/item/-/32717936245.html Die Lib grad neu geladen. I2C Scanner sagt dass es die 3C Adresse ist, mit anderen Libs läufts auch, Verkabelung muss dann ja auch passen.
1 | /* TODO: define displaycontroller */
|
2 | #define SSD1306 // or SSD1306, check datasheet of your display
|
3 | /* TODO: define displaymode */
|
4 | #define GRAPHICMODE // TEXTMODE for only text to display,
|
5 | // GRAPHICMODE for text and graphic
|
6 | |
7 | #define LCD_I2C_ADR 0x3C
|
1 | extern "C"{ |
2 | #include "lcd.h" |
3 | }
|
4 | |
5 | void setup() { |
6 | lcd_init(LCD_DISP_ON); // init lcd and turn on |
7 | lcd_puts("Hello Wuüorld"); // put string from RAM to display (TEXTMODE) |
8 | lcd_gotoxy(0, 2); // set cursor to first column at line 3 |
9 | lcd_puts_p(PSTR("String from flash")); // puts string form flash to |
10 | }
|
11 | void loop() {} |
Und das Display bleibt immer noch schwarz. Hab jetzt den Arduino UNO, mit USBasp programmiert.
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 ;)
:
Bearbeitet durch User
auch so läuft es nicht. Man kann es auch so einbinden, dann wirds in dem ganzem Library Ordner nach lcd21.h gesucht.
1 | extern "C" { |
2 | #include <lcd21.h> |
3 | }
|
:
Bearbeitet durch User
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
Das Bild ist von einem SH1106 (1.3"), bei meinem SSD1306 (0.96") ist auch GND außen ;)
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.
Ich denke eher das ist für die I2C Adresse, nicht für SPI. Ist nur ne Vermutung, nicht weiter damit befasst.
Du denkst? Bist aber nicht sicher?
:
Bearbeitet durch User
Ich hab 2 Displays bestellt, 1 SPI und 1 I2C. Beim SPI sind mehr Pins, deshalb dachte ich es ist schon richtig mit dem I2C.
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.
Das Problem ist so alt wie I2C selbst, schiebe mal 0x78 um ein Bit nach rechts. Beitrag "Re: Kann mir bitte wer beim USI-TWI helfen?"
Beitrag #5322585 wurde vom Autor gelöscht.
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.
J. W. schrieb: > #define LCD_I2C_ADR 0x3C// 0x7A Ich glaube nicht das 0x3C richtig ist. Versuch es mal mit 0x78.
1 | (0x3C << 1) |
Ich glaub auch nicht dass es richtig ist, bei dieser Lib.
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
Hallo Sebastian, ein Funktion zum Zentrieren ist nicht enthalten. Da könnte man mit der strlen-Funktion aus der string.h arbeiten.
Hi M. Köhler Erstmal danke für die Library. Leider funktioniert bei mir gar nichts. Ich verwende ein 128x32 OLED mit SSD1306. Dieses steuere ich mit einem ATmega 644p mit 20MHz an. Ich habe deinen Code von GitHub heruntergeladen und die nötigen Anpassungen vorgenommen(angehängt) und eine Codezeile hinzugefügt:
1 | #if defined(__AVR_ATmega328P__) || defined(__AVR_ATmega168P__) || defined(__AVR_ATmega88P__) || defined(__AVR_ATmega48P__) || defined(__AVR_ATmega1284P__) || defined(__AVR_ATmega644P__)
|
Es zeigt mir nichts am OLED an. Ich nehme an ich habe die Hardware richtig verdrahtet. SDL von Atmega->SCK des OLED mit 4.7kOhm Pull-Up SDA von Atmega->SDA des OLED mit 4.7kOhm Pull-Up VCC->5V Kannst du mit weiterhlefen? EDIT: habe ausversehen zweimal das gleiche Bild angehängt Mit freundlichen Grüssen Fabian
:
Bearbeitet durch User
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
1 | //Hello World der uCs
|
2 | #include <avr/io.h> |
3 | #include <util/delay.h> |
4 | void main void { |
5 | DDRB |= (1 << PB1); |
6 | for(;;) { |
7 | PORTB ^= (1 << PB1); //toggel PB1 |
8 | delay_ms(500); |
9 | }
|
10 | }
|
11 | //aus dem Kopf getippt, Fehler ggf. inclusive ;)
|
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.
:
Bearbeitet durch User
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.
Vielen Dank für die schnelle Antwort. Wo finde ich die aktuellste Version deiner Library? Auf Github?
Ja, auf Github, Link ist im Eröffnungspost ;) Da gibts einige Änderungen inzwischen, z.B. sind die I2C-Funktionen in einer eigenen Lib ausgelagert worden sodass man auch eigenen I2C-Funktionen nutzen kann ;)
:
Bearbeitet durch User
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
Marius K. schrieb: > Ich meinte mit dünner Informationslage, dass Google kein Datenblatt des > SSD1315 bekannt zu sein scheint... https://www.google.com/search?q=SSD1315+datasheet
Ich habe auf den Link geklickt und kein passendes Ergebnis erhalten.
Stefanus F. schrieb: > Ich habe auf den Link geklickt und kein passendes Ergebnis erhalten. Da war ich wohl zu nachlässig ... https://www.mouser.com/ds/2/131/LPCXpresso_Experiment_Kit_Users_Guide-908526.pdf Die arbeiten damit. Da gibt es auch Anregungen https://github.com/twchad/Adafruit_Python_SSD1351 Aber ja, scheint dünn zu sein - mea culpa.
Stefanus F. schrieb: > SSD1315 und nicht SSD1351 ! Wie recht Du doch hast. Hast Du mal die Befehle mit 1306 etc. verglichen?
> Hast Du mal die Befehle mit 1306 etc. verglichen?
Nein. Da ich weder ein SSD1315 noch ein SSD1551 besitze, ist das für
mich nicht wichtig.
Stefanus F. schrieb: > Nein. Da ich weder ein SSD1315 noch ein SSD1551 besitze, ist das für > mich nicht wichtig. SSD1306 hast Du gelesen?
> 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.
Welches ist denn nun die letzte gültige Lib? Für Text und Grafik. Benutze Atmel Studio 7. Evtl. könnte ein Datum ganz vorn/oben eingefügt werden?
:
Bearbeitet durch User
Reinhard O. schrieb: > Welches ist denn nun die letzte gültige Lib? Im 1. Post ist ein Github Repository verlinkt: https://github.com/Sylaina/oled-display
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.
lcd_display() hatte ich rausgelöscht! Danke!
:
Bearbeitet durch User
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
:
Bearbeitet durch User
Beitrag #5522868 wurde vom Autor gelöscht.
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 | static inline uint8_t |
6 | map_char2fnt (char c) |
7 | {
|
8 | uint8_t i, idx; |
9 | if ((c >= 0x20) && (c <= 0x7f)) |
10 | idx = (uint8_t) c - 0x20; |
11 | else
|
12 | {
|
13 | for (i = 0;(pgm_read_byte(&fnt_map[i].idx) != 0xff) |
14 | && (pgm_read_byte(&fnt_map[i].c) != c); i++); |
15 | idx = pgm_read_byte(&fnt_map[i].idx); |
16 | }
|
17 | return idx; |
18 | }
|
19 | |
20 | |
21 | /*
|
22 | * print a single character on display and advance cursor
|
23 | *
|
24 | */
|
25 | void
|
26 | lcd_putc (char c) |
27 | {
|
28 | uint8_t fnt_idx; |
29 | fnt_idx = map_char2fnt (c); |
30 | cursorPosition++; |
31 | if (fnt_idx != 0xff) |
32 | {
|
33 | #ifdef TEXTMODE
|
34 | i2c_start(OLED_I2C_ADR); |
35 | i2c_byte(OLED_DTA_PREFIX); // 0x00 for command, 0x40 for data |
36 | #endif
|
37 | for (uint8_t i = 0; i < 6; i++) |
38 | {
|
39 | #ifdef GRAPHICMODE
|
40 | displayBuffer.buf[actualIndex + i] = pgm_read_byte( |
41 | &oled_font6x8[fnt_idx][i]); // print font to ram, print 6 columns |
42 | #else
|
43 | i2c_byte(pgm_read_byte(&oled_font6x8[fnt_idx][i])); // print font to ram, print 6 columns |
44 | #endif
|
45 | }
|
46 | #ifdef TEXTMODE
|
47 | i2c_stop(); |
48 | #endif
|
49 | }
|
50 | #ifdef GRAPHICMODE
|
51 | actualIndex += 6; |
52 | #endif
|
53 | }
|
Die fnt_map sieht so aus und mapped nur die Sonderzeichen:
1 | typedef struct |
2 | {
|
3 | char c; // char-code |
4 | uint8_t idx; // index in font-table |
5 | } fnt_map_t; |
6 | |
7 | // font-map for extra-chars
|
8 | const fnt_map_t fnt_map[] PROGMEM = |
9 | {
|
10 | { 132, 97 }, // ä |
11 | { 148, 99 }, // ö |
12 | { 129, 95 }, // ü |
13 | { 142, 98 }, // Ä |
14 | { 153, 100 }, // Ö |
15 | { 154, 96 }, // Ü |
16 | { 248, 101 }, // ° |
17 | { 225, 102 }, // ß |
18 | // { 230, 103 }, // µ * not yet implemented *
|
19 | // { 234, 104 }, // Omega (Ohm) * not yet implemented *
|
20 | { 0, 0xff } // end of table |
21 | };
|
Im Lauf des Tages, sobald ich den Code mit AVR getestet hab, werde ich den neuen Code hochladen. Insgesamt ist der Code (und auch das Compilat) dadurch kürzer geworden. Harry
:
Bearbeitet durch User
Beitrag #5524800 wurde vom Autor gelöscht.
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 | void lcd_on(uint8_t onoff); |
Damit kann man das Display abschalten und in den Stromspar-Mode versetzen. Der Bildschirminhalt bleibt dabei erhalten. * Bei der Ausgabe von Strings wird am Ende einer Zeile automatisch ein Zeilenumbruch eingefügt und in der folgenden Zeile weiter geschrieben. In der letzten Zeile wird zurück auf die erste Zeile gesprungen. * SH1106 fehlt nach wie vor * Im Zeichensatz sollten noch 2 Zeichen eingepflegt werden: µ -> Bsp: µV, µA, µF etc. Omega -> das Zeichen für Ohm Die sind derzeit nur als Dummys im Zeichensatz.(die letzten 2 Zeichen) Details siehe Code. Harry
:
Bearbeitet durch User
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.
Fabian F. schrieb: > Du kennst den Font Generator für das Display? > http://oleddisplay.squix.ch/#/home Danke! Schau ich mir an.
Die Änderungen an dem originalen Code von Michael Köhler sind inzwischen so umfangreich geworden, daß kein Stein mehr auf dem Anderen geblieben ist. Hinzu gekommen ist u.A. ein 6- und 4-Zeilen Modus Besonders der 6-Zeilen Mode sieht wirklich schick aus (siehe Anhang) Der läuft allerdings leider nur im Grafik-Mode. Was geblieben ist, ist die Möglichkeit, weiter den Text-Mode mit einem Speicherbedarf von <2k Flash und 21 Byte RAM zu nutzen. (nur auf 8bit-AVR) Zusätzlich steht im Text-Mode jetzt auch ein 4-zeiliger Mode zur Verfügung, der die Portierung von einem klassischen HD44780-Display erleichtern sollte. Der funktioniert zwar im Textmode, sieht aber auch erst im Grafik-Modus wirklich schick aus, da ich da das gesamte Bild auf dem Screen zentrieren kann. Zusätzlich wurden \n, \r und \b in der putc()-Funktion implementiert. Aktuell muß ich noch einen Bug in der STM32-Umsetzung beseitigen, und sobald das auch läuft, werde ich einen neuen Thread eröffnen, da mein Fork mit dem Original ohnehin nicht mehr viel zu tun hat. Der neue Code wird dann auch via GitHub zur Verfügung stehen. Harry
:
Bearbeitet durch User
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 gehts zu meinem Fork: Beitrag "Universelles Oled-Libary (SSD1306) für AVR(8bit) und STM32/HAL"
:
Bearbeitet durch User
Hallo Harry, ich hab mir mal deine Lib angeschaut und mir ist der ein und andere Schnitzer aufgefallen. Ich fang mal mit was einfachem an:
1 | void lcd_command(uint8_t cmd[], uint8_t size, uint8_t fromFlash) |
2 | {
|
3 | i2c_start(OLED_I2C_ADR); |
4 | i2c_byte(OLED_CMD_PREFIX); // 0x80 for command |
5 | for (uint8_t i = 0; i < size; i++) |
6 | {
|
7 | if (fromFlash == TRUE) |
8 | i2c_byte(pgm_read_byte(&cmd[i])); |
9 | else
|
10 | i2c_byte((uint8_t)cmd[i]); |
11 | }
|
12 | i2c_stop(); |
13 | }
|
Hier schon mal eine Frage: Warum hast du die Unterscheidung, ob die Daten im RAM oder im FLASH liegen in die Command-Funktion verschoben? Du (und auch ich) laden nur ein einziges Mal Daten aus dem Flash: Bei der Initialisierung. Da so eine if-Schleife für einen µC eigentlich immer doof ist, die Command-Funktion aber öfter aufgerufen wird, ist das eigentlich nicht sehr sinnvoll. Und bei lcd_data() hast du das auch gemacht und auch da ist es genauso wenig sinnvoll. Dann musst du noch mal überprüfen, ob wirklich alles so geht wie du dir das vorgestellt hast. Willst zu z.B. wirklich niemals auf einem ARM einen String aus dem Flash laden? Mir fielen nämlich folgende Zeilen auf:
1 | ...
|
2 | #ifndef __ARM_ARCH
|
3 | void lcd_puts_p(const char* progmem_s) |
4 | ...
|
Beim ARM solls also wirklich nötig sein, dass alle Strings im RAM liegen müssen?
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):
1 | #ifdef __ARM_ARCH
|
2 | /*
|
3 | * ARM-speciffic macros and functions
|
4 | */
|
5 | #define PROGMEM
|
6 | #define pgm_read_byte(a) (*(a))
|
7 | #define PSTR(a) (a)
|
8 | #define lcd_puts_p(a) lcd_puts(a)
|
9 | #define memcpy_P(a,b,c) memcpy(a,b,c)
|
:
Bearbeitet durch User
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.
1 | #ifdef GRAPHICMODE
|
2 | #if (OLED_LINES == 8)
|
3 | memcpy_P(&displayBuffer.buf[cursor.y][(cursor.x * OLED_FONT_WIDTH) + OLED_HSHIFT], |
4 | &oled_font6x8[fnt_idx], OLED_FONT_WIDTH); |
5 | #else
|
Mir ist ein sauberer Programmierstil wichtiger, als irgendwo einzelne Takt-Zyklen einzusparen.
:
Bearbeitet durch User
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.
:
Bearbeitet durch User
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 | int main() |
13 | {
|
14 | char s[21]; |
15 | // put your setup code here, to run once:
|
16 | lcd_init(OLED_DISPLAYON); // init lcd and turn on |
17 | |
18 | #if defined GRAPHICMODE
|
19 | sprintf(s, "%d-Line graphic-mode\r\n", OLED_LINES); |
20 | #else
|
21 | sprintf(s, "%d-Line text-mode\r\n", OLED_LINES); |
22 | #endif
|
23 | lcd_puts(s); // put string from RAM to display (TEXTMODE) or buffer (GRAPHICMODE) |
24 | lcd_puts("20 chars per line\r\n"); |
25 | lcd_puts_p(PSTR("special chars:\r\n\x84\x94\x81\x8e\x99\x9a\xf8\xe1\r\n")); |
26 | for (uint8_t i=4;i < (OLED_LINES - 1);i++) |
27 | {
|
28 | sprintf(s, "Line %2d\r\n", i+1); |
29 | lcd_puts(s); // put string from RAM to display (TEXTMODE) or buffer (GRAPHICMODE) |
30 | } /**/ |
31 | #if defined GRAPHICMODE
|
32 | lcd_puts ("Isn't it nice?"); |
33 | #else
|
34 | lcd_puts ("Isn't it ugly?"); |
35 | #endif
|
36 | |
37 | // lcd_gotoxy(0,2); // set cursor to first column at line 3
|
38 | // lcd_puts_p(PSTR("String from flash")); // puts string form flash to display (TEXTMODE) or buffer (GRAPHICMODE)
|
39 | #if defined GRAPHICMODE
|
40 | lcd_drawRect(0,0,127,63,WHITE); |
41 | lcd_drawCircle(96,42,7,WHITE); // draw circle to buffer white lines |
42 | lcd_display(); // send buffer to display |
43 | #endif
|
44 | |
45 | while(1) |
46 | {
|
47 | |
48 | }
|
49 | |
50 | }
|
Harry L. schrieb: > Btw. erreich ich auf einem STM32F1xx >40fps > Schnell genug? Aber sicher nicht bei 400 kHz Taktrate.
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.
:
Bearbeitet durch User
M. K. schrieb: > Das Display besteht aus 128*96 Pixel 128 * 64 Pixel = 8192 Bit = 1024 Byte = 1kB Ich sende via DMA den kompletten Buffer in einem Rutsch an den Controller, und sobald der fertig ist, geht das Spielchen von Vorne los. Die Präambel (1 Byte) muss dabei nur 1mal pro Buffer-Write gesendet werden. Das Programm läuft während dessen ungebremst weiter.
:
Bearbeitet durch User
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!
Ach das meinst du, da hab ich meinen Code von damals genommen:
1 | #include "main.h" |
2 | |
3 | #include <stdlib.h> |
4 | #include <avr/io.h> |
5 | #include <avr/interrupt.h> |
6 | #include "i2c_master.h" |
7 | #include "lcd.h" |
8 | |
9 | volatile uint16_t overflows=0; |
10 | |
11 | int main(void) |
12 | {
|
13 | |
14 | i2c_init(); |
15 | |
16 | lcd_init(OLED_DISPLAYON); |
17 | lcd_clrscr(); |
18 | |
19 | sei(); |
20 | |
21 | TCCR1B |= (1 << CS00); |
22 | lcd_puts("M. Koehler 2016/2017"); |
23 | TCCR1B &= ~(1 << CS00); |
24 | |
25 | |
26 | char time[6]; |
27 | |
28 | dtostrf((overflows*65536.0+TCNT1)/F_CPU*1e3, |
29 | 6, |
30 | 3, |
31 | time); |
32 | lcd_gotoxy(0,6); |
33 | lcd_puts("Time to print Line 1:"); |
34 | lcd_gotoxy(0,7); |
35 | lcd_puts(time); |
36 | lcd_puts("ms"); |
37 | |
38 | lcd_display(); |
39 | for(;;){ |
40 | /* insert your main loop code here */
|
41 | }
|
42 | return 0; /* never reached */ |
43 | }
|
44 | ISR(TIMER1_OVF_vect){ |
45 | overflows++; |
46 | }
|
Und wie gesagt, bei meinem Code bekomme ich knapp 5ms angezeigt, bei deinem knapp 10ms.
M. K. schrieb: > Und wie gesagt, bei meinem Code bekomme ich knapp 5ms angezeigt, bei > deinem knapp 10ms. Text- oder GraphicMode? Für den Text-Mode kann ich mir das kaum vorstellen. Mein Graphic-Mode ist allerdings deutlich aufwendiger als deiner, da ich die Ausgabe vertikal wie horizontal zentriere was einiges an Bit-Shifts erfordert, aber auch das erklärt nicht so einen Unterschied. Allerdings stört mich das bei reiner Textausgabe sowieso wenig,da das immer noch mehr als schnell genug für unsere Augen ist. Am meisten Zeit und Platz vergeudest du übrigens hiermit:
1 | dtostrf((overflows*65536.0+TCNT1)/F_CPU*1e3, |
2 | 6, |
3 | 3, |
4 | time); |
Wozu du da float brauchst, ist mir vollkommen schleierhaft.
:
Bearbeitet durch User
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.
M. K. schrieb: > Das war die einfachste/schnellste Variante x,yz ms > anzuzeigen. Die einfachste vielleicht, aber ganz sicher nicht die schnellste..
Sei mir bitte nicht böse, aber ich gewinne zunehmend den Eindruck, daß du angepisst bist, weil jemand es gewagt hat, deinen Code einem kompletten Redesign zu unterziehen, und du darum so lange mit dem Kopf schüttelst, bis du das Haar in der Suppe findest. Glaub mir einfach, daß unsere Design-Goals die Selben sind: Größe und Geschwindigkeit Es macht aber imho wenig Sinn, einige gesparte Taktzyklen mit schlecht les-/wartbarem Code zu erkaufen, und erst Recht dann nicht, wenn diese Einsparungen nur minimalen Einfluss auf das Gesamt-Ergebnis haben. Das Ziel meines Redesign war nicht, deine Programmier-Fähigkeiten in Frage zu stellen, sondern die Usability dieses Library zu verbessern. Du hängst dich an Kleinigkeiten auf, aber die wirklich relevanten Unterschiede hast du bisher mit keinem Wort erwähnt: * die deutlich verbesserte putc-Routine * die leichte Erweiterbarkeit des Font um individuelle Sonderzeichen. * Die Möglichkeit bei den Graphic-Funktionen nicht nur s/w sondern auch invertierend zu zeichnen. Sowas ist mir die paar Bytes mehr an Code wert, und selbst wenn meine Funktionen in einzel-Aspekten vielleicht sogar etwas langsamer als deine laufen, so sind das bezogen auf den gesamten Bildaufbau ganz sicher keine 100% Unterschied, und ich behaupte, daß das ein normaler Mensch auf dem Display ganz sicher nicht wahrnehmen wird.
:
Bearbeitet durch User
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 | const fnt_map_t fnt_map[] PROGMEM = |
3 | {
|
4 | { 132, 97 }, // ä |
5 | { 148, 99 }, // ö |
6 | { 129, 95 }, // ü |
7 | { 142, 98 }, // Ä |
8 | { 153, 100 }, // Ö |
9 | { 154, 96 }, // Ü |
10 | { 248, 101 }, // ° |
11 | { 225, 102 }, // ß |
12 | { 230, 103 }, // µ * only dummy in font * |
13 | { 234, 104 }, // Omega (Ohm) * only dummy in font * |
14 | { 0, 0xff } // end of table |
15 | };
|
16 | |
17 | |
18 | |
19 | /*
|
20 | * maps char to index of font-table
|
21 | * if char not found, 0xff is returned
|
22 | */
|
23 | static uint8_t map_char2fnt(char c) |
24 | {
|
25 | uint8_t i, idx; |
26 | if ((c >= 0x20) && (c <= 0x7f)) |
27 | idx = (uint8_t) c - 0x20; |
28 | else
|
29 | {
|
30 | for (i = 0; |
31 | (pgm_read_byte(&fnt_map[i].idx) != 0Xff) |
32 | && (pgm_read_byte(&fnt_map[i].c) != c); i++) |
33 | ;
|
34 | idx = pgm_read_byte(&fnt_map[i].idx); |
35 | }
|
36 | return idx; |
37 | }
|
M. K. schrieb: > Der Referenzstring aus meinem Eröffnungpost benötigt nun im Fastmode > (400 kHz I2C-Taktrate) ca. 2.6 ms bis er geschrieben ist im Textmode. Und du glaubst wirklich, daß ein Mensch bei einer Textausgabe den Unterschied zw. 2,6ms und 12,5ms "sieht"? Genau die Punkte, die mich zum Redesign bewogen haben sind in dieser Version genauso enthalten - nur teilweise "verschlimmbessert" Das sind genau die Optimierungen, die in der Praxis genau gar nichts bringen, aber den Code alles Andere als schöner machen.
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.
1 | uint16_t *MyTimer; |
2 | |
3 | uint32_t uptime; |
4 | |
5 | #define MYTIMER (*(MyTimer))
|
6 | |
7 | #define TIMETEST
|
8 | |
9 | int main() |
10 | {
|
11 | char s[21]; |
12 | uint32_t fulltime, linetime; |
13 | |
14 | // put your setup code here, to run once:
|
15 | lcd_init(OLED_DISPLAYON); // init lcd and turn on |
16 | lcd_clrscr(); |
17 | uint8_t teststring[]="01234567890123456789"; |
18 | |
19 | #ifdef TIMETEST
|
20 | init_SysTimer(&uptime); |
21 | MyTimer = request_SysTimer(); |
22 | |
23 | MYTIMER = 0; |
24 | for (uint8_t i=0; i<7;i++) |
25 | {
|
26 | lcd_gotoxy(0,i); |
27 | lcd_puts(teststring); |
28 | }
|
29 | fulltime = (uint32_t)MYTIMER; |
30 | linetime = (fulltime * 10) / 7; |
31 | sprintf(s, "%ld,%ld ms/line", linetime / 10, linetime % 10); |
32 | lcd_gotoxy(0,7); |
33 | lcd_puts(s); |
34 | #endif
|
:
Bearbeitet durch User
Noch mehr Timing: Das Schreiben 1 kompl. Zeile (20 Zeichen) im aufwendigen 6-Zeilen-Mode in den Framebuffer: 1,0ms Das Übertragen des Framebuffer auf das Display: 25,4ms Für das Beschreiben des vollst. Display im 6-Zeilen-Mode macht das dann: ((6 * 1ms) + 25,4ms) / 6 = 5,23ms pro Zeile. Da beim Überragen einer Zeile des Framebuffe auf das Display 25,4 ms / 8 = 3,18 ms/Zeile benötigt werden, erscheinen mir die von Michael gemessenen 2,6ms unglaubwürdig. Entweder war das keine vollst. Zeile mit 20 Zeichen, oder da ist irgendwo ein Messfehler.
:
Bearbeitet durch User
Harry L. schrieb: > Und es gibt immer noch 2 komplett unabhängige lcd_put() (Text- und > Graphic-Mode), die sich nur in wenigen Zeilen unterscheiden. > > Wozu? Das steht weiter oben warum das so ist. Das werde ich mit Sicherheit nicht noch einmal erklären. Harry L. schrieb: > Wartbarer Code sieht anders aus! Was willst du daran warten, was soll daran unübersichtlich sein? Harry L. schrieb: > M. K. schrieb: >> - einige Steuerzeichen wurde ergänzt > > Und gleich ne ganze switch-Kaskade um das Sonderzeichen auszuwählen... > Mag vielleicht paar ns sparen, ist aber hässlicher Stil und dazu > unflexibel. In wiefern soll das unflexibel sein? Und was daran ist hässlicher Stil? Ich mein, die Steuerzeichen wählst auch du über ne Switch aus, warum ist das bei dir kein hässlicher Stil aber bei mir? Den check ich nicht. Harry L. schrieb: > Meine Version ist flexibler/generischer bei Erweiterungen um einzelne > Zeichen, funktioiert mit allen Zeichen und belegt weniger Flash Ob meine Variante weniger Flash belegt muss ich mal gleich schaun aber weniger flexibel ist sie definitiv nicht. Wie kommst du darauf? Harry L. schrieb: > Und du glaubst wirklich, daß ein Mensch bei einer Textausgabe den > Unterschied zw. 2,6ms und 12,5ms "sieht"? Nö, aber je schneller das Display abgefrühstückt ist desto eher hat man Zeit in der Main andere Dinge zu tun. Es wäre ja schon irgendwie, überspitzt formuliert, blöd wenn man in der Main nur Zeit hätte das Display zu beschreiben. Harry L. schrieb: > Genau die Punkte, die mich zum Redesign bewogen haben sind in dieser > Version genauso enthalten - nur teilweise "verschlimmbessert" Das ist natürlich Unsinn. Harry L. schrieb: > Das sind genau die Optimierungen, die in der Praxis genau gar nichts > bringen, aber den Code alles Andere als schöner machen. Du findest es jetzt also unschöner, dass die Suche&Auswahl des Sonderzeichens nicht mehr in der putc() geschieht sondern übersichtlicher in der Headerdatei, die auch den Font beinhaltet? Interessant. Harry L. schrieb: > Meine Ausgabe (Textmode, 20 Zeichen/Zeile) dauert 4,4ms pro volle Zeile > (20 Zeichen schreiben) Das ist bei mir ebenso ;) Harry L. schrieb: > Das Übertragen des Framebuffer auf das Display: 25,4ms Das dauert bei mir im Grafikmode 26,858ms. Übrigens: 25,4ms entsprechen nicht > 40fps sondern < 40fps ;) Harry L. schrieb: > Da beim Überragen einer Zeile des Framebuffe auf das Display 25,4 ms / 8 > = 3,18 ms/Zeile benötigt werden, erscheinen mir die von Michael > gemessenen 2,6ms unglaubwürdig. > > Entweder war das keine vollst. Zeile mit 20 Zeichen, oder da ist > irgendwo ein Messfehler. War ein Messfehler. Ich hatte doch in der Tat die falsche Taktquelle für den Atmega ausgewählt sodass der Atmega nicht mit 8 MHz lief. Blöder Fehler. Am Besten finde ich deine Kritik an der Wartbarkeit des Codes, und dann lese ich z.B. bei dir solche Dinge:
1 | ...
|
2 | #ifdef __ARM_ARCH
|
3 | ...
|
4 | #endif
|
5 | ...
|
6 | #ifdef __ARM_ARCH
|
7 | ...
|
8 | #endif
|
9 | ...
|
Also wirklich übersichtlicher/besser Wartbar ist das ja nicht. Am besten gefällt mir das:
1 | ...
|
2 | // line 153
|
3 | #ifndef __ARM_ARCH
|
4 | ...
|
5 | #endif
|
6 | //line 187
|
7 | #ifdef __ARM_ARCH
|
8 | ...
|
9 | #endif
|
10 | ...
|
Warum du bei sowas kein #elif benutzt versteh ich nicht. Aber, bzgl. Wartbarkeit, wirklich übersichtlich durch diese ganzen, ich sag mal, Spagetti-#if's ist dein Code nicht wirklich. Warum hast du hier nicht mal richtig nach Architektur sortiert wie etwa so:
1 | ...
|
2 | #ifdef __ARM_ARCH
|
3 | // alles was zum ARM gehört hier rein
|
4 | #elif
|
5 | // hier alles was zum AVR gehört
|
6 | #endif
|
7 | // hier (oder vor das ifdef) hin alles, was für ARM und AVR benutzt werden soll
|
8 | ...
|
Das wäre erheblich übersichtlicher als so, wie du es jetzt hast. EDIT: Ich habe nun auch noch mal verglichen. Mikrocontroller ist ein AVR Atmega328p mit internen RC, auf 8 MHz eingestellt (Standardfuse mit CLKDIV8 ausgeschaltet) Im TEXTMODE belegt deine Library mit der nachfolgenden Main 5118 Bytes im Flash und es dauert 4.903ms bis die Zeile auf dem Display steht (kein Overflow vom Timer und der Count steht bei 39227). Meine Library belegt 4936 Bytes und sie braucht grade mal 4.399ms bis der Text im Display steht (kein Overflow vom Timer und der Count steht bei 35195) Im GRAPHICMODE belegt deine Library mit der nachfolgenden Main 6426 Bytes im Flash und es dauert 28.177ms bis die Zeile auf dem Display steht (3 Overflows vom Timer und der Count steht bei 28810). Meine Library belegt 6138 Bytes und sie braucht grade mal 27.766ms bis der Text im Display steht (3 Overflows vom Timer und der Count steht bei 25517). Mit deiner Library braucht der Atmega 1. länger bis die Anzeige da ist und 2. belegt sie mehr Flash-Speicher
1 | //Testcode
|
2 | #include <stdlib.h> |
3 | #include <avr/io.h> |
4 | #include <avr/interrupt.h> |
5 | #include "i2c_master.h" |
6 | #include "lcd.h" |
7 | #include <util/delay.h> |
8 | volatile uint32_t overflows=0; |
9 | |
10 | int main(void) |
11 | {
|
12 | TIMSK1 |= (1 << TOIE1); |
13 | i2c_init(); |
14 | |
15 | lcd_init(OLED_DISPLAYON); |
16 | lcd_clrscr(); |
17 | |
18 | sei(); |
19 | lcd_gotoxy(0, 0); |
20 | TCCR1B |= (1 << CS10); |
21 | lcd_puts(("M. Koehler 2016/2017")); |
22 | #ifdef GRAPHICMODE
|
23 | lcd_display(); |
24 | #endif
|
25 | TCCR1B &= ~(1 << CS10); |
26 | |
27 | char time[6]; |
28 | lcd_gotoxy(0, 2); |
29 | lcd_puts_p(PSTR("OVF: ")); |
30 | ltoa(overflows, |
31 | time, |
32 | 10); |
33 | lcd_puts(time); |
34 | |
35 | lcd_gotoxy(0, 3); |
36 | lcd_puts_p(PSTR("TCNT1: ")); |
37 | ltoa(TCNT1, |
38 | time, |
39 | 10); |
40 | lcd_puts(time); |
41 | |
42 | dtostrf((overflows*65536.0+TCNT1)/(float)F_CPU*1e3, |
43 | 6, |
44 | 3, |
45 | time); |
46 | |
47 | lcd_gotoxy(0,5); |
48 | lcd_puts_p(PSTR("Time to print line 1:\r\n")); |
49 | lcd_puts(time); |
50 | lcd_puts_p(PSTR("ms")); |
51 | #ifdef GRAPHICMODE
|
52 | lcd_display(); |
53 | #endif
|
54 | for(;;){ |
55 | /* insert your main loop code here */
|
56 | }
|
57 | return 0; /* never reached */ |
58 | }
|
59 | ISR(TIMER1_OVF_vect){ |
60 | overflows++; |
61 | }
|
EDIT2: Ich hab natürlich die Library von Harry auf 8-Zeilen-Modus gesetzt und den I2C-Bus auf 400 kHz eingestellt (I2C_HIGHSPEED definiert in der i2c_master.h).
:
Bearbeitet durch User
M. K. schrieb: > Du findest es jetzt also unschöner, dass die Suche&Auswahl des > Sonderzeichens nicht mehr in der putc() geschieht sondern > übersichtlicher in der Headerdatei, die auch den Font beinhaltet? > Interessant. Die Aussage ist schlicht und einfach falsch! In der .fnt-Datei befindet sich nur die Tabelle mit der Zuordnung. Die Funktion um den Index eines Zeichen innerhalb des Font zu ermitteln steht in lcd.c. M. K. schrieb: > Am Besten finde ich deine Kritik an der Wartbarkeit des Codes, und dann > lese ich z.B. bei dir solche Dinge: > ... > #ifdef __ARM_ARCH > ... > #endif > ... > #ifdef __ARM_ARCH > ... > #endif > ... Das ist geradezu lächerlich! Hättest du dir die Mühe gemacht, den Code zu verstehen würdst du hier nicht solche Pseudo-Argumente auffahren. M. K. schrieb: > Im TEXTMODE belegt deine Library mit der nachfolgenden Main 5118 Bytes > im Flash und es dauert 4.903ms bis die Zeile auf dem Display steht (kein > Overflow vom Timer und der Count steht bei 39227). > Meine Library belegt 4936 Bytes und sie braucht grade mal 4.399ms bis > der Text im Display steht (kein Overflow vom Timer und der Count steht > bei 35195) > > Im GRAPHICMODE belegt deine Library mit der nachfolgenden Main 6426 > Bytes im Flash und es dauert 28.177ms bis die Zeile auf dem Display > steht (3 Overflows vom Timer und der Count steht bei 28810). > Meine Library belegt 6138 Bytes und sie braucht grade mal 27.766ms bis > der Text im Display steht (3 Overflows vom Timer und der Count steht bei > 25517). > > Mit deiner Library braucht der Atmega 1. länger bis die Anzeige da ist > und 2. belegt sie mehr Flash-Speicher Jaja, wer misst, misst Mist! Das ganze inkl. main, startup und deinem Timer-Zeugs (für die Messung selbst) als Summe ist völlig nichts-sagend. Für meine Version hab ich valide Werte ermittelt: Beitrag "Re: Universelles Oled-Libary (SSD1306) für AVR(8bit) und STM32/HAL" Demnach brauch ich in der kleinsten Variante 1853 Byte Flash und 9 Byte RAM. Wenn du unbedingt vergleichen willst, dann bitte auch mit belastbaren Zahlen.
:
Bearbeitet durch User
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 ;)
:
Bearbeitet durch User
M. K. schrieb: > Harry L. schrieb: >> Das ganze inkl. main, startup und deinem Timer-Zeugs (für die Messung >> selbst) als Summe ist völlig nichts-sagend. > > Sorry, aber das zeigt eindeutig, dass du anscheinend absolut keine hast, > wie man Zeiten mit einem AVR misst. Und was hat das mit Zeiten zu tun? Dabei ging es um Code/RAM-Grösse. Wie ich meine Zeiten ermittelt hab, hab ich hier beschrieben: Beitrag "Re: Universelles Oled-Libary (SSD1306) für AVR(8bit) und STM32/HAL" M. K. schrieb: > Damit ich meine Library (i2c + lcd) mit deiner (ebenfalls i2c + lcd) > Vergleichen kann habe ich den selben Testcode verwendet, der Controller > war/ist exakt gleich eingestellt und dabei habe ich obige Werte schlicht > mit gemessen. Ich habe sogar zuvor mittels Portpin auch noch einen Puls > erzeugt (Pin setzen vor dem Beschreiben und löschen nach dem > Beschreiben) um sicher sein zu können, dass ich diesmal auch richtig > messe und der Puls hatte stets auch die Zeit, die ich gemessen habe. > Mein Test ist damit mehr als nur belastbar, er ist verifizierbar. Du wirfst wahllos Performace und Grösse durcheinander. Zur Laufzeit-Ermittlung: s.o. belastbar und valide ist anders. Tip: die tatsächliche Code-Grösse eines Object-File ermittelt man mit "size" https://linux.die.net/man/1/size
:
Bearbeitet durch User
Harry L. schrieb: > Und was hat das mit Zeiten zu tun? > Dabei ging es um Code/RAM-Grösse. 1. Wenn du nicht weißt wie man mit einem Timer auf dem AVR Zeiten misst halte ich es für sehr anmaßend, dass du die Ergebnisse anzweifelst 2. Es ging nicht nur um die Code-Größe sondern auch um die Zeiten. Um die RAM-Größe ging es bisher noch gar nicht. Harry L. schrieb: > Du wirfst wahllos Performace und Grösse durcheinander. > Zur Laufzeit-Ermittlung: s.o. > > belastbar und valide ist anders. Wo? Wo würfel ich das durcheinander? Nur weil dir das nicht passt? Dein Code kann gar nicht schneller sein als meiner. Und zwar ganz einfach weil ich ein Zeichen so übermittele
1 | i2c_start(LCD_ADRESSE); |
2 | i2c_byte(LCD_DATA_PREFIX); |
3 | for(uint8_t i; i<CHAR_FONT_SIZE;i++){ |
4 | i2c_byte(CHAR[pos_in_FONT][i]); |
5 | }
|
und du machst das so
1 | for(uint8_t i; i<CHAR_FONT_SIZE;i++){ |
2 | lcd_data(CHAR[pos_in_FONT][i]); |
3 | }
|
mit
1 | void lcd_data(uint8_t data){ |
2 | i2c_start(LCD_ADRESSE); |
3 | i2c_byte(LCD_DATA_PREFIX); |
4 | i2c_byte(data); |
Ich habs vereinfacht nur um was zu verdeutlichen: Ich sende die LCD-Adresse mit jedem Zeichen, die bei dir und mir aus 8 Bytes bestehen, lediglich ein mal. Das Gleiche gilt für das Kommando, dass dem LCD nun Daten übermittelt werden. Du sendest aber mit jedem Byte eines Zeichens die LCD-Adresse und das Kommando für Daten. Damit musst du 7*2 Bytes = 14 Bytes mehr als ich dem Display schicken mit jedem Zeichen, dass du darstellen willst. Und wenn wir beide das Display mit gleicher Geschwindigkeit betreiben musst du länger brauchen da du viel mehr Daten ans Display übermittelst als ich. Übrigens: Du hast immer noch nicht erklärt was du überhaupt an der lcd_putc-Funktion warten willst. Harry L. schrieb: > Tip: die tatsächliche Code-Grösse eines Object-File ermittelt man mit > "size" Beim avr-gcc Toolchain heist es avr-size. Und was meinst du wie ich die Größe ermittelt hatte? Kannst du in meinem Github nachlesen ;)
:
Bearbeitet durch User
M. K. schrieb: > Ich habs vereinfacht nur um was zu verdeutlichen: Ich sende die > LCD-Adresse mit jedem Zeichen, die bei dir und mir aus 8 Bytes bestehen, > lediglich ein mal. > Das Gleiche gilt für das Kommando, dass dem LCD nun Daten übermittelt > werden. > > Du sendest aber mit jedem Byte eines Zeichens die LCD-Adresse und das > Kommando für Daten. Damit musst du 7*2 Bytes = 14 Bytes mehr als ich dem > Display schicken mit jedem Zeichen, dass du darstellen willst. Du vergisst dabei, daß bei mir die 20 Zeichen (im Text-Mode) zentriert werden. D.h.: ich muß mindestens am Anfang jeder Zeile einmal den RAM-Cursor neu initialisieren. Das könnte man darauf beschränken, aber bläht imho den Code nur unnötig auf. Die paar µs durch das zusätzliche gotoxy kratzen mich nicht wirklich. 4,4ms/Zeile sind für mich ok, und weitere Optimierungen stehen imho in keinem sinnvollen Verhältnis zum Aufwand. M. K. schrieb: > Übrigens: Du hast immer noch nicht erklärt was du überhaupt an der > lcd_putc-Funktion warten willst. 2 nahezu identische Funktionen für putc für die Text- bzw. Graphic-Ausgabe ist alles Andere als wartungsfreundlich. Und solche Konstruktionen:
1 | uint8_t getCharPosition(char value){ |
2 | // getting chars position at font-array
|
3 | switch (value) { |
4 | case 'ü': |
5 | value = 95; // ü |
6 | break; |
7 | case 'Ü': |
8 | value = 96; // Ü |
9 | break; |
10 | case 'ä': |
11 | value = 97; // ä |
12 | break; |
13 | case 'Ä': |
14 | value = 98; // Ä |
15 | break; |
16 | ...
|
17 | ...
|
18 | ...
|
sind einfach nur übel!
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
Ich bin raus aus dieser Diskussion. Hab keine lust mehr, gegen Wände zu reden. Du mußt noch viel lernen!
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.
:
Bearbeitet durch User
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?
Ohne PullUps wird das nix... Wer misst, misst Mist
> 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!
Harry L. schrieb: > Und die gehören da auch nicht hin! Habe es mal auf chinesich übersetzt - für die Zielgruppe: 他们也不属于那里!
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.
Dann hast du 10k Ohm. Fuer die maximale Bitrate ist das zu viel.
Stefanus F. schrieb: > Dann hast du 10k Ohm. Fuer die maximale Bitrate ist das zu viel. Bei 3,3V... Bei 5V wären das sogar 15k.... https://www.nxp.com/docs/en/user-guide/UM10204.pdf
Die I²C Spezifikation alleine reicht so nicht. Man muss die Kapazitäten der Leitungen und Bauteile berücksichtigen.
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.
:
Bearbeitet durch User
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. Auch mit 0x78 bleibt es dunkel.
OLEDer schrieb: > Allerdings steht in der "lcd.h" 0x7A nicht 0x78, kann das der Fehler > sein? > Gleich mal ausprobieren. Für unmodifizierte Displays muß die Adresse 0x78 sein 0x78 = 0x3c << 1 Bit 0 ist für R/W zuständig. Die I²C-Adresse steht in den oberen 7bit.
:
Bearbeitet durch User
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.
Setze den
1 | #define PSC_I2C 1 // prescaler i2c
|
mal auf 2. So wird der Wert für TWBR zu groß - bzw. nach Zuweisung unpassend (das sollte im Header mit einer Meldung bedacht werden ... - nur so, als Anregung :-) )
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.
Die Lösung ist, statt der Umlaute im Source die numerischen Konstanten zu nutzen. Also z.B. statt 'ä' '\x84'
:
Bearbeitet durch User
Harry L. schrieb: > Also z.B. statt 'ä' '\x84' Das wäre allerdings nicht ISO8859-1[5]. Dort liegen die Umlaute wie folgt:
1 | $ echo -n 'äöüÄÖÜß' | iconv -f utf-8 -t iso8859-1 | hd |
2 | 00000000 e4 f6 fc c4 d6 dc df |.......| |
3 | 00000007 |
:
Bearbeitet durch Moderator
Jörg W. schrieb: > Harry L. schrieb: >> Also z.B. statt 'ä' '\x84' > > Das wäre allerdings nicht ISO8859-1[5]. > > Dort liegen die Umlaute wie folgt: > >
1 | > $ echo -n 'äöüÄÖÜß' | iconv -f utf-8 -t iso8859-1 | hd |
2 | > 00000000 e4 f6 fc c4 d6 dc df |.......| |
3 | > 00000007 |
4 | > |
"welchen" 8Bit-Zeichensatz man nutzt, ist dabei doch vollkommen egal. So lange man im Source numerische Konstanten für die Sonderzeichen nutzt ist das eindeutig, und der Compiler hat nix zu meckern. .
:
Bearbeitet durch User
OLEDer schrieb: > Da steht nur drin, was ich ändern muss, aber nicht der Befehl dafür. Richtig, aber ich dachte auch, dass das eindeutig ist. So wie z.B. ein "make all" das entsprechende Programm samt EEPROM-File und Co erzeugt. OLEDer schrieb: > Dann müsste der Link im ersten Post korrigiert werden, denn der verweißt > noch auf die ältere Version. Öhm, nö. Nicht den Dateianhang laden sondern dem Link im ersten Post folgen, der führt dich zur aktuellen Version der Lib M. K. schrieb: >> Edit: Github link https://github.com/Sylaina/oled-display.git Harry L. schrieb: > So lange man im Source numerische Konstanten für die Sonderzeichen nutzt > ist das eindeutig, und der Compiler hat nix zu meckern. Das ist zwar richtig aber später in der main wird wohl kaum einer auf die Idee kommen, statt z.B. 'ä' ein '0x84' zu schreiben und schon wirds wieder wichtig, was der Editor/Compiler benutzt. Wenn der nämlich ein Charset benutzt, bei dem ein 'ä' z.B. nicht bei '0x84' steht sondern bei z.B. '0xe4' (da stehts bei ISO 8859-1, unserem typischen Latin-1) bekommt man wieder nicht das, was man eigentlich will.
M. K. schrieb: > Harry L. schrieb: >> So lange man im Source numerische Konstanten für die Sonderzeichen nutzt >> ist das eindeutig, und der Compiler hat nix zu meckern. > > Das ist zwar richtig aber später in der main wird wohl kaum einer auf > die Idee kommen, statt z.B. 'ä' ein '0x84' zu schreiben und schon wirds > wieder wichtig, was der Editor/Compiler benutzt. Wenn der nämlich ein > Charset benutzt, bei dem ein 'ä' z.B. nicht bei '0x84' steht sondern bei > z.B. '0xe4' (da stehts bei ISO 8859-1, unserem typischen Latin-1) > bekommt man wieder nicht das, was man eigentlich will. Das Kunststück,das für alle denkbaren IDE/Editoren/OS hinzubekommen will ich sehen!
:
Bearbeitet durch User
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.
:
Bearbeitet durch User
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.
:
Bearbeitet durch User
M. K. schrieb: > Das ist zwar richtig aber später in der main wird wohl kaum einer auf > die Idee kommen, statt z.B. 'ä' ein '0x84' zu schreiben Ich habe mir dann immer mit sowas beholfen:
1 | #define sz "\xdf"
|
2 | #define ae "\xe4"
|
3 | |
4 | ...
|
5 | printf("Damit geht das verl"ae sz"lich"); |
Harry L. schrieb: > Hab keinerlei Lust, hier ein weiteres Faß auf zu machen. Fein, wir haben vom letzten noch genug. :/ OLEDer schrieb: > Zu den Umlauten: > > Ich hätte jetzt gedacht, das Atmel Studio so etwas hin bekommt. Offensichtlich haben sie bei Atmel/Microchip nicht dran gedacht, ein iconv-Binary mitzuliefern. Mach doch bei ihnen einfach mal einen Bugreport auf.
:
Bearbeitet durch Moderator
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"ae sz"lich"); |
ist bei weitem nicht so leicht zu lesen wie ein
1 | printf("Damit geht das verläßlich"); |
Harry L. schrieb: > Mich mit dem Compiler über den verwendeten Zeichensatz herum zu streiten > wiederstrebt mir zu tiefst. Was hat das mit herumstreiten zu tun. Das sind stink normale Einstellparameter. Wenn man so Sachen wie delay_ms verwendet muss man dem Compiler ja auch die korrekte Taktfrequenz des µCs mitteilen. Da kann man im makefile, das man ja eigentlich auch beim Code mitliefert, auch direkt die flags für die entsprechenden Charsets setzen. Harry L. schrieb: > Der Code sollte auf jedem System mit jeder Codepage zum selben Ergebnis > führen. Das kann schon per Definition nicht funktionieren da es unterschiedliche Charsets ad absurdum führen würde. Latin-1 und DOS-Latin-1 z.B. klingen ähnlich und haben Umlaute und Co doch nicht an den gleichen Stellen stehen. Zwei Charsets, die insbesondere beim extenden Set definitiv zu unterschiedlichen Ergebnissen kommen.
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.