12 zeigt mir auch im SerialMonitor an.
Ich schick die Daten über RS485, nur so am rande.
#include "lcd.h"
void setup(){
Serial.begin( 19200 );
pinMode(23,OUTPUT); digitalWrite(23,1);
lcd_init(LCD_DISP_ON); // init lcd and turn on
lcd_puts("Hello World"); // put string from RAM to display (TEXTMODE)
or buffer (GRAPHICMODE)
lcd_gotoxy(0,2); // set cursor to first column at line 3
lcd_puts_p(PSTR("String from flash")); // puts string form flash to
display (TEXTMODE) or buffer (GRAPHICMODE)
I2C_ErrorCode=12;
Serial.print(I2C_ErrorCode);
Serial.write("\r\n"); // Zeilenumbruch fuer die Anzeige
}
void loop(){
Serial.print(I2C_ErrorCode);
Serial.write("\r\n"); // Zeilenumbruch fuer die Anzeige
delay(5000);
}
Dann bin ich leider überfragt. Wenn der Errorcode 0 bleibt (ist bei dir
ja anscheinend so) und der setup() auch ausgeführt wird (was ja durch
die 12 bestätigt ist) dann hat die Kommunikation mit dem Display
funktioniert und du müsstest eigentlich was angezeigt bekommen.
Arduino hat kein Atmega324PA, ich verwende aber die Arduino IDE.
So sieht die i2c.h aus:
/* TODO: setup i2c/twi */
#define F_I2C 100000UL// clock i2c
#define PSC_I2C 1 // prescaler i2c
#define SET_TWBR (F_CPU/F_I2C-16UL)/(PSC_I2C*2UL)
Im Anhang hab ich die ohne deiner i2c.h probiert, dafür dann mit Wire.h
von Arduino. Allerdings sind da noch punkte rechts neben dem Text.
Fuses sollten ja passen, 16 Mhz Quarz.
EDIT:
Jetzt bekomme ich Error 5, keine ahnung was ich geändert hab.
ErrorCode 5 bedeutet schon mal, dass der Start fehlgeschlagen ist,
sprich die Kommunikation mit dem I2C hat nicht geklappt (dafür steht das
erste Bit im ErrorCode). Die 4 steht dafür, dass das Übertragen des
Bytes nicht geklappt hat (ist das dritte Bit in ErrorCode, vgl. auch
i2c.h).
Ich hab grade aus meinem github noch mal die Library herunter geladen
weil ich dachte, ich hab vielleicht noch nen Fehler drin, und sie
einfach Übersetzen lassen und hoch geladen auf einen Atmega328pn (make
flash). Das hat sofort fehlerfrei geklappt. Umgestellt auf Textmode mit
dem Ergebnis auch das klappt auf Anhieb. Die Library ist in C
geschrieben, ich weis leider nicht ob man C++ noch irgendwie sagen muss,
dass es eine C Library ist. Ich denke aber, der Fehler liegt nicht in
der Library sondern wie sie eingebunden wird. Weis z.B. auch der Linker
was er damit machen soll, welches Encoding er benutzen soll usw.?
Stefan U. schrieb:> Theoretisch müsste es aber auch mit deinem AVR funktionieren.
Es funktioniert auch, auf den Pins D4 und D5.
Also ist es eine SoftI2C-OLED-Lib
Ja, ich habe mich für das soft-I²C entschieden, um beliebige Pins
verwenden zu können. Beim ESP8266 (für den ich das geschrieben hatte)
gibt es ohnehin keinen freien I²C in Hardware.
So, ich bin nun noch mal dazu gekommen das Ganze mit Arduino zu testen
und es funktioniert problemlos. Die Libraries (aus dem Github geladen)
für das LCD und I2C habe ich in den Projektordner kopiert.
1
extern"C"{
2
#include"lcd.h"
3
}
4
5
voidsetup(){
6
// put your setup code here, to run once:
7
lcd_init(LCD_DISP_ON);// init lcd and turn on
8
9
lcd_puts("Hello World");// put string from RAM to display (TEXTMODE) or buffer (GRAPHICMODE)
10
lcd_gotoxy(0,2);// set cursor to first column at line 3
11
lcd_puts_p(PSTR("String from flash"));// puts string form flash to display (TEXTMODE) or buffer (GRAPHICMODE)
12
#if defined GRAPHICMODE
13
lcd_drawCircle(64,32,7,WHITE);// draw circle to buffer white lines
14
lcd_display();// send buffer to display
15
#endif
16
}
17
18
voidloop(){
19
// put your main code here, to run repeatedly:
20
21
}
Der Sketch belegt 2344 Bytes (GRAPHICMODE, als Vergleich: der gleiche
Code nur in C wie im github-Beispiel belegt lediglich 1884 Bytes).
Wichtig ist, dass man
1
extern"C"{
2
#include"lcd.h"
3
}
schreibt. Schreibt man
1
#include"lcd.h"
meckert u.a. der Linker, dass er die jeweiligen Referenzen auf die
einzelnen Funktionen (z.B. lcd_init()) nicht auflösen kann.
Ein weiteres Manko ist, dass man dem Compiler/Linker auch noch irgendwie
beibringen muss, welchen Charset er für die Quellcode-Dateien verwenden
soll. Es wird nämlich beim ersten Compilieren u.a. vor den Umlauten
(ä,ö,ü usw.) gewarnt, diese sind auch nicht verarbeitet, d.h. versucht
man z.B. ein ä aufs Display zu bringen erscheint schlicht nichts. In
meinem Makefile steht deshalb
Ich hab noch einige andere Librarys getestet, bei den wird maximal 4%
RAM belegt.
Bei deiner werden 50% fürs Hello World benötigt, das ist ein Grund warum
ich mich noch nicht für deine Lib sicher entscheiden kann.
Kannst du da noch was machen?
main.c funktioniert in der Arduino IDE natürlich auch.
J. W. schrieb:> Ich hab noch einige andere Librarys getestet, bei den wird maximal 4%> RAM belegt.> Bei deiner werden 50% fürs Hello World benötigt, das ist ein Grund warum> ich mich noch nicht für deine Lib sicher entscheiden kann.
Du kannst meine Libary auch auf Textmodus umstellen (siehe lcd.h) wenn
du nur Text ausgeben möchtest aber nicht Zeichnen willst. Dann benötigt
sie auch nicht so viel RAM (grade mal 2 Byte wenn ich das noch recht in
Erinnerung habe). Im Grafik-Modus benötigt sie die Display-Größe als
Speicher im RAM da ja via I2C der SSD1306/SH1106 nicht ausgelesen werden
kann was dann aber schon beim Zeichnen eines Diagrams recht schwierig
bis unmöglich wird.
Ich nehme mal an die Library, die du jetzt benutzt, läuft auch nur im
Textmodus. Zumindest ist mir kein Lib bekannt, die bei diesen
Controllern im Grafikmodus keinen RAM in Größe des Displays als Puffer
vorhalten. Daher hatte ich diese Lib ja geschrieben da ich so ein
Display an einem Atmega 8 einsetzen wollte zur Textanzeige aber das mit
den Libs, die ich damals fand, nicht ging wegen des Puffers. ;)
Prinzipiell kann man Grafik auch ohne Pufferspeicher ausgeben. Aber man
muss immer 8 Bits (vertikal untereinander) gleichzeitig schreiben.
Wenn ich nun z.B. ganz oben eine horizontale Linie zeichnen will, und
dann 4 Pixel Tiefer noch eine, wird es kompliziert. Beim Zeichnen der
zweiten Linie muss ich zwangsläufig die Bits der ersten Linie
überschreiben.
Damit dabei die erste Linie nicht verloren geht, müsste ich den Speicher
lesen können, das geht bei I²C aber nicht.
Unterm Strich bedeutet das, man kann immer nur 8 Pixel-Reihen am Stück
beschreiben. Text und Bitmaps kann man auf diese Weise problemlos im
8-Linien Raster ausgeben, aber das Zeichnen von geometrischen Figuren
wird ohne Pufferspeicher extrem kompliziert.
Stefan U. schrieb:> Text und Bitmaps kann man auf diese Weise problemlos im> 8-Linien Raster ausgeben, aber das Zeichnen von geometrischen Figuren> wird ohne Pufferspeicher extrem kompliziert.
Deswegen schrieb ich oben schwierig bis unmöglich: Text& Bitmaps gehen
noch ohne Pufferspeicher (wobei ich grade die Bitmap-Funktion mit
Pufferspeicher implementiert habe ;)) aber beliebige, geometrische
Figuren bzw. beliebige Graphen gehen ohne Pufferspeicher schlicht nicht.
Habe so ein OLED, in weiß. Damals gabs da keine Auswahl und die waren
ohne Versandkosten.
https://de.aliexpress.com/item/-/32717936245.html
Die Lib grad neu geladen.
I2C Scanner sagt dass es die 3C Adresse ist, mit anderen Libs läufts
auch, Verkabelung muss dann ja auch passen.
1
/* TODO: define displaycontroller */
2
#define SSD1306 // or SSD1306, check datasheet of your display
3
/* TODO: define displaymode */
4
#define GRAPHICMODE // TEXTMODE for only text to display,
5
// GRAPHICMODE for text and graphic
6
7
#define LCD_I2C_ADR 0x3C
1
extern"C"{
2
#include"lcd.h"
3
}
4
5
voidsetup(){
6
lcd_init(LCD_DISP_ON);// init lcd and turn on
7
lcd_puts("Hello Wuüorld");// put string from RAM to display (TEXTMODE)
8
lcd_gotoxy(0,2);// set cursor to first column at line 3
9
lcd_puts_p(PSTR("String from flash"));// puts string form flash to
10
}
11
voidloop(){}
Und das Display bleibt immer noch schwarz.
Hab jetzt den Arduino UNO, mit USBasp programmiert.
Hast du das Display umkonfiguriert? Das wird default-mäßig als
SPI-Display ausgeliefert, so les ich das oben nämlich, sie Anleitung
dazu.
Wenn du es als I2C schon umgelötet hast: Kannst du mal dein Arduino
Projektordner für das Display mit dem kompletten Code zippen und hier
einem Beitrag anhängen? Ich kann hier nämlich absolut keinen Fehler
feststellen, auch mit der Arduino IDE. Ich habs jetzt mit verschiedenen
SSD1306 und SH1106 Display getestet, die laufen alle perfekt an.
Wo wie was konfigurieren? Das Display ist ein I2C, wie auf den Bildern
mit SDA, SCL, VCC und GND. Da muss man nix mehr löten.
Läuft ja mit anderen I2C Libs.
Habs mir runtergeladen und compiliert bzw. versucht, Arduino IDE meldet
sofort beim Übersetzen den folgenden Fehler:
/Users/michael/Downloads/oled-display-master-2/examples/oled-display/ole
d-display.ino:2:19: fatal error: lcd.h: No such file or directory
#include "lcd.h"
Das liegt daran, dass die Library einige Dateiebenen höher liegt, durch
das
1
extern"C"{
2
#include"lcd.h"
3
}
wird aber erwartet, dass die Library in der selben Dateiebenen liegt wie
die .ino. Ich hab die Library (lcd.h, lcd.c, i2c.h und i2c.c) einfach
mal ins Verzeichnis der .ino kopiert und schon wirds fehlerfrei
übersetzt und das Display zeigt auch was an ;)
Wie gesagt, ich kann den Fehler hier nicht reproduzieren. Weder als
lokale Library (vgl. Dateianhang) noch als globale Library, bei mir
läuft das stets problemlos an. OK, ich hab noch nicht geschaut wie man
in der Arduino IDE dem Compiler sagen kann, dass er das charset
iso-8859-15 bei den Dateien verwenden soll (ist für all die tollen,
deutschen, Sonderzeichen wie ä,ö,ü usw.) aber sonst: fehlerfrei.
Bei mir ist GND links (aussen), bei deinem ist VCC aussen.
Ist also schon mal ein anderes Display.
Ist mir nur aufgefallen, vielleicht hats ja nichts zu bedeuten.
Alle anderen Libs funktionieren, hab einige getestet
https://forum.arduino.cc/index.php?topic=529600.msg3610291#msg3610291
J. W. schrieb:> Habe so ein OLED, in weiß. Damals gabs da keine Auswahl und die> waren ohne Versandkosten.> https://de.aliexpress.com/item/-/32717936245.html
Auf dem Bild sieht man R3/4 als 0R Widerstände, damit kann man eventuell
SPI/I2C oder die I2C Adresse umstellen.
Das hatte ich ja weiter oben schon mal angefragt ob das Display in I2C
konfiguriert ist oder auf SPI. Anscheinend ist es auf die I2C
konfiguriert wenn die anderen Libraries funktionieren. Daher denke ich
auch das ist kein Problem mit dem Wirering ist.
Naja, bei mir lässt sich der Code problemlos übersetzen und das Display
läuft problemlos. Vielleicht versuchst du mal als Adresse die 0x78 oder
die 0x7A ggf. ist deine ermittelte Adresse nicht richtig.
Unfassbar. Problem gelöst. Wieso kommst auch nicht früher mit der
Adresse 0x78? :D
Die Frage bleibt jetzt aber, warum es bei anderen mit 0x3C läuft und mit
deiner mit 0x78.
Jetzt weiß ich auch was ihr mit konfigurieren meint.
Hab das SPI Display ausgepackt und die Widerstände angeschaut, R3 und R4
sind gelötet. Bei dem I2C Display sind R1, R4 und R8 gelötet.
Mal davon abgesehen dass die Platinen verschieden sind und bei SPI
Version noch RES, DC und CS Pins vorhanden sind.
Habs mal auf I2C umgelötet, also R1, R4 und R8 gebrückt, I2C Scanner
erkennt den nicht.
Johannes S. schrieb:> Das Problem ist so alt wie I2C selbst, schiebe mal 0x78 um ein Bit nach> rechts.> Beitrag "Re: Kann mir bitte wer beim USI-TWI helfen?"
Das ist ein interessanter Beitrag, das war mir so auch nicht bewusst.
Ich hab die lcd.h an der Stelle, an der die Adresse angegeben wird,
entsprechend mit einem Kommentar versehen.
Die Displays, die ich hier hab, haben halt alle die Adresse nach dem
Slave-Mode angegeben.
Je nach Lib ist das halt ein wenig unterschiedlich.
Die Adresse wird um 1 nach links geschoben. Im ersten Bit steht dann bei
der Übermittlung der Adresse, ob gelesen oder geschrieben werden soll.
Richtig, bei der Adresse erwartet meine Library die 8-Bit Adresse. Da
das SSD1306 bzw das SH1106 bei I2C nicht gelesen werden kann macht es
keinen Sinn hier die 7-Bit Adresse anzugeben sodass die Library selbst
zwischen Lesen und Schreiben wählen könnte. Wie gesagt, diese
Information habe ich heute Morgen dem Quellcode als Comment hinzugefügt
;)
Hallo und vorab eine echt gute Library!
Eine Frage. Gibt es eine Option das man den Text z.b. Zentrieren kann?
Ich muss mich nun erstmal damit auseinander setzen :) vielen Dank für
eine Info schon mal ob es schon vielleicht möglich ist.
Verwende im übrigen ein SD1306
Gruß Sebastian
Hi M. Köhler
Erstmal danke für die Library.
Leider funktioniert bei mir gar nichts.
Ich verwende ein 128x32 OLED mit SSD1306. Dieses steuere ich mit einem
ATmega 644p mit 20MHz an.
Ich habe deinen Code von GitHub heruntergeladen und die nötigen
Anpassungen vorgenommen(angehängt) und eine Codezeile hinzugefügt:
Es zeigt mir nichts am OLED an. Ich nehme an ich habe die Hardware
richtig verdrahtet.
SDL von Atmega->SCK des OLED mit 4.7kOhm Pull-Up
SDA von Atmega->SDA des OLED mit 4.7kOhm Pull-Up
VCC->5V
Kannst du mit weiterhlefen?
EDIT: habe ausversehen zweimal das gleiche Bild angehängt
Mit freundlichen Grüssen
Fabian
Packe mal dein Projekt in ein ZIP-File und lade es hier hoch, dann schau
ich es mir heute Abend an, vorher komme ich leider nicht dazu da ich
grade unterwegs bin.
Schließe mal LEDs (mit 2,2k oder 4,7k) Vorwiderstand parallel zu den
Pull-up Widerständen an und schaue, ob sie beide flackern.
Am besten kann man was sehen, wenn man die Übertragung erheblich
verlangsamt.
Hast du einen Logic Analyzer? Falls nicht wäre jetzt der richtige
Moment, sich einen anzuschaffen. Zur Analyse von I²C Problemen sind die
Dinger Top und kosten nicht mehr als 15 Euro.
Vielen Dank für die schnellen Antworten.
Ich habe mein Programm angehängt.
Wir haben, glaube ich, irgendwo noch so ein Logic Analyzer. Mal schauen,
ob ich mit diesem etwas herausfinde.
Aber ich glaube das Problem ist, dass er gar nicht zum senden kommt.
Mit freundlichen Grüssen
Fabian
> Aber ich glaube das Problem ist, dass er gar nicht zum senden kommt.
Glauben ist nicht Wissen. Die Aussage ist nicht dumm, aber sie sollte
überprüft werden. Deswegen ja mein Vorschlag mit den LEDs.
Mit einem Debugger kannst du herausfinden, ob und wo das Programm hängt.
Hast du das wenigstens gemacht?
Fabian G. schrieb:> Vielen Dank für die schnellen Antworten.>> Ich habe mein Programm angehängt.> Wir haben, glaube ich, irgendwo noch so ein Logic Analyzer. Mal schauen,> ob ich mit diesem etwas herausfinde.> Aber ich glaube das Problem ist, dass er gar nicht zum senden kommt.>> Mit freundlichen Grüssen> Fabian
Ich hab mir den Code angeschaut und das sieht alles soweit OK aus.
Es fällt zunächst mal auf, dass du noch eine ältere Version der Lib
benutzt. Dennoch sollte auch diese laufen.
Die Adresse des Displays ist im 7-Bit-Mode angegeben, hast du auch mal
versucht die Adresse im 8-Bit-Mode anzugeben (also statt 0x3c 0x78
angeben? Und ist die Adresse auch sicher die richtige?
Und zu guter letzt: Läuft dein uC auch wirklich mit 20 MHz? Fuses alle
richtig gesetzt? In meiner Anfangszeit hab ich z.B. gerne vergessen die
DIV8-Fuse auszumachen => Hello World der uCs mal programmieren und
Zeiten kontrollieren
So habe nun die Fehler gefunden.
Einerseits musste ich die com Ports anpassen und die Adresse, wie du
geschrieben hast, im 8-Bit modus angeben.
Kann ich mit deiner Bibliothek die Schriftgrösse ändern? Wenn ja, wie?
Mit freundlichen Grüssen und ein schönes Wochenende
Fabian
Nein, die Schriftgröße ist damit nicht anpassbar. Die aktuelle Version
ist in der Lage Bitmaps zu zeichnen, damit könnte man sich auch andere
Schriftgrößen generieren.
Und diese Bitmaps benötigen viel Speicherplatz/Arbeitsspeicher?
Wie viele kann ich davon zeichnen?
Ist es möglich diese Bitmaps in schneller Abfolge nacheinander
auszugeben?
EDIT: Habe noch eine zusätzliche Frage
Du verwendest einen TIMER für den Serial Clock, sehe ich das richtig?
Für was brauchst du den TIMER_COUNTER?
1
ISR(TIMER_INT_vec){
2
TIMER_COUNTER=0;
3
LCD_PORT^=(1<<SDC_Pin);
4
}
Kommt in der Regel ein I2C-Programm nicht ohne zusätzliches Timer aus?
Dachte der Mikrocontroller generiert diesen Serial Clock selber, ohne
Timer.
Nein, ich verwende keinen Timer. Wie schon gesagt, du benutzt noch eine
sehr alte Version der Library. Der Timer war einst gedacht für
Software-I2C, das hab ich aber nie weiter entwickelt, war eine Spinnerei
aus den Anfangstagen der Lib.
Zu den Bitmaps: Meine Library kann Bitmaps zeichnen, sie beinhaltet aber
keine, die musst du selbst erstellen oder dir entsprechend besorgen aus
dem Internet. Wie schnell sie Bitmaps hintereinander zeichnen kann hängt
von der Größe der Bitmaps ab und der eingestellten
Kommunikationsgeschwindigkeit. 10 Pixel sind halt schneller gezeichnet
als 100 Pixel bei gleicher Kommunikationsgeschwindigkeit.
Ja, auf Github, Link ist im Eröffnungspost ;)
Da gibts einige Änderungen inzwischen, z.B. sind die I2C-Funktionen in
einer eigenen Lib ausgelagert worden sodass man auch eigenen
I2C-Funktionen nutzen kann ;)
Guten Abend!
Eine schöne Lib, wo hast du die nötigen Informationen her ? Die
Informationslage zu den SSD13XX Chips ist ja recht dünn gesäht...
Ist irgendwas zum Aufbau des SSD1315 im Vergleich zum SSD1306 bekannt ?
Kann man den mit der 1306er Lib ansteuern ? Zum SSD1315er gibts leider
iwie gar nichts zu finden...
Viele Grüße
> Die Informationslage zu den SSD13XX Chips ist ja recht dünn gesäht...
Eigentlich steht im Datenblatt des SSD1306 alles drin, was man für
diesen Chip wissen muss. Funktionierende Code-Beispiele helfen dabei, es
zu verstehen.
Bezüglich des SSD1315 würde ich also ebenfalls zuerst mal das Datenblatt
suchen, wenn ich Fragen dazu hätte.
Marius K. schrieb:> Eine schöne Lib, wo hast du die nötigen Informationen her ?
Aus dem Datenblatt. Da stehen neben den elektrischen/mechnischen Daten
auch alle Befehle drin und, je nach Datenblatt, auch die ganzen Routinen
zum Initialisieren usw.
"Bezüglich des SSD1315 würde ich also ebenfalls zuerst mal das
Datenblatt
suchen, wenn..."
Ich meinte mit dünner Informationslage, dass Google kein Datenblatt des
SSD1315 bekannt zu sein scheint...
Ich hab das Teil mal probehalber an einen Pi angeschlossen und die
Adafruit Bib für SSD1306 getestet. Es scheint zu funktionieren, das
würde bedeuten ein 1315 ist softwareseitig kompatibel zu einem 1306...
Viele Grüße
> SSD1306 hast Du gelesen?
Ja, und eine Implementierung danach veröffentlicht. Aber ich will sie
niemandem aufdrängen, danach hat ja auch gerade keiner gefragt.
Stefanus F. schrieb:> Aber ich will sie> niemandem aufdrängen, danach hat ja auch gerade keiner gefragt.
Ich habe nach dem Vergleich zum 1315 gefragt ...
> Ich habe nach dem Vergleich zum 1315 gefragt ...
Nein, du hast gefragt, ob ich das Datenblatt von SSD1306 gelesen habe.
Abgesehen davon, wie soll ich die Datenblätter miteinander vergleichen?
Wir sich doch immer noch auf der Suche nach dem Datenblatt des SSD1315!
Das ist doch gerade das Thema dieses Threads. Jemand sucht das
Datenblatt vom SSD1315 weil er es mit dem SSD1306 vergleichen will. Du
hast ein paar nicht hilfreiche Links gepostet und forderst nun mich (ich
war übrigens nicht der suchende) auf, die Datenblätter zu vergleichen.
Wo ist da die Logik?
Stefanus F. schrieb:> Wo ist da die Logik?
Frag dazu bitte den Marius K. (zephram).
Auch ich habe keine Lust irgendetwas für ihn zu Suchen oder zu
Vergleichen.
Jungs, immer mit der Ruhe, war doch nur die Frage ob wer das Datenblatt
für den 1315er rumfliegen hat, dann hätte ich mal versucht die 1306er
Lib anzupassen, was aber ja eh, wie gesagt, unnötig erscheint, weil der
1315 funzt ja mit der 1306er Lib ^^\
Viele Grüße
Marius K. schrieb:> unnötig erscheint, weil der> 1315 funzt ja mit der 1306er Lib ^^
Ja, scheint mir auch so. Es gibt einige Varianten 13xx lt.
Datenblättern, welche aber wohl nur "Ausstattungsvarianten" sind. Ich
habe noch etwas rumgeschaut, bin aber auch nicht schlauer geworden.
Würde es mit dem 1306-Code versuchen - falls nicht O.K.den "Pseudo
1351-Code" (ohne den verglichen zu haben, da für mich nicht relevant -
bisher).
Ich vermute, das es sich sowieso nur um Ausstattungsvarianten handelt -
weiß es aber ehrlich gesagt nicht.
"Ich vermute, das es sich sowieso nur um Ausstattungsvarianten handelt"
Seh ich auch so ^^ Auf dem Foto wird das Teil von einer kleinen App auf
node.js mittels dem Paket oled-js-pi angesteuert die auf nem Pi Zero W
läuft. Diese Lib ist ebenfalls für 1306er...
Viele Grüße
Ich würde die Library gerne in einem GPLv2-only-Projekt verwenden. Der
Code auf github ist jedoch als GPLv3 ausgewiesen, so dass hier
inkompatible Lizenzen zusammen kommen.
Ist es vielleicht möglich, diese Library auch unter GPL2 zu
veröffentlichen?
Hallo zusammen,
ich hoffe einer von denjenigen bei denen das Display SSD1306 schon läuft
ist so nett und hilft mir ein wenig auf die Sprünge.
Ich würde das Display auch gerne in mein Projekt einbauen.
Mir ist klar, wie ich die Displaymatrix berechne. Nur wie ich dem
Display das mitteile (Befehle/Daten) ist mir nicht ganz ersichtlich aus
dem Datenblatt.
Da steht viel drinnen. Aber wo nur steht was ich brauche? ;)
I2C Grundaufbau ist eigentlich klar.
Hier mal meine Ansätze wie ich folgende Grundfunktionen aufbauen würde.
So gehts wohl nicht, das hab ich gemerkt :(
Display einschalten:
1
start condition //I2C starten
2
0x78 // Display addresse + last bit (0) is write mode /(1) is read mode
3
ACK
4
0x40 // Befehl folgt
5
ACK
6
0xAF // Display einschalten
7
ACK
8
stop condition // I2C stop
Display ausschalten:
1
start condition //I2C starten
2
0x78 // Display addresse + last bit (0) is write mode /(1) is read mode
3
ACK
4
0x40 // Befehl folgt
5
ACK
6
0xAE // Display ausschalten
7
ACK
8
stop condition // I2C stop
Display alles löschen (alle Bytes auf 0x00):
1
start condition //I2C starten
2
0x78 // Display addresse // last bit (0) is write mode //(1) is read mode
3
ACK
4
0x40 // Befehl folgt
5
ACK
6
0x?? // Display clear
7
ACK
8
stop condition // I2C stop
Display page (Daten) setzen:
1
start condition //I2C starten
2
0x78 // Display addresse // last bit (0) is write mode //(1) is read mode
3
ACK
4
0x40 // Befehl folgt
5
ACK
6
0xB0 // Setze Page 0 0xB0-B7 für page 0-7
7
ACK
8
0xD3 // Setze Display offset
9
ACK
10
0x05 // 0x00 - 0x7F Für Spaltenoffset 0-127
11
ACK
12
0x00 // Sende folgende Daten
13
ACK
14
0xFF // Daten 0xFF zum ersten Byte
15
ACK
16
0xFF // Daten 0xFF zum zweiten Byte
17
ACK
18
... Wiederholung der Datenbytes bis alle Informationen übertragen sind
19
ACK
20
stop condition // I2C stop
Wo hab ich da Fehler eingebaut?
Wie müsste man diese Grundfunktionen richtig implementieren?
Wäre super wenn mir jemand weiterhelfen würde.
Vielen lieben Dank im Vorraus
Liebe Grüße
Max
Bei mir sind die Sequenzen etwas länger, kannst du gerne hier abgucken:
http://stefanfrings.de/esp8266/WIFI-Kit-8-Test2.zip
Ich habe das aus mehreren Libraries und Infos aus dem Datenblatt
zusammen gewürfelt, weil es bei mir zuerst auch nicht richtig
funktionierte. Mit dem jetzigen Stand habe ich allerdings nun ein gutes
Gefühl.
Du darfst meinen Code frei ohne Lizenz-Beschränkungen nutzen. Das
Einzige, was darin wirklich (fast*) 1:1 kopiert wurde, ist der
Zeichensatz. Und der war vom ursprünglichen Autor als "Freeware"
freigegeben.
*) ich habe deutsche Umlaute hinzugefügt.
Hi,
wow die Antwort kam ja fix.
OK ich hab gesehen da sind viele Unterschiede
command bei dir 0x00; bei mir 0x40
write byte 0, bei mir 1....
alleine in der init schon
und viele andere Dinge gesetzt die ich nicht berücksichtigt habe.
wie: Multiplex ratio etc hab ich gar nicht vorgesehen gehabt.
Vielen Dank dafür.
Ich werd mal versuchen deine .cpp in .c umzubauen.
Ich brauche das in klasischem c.
Hoffe dann klappt das.
Braucht man wirklich all diese zusätzlichen Infos?
Oder kennt da jemand nocht nen einfachen Basis Ansteuerungssatz?
Gruß
Max
> Ich werd mal versuchen deine .cpp in .c umzubauen.> Ich brauche das in klasischem c.> Hoffe dann klappt das.
Das wird Dir ganz sicher problemlos gelingen. Mein Code enthält keine
komplizierte Tricks. Von C++ habe ich auch nur einen Bruchteil der
möglichen Sprache-Konstrukte genutzt.
Hallo Stefanus,
ja ich bin es gerade durchgegangen.
Das sieht alles logisch aufgebaut aus.
Und auch schön Kommentiert. Daumen hoch
Danke nochmal für die schnelle Hilfe.
Die Bytefolgen kann man da schön rausziehen.
Auch hast du Commands und Daten immer getrennt in I2C gesendet, nicht in
ein ewig Telegramm vermischt. Hätte mir dann wohl auch Probleme dabei
gegeben wenn ich alles auf einmal gesendet hätte.
Gruß
Max
Man kann Kommandos und Daten auch an einem Stück hintereinander senden.
Ich wollte den Code aber lieber übersichtlich halten, anstatt die
letzten Mikrosekunden Performance heraus zu quetschen.
Wenn der Grafikmodus (lcd.h) eingestellt ist, muß zwingend eine Grafik
dargestellt werden. Auch wenn es nur ein winziger Kreis in einer Ecke
ist. Ansonsten wird bei mir kein Text dargestellt. Ist das so gewollt?
Reinhard O. schrieb:> Wenn der Grafikmodus (lcd.h) eingestellt ist, muß zwingend eine Grafik> dargestellt werden. Auch wenn es nur ein winziger Kreis in einer Ecke> ist. Ansonsten wird bei mir kein Text dargestellt. Ist das so gewollt?
Öhm, das kann sein. Im Grafikmode ist auch der Text einfach nur Grafik.
Egal ob es Grafik oder Text ist, ein lcd_display() muss im Grafikmode
immer gesendet werden um die Anzeige zu aktualisieren. Schau mal ob du
nicht zufällig das lcd_display(); gelöscht hast als du im Grafikmode nur
Text anzeigen wolltest.
Bei der Gelegenheit sei einmal angemerkt dass es einem
nativ Englischsprechenden die Haare und Zehennägel zu
Berge stehen lässt wenn er manche englischen Ausdrücke
in den Sourcen sieht.
z.B. LCD_display:
Ja, das ist es wieder, das Liquid Crystal Display Display.
Das Display "displayed". Aber die benannte Funktion displayed
nicht sondern sie schiebt den Inhalt des Buffers in das Display-
Array. Also dürfte sie besser display_update() heissen.
z.B. actual (kommt mehrmals vor).
Das Wort steht nicht - wie der Verfasser vermutet - für
"aktuell" sondern für "tatsächlich".
Wenn ich also übersetze: displayBuffer[actualIndex+i]
wie würde ich dann "tatsächlicher Index" verstehen sollen?
Gäbe es dann auch einen "nicht so tatsächlichen Index"?
Mir ist es ein Graus, es lebe das Kauderwelsch Englisch.
SCNR
Bessa Wissa schrieb:> Bei der Gelegenheit sei einmal angemerkt dass es einem> nativ Englischsprechenden die Haare und Zehennägel zu> Berge stehen lässt wenn er manche englischen Ausdrücke> in den Sourcen sieht.Bessa Wissa schrieb:> Mir ist es ein Graus, es lebe das Kauderwelsch Englisch.
Dann geh doch zum Duden - Verlag und verschone uns hier mit deinem
Gesülze.
So einen Haarspalter wie dich muss man erstmal suchen :-(
LCD-Display oder LED-Display hat sich umgangsprachlich längst etabliert.
Das kennen sogar die Kleinkinder.
Welscher schrieb:> LCD-Display oder LED-Display hat sich umgangsprachlich längst etabliert.> Das kennen sogar die Kleinkinder.
Genau so sieht es aus. Zudem könnte man auch noch erkennen, dass es
später dem geneigte Leser helfen könnte. Sobald er lcd_* im Code liest
könnte man erahnen, dass es eine Funktion für das Display ist und dass
lcd_display eventuell bedeuten könnte, am LCD etwas zur Anzeige ("to
display") zu bringen und genau das macht ja die Funktion.
Und zum Thema "actual"...naja, hätte sich Bessa Wissa den Code
angeschaut wüsste er/sie, dass actualIndex sich auf die tatsächliche
Cursor-Position bezieht, also eigentlich auch nicht soo verkehrt ist.
Und ja, es gibt ja auch eine nicht tatsächliche Cursor-Position.
Da könnten wir gleich bei der deutschen Sprache weitermachen, ohne lange
zu forschen. Und wenn man einmal mit nativ englisch sprechenden Bürgern
in einer Gaststätte war, bäumen sich einem zu entsprechende später
Stunde nicht nur die Zehennägel auf.
Da lobe ich mir doch das doppelt gemoppelte LCD-Display.
Erstmal ein Danke an Michael Köhler für den Code!
Ich hab das Library um Unterstützung für STM32/HAL erweitert, und paar
kleinere Fehler beseitigt.
Gegenüber der Original-Version ergeben sich folgende Äderungen:
* lcd_init wird jetzt ohne Parameter aufgerufen.
Ursprünglich wurde versucht, LCD_DISP_ON an die originale init_sequence
anzuhängen, was aber fehlschlagen muß, da die sich im PROGMEM befindet
(warum der Compiler da nicht meckert ist mir ein Rätsel)
* i2c.h und i2c.c wurden in i2c_master.h und i2c_master.c umbenannt, um
Konflikte mit anderen i2c-Librarys zu vermeiden.
Wenn der Code mit einem ARM-gcc übersetzt wird, werden die nicht
genutzt.
* die Definitionen von YES und NO wurden durch die korrekten
Definituionen von TRUE und FALSE ersetzt.
* ein Fehler in lcd_invert wurde korigiert.
* Wenn man das Library auf einem STM32 nutzt, muß bei lcd_init() als
einziger Parameter die Adresse des Handles der I²C-Schnittstelle
übergeben werden.
Bsp.:
1
lcd_init(&hi2c1);
*Der Aufruf von lcd_display() ist mit STM32 nicht mehr erforderlich, da
das Display-Update im Hintergrund mit DMA und Interrupt erfolgt.
Aus Gründen der Kompatibilität ist die Funktion auch bei STM32 weiter
enthalten, tut aber nichts.
* Bei Nutzung mit STM32 läuft das Lbrary IMMER im Graphic-Mode.
* Auf AVRs sollte sich das Library unverändert nutzen lassen, lediglich
lcd_init() braucht keine LCD_DISP_ON als Parameter.
Bitte testen und Rückmeldung geben, da ich das nicht testen konnte!
* Der Code "erkennt" selbst, mit welchem Compiler er übersetzt wird, und
es müssen keine zusätzlichen Defines gesetzt werden
* Es könnte/wird vermutlich noch Probleme mit den SH1106-Displays auf
STM32 geben, was ich mangels Hardware nicht testen kann.
Freue mich über Rückmeldung.
Harry
Harry L. schrieb:> * lcd_init wird jetzt ohne Parameter aufgerufen.Harry L. schrieb:> * Wenn man das Library auf einem STM32 nutzt, muß bei lcd_init() als> einziger Parameter die Adresse des Handles der I²C-Schnittstelle> übergeben werden.> Bsp.: lcd_init(&hi2c1);
Konsistenz ist Wahrheit :-) sagte mein Ex-Chef-Chef-Chef ...
Harry L. schrieb:> ...> Freue mich über Rückmeldung.> ...
Danke für deine Mühe. Bei Gelegenheit werde ich mir das mal anschaun und
ggf. übernehmen wenn ich darf ;).
Harry L. schrieb:> * lcd_init wird jetzt ohne Parameter aufgerufen.> Ursprünglich wurde versucht, LCD_DISP_ON an die originale init_sequence> anzuhängen, was aber fehlschlagen muß, da die sich im PROGMEM befindet> (warum der Compiler da nicht meckert ist mir ein Rätsel)
Das hast du nicht richtig gesehen. Richtig ist, dass die Init-Sequence
im PROGMEM liegt. Bei der lcd_init wird aber die Init-Sequence aus dem
PROGMEM in eine Array, das im SRAM liegt, geladen, dann wird der
Parameter LCD_DISP_ON dem Array noch hinten angehangen und anschließend
das Array zum Display übertragen ;)
Den Parameter bei lcd_init() werde ich aber lassen, eine Idee der
Library war ja u.a. dass man ein HD44780-Display (Library von Peter
Fleury) durch ein OLED-Display ersetzen kann und lediglich die Library
im entsprechenden Projekt austauschen muss ohne den Code sonst zu
ändern. Ich muss nur mal schaun dass ich noch die Cursor-Funktionen
implementiere.
M. K. schrieb:> ggf. übernehmen wenn ich darf
Du darfst nicht nur, du sollst sogar! ;)
M. K. schrieb:> Den Parameter bei lcd_init() werde ich aber lassen, eine Idee der> Library war ja u.a. dass man ein HD44780-Display (Library von Peter> Fleury) durch ein OLED-Display ersetzen kann und lediglich die Library> im entsprechenden Projekt austauschen muss ohne den Code sonst zu> ändern.
Ok, hab ich wieder eingebaut.
Ich hab jetzt doch noch grössere Änderungen am Code vorgenommen:
* zahlreiche "MagicNumbers" durch sinnvolle Defines ersetzt
* Kommentare hinzugefügt
* Die putc()-Funktion hat mir gar nicht gefallen.
Ich hab die neu gebaut, und das jetzt so gelöst:
1
/*
2
* maps char to index of font-table
3
* if char not found, 0xff is returned
4
*/
5
staticinlineuint8_t
6
map_char2fnt(charc)
7
{
8
uint8_ti,idx;
9
if((c>=0x20)&&(c<=0x7f))
10
idx=(uint8_t)c-0x20;
11
else
12
{
13
for(i=0;(pgm_read_byte(&fnt_map[i].idx)!=0xff)
14
&&(pgm_read_byte(&fnt_map[i].c)!=c);i++);
15
idx=pgm_read_byte(&fnt_map[i].idx);
16
}
17
returnidx;
18
}
19
20
21
/*
22
* print a single character on display and advance cursor
23
*
24
*/
25
void
26
lcd_putc(charc)
27
{
28
uint8_tfnt_idx;
29
fnt_idx=map_char2fnt(c);
30
cursorPosition++;
31
if(fnt_idx!=0xff)
32
{
33
#ifdef TEXTMODE
34
i2c_start(OLED_I2C_ADR);
35
i2c_byte(OLED_DTA_PREFIX);// 0x00 for command, 0x40 for data
36
#endif
37
for(uint8_ti=0;i<6;i++)
38
{
39
#ifdef GRAPHICMODE
40
displayBuffer.buf[actualIndex+i]=pgm_read_byte(
41
&oled_font6x8[fnt_idx][i]);// print font to ram, print 6 columns
42
#else
43
i2c_byte(pgm_read_byte(&oled_font6x8[fnt_idx][i]));// print font to ram, print 6 columns
44
#endif
45
}
46
#ifdef TEXTMODE
47
i2c_stop();
48
#endif
49
}
50
#ifdef GRAPHICMODE
51
actualIndex+=6;
52
#endif
53
}
Die fnt_map sieht so aus und mapped nur die Sonderzeichen:
Im Lauf des Tages, sobald ich den Code mit AVR getestet hab, werde ich
den neuen Code hochladen.
Insgesamt ist der Code (und auch das Compilat) dadurch kürzer geworden.
Harry
So, hier nun die neue Version.
Alle Dinge, die vom User einstellbar sind befinden sich jetzt in
oled_config.h.
Den Code hab ich teilweise ziemlich stark umgebaut und kommentiert.
Getestet hab ich mit einem SSD1306 auf AVR im Text- und Graphicmode,
sowie mit STM32.
Was noch offen ist, ist die Unterstützung für SH1106.
Ich werd mir mal so ein Display bestellen, damit ich das auch
vervollständigen und testen kann, aber vielleicht hat ja auch jemand von
euch Lust dazu.
Viel ist da nicht mehr zu tun.
Wie üblich:
Bitte um Rückmeldungen!
Harry
Und noch eine neue Version
* kleinere Bugs beseitigt
* Code weiter aufgeräumt
* Redundanzen im Code beseitigt
* neue Funktion:
1
voidlcd_on(uint8_tonoff);
Damit kann man das Display abschalten und in den Stromspar-Mode
versetzen.
Der Bildschirminhalt bleibt dabei erhalten.
* Bei der Ausgabe von Strings wird am Ende einer Zeile automatisch ein
Zeilenumbruch eingefügt und in der folgenden Zeile weiter geschrieben.
In der letzten Zeile wird zurück auf die erste Zeile gesprungen.
* SH1106 fehlt nach wie vor
* Im Zeichensatz sollten noch 2 Zeichen eingepflegt werden:
µ -> Bsp: µV, µA, µF etc.
Omega -> das Zeichen für Ohm
Die sind derzeit nur als Dummys im Zeichensatz.(die letzten 2 Zeichen)
Details siehe Code.
Harry
Du kennst den Font Generator für das Display?
http://oleddisplay.squix.ch/#/home
Generiert sehr Speicher-effizient auch größere Fonts. Ist nur etwas
kmplizierter zu prozessieren.
Die Änderungen an dem originalen Code von Michael Köhler sind inzwischen
so umfangreich geworden, daß kein Stein mehr auf dem Anderen geblieben
ist.
Hinzu gekommen ist u.A. ein 6- und 4-Zeilen Modus
Besonders der 6-Zeilen Mode sieht wirklich schick aus (siehe Anhang)
Der läuft allerdings leider nur im Grafik-Mode.
Was geblieben ist, ist die Möglichkeit, weiter den Text-Mode mit einem
Speicherbedarf von <2k Flash und 21 Byte RAM zu nutzen. (nur auf
8bit-AVR)
Zusätzlich steht im Text-Mode jetzt auch ein 4-zeiliger Mode zur
Verfügung, der die Portierung von einem klassischen HD44780-Display
erleichtern sollte.
Der funktioniert zwar im Textmode, sieht aber auch erst im Grafik-Modus
wirklich schick aus, da ich da das gesamte Bild auf dem Screen
zentrieren kann.
Zusätzlich wurden \n, \r und \b in der putc()-Funktion implementiert.
Aktuell muß ich noch einen Bug in der STM32-Umsetzung beseitigen, und
sobald das auch läuft, werde ich einen neuen Thread eröffnen, da mein
Fork mit dem Original ohnehin nicht mehr viel zu tun hat.
Der neue Code wird dann auch via GitHub zur Verfügung stehen.
Harry
Ich hasse ja eigentlich meckerrei in der Codeecke. Aber hättest du das
Display nicht mal abwischen können? Sieht ja aus wie 10 Jahre
Industrieeinsatz.
Ansonsten, danke für deine Arbeit, ich habe ein wenig in asm mit dem
Display gespielt, wenn mal mehr Zeit ist geht es da hoffentlich weiter.
Hier schon mal eine Frage: Warum hast du die Unterscheidung, ob die
Daten im RAM oder im FLASH liegen in die Command-Funktion verschoben? Du
(und auch ich) laden nur ein einziges Mal Daten aus dem Flash: Bei der
Initialisierung. Da so eine if-Schleife für einen µC eigentlich immer
doof ist, die Command-Funktion aber öfter aufgerufen wird, ist das
eigentlich nicht sehr sinnvoll. Und bei lcd_data() hast du das auch
gemacht und auch da ist es genauso wenig sinnvoll.
Dann musst du noch mal überprüfen, ob wirklich alles so geht wie du dir
das vorgestellt hast. Willst zu z.B. wirklich niemals auf einem ARM
einen String aus dem Flash laden? Mir fielen nämlich folgende Zeilen
auf:
1
...
2
#ifndef __ARM_ARCH
3
voidlcd_puts_p(constchar*progmem_s)
4
...
Beim ARM solls also wirklich nötig sein, dass alle Strings im RAM liegen
müssen?
M. K. schrieb:> Beim ARM solls also wirklich nötig sein, dass alle Strings im RAM liegen> müssen?
Der ARM hat einen linearen Adressraum für RAM und Flash, da ist die
unterschiedliche Behandlung wie beim AVR nicht nötig. Der (kopierte?)
Kommentar in dem STM32 Beispiel ist da irreführend.
Die paar Zyklen für die if-Abfrage dürften kaum wehtun, dafür ist der
Code sicher wenn die Daten im Ram liegen. Wenn man das 'fromFlash' Flag
beim Aufruf richtig setzt.
Ich mische mich da mal ein:
M. K. schrieb:> Warum hast du die Unterscheidung, ob die> Daten im RAM oder im FLASH liegen in die Command-Funktion verschoben?
Vielleicht, weil es nur eine kleine if Anweisung kostet. Ich vermute,
dass der Compiler sie heraus optimiert, wenn die Funktion mit einer
Konstante aufgerufen wird. Aber selbst wenn nicht: Ein if mehr oder
weniger macht den Kohl nicht fett.
> Willst zu z.B. wirklich niemals auf einem ARM> einen String aus dem Flash laden?> Beim ARM solls also wirklich nötig sein, dass alle Strings im RAM liegen> müssen?
Die mir bekannten ARM Controller haben einen gemeinsamen Adressraum für
Flash und RAM. Die ganze _P Funktionen sind dort schlicht unnötig.
Nachtrag: Jetzt merke ich gerade, dass Johannes S. schon das selbe
schrieb. Egal, kommt mein Senf halt noch oben drauf :-)
Johannes S. schrieb:> Der ARM hat einen linearen Adressraum für RAM und Flash, da ist die> unterschiedliche Behandlung wie beim AVR nicht nötig.
Ah, OK. Mit ARMs hatte ich bisher wenig bis gar nichts zu tun.
Johannes S. schrieb:> Die paar Zyklen für die if-Abfrage dürften kaum wehtun, dafür ist der> Code sicher wenn die Daten im Ram liegen.
Naja, die Unterscheidung gibts bei mir ja auch, allerdings nur da, wo
sie gebraucht wird. Die Frage war ja, warum er (Harry) es verschoben
hat. Bei einem ARM würde ich wahrscheinlich eh zur u8g-lib oder
ähnliches greifen.
Wie oben schon erklärt:
Die einzelne if-Bedingung tut nicht weh.
Auf die Art hab ich aber eine Funktion um Daten auf den I²C-Bus zu
schreiben und nicht unübersichtlich viele Einzelabfragen quer über den
Code verstreut.
M. K. schrieb:> Du> (und auch ich) laden nur ein einziges Mal Daten aus dem Flash
Ich schreibe im Textmode auch die Fonts diekt aus dem Flash.
Das spart mehr CPU-Zyklen als ich schlimmstenfalls durch die
if.Bedingung verliere.
Alles, was mit AVR-PROGMEM zu tun hat, wird via Makro unwirksam gemacht,
sobald für ARM compiliert wird (bei ARM reicht const um das ins Flash zu
legen):
Harry L. schrieb:> Die einzelne if-Bedingung tut nicht weh.
Aber sie unnötig oft aufrufen muss ja auch nicht sein ;)
Harry L. schrieb:> Auf die Art hab ich aber eine Funktion um Daten auf den I²C-Bus zu> schreiben und nicht unübersichtlich viele Einzelabfragen quer über den> Code verstreut.
Nun, die waren vorher auch nicht da ;)
900ss D. schrieb:> M. K. schrieb:>> if-Schleife>> Aua......
Oh, ein Genauer. Ich denke jeder weiß, was gemeint war, auch du. ;)
M. K. schrieb:> Bei einem ARM würde ich wahrscheinlich eh zur u8g-lib oder> ähnliches greifen.
Weshalb?
Genau DAS wolltest du ja mit deinem Library vermeiden, und warum sollte
man das auf einem ARM brauchen?
Dem Display ist es herzlich egal, welcher Controller die (korrekten)
Daten liefert.
Auch ARM hat nur eine endliche Menge Speicher, und bei der
µC-Programmierung sollte man immer den Speicherverbrauch im Auge
behalten.
M. K. schrieb:> Nun, die waren vorher auch nicht da ;)Jede Art von Redundanz reduziert die Wartbarkeit eines Code.
Ausserdem lese ich (s.o.) im Textmode die Font-Daten direkt aus dem
Flash ohne die im RAM zwischen zu speichern.
Harry L. schrieb:> Weshalb?>> Genau DAS wolltest du ja mit deinem Library vermeiden
Und genau da beißt sich die Katze in den Schwanz. Ich hab die Lib
erstellt weil u.a. die u8g-lib einfach zu groß für einen Atmega48/88
ist.
Harry L. schrieb:> Jede Art von Redundanz reduziert die Wartbarkeit eines Code.> Mir ist ein sauberer Programmierstil wichtiger, als irgendwo einzelne> Takt-Zyklen einzusparen.
Ja, aber viele kleine, gesparte Taktzyklen, können zu unschönen
Nebeneffekten führen. Ist ja auch so ein netter Nebeneffekt, dass meine
Lib auch noch schneller ist als die u8g-lib ;)
Vergleich doch einfach mal die Codegrösse der ursprünglichen mit meiner
Library!
Da ist kein grosser Unterschied, und wenn du die Geschwindigkeit im
8Zeilen-Mode vergleichst, ist meine Version theoretisch sogar schneller,
da ich mir das Zwischenspeichern der Font-Daten im RAM erspare.
"Theoretisch" deshalb, da der wirklich limitierende Faktor die
Geschwindigkeit des I²C-Bus ist.
Die erstmal auf 400 kHz hoch zu drehen bringt erheblich mehr, als der
Versuch irgendwo einzelne Taktzyklen zu sparen.
Harry L. schrieb:> Vergleich doch einfach mal die Codegrösse der ursprünglichen mit meiner> Library!
Hab ich, meine Code braucht weniger Flash-Speicher.
Harry L. schrieb:> Da ist kein grosser Unterschied, und wenn du die Geschwindigkeit im> Text-Mode vergleichst, ist meine Version sogar schneller, da ich mir das> Zwischenspeichern der Font-Daten im RAM erspare.
Nö, da irrst du da du mit deinem Umstricken sehr viel öfters ein
i2c_start und i2c_stop aufrufst. Meine Lib braucht bei 400 kHz Taktrate
rund 5 ms zum Beschreiben einer Zeile, deine Lib braucht rund 10 ms
M. K. schrieb:> Meine Lib braucht bei 400 kHz Taktrate> rund 5 ms zum Beschreiben einer Zeile, deine Lib braucht rund 10 ms
Dann würde ich aber gern mal sehen, wie du auf diese Werte kommst...
Btw. erreich ich auf einem STM32F1xx >40fps
Schnell genug?
J. W. schrieb:> oled-display:11: error: 'lcd_display' was not declared in this scope> lcd_display();> ^> exit status 1> 'lcd_display' was not declared in this scope
Dann zeig mal deinen Code!
im Verz. AVR-sample befindet sich ein Beispiel.
1
/*
2
* main.c
3
*
4
* Created on: 16.08.2018
5
* Author: harry
6
*/
7
8
#include<avr/io.h>
9
#include<stdio.h>
10
#include"lcd.h"
11
12
intmain()
13
{
14
chars[21];
15
// put your setup code here, to run once:
16
lcd_init(OLED_DISPLAYON);// init lcd and turn on
17
18
#if defined GRAPHICMODE
19
sprintf(s,"%d-Line graphic-mode\r\n",OLED_LINES);
20
#else
21
sprintf(s,"%d-Line text-mode\r\n",OLED_LINES);
22
#endif
23
lcd_puts(s);// put string from RAM to display (TEXTMODE) or buffer (GRAPHICMODE)
M. K. schrieb:> Harry L. schrieb:>> Btw. erreich ich auf einem STM32F1xx >40fps>> Schnell genug?>> Aber sicher nicht bei 400 kHz Taktrate.
Aber Ja!
Rechne mal nach! ;)
Harry L. schrieb:> M. K. schrieb:>> Harry L. schrieb:>>> Btw. erreich ich auf einem STM32F1xx >40fps>>> Schnell genug?>>>> Aber sicher nicht bei 400 kHz Taktrate.>> Aber Ja!>> Rechne mal nach! ;)
Hab ich. Das Display besteht aus 128*64 Pixel, macht also 12288 Bits zum
übertragen. Bei 40 fps musst du 327680 Bits übertragen. Wird eng bei 400
kHz. Und der Overhead ist da nicht mit drin.
Harry L. schrieb:> Dann zeig mal deinen Code!
Öhm, der steht doch oben.
M. K. schrieb:> Das Display besteht aus 128*96 Pixel
128 * 64 Pixel = 8192 Bit = 1024 Byte = 1kB
Ich sende via DMA den kompletten Buffer in einem Rutsch an den
Controller, und sobald der fertig ist, geht das Spielchen von Vorne los.
Die Präambel (1 Byte) muss dabei nur 1mal pro Buffer-Write gesendet
werden.
Das Programm läuft während dessen ungebremst weiter.
Harry L. schrieb:> M. K. schrieb:>> Das Display besteht aus 128*96 Pixel>> 128 * 64 Pixel = 1024 Byte = 1kB
Ja, hatte mich oben vertan mit der größe. Eng wirds dennoch.
Dass es auf dem STM besser/schneller geht als auf nem AVR glaub ich dir
ja gern. Ich habs halt hier auf nem Atmega328p verglichen und da zeigt
sich, dass mein Code schneller unterwegs ist.
M. K. schrieb:> Ich habs halt hier auf nem Atmega328p verglichen und da zeigt> sich, dass mein Code schneller unterwegs ist.
Den Beweis bist du bisher aber schuldig geblieben.
Und ich meine nicht die Anzahl der Taktzyklen, sondern die tatsächliche
Geschwindigkeit der Ausgabe auf dem Display.
Harry L. schrieb:> Den Beweis bist du bisher aber schuldig geblieben.> Und ich meine nicht die Anzahl der Taktzyklen, sondern die tatsächliche> Geschwindigkeit der Ausgabe auf dem Display.
Welchen Beweis denn bitte schön? Was genau erwartest du? Verstehe ich
nicht.
M. K. schrieb:> Welchen Beweis denn bitte schön? Was genau erwartest du? Verstehe ich> nicht.
Eine nachvollziehbare Erklärung/Beweis, daß deine Funktionen so viel
schneller sind wie du behauptest (5ms vs. 10ms)
Zeig mir ein Code-Beispiel an dem das erkennbar ist!
M. K. schrieb:> Und wie gesagt, bei meinem Code bekomme ich knapp 5ms angezeigt, bei> deinem knapp 10ms.
Text- oder GraphicMode?
Für den Text-Mode kann ich mir das kaum vorstellen.
Mein Graphic-Mode ist allerdings deutlich aufwendiger als deiner, da ich
die Ausgabe vertikal wie horizontal zentriere was einiges an Bit-Shifts
erfordert, aber auch das erklärt nicht so einen Unterschied.
Allerdings stört mich das bei reiner Textausgabe sowieso wenig,da das
immer noch mehr als schnell genug für unsere Augen ist.
Am meisten Zeit und Platz vergeudest du übrigens hiermit:
1
dtostrf((overflows*65536.0+TCNT1)/F_CPU*1e3,
2
6,
3
3,
4
time);
Wozu du da float brauchst, ist mir vollkommen schleierhaft.
Harry L. schrieb:> Am meisten Zeit und Platz vergeudest du übrigens> hiermit:dtostrf((overflows*65536.0+TCNT1)/F_CPU*1e3,> 6,> 3,> time);>> Wozu du da float brauchst, ist mir vollkommen schleierhaft.
Das ist in der Zeitmessung nicht mehr mit drin und wenn es dir
vollkommen schleierhaft ist wozu ich da float benutze kann ich da auch
nicht weiter helfen. Das war die einfachste/schnellste Variante x,yz ms
anzuzeigen.
Sei mir bitte nicht böse, aber ich gewinne zunehmend den Eindruck, daß
du angepisst bist, weil jemand es gewagt hat, deinen Code einem
kompletten Redesign zu unterziehen, und du darum so lange mit dem Kopf
schüttelst, bis du das Haar in der Suppe findest.
Glaub mir einfach, daß unsere Design-Goals die Selben sind:
Größe und Geschwindigkeit
Es macht aber imho wenig Sinn, einige gesparte Taktzyklen mit schlecht
les-/wartbarem Code zu erkaufen, und erst Recht dann nicht, wenn diese
Einsparungen nur minimalen Einfluss auf das Gesamt-Ergebnis haben.
Das Ziel meines Redesign war nicht, deine Programmier-Fähigkeiten in
Frage zu stellen, sondern die Usability dieses Library zu verbessern.
Du hängst dich an Kleinigkeiten auf, aber die wirklich relevanten
Unterschiede hast du bisher mit keinem Wort erwähnt:
* die deutlich verbesserte putc-Routine
* die leichte Erweiterbarkeit des Font um individuelle Sonderzeichen.
* Die Möglichkeit bei den Graphic-Funktionen nicht nur s/w sondern auch
invertierend zu zeichnen.
Sowas ist mir die paar Bytes mehr an Code wert, und selbst wenn meine
Funktionen in einzel-Aspekten vielleicht sogar etwas langsamer als deine
laufen, so sind das bezogen auf den gesamten Bildaufbau ganz sicher
keine 100% Unterschied, und ich behaupte, daß das ein normaler Mensch
auf dem Display ganz sicher nicht wahrnehmen wird.
Harry L. schrieb:> Sei mir bitte nicht böse, aber ich gewinne zunehmend den Eindruck, daß> du angepisst bist, weil jemand es gewagt hat, deinen Code einem> kompletten Redesign zu unterziehen, und du darum so lange mit dem Kopf> schüttelst, bis du das Haar in der Suppe findest.
Nö, das ist überhaupt nicht der Fall, es ist gar das Gegenteil. Ich
finde toll was du gemacht hast, das ist keine Frage. Mir sind halt
gestern nur zwei, ich sag mal, Merkwürdigkeiten aufgefallen und die hab
ich angesprochen da sie aus meiner Sicht keinen Sinn machten.
M. K. schrieb:> Nö, das ist überhaupt nicht der Fall, es ist gar das Gegenteil. Ich> finde toll was du gemacht hast, das ist keine Frage. Mir sind halt> gestern nur zwei, ich sag mal, Merkwürdigkeiten aufgefallen und die hab> ich angesprochen da sie aus meiner Sicht keinen Sinn machten.
Ok, dann hab ich das wohl falsch interprettiert.
Sorry!
Du beziehst dich auf den aktuellen Code im Github?
Der Link wurde in diesem Thread ja noch gar nicht genannt.
https://github.com/HarryLipphaus/OledLib
Sodele, hab ein wenig an meiner Lib rumgeschnitzt.
- lcd_putc()
Habe ich vereinfacht wodurch sie übersichtlicher (und noch mal
schneller) wurde.
- Sonder-/Extrazeichen
und deren Auswertung sind nun, wie auch der Font, in eine eigenen
Header-Datei gewandert.
- einige Steuerzeichen wurde ergänzt
die Lib erkennt nun die Steuerzeichen tab, linefeed und carrige-return.
- lcd-invert()
wurde gefixt, hier war noch ein Fehler drin denn unabhängig vom Argument
wurde das Display da immer auf Not-Inverted gesetzt, da ist mir ein
Tippfehler unterlaufen gewesen.
Der Referenzstring aus meinem Eröffnungpost benötigt nun im Fastmode
(400 kHz I2C-Taktrate) ca. 2.6 ms bis er geschrieben ist im Textmode.
https://github.com/Sylaina/oled-display
M. K. schrieb:> Sodele, hab ein wenig an meiner Lib rumgeschnitzt.>> - lcd_putc()>> Habe ich vereinfacht wodurch sie übersichtlicher (und noch mal> schneller) wurde.
Und es gibt immer noch 2 komplett unabhängige lcd_put() (Text- und
Graphic-Mode), die sich nur in wenigen Zeilen unterscheiden.
Wozu?
Wartbarer Code sieht anders aus!
M. K. schrieb:> - einige Steuerzeichen wurde ergänzt
Und gleich ne ganze switch-Kaskade um das Sonderzeichen auszuwählen...
Mag vielleicht paar ns sparen, ist aber hässlicher Stil und dazu
unflexibel.
Was stört dich an meiner Variante?
* Die 22 Byte Flash für die Tabelle?
* Die paar ns, die er bei dem selten auftretenden Sonderzeichen zum
Durchsuchen der Tabelle benötigt?
Meine Version ist flexibler/generischer bei Erweiterungen um einzelne
Zeichen, funktioiert mit allen Zeichen und belegt weniger Flash
1
// font-map for extra-chars
2
constfnt_map_tfnt_map[]PROGMEM=
3
{
4
{132,97},// ä
5
{148,99},// ö
6
{129,95},// ü
7
{142,98},// Ä
8
{153,100},// Ö
9
{154,96},// Ü
10
{248,101},// °
11
{225,102},// ß
12
{230,103},// µ * only dummy in font *
13
{234,104},// Omega (Ohm) * only dummy in font *
14
{0,0xff}// end of table
15
};
16
17
18
19
/*
20
* maps char to index of font-table
21
* if char not found, 0xff is returned
22
*/
23
staticuint8_tmap_char2fnt(charc)
24
{
25
uint8_ti,idx;
26
if((c>=0x20)&&(c<=0x7f))
27
idx=(uint8_t)c-0x20;
28
else
29
{
30
for(i=0;
31
(pgm_read_byte(&fnt_map[i].idx)!=0Xff)
32
&&(pgm_read_byte(&fnt_map[i].c)!=c);i++)
33
;
34
idx=pgm_read_byte(&fnt_map[i].idx);
35
}
36
returnidx;
37
}
M. K. schrieb:> Der Referenzstring aus meinem Eröffnungpost benötigt nun im Fastmode> (400 kHz I2C-Taktrate) ca. 2.6 ms bis er geschrieben ist im Textmode.
Und du glaubst wirklich, daß ein Mensch bei einer Textausgabe den
Unterschied zw. 2,6ms und 12,5ms "sieht"?
Genau die Punkte, die mich zum Redesign bewogen haben sind in dieser
Version genauso enthalten - nur teilweise "verschlimmbessert"
Das sind genau die Optimierungen, die in der Praxis genau gar nichts
bringen, aber den Code alles Andere als schöner machen.
Harry L. schrieb:> Und du glaubst wirklich, daß ein Mensch bei einer Textausgabe den> Unterschied zw. 2,6ms und 12,5ms "sieht"?
Ob der Rest des Programms 9,9ms mehr oder Weniger zur Verfügung hat,
kann schon einen erheblichen Unterschied machen.
Stefanus F. schrieb:> Harry L. schrieb:>> Und du glaubst wirklich, daß ein Mensch bei einer Textausgabe den>> Unterschied zw. 2,6ms und 12,5ms "sieht"?>> Ob der Rest des Programms 9,9ms mehr oder Weniger zur Verfügung hat,> kann schon einen erheblichen Unterschied machen.
Jaja....weil man natürlich die zeitkritischen Dinge in der main()
erledigt....
Wenn man programmieren kann, ist es vollkommen unerheblich, wie lange
die Ausgabe eines String auf einem Display dauert.
Die Display-Ausgabe hat sowieso die niedrigste Priorität von Allen.
Da zählt nur, daß es für den Bediener (Mensch) schnell genug ist damit
der nicht ungeduldig wird.
Ich hab jetzt auch mal nachgemessen:
Meine Ausgabe (Textmode, 20 Zeichen/Zeile) dauert 4,4ms pro volle Zeile
(20 Zeichen schreiben)
So gemessen:
MyTimer wird im ms-Takt von einem HW-Timer incrementiert.
Noch mehr Timing:
Das Schreiben 1 kompl. Zeile (20 Zeichen) im aufwendigen 6-Zeilen-Mode
in den Framebuffer: 1,0ms
Das Übertragen des Framebuffer auf das Display: 25,4ms
Für das Beschreiben des vollst. Display im 6-Zeilen-Mode macht das dann:
((6 * 1ms) + 25,4ms) / 6 = 5,23ms pro Zeile.
Da beim Überragen einer Zeile des Framebuffe auf das Display 25,4 ms / 8
= 3,18 ms/Zeile benötigt werden, erscheinen mir die von Michael
gemessenen 2,6ms unglaubwürdig.
Entweder war das keine vollst. Zeile mit 20 Zeichen, oder da ist
irgendwo ein Messfehler.
Harry L. schrieb:> Und es gibt immer noch 2 komplett unabhängige lcd_put() (Text- und> Graphic-Mode), die sich nur in wenigen Zeilen unterscheiden.>> Wozu?
Das steht weiter oben warum das so ist. Das werde ich mit Sicherheit
nicht noch einmal erklären.
Harry L. schrieb:> Wartbarer Code sieht anders aus!
Was willst du daran warten, was soll daran unübersichtlich sein?
Harry L. schrieb:> M. K. schrieb:>> - einige Steuerzeichen wurde ergänzt>> Und gleich ne ganze switch-Kaskade um das Sonderzeichen auszuwählen...> Mag vielleicht paar ns sparen, ist aber hässlicher Stil und dazu> unflexibel.
In wiefern soll das unflexibel sein? Und was daran ist hässlicher Stil?
Ich mein, die Steuerzeichen wählst auch du über ne Switch aus, warum ist
das bei dir kein hässlicher Stil aber bei mir? Den check ich nicht.
Harry L. schrieb:> Meine Version ist flexibler/generischer bei Erweiterungen um einzelne> Zeichen, funktioiert mit allen Zeichen und belegt weniger Flash
Ob meine Variante weniger Flash belegt muss ich mal gleich schaun aber
weniger flexibel ist sie definitiv nicht. Wie kommst du darauf?
Harry L. schrieb:> Und du glaubst wirklich, daß ein Mensch bei einer Textausgabe den> Unterschied zw. 2,6ms und 12,5ms "sieht"?
Nö, aber je schneller das Display abgefrühstückt ist desto eher hat man
Zeit in der Main andere Dinge zu tun. Es wäre ja schon irgendwie,
überspitzt formuliert, blöd wenn man in der Main nur Zeit hätte das
Display zu beschreiben.
Harry L. schrieb:> Genau die Punkte, die mich zum Redesign bewogen haben sind in dieser> Version genauso enthalten - nur teilweise "verschlimmbessert"
Das ist natürlich Unsinn.
Harry L. schrieb:> Das sind genau die Optimierungen, die in der Praxis genau gar nichts> bringen, aber den Code alles Andere als schöner machen.
Du findest es jetzt also unschöner, dass die Suche&Auswahl des
Sonderzeichens nicht mehr in der putc() geschieht sondern
übersichtlicher in der Headerdatei, die auch den Font beinhaltet?
Interessant.
Harry L. schrieb:> Meine Ausgabe (Textmode, 20 Zeichen/Zeile) dauert 4,4ms pro volle Zeile> (20 Zeichen schreiben)
Das ist bei mir ebenso ;)
Harry L. schrieb:> Das Übertragen des Framebuffer auf das Display: 25,4ms
Das dauert bei mir im Grafikmode 26,858ms. Übrigens: 25,4ms entsprechen
nicht > 40fps sondern < 40fps ;)
Harry L. schrieb:> Da beim Überragen einer Zeile des Framebuffe auf das Display 25,4 ms / 8> = 3,18 ms/Zeile benötigt werden, erscheinen mir die von Michael> gemessenen 2,6ms unglaubwürdig.>> Entweder war das keine vollst. Zeile mit 20 Zeichen, oder da ist> irgendwo ein Messfehler.
War ein Messfehler. Ich hatte doch in der Tat die falsche Taktquelle für
den Atmega ausgewählt sodass der Atmega nicht mit 8 MHz lief. Blöder
Fehler.
Am Besten finde ich deine Kritik an der Wartbarkeit des Codes, und dann
lese ich z.B. bei dir solche Dinge:
1
...
2
#ifdef __ARM_ARCH
3
...
4
#endif
5
...
6
#ifdef __ARM_ARCH
7
...
8
#endif
9
...
Also wirklich übersichtlicher/besser Wartbar ist das ja nicht. Am besten
gefällt mir das:
1
...
2
// line 153
3
#ifndef __ARM_ARCH
4
...
5
#endif
6
//line 187
7
#ifdef __ARM_ARCH
8
...
9
#endif
10
...
Warum du bei sowas kein #elif benutzt versteh ich nicht.
Aber, bzgl. Wartbarkeit, wirklich übersichtlich durch diese ganzen, ich
sag mal, Spagetti-#if's ist dein Code nicht wirklich. Warum hast du hier
nicht mal richtig nach Architektur sortiert wie etwa so:
1
...
2
#ifdef __ARM_ARCH
3
// alles was zum ARM gehört hier rein
4
#elif
5
// hier alles was zum AVR gehört
6
#endif
7
// hier (oder vor das ifdef) hin alles, was für ARM und AVR benutzt werden soll
8
...
Das wäre erheblich übersichtlicher als so, wie du es jetzt hast.
EDIT:
Ich habe nun auch noch mal verglichen. Mikrocontroller ist ein AVR
Atmega328p mit internen RC, auf 8 MHz eingestellt (Standardfuse mit
CLKDIV8 ausgeschaltet)
Im TEXTMODE belegt deine Library mit der nachfolgenden Main 5118 Bytes
im Flash und es dauert 4.903ms bis die Zeile auf dem Display steht (kein
Overflow vom Timer und der Count steht bei 39227).
Meine Library belegt 4936 Bytes und sie braucht grade mal 4.399ms bis
der Text im Display steht (kein Overflow vom Timer und der Count steht
bei 35195)
Im GRAPHICMODE belegt deine Library mit der nachfolgenden Main 6426
Bytes im Flash und es dauert 28.177ms bis die Zeile auf dem Display
steht (3 Overflows vom Timer und der Count steht bei 28810).
Meine Library belegt 6138 Bytes und sie braucht grade mal 27.766ms bis
der Text im Display steht (3 Overflows vom Timer und der Count steht bei
25517).
Mit deiner Library braucht der Atmega 1. länger bis die Anzeige da ist
und 2. belegt sie mehr Flash-Speicher
EDIT2: Ich hab natürlich die Library von Harry auf 8-Zeilen-Modus
gesetzt und den I2C-Bus auf 400 kHz eingestellt (I2C_HIGHSPEED definiert
in der i2c_master.h).
M. K. schrieb:> Du findest es jetzt also unschöner, dass die Suche&Auswahl des> Sonderzeichens nicht mehr in der putc() geschieht sondern> übersichtlicher in der Headerdatei, die auch den Font beinhaltet?> Interessant.
Die Aussage ist schlicht und einfach falsch!
In der .fnt-Datei befindet sich nur die Tabelle mit der Zuordnung.
Die Funktion um den Index eines Zeichen innerhalb des Font zu ermitteln
steht in lcd.c.
M. K. schrieb:> Am Besten finde ich deine Kritik an der Wartbarkeit des Codes, und dann> lese ich z.B. bei dir solche Dinge:> ...> #ifdef __ARM_ARCH> ...> #endif> ...> #ifdef __ARM_ARCH> ...> #endif> ...
Das ist geradezu lächerlich!
Hättest du dir die Mühe gemacht, den Code zu verstehen würdst du hier
nicht solche Pseudo-Argumente auffahren.
M. K. schrieb:> Im TEXTMODE belegt deine Library mit der nachfolgenden Main 5118 Bytes> im Flash und es dauert 4.903ms bis die Zeile auf dem Display steht (kein> Overflow vom Timer und der Count steht bei 39227).> Meine Library belegt 4936 Bytes und sie braucht grade mal 4.399ms bis> der Text im Display steht (kein Overflow vom Timer und der Count steht> bei 35195)>> Im GRAPHICMODE belegt deine Library mit der nachfolgenden Main 6426> Bytes im Flash und es dauert 28.177ms bis die Zeile auf dem Display> steht (3 Overflows vom Timer und der Count steht bei 28810).> Meine Library belegt 6138 Bytes und sie braucht grade mal 27.766ms bis> der Text im Display steht (3 Overflows vom Timer und der Count steht bei> 25517).>> Mit deiner Library braucht der Atmega 1. länger bis die Anzeige da ist> und 2. belegt sie mehr Flash-Speicher
Jaja, wer misst, misst Mist!
Das ganze inkl. main, startup und deinem Timer-Zeugs (für die Messung
selbst) als Summe ist völlig nichts-sagend.
Für meine Version hab ich valide Werte ermittelt:
Beitrag "Re: Universelles Oled-Libary (SSD1306) für AVR(8bit) und STM32/HAL"
Demnach brauch ich in der kleinsten Variante 1853 Byte Flash und 9 Byte
RAM.
Wenn du unbedingt vergleichen willst, dann bitte auch mit belastbaren
Zahlen.
Leute, streitet euch doch nicht um solche Nichtigkeiten!
Jeder Programmierer hat seinen eigenen Stil. Ich arbeite seit vielen
Jahren in Teams und hätte es nicht vom ungelernten Anfänger zum Senior
mit Führungsverantwortung gebracht, wenn ich mich an solchen
Kleinigkeiten aufgezogen hätte.
Ihr solltet beide akzeptieren, dass andere Lösung auch OK sind. Im
echten Leben ist es völlig egal, welche Lösung die Beste ist, solange
man damit das Ziel erreicht.
Schau euch doch nur mal Microsoft an. Jeder Dummkopf sieht, das deren
Produkte bei weitem nicht optimal sind, und doch ist es eines der
erfolgreichsten Softwarehäuser. Ein Grund ist ganz sicher der, dass die
Manager sich nicht auf der Suche nach Perfektion festbeißen.
Lasst es gut sein und freut eich statt dessen darüber, dass eure
Software tut, was sie soll. Es gibt genug Menschen, die sich mit nicht
funktionierendem Schrott auseinandersetzen müssen.
Ihr habt hier echt ein Luxusproblem. Lernt bitte, andere Lösungen und
Meinungen zu akzeptieren. Es verlangt doch niemand, dass ihr euch auf
die eine einzig wahre Wahrheit einigt. Die gibt es ohnehin nur bei
religiösen Fanatikern. Über dieses Stadium sollten wir Techniker doch
erhaben sein, oder nicht?
So funktioniert Open-Source aber nicht!
Da setzt sich nämlich die bessere Lösung durch, und die übernimmt man
dann in seinem Code.
Ich gewinne hier zunehmend den Eindruck, daß es eben doch primär um
Eitelkeiten geht.
Harry L. schrieb:> So funktioniert Open-Source aber nicht!> Da setzt sich nämlich die bessere Lösung durch
Nein, das ist die Theorie des Herrn Darwin.
Die Philosophie von Open-Source ist, dass jeder den Code nach seinem
Gusto ändern kann und dadurch eine große Vielfalt entsteht.
> Ich gewinne hier zunehmend den Eindruck, daß es eben doch primär um> Eitelkeiten geht.
Wenn schon, dann geht es um deine Eitelkeiten.
Nachtrag: Dein -1 kommt von woanders her. Ich finde deine Beiträge
lesenswert weil du deine Meinung nachvollziehbar kund getan hast. Es
sagt ja niemand, dass ich gleicher Meinung sein muss. Aber du hast das
sicher schon bemerkt, dass die Bewertung von "lesenswert/nicht
lesenswert" oft einfach als "stimme zu/stimme nicht zu" missbraucht
wird.
Stefanus F. schrieb:> Die Philosophie von Open-Source ist, dass jeder den Code nach seinem> Gusto ändern kann und dadurch eine große Vielfalt entsteht.
Und genau aus dieser Vielfalt setzt sich das Bessere durch.
Wäre es anders, wäre ein Linux wie wir es heute kennen niemals
entstanden.
Stefanus F. schrieb:>> Ich gewinne hier zunehmend den Eindruck, daß es eben doch primär um>> Eitelkeiten geht.>> Wenn schon, dann geht es um deine Eitelkeiten.
Wir sind doch hier nicht im Kindergarten, wo der Sandhaufen von Kevin
eine genau so tolle Sandburg ist wie der Sandhaufen von Jaqueline.
Wir reden doch über Fakten.
ich hätte/habe jedenfalls kein Problem damit, fremden Code zu
übernehmen, "wenn" er tatsächlich nach Fakten-Lage besser/effektiver als
meine Lösung ist.
Harry L. schrieb:> Das ganze inkl. main, startup und deinem Timer-Zeugs (für die Messung> selbst) als Summe ist völlig nichts-sagend.
Sorry, aber das zeigt eindeutig, dass du anscheinend absolut keine
Ahnung hast, wie man Zeiten mit einem AVR misst.
Harry L. schrieb:> Wenn du unbedingt vergleichen willst, dann bitte auch mit belastbaren> Zahlen.
Ich habe meinen Test-Code gepostet, auf Github gib es die entsprechende
Library zum herunter laden und das kann so nun jeder selber gegenprüfen.
Damit ich meine Library (i2c + lcd) mit deiner (ebenfalls i2c + lcd)
Vergleichen kann habe ich den selben Testcode verwendet, der Controller
war/ist exakt gleich eingestellt und dabei habe ich obige Werte schlicht
mit gemessen. Ich habe sogar zuvor mittels Portpin auch noch einen Puls
erzeugt (Pin setzen vor dem Beschreiben und löschen nach dem
Beschreiben) um sicher sein zu können, dass ich diesmal auch richtig
messe und der Puls hatte stets auch die Zeit, die ich gemessen habe.
Mein Test ist damit mehr als nur belastbar, er ist verifizierbar.
Stefanus F. schrieb:> Die Philosophie von Open-Source ist, dass jeder den Code nach seinem> Gusto ändern kann und dadurch eine große Vielfalt entsteht.
Und genau das war auch meine Intention und es freut mich sehr, dass
Harry meine Lib als Ausgangsbasis benutzt hat um sie auf den ARM zu
bringen. Sowas finde ich toll und ich bin diesbezüglich auch riesig
Stolz darauf.
Harry L. schrieb:> ich hätte/habe jedenfalls kein Problem damit, fremden Code zu> übernehmen, "wenn" er tatsächlich nach Fakten-Lage besser/effektiver als> meine Lösung ist.
Anscheinend schon ;)
M. K. schrieb:> Harry L. schrieb:>> Das ganze inkl. main, startup und deinem Timer-Zeugs (für die Messung>> selbst) als Summe ist völlig nichts-sagend.>> Sorry, aber das zeigt eindeutig, dass du anscheinend absolut keine hast,> wie man Zeiten mit einem AVR misst.
Und was hat das mit Zeiten zu tun?
Dabei ging es um Code/RAM-Grösse.
Wie ich meine Zeiten ermittelt hab, hab ich hier beschrieben:
Beitrag "Re: Universelles Oled-Libary (SSD1306) für AVR(8bit) und STM32/HAL"M. K. schrieb:> Damit ich meine Library (i2c + lcd) mit deiner (ebenfalls i2c + lcd)> Vergleichen kann habe ich den selben Testcode verwendet, der Controller> war/ist exakt gleich eingestellt und dabei habe ich obige Werte schlicht> mit gemessen. Ich habe sogar zuvor mittels Portpin auch noch einen Puls> erzeugt (Pin setzen vor dem Beschreiben und löschen nach dem> Beschreiben) um sicher sein zu können, dass ich diesmal auch richtig> messe und der Puls hatte stets auch die Zeit, die ich gemessen habe.> Mein Test ist damit mehr als nur belastbar, er ist verifizierbar.
Du wirfst wahllos Performace und Grösse durcheinander.
Zur Laufzeit-Ermittlung: s.o.
belastbar und valide ist anders.
Tip: die tatsächliche Code-Grösse eines Object-File ermittelt man mit
"size"
https://linux.die.net/man/1/size
Harry L. schrieb:> Und was hat das mit Zeiten zu tun?> Dabei ging es um Code/RAM-Grösse.
1. Wenn du nicht weißt wie man mit einem Timer auf dem AVR Zeiten misst
halte ich es für sehr anmaßend, dass du die Ergebnisse anzweifelst
2. Es ging nicht nur um die Code-Größe sondern auch um die Zeiten. Um
die RAM-Größe ging es bisher noch gar nicht.
Harry L. schrieb:> Du wirfst wahllos Performace und Grösse durcheinander.> Zur Laufzeit-Ermittlung: s.o.>> belastbar und valide ist anders.
Wo? Wo würfel ich das durcheinander? Nur weil dir das nicht passt? Dein
Code kann gar nicht schneller sein als meiner. Und zwar ganz einfach
weil ich ein Zeichen so übermittele
1
i2c_start(LCD_ADRESSE);
2
i2c_byte(LCD_DATA_PREFIX);
3
for(uint8_ti;i<CHAR_FONT_SIZE;i++){
4
i2c_byte(CHAR[pos_in_FONT][i]);
5
}
und du machst das so
1
for(uint8_ti;i<CHAR_FONT_SIZE;i++){
2
lcd_data(CHAR[pos_in_FONT][i]);
3
}
mit
1
voidlcd_data(uint8_tdata){
2
i2c_start(LCD_ADRESSE);
3
i2c_byte(LCD_DATA_PREFIX);
4
i2c_byte(data);
Ich habs vereinfacht nur um was zu verdeutlichen: Ich sende die
LCD-Adresse mit jedem Zeichen, die bei dir und mir aus 8 Bytes bestehen,
lediglich ein mal.
Das Gleiche gilt für das Kommando, dass dem LCD nun Daten übermittelt
werden.
Du sendest aber mit jedem Byte eines Zeichens die LCD-Adresse und das
Kommando für Daten. Damit musst du 7*2 Bytes = 14 Bytes mehr als ich dem
Display schicken mit jedem Zeichen, dass du darstellen willst.
Und wenn wir beide das Display mit gleicher Geschwindigkeit betreiben
musst du länger brauchen da du viel mehr Daten ans Display übermittelst
als ich.
Übrigens: Du hast immer noch nicht erklärt was du überhaupt an der
lcd_putc-Funktion warten willst.
Harry L. schrieb:> Tip: die tatsächliche Code-Grösse eines Object-File ermittelt man mit> "size"
Beim avr-gcc Toolchain heist es avr-size. Und was meinst du wie ich die
Größe ermittelt hatte? Kannst du in meinem Github nachlesen ;)
M. K. schrieb:> Ich habs vereinfacht nur um was zu verdeutlichen: Ich sende die> LCD-Adresse mit jedem Zeichen, die bei dir und mir aus 8 Bytes bestehen,> lediglich ein mal.> Das Gleiche gilt für das Kommando, dass dem LCD nun Daten übermittelt> werden.>> Du sendest aber mit jedem Byte eines Zeichens die LCD-Adresse und das> Kommando für Daten. Damit musst du 7*2 Bytes = 14 Bytes mehr als ich dem> Display schicken mit jedem Zeichen, dass du darstellen willst.
Du vergisst dabei, daß bei mir die 20 Zeichen (im Text-Mode) zentriert
werden.
D.h.: ich muß mindestens am Anfang jeder Zeile einmal den RAM-Cursor neu
initialisieren.
Das könnte man darauf beschränken, aber bläht imho den Code nur unnötig
auf.
Die paar µs durch das zusätzliche gotoxy kratzen mich nicht wirklich.
4,4ms/Zeile sind für mich ok, und weitere Optimierungen stehen imho in
keinem sinnvollen Verhältnis zum Aufwand.
M. K. schrieb:> Übrigens: Du hast immer noch nicht erklärt was du überhaupt an der> lcd_putc-Funktion warten willst.
2 nahezu identische Funktionen für putc für die Text- bzw.
Graphic-Ausgabe ist alles Andere als wartungsfreundlich.
Und solche Konstruktionen:
Harry L. schrieb:> 2 nahezu identische Funktionen für putc für die Text- bzw.> Graphic-Ausgabe ist alles Andere als wartungsfreundlich.
Nochmal: Es hat seinen Grund warum sie nahezu identisch sind und was
willst du daran warten?
Harry L. schrieb:> 4,4ms/Zeile sind für mich ok, und weitere Optimierungen stehen imho in> keinem sinnvollen Verhältnis zum Aufwand.
Mein Testcode hat gezeigt, dass meine Lib, dein Ausgang also, rund 10%
schneller ist. Eigentlich hast du Aufwand reingesteckt um es langsamer
zu machen. Dass dir das aber dennoch genügt ist auch völlig OK.
Harry L. schrieb:> Und solche Konstruktionen:> ...> sind einfach nur übel!
Was ist daran übel? Das ist genauso übersichtlich wie deine Tabelle. Ich
hab das Mapping nur auf anderem Wege gelöst, das ist aber deshalb nicht
schlechter wie ich oben auch gezeigt habe. Weder von der Codegröße noch
von der Performance
Harry L. schrieb:> Und genau aus dieser Vielfalt setzt sich das Bessere durch.
Auch das passiert nicht immer … davon abgesehen: was „das Bessere“
ist, legen die Nutzer fest, nicht die Autoren.
Jörg W. schrieb:> Auch das passiert nicht immer … davon abgesehen: was „das Bessere“ ist,> legen die Nutzer fest, nicht die Autoren.
Und danach gibt es nichts besseres als Arduino : (weiß gerade nicht ob
und welchen Smiley ich anbringen soll).
Harry L. schrieb:> Ich bin raus aus dieser Diskussion.> Hab keine lust mehr, gegen Wände zu reden.>> Du mußt noch viel lernen!
Das Problem ist ja nur, dass du gegen die Wand redest, die du selbst
erbaut hast.
Ich gehe ja auf deine Vorschläge ein, so habe ich ja z.B. die
lcd_putc()-Funktion umgebaut. Da war deine Kritik auch völlig
berechtigt.
Dann habe ich, weil ich eben der Meinung war, dass dein Code länger
brauchen müsste als meiner (das hatte ich ja an deiner Library
kritisiert), einen Performance-Test durchgeführt.
Es stellte sich stets heraus, dass meine Vermutung zu traf.
Das hast du nicht geglaubt: Post #5552007
Ich habe dann meinen Code mit dem ich das getestet hatte, gepostet: Post
#5552108
Hier hast du z.b. bemängelt, dass ich mit float gerechnet habe, wie ich
die Zeit bestimmt habe, war die trotz Code und Angabe, wie der
Mikrocontroller eingestellt ist, überhaupt nicht klar.
Wirklich gegengemessen hast du zu diesem Zeitpunkt nicht.
Ich habe zwischenzeitlich aufgrund deiner berechtigten Kritik am Umgang
mit Sonderzeichen in der putc-Funktion meine Library umgebaut.
Auch hier führte ich den obigen Performance-Test durch und kam auf eine
neue, noch schnellere, Zeit.
Auch das hast du bemängelt: Post #5557315
Du hattest es als unglaubwürdig bezeichnet, darauf hin hab ich meine
Code nochmal überprüft und festgestellt, dass der Mikrocontroller falsch
eingestellt war: Post #5557816
Auch dafür danke ich dir denn du hast mir so einen Fehler gezeigt.
Hier habe ich dann den Mikrocontroller richtig eingestellt und deine und
meine Library miteinander verglichen. Das Ergebnis davon war, dass meine
Library immer noch kleiner und auch schneller ist als deine Library.
Und an diesem Punkt hast du meine Testmethode als nicht geeignet
bezeichnet du hattest ja zwischenzeitlich einen eigenen Test ins Feld
geführt.
Mein Test soll ja nicht valide und belastbar sein. Und das obwohl der
Code zum Test oben für jeden, sogar für Gäste, zugänglich und nachlesbar
ist. Ich weis hier ehrlich nicht wie man mehr valide sein will, sein
kann, wenn man schon alles für jederman sichtbar veröffentlicht hat.
Mehr valide&belastbar geht dabei gar nicht.
Nachfragen, was du z.B. an der putc() warten willst oder warum das
Handhaben von Sonderzeichen schlecht sein soll hast du bisher nicht
beantwortet.
Ich bin jetzt aber dennoch darauf eingegangen und habe meine Library nun
noch einmal umstrukturiert.
- Es gibt jetzt keine gleichnamigen Funktionen mehr, die sich bzgl.
Textmode und Graphicmode nur minimal unterscheiden. Die Unterscheidung,
ob das Display im Graphicmode oder Textmode ist, ist nun direkt in den
Funktionen untergebracht (das gilt auch für die lcd_gotoxy() und
lcd_clrscr()).
- Sonderzeichen werden nun durch ein zweidimensionales Array zugeordnet
wo sie im Font-Satz stehen, die lcd_putc()-Funktion durchsucht dieses
Array.
Die Performance meiner Library hat sich dadurch im Graphicmode noch
einmal minimal gesteigert (knapp eine Millisekunde), beim Textmode ist
die Performance gleich geblieben.
Die Code-Größe hat sich nicht nennenswert verändert.
Unterm Strich: Meine Library ist immer noch schneller als deine Variante
und benötigt weniger Flash/RAM. Um es mal in deiner Darstellung zu
visualisieren (meine war ja anscheinend nicht ausreichend):
Speicherbedarf
1
Modul | Code (Flash) | Stat. RAM
2
------------+--------------+------------
3
I2C-Core | 120 Byte | 0
4
Oled (TXT) | 1569 Byte | 2 Byte
5
Oled (GFX) | 2789 Byte | 1026 Byte
Ich finde es schade, dass du dich so aus der Diskussion verabschiedest.
Ich hätte da einen Vorschlag:
jetzt, wo das Wetter wieder besser wird, stellt Ihr euch gegenüber,
jeder mit einem Wasserschlauch bewaffnet, und tragt den Streit aus!
M. K. schrieb:> Ich finde es schade, dass du dich so aus der Diskussion verabschiedest.
Nein es ist gut damit der Kindergarten-Zank aufhört. Echt albern.
Hi sylaina,
vielen Dank zunächst für die ganze Arbeit!
Ich bräuchte allerdings einmal Hilfe, da ich die Lib nicht lauffähig
bekomme.
Als Display benutze ich das 0,96" Display von 42project (mit SSD1306
Treiber), als uC den ATMega164PA.
Mit einem Arduino Uno und der U8glib funktioniert es problemlos,
allerdings ist mit diese Lib zu groß und unübersichtlich für persönliche
Erweiterungen.
SDA und SCL sind direkt an dem uC angeschlossen, da das Display soweit
ich weiß über interne Pull-Ups verfügt.
Zum Test habe ich dein Beispiel aus der Lib (Git) genommen, das dort in
der Main hinterlegt ist.
Muss ich selbst an dem uC noch Einstellungen vornehmen, die dort nicht
vermerkt sind?
Den mit diesem simplen Code bleibt das Display leider schwarz.
Danke für deine Hilfe.
Treiber habe ich in der "lcd.h" auf SSD1306 geändert und von "Graphic"
in "textmode" gewechselt.
Hab grade noch mal mit meinem ATMega328P probiert, auch hier
funktioniert es nicht.
Mit meinem Messgerät messe ich auf der "SCL" Leitung einen Takt von
50kHz, in der "lcd.h" sind 100.000 eingetragen. Ist dem so richtig?
> SDA und SCL sind direkt an dem uC angeschlossen, da das Display soweit> ich weiß über interne Pull-Ups verfügt.
Du kannst das ganz einfach nachmessen: Im Ruhezustand muss der Pegel
HIGH sein und ein Amperemeter (von SDA nach GND bzw. SCL nach GND)
müsste ca. 1mA anzeigen.
Dieter F. schrieb:> Harry L. schrieb:>> Ohne PullUps wird das nix..>> Sind auf dem OLED.
Auf Deinem vielleicht...auf meinem nicht.
Und die gehören da auch nicht hin!
Stefanus F. schrieb:> Du kannst das ganz einfach nachmessen: Im Ruhezustand muss der Pegel> HIGH sein und ein Amperemeter (von SDA nach GND bzw. SCL nach GND)> müsste ca. 1mA anzeigen.
Habe ich grade mal gemacht. Es fließen jeweils 0.33mA.
OLEDer schrieb:> Muss ich selbst an dem uC noch Einstellungen vornehmen, die dort nicht> vermerkt sind?> Den mit diesem simplen Code bleibt das Display leider schwarz.
Ja, in der lcd.h musst du z.B. einstellen, dass es ein SSD1306-Display
ist, das Github ist auf SH1106 eingestellt.
Die Adresse musst du auch korrekt einstellen. Auf den Displays, so meine
Erfahrung, ist meist die Adresse im 8-Bit-Format angegeben. Daher ist da
in meiner Lib diese merkwürdige Shift-Option. Willst du die Adresse
direkt im 7-bit-Format angeben (statt z.B. 0x78 gleich 0x3c angeben)
dann darfst du natürlich nicht shiften.
Zudem viel mir grade beim Github auf, dass ich vergessen hatte, die
font.c dem Linker hinzuwerfen, das habe ich grade noch korrigiert (das
wirft aber typischerweise Fehler da er dann den Font nicht linken kann).
Stefanus F. schrieb:> Die I²C Spezifikation alleine reicht so nicht. Man muss die Kapazitäten> der Leitungen und Bauteile berücksichtigen.
Kann man bei Kabellängen unter ~50cm komplett ignorieren...
So, wie es in o.g. DB steht funktioniert das auch.
Stefanus F. schrieb:> Dann hast du 10k Ohm. Fuer die maximale Bitrate ist das zu viel.
Ja es sind 3.3 V für das Display.
Aber da es mit der normalen U8glib funktioniert, dürfte es eigentlich
kein Problem darstellen.
M. K. schrieb:> Ja, in der lcd.h musst du z.B. einstellen, dass es ein SSD1306-Display> ist, das Github ist auf SH1106 eingestellt.
Hatte ich oben noch beigefügt, Treiber ist entsprechend eingestellt. Die
F_CPU muss ich auch noch manuell einfügen, ist das richtig? Das habe ich
auch bereits gemacht.
> Die Adresse musst du auch korrekt einstellen. Auf den Displays, so meine> Erfahrung, ist meist die Adresse im 8-Bit-Format angegeben. Daher ist da> in meiner Lib diese merkwürdige Shift-Option. Willst du die Adresse> direkt im 7-bit-Format angeben (statt z.B. 0x78 gleich 0x3c angeben)> dann darfst du natürlich nicht shiften.
Das hatte ich auch noch nicht so ganz verstanden. Die Adresse meines
Displays (I2C-Scanner) ist 0x3C, ich habe jetzt vermutet das es sich um
die Adresse handelt, die Bereits in der lcd.h angegeben ist, jedoch in
einem anderen Format. Diese habe ich soweit nicht verändert.
Allerdings steht in der "lcd.h" 0x7A nicht 0x78, kann das der Fehler
sein?
Gleich mal ausprobieren.
OLEDer schrieb:> Allerdings steht in der "lcd.h" 0x7A nicht 0x78, kann das der Fehler> sein?> Gleich mal ausprobieren.
Für unmodifizierte Displays muß die Adresse 0x78 sein
0x78 = 0x3c << 1
Bit 0 ist für R/W zuständig.
Die I²C-Adresse steht in den oberen 7bit.
Harry L. schrieb:> 0x78 = 0x3c << 1>> Bit 0 ist für R/W zuständig.> Die I²C-Adresse steht in den oberen 7bit.
Danke für den Hinweis, das macht es etwas verständlicher.
... in einem Buch (vor Jahren, welches weiß ich nicht mehr), wurde
behauptet, ein I2C Device besitze 2 Adressen, eine Adresse zum Lesen,
eine zum Schreiben.
Wenn man dieses so betrachtet hat ein Display die Adresse 0x78 und 0x79
und das R/W Flag ist somit Bestandteil der Adresse (und nicht wirklich
ein Flag).
Wenn man es als Flag und nicht als Bestandteil der Adresse sieht, dann
besteht die Adresse aus 7 Bits deren niederwertiges Bit in D1 im Byte
(und nicht D0) ist.
Ist das nirgendwo festgelegt, wie das zu betrachten ist ?
OLEDer schrieb:> Hatte ich oben noch beigefügt, Treiber ist entsprechend eingestellt. Die> F_CPU muss ich auch noch manuell einfügen, ist das richtig? Das habe ich> auch bereits gemacht.
Ich schau mal was du so geschrieben hattest, hab mir nicht alles genau
durchgelesen.
OLEDer schrieb:> Mit meinem Messgerät messe ich auf der "SCL" Leitung einen Takt von> 50kHz, in der "lcd.h" sind 100.000 eingetragen. Ist dem so richtig?
Öhm...das ist nicht richtig, wenn du 100 kHz einstellst soll es auch mit
100 kHz laufen. Entweder stimmt das F_CPU nicht oder was anderes. Was
direkt aber auffällt: Die I2C-Settings werden in der i2c.h eingestellt,
nicht in der lcd.h.
Bevor wir weiter lang rumraten: Zippe doch mal dein Projekt und lade es
hier hoch, dann könnten wir es runter laden und mal schaun. Benutzt du
z.B. einen Arduino Nano/Uno mit der Arduino-IDE? Da sind besondere
Einstellungen dann noch nötig die im Github in der Readme ganz unten
beschrieben sind.
Ralph S. schrieb:> ... in einem Buch (vor Jahren, welches weiß ich nicht mehr), wurde> behauptet, ein I2C Device besitze 2 Adressen, eine Adresse zum Lesen,> eine zum Schreiben.
Hm, das kann man so sehen, dann muss man aber sagen, dass jeder
I2C-Baustein aus mindestens 2 I2C-Geräten besteht. Ne, diese
Betrachtungsweise ist im Prinzip unsinn.
Man kann sagen, dass ein I2C-Device eine 8-bit Adresse hat bei der das
LSB dem Device schlicht nur mitteilt, ob das Device gelesen oder
beschrieben werden soll.
Die OLED-Displays mit SSD1306 bzw. SH1106 können jedoch mit dem
I2C-Interface nicht quatschen, deshalb muss man bei diesen Displays mit
einem Puffer arbeiten wenn man darauf zeichnen will und dabei den
aktuellen Inhalt nicht löschen möchte. Und deshalb werte ich auch das
Ack/NAck bei den Displays nicht aus (das ist das Einzige, dass sie einem
zurück liefern), es ist mir wurscht wie sie Antworten wenn ich ihnen
Daten schicke. Wenn was schief geht könnten sie mir eh nicht sagen, was
schief gegangen ist.
M. K. schrieb:> Wenn was schief geht könnten sie mir eh nicht sagen, was> schief gegangen ist
Wenn sie nicht antworten weißt du aber, DASS etwas schief gegangen
ist...
M. K. schrieb:> Bevor wir weiter lang rumraten: Zippe doch mal dein Projekt und lade es> hier hoch, dann könnten wir es runter laden und mal schaun. Benutzt du> z.B. einen Arduino Nano/Uno mit der Arduino-IDE? Da sind besondere> Einstellungen dann noch nötig die im Github in der Readme ganz unten> beschrieben sind.
Wie gesagt nutze ich einen ATMega164PA, den Code erstelle ich in Atmel
Studio 7 und nutze einen ISP zum übertragen, da der chip45 Bootloader
nicht für den PA funktioniert.
mal auf 2.
So wird der Wert für TWBR zu groß - bzw. nach Zuweisung unpassend (das
sollte im Header mit einer Meldung bedacht werden ... - nur so, als
Anregung :-) )
Dieter F. schrieb:> So wird der Wert für TWBR zu groß
Dann hätte er nicht weiter compilieren können, der gcc wäre mit Fehler
stehen geblieben. Kann man sich auch selbst ausrechnen: Bei 16 MHz und
100 kHz I2C Taktrate kommt da 72 bei raus. Das ist bei weitem nicht zu
groß für TWBR.
OLEDer schrieb:> Wie gesagt nutze ich einen ATMega164PA, den Code erstelle ich in Atmel> Studio 7 und nutze einen ISP zum übertragen, da der chip45 Bootloader> nicht für den PA funktioniert.
Ich glaube auch nicht, dass es am ISP liegt.
Ich hab mal rein geschaut, mit dem Atmel Studio kenn ich mich aber nicht
aus. Das nutze ich idR nur wenn ich einen Attiny4 oder ähnliches
(TPI-Schnittstelle) programmieren/flashen will.
1. Frage: Das Projekt kompiliert absolut ohne Fehlermeldung, ja? Ich
erhalte beim Build die Meldung "recipe for target "Display_test.elf"
failed.". Ich kann das aber auf die Schnelle nicht interpretieren, mir
scheint aber, dass er irgend etwas nicht findet. Beim zweiten
Build-Versuch wird dann fehlerfrei übersetzt. Es sollte aber auch schon
beim 1. Build funktionieren.
2. Hinweis: F_CPU kann man auch als Projektvariable anlegen, dann ist
sie jedem File bekannt. Ich mein das ging irgendwie über
Properties-Symbols. Google weis hier sicher mehr.
Ralph S. schrieb:> Ist das nirgendwo festgelegt, wie das zu betrachten ist ?
In der I²C Spezifikation
(https://www.nxp.com/docs/en/user-guide/UM10204.pdf) steht:
> After the START condition (S), a slave address is sent. This address> is seven bits long followed by an eighth bit which is a data direction> bit (R/W).
Für mich ist damit klar, dass die Slave Adresse 7bit groß ist. Dieses
R/W Bit ist nicht Bestandteil der Adresse. Das wird auch in sämtlichen
folgenden Diagrammen und Tabellen so dargestellt.
Deswegen halte ich es für falsch, dass viele Libraries als Input 8bit
Werte inclusive R/W Bit erwarten und dass dann "address" nennen.
Richtig verwirrend wird es bei dieser kruden 8bit Variante, wenn man
einen I²C Slave ansprechen will, der nur Write Operationen kennt. Dann
muss man nämlich immer noch die 8bit Adresse mit bit0=Low konfigurieren,
obwohl tatsächlich immer bit0=High gesendet wird.
M. K. schrieb:> Dann hätte er nicht weiter compilieren können, der gcc wäre mit Fehler> stehen geblieben. Kann man sich auch selbst ausrechnen: Bei 16 MHz und> 100 kHz I2C Taktrate kommt da 72 bei raus. Das ist bei weitem nicht zu> groß für TWBR.
Hast Recht - schlechter Morgen ...
M. K. schrieb:> 1. Frage: Das Projekt kompiliert absolut ohne Fehlermeldung, ja? Ich> erhalte beim Build die Meldung "recipe for target "Display_test.elf"> failed.". Ich kann das aber auf die Schnelle nicht interpretieren, mir> scheint aber, dass er irgend etwas nicht findet. Beim zweiten> Build-Versuch wird dann fehlerfrei übersetzt. Es sollte aber auch schon> beim 1. Build funktionieren.
Beim ersten mal bekomme ich nur eine Warnung für die Umlaute.
"case lable value less than minimum value for type"
"multi-character character constant [-Wmultichar]"
Ansonsten läuft es problemlos durch.
Auch eine Änderung am prescaler hat nichts bewirkt.
Ich hab nochmal etwas rum probiert, jetzt funktioniert es.
Zum einen lag es wohl an der falschen Adresse in der "lcd.h", da dort
standardmäßig 0x7A steht und zum anderen das ich im Projekt selbst noch
328P stehen hatte, beim flaschen aber 164PA ausgewählt habe.
Vielen dank für eure Hilfe und ganz besondern nochmal an sylaina für die
tolle Lib, wirklich hervorragende Arbeit!!
OLEDer schrieb:> Beim ersten mal bekomme ich nur eine Warnung für die Umlaute.>> "case lable value less than minimum value for type"> "multi-character character constant [-Wmultichar]"
Da wird das Encoding des Quellcodes nicht richtig erkannt, schau dir
noch mal die Readme an, da steht drin welches Flag man wie setzen muss
damit der Compiler die Quellcode-Dateien auch richtig dekodiert mit dem
richtigen Encoding.
Zudem hab ich gesehen, dass du noch eine alte Version meiner Lib
benutzt. Geh mal auf:
https://www.github.com/Sylaina/oled-display/
da findest du die aktuelle Version. Die braucht zum einem noch etwas
weniger Flash und ist noch schneller als die alte Version.
M. K. schrieb:> Da wird das Encoding des Quellcodes nicht richtig erkannt, schau dir> noch mal die Readme an, da steht drin welches Flag man wie setzen muss> damit der Compiler die Quellcode-Dateien auch richtig dekodiert mit dem> richtigen Encoding.
Da steht nur drin, was ich ändern muss, aber nicht der Befehl dafür.
Wenn ich den Befehl "-finput-charset=utf-8 -fexec-charset=iso-8859-15"
aus dem Makefile nehme, bekomme ich den Fehler:
"no iconv implementation, cannot convert from UTF - 8 to iso..."
Den oben genannten befehl füge ich bei
Toolchain -> AVR/GNU C Compiler -> Miscellanneous
ein.
> Zudem hab ich gesehen, dass du noch eine alte Version meiner Lib> benutzt.
Dann müsste der Link im ersten Post korrigiert werden, denn der verweißt
noch auf die ältere Version.
OLEDer schrieb:> "no iconv implementation, cannot convert from UTF - 8 to iso..."
Ohne ein erreichbares iconv bleibt dir nur übrig, den Quelltext selbst
gleich als ISO-8859-1[5] abzuspeichern. Wie das geht (und ob es
überhaupt geht), hängt vom jeweils benutzten Editor ab.
"welchen" 8Bit-Zeichensatz man nutzt, ist dabei doch vollkommen egal.
So lange man im Source numerische Konstanten für die Sonderzeichen nutzt
ist das eindeutig, und der Compiler hat nix zu meckern.
.
OLEDer schrieb:> Da steht nur drin, was ich ändern muss, aber nicht der Befehl dafür.
Richtig, aber ich dachte auch, dass das eindeutig ist. So wie z.B. ein
"make all" das entsprechende Programm samt EEPROM-File und Co erzeugt.
OLEDer schrieb:> Dann müsste der Link im ersten Post korrigiert werden, denn der verweißt> noch auf die ältere Version.
Öhm, nö. Nicht den Dateianhang laden sondern dem Link im ersten Post
folgen, der führt dich zur aktuellen Version der Lib
M. K. schrieb:>> Edit: Github link https://github.com/Sylaina/oled-display.gitHarry L. schrieb:> So lange man im Source numerische Konstanten für die Sonderzeichen nutzt> ist das eindeutig, und der Compiler hat nix zu meckern.
Das ist zwar richtig aber später in der main wird wohl kaum einer auf
die Idee kommen, statt z.B. 'ä' ein '0x84' zu schreiben und schon wirds
wieder wichtig, was der Editor/Compiler benutzt. Wenn der nämlich ein
Charset benutzt, bei dem ein 'ä' z.B. nicht bei '0x84' steht sondern bei
z.B. '0xe4' (da stehts bei ISO 8859-1, unserem typischen Latin-1)
bekommt man wieder nicht das, was man eigentlich will.
M. K. schrieb:> Harry L. schrieb:>> So lange man im Source numerische Konstanten für die Sonderzeichen nutzt>> ist das eindeutig, und der Compiler hat nix zu meckern.>> Das ist zwar richtig aber später in der main wird wohl kaum einer auf> die Idee kommen, statt z.B. 'ä' ein '0x84' zu schreiben und schon wirds> wieder wichtig, was der Editor/Compiler benutzt. Wenn der nämlich ein> Charset benutzt, bei dem ein 'ä' z.B. nicht bei '0x84' steht sondern bei> z.B. '0xe4' (da stehts bei ISO 8859-1, unserem typischen Latin-1)> bekommt man wieder nicht das, was man eigentlich will.
Das Kunststück,das für alle denkbaren IDE/Editoren/OS hinzubekommen will
ich sehen!
M. K. schrieb:> Richtig, aber ich dachte auch, dass das eindeutig ist. So wie z.B. ein> "make all" das entsprechende Programm samt EEPROM-File und Co erzeugt.
Das stimmt, aber dafür müsste man sich dann mit Compiler Befehlen und
deren Implementierung auskennen.
> Öhm, nö. Nicht den Dateianhang laden sondern dem Link im ersten Post> folgen, der führt dich zur aktuellen Version der Lib
Ich hab den Thred anfangs erst einmal durchgelesen und dann wie weiter
unten geschrieben im ersten Post den github Link benutzt. Da bin ich auf
die Lib gekommen die ich bisher benutzt habe.
Wie auch immer, jetzt habe ihc ja die aktuelle Version.
Zu den Umlauten:
Ich hätte jetzt gedacht, das Atmel Studio so etwas hin bekommt. Naja, so
kann man sich täuschen. Aber ich denke, ich kann auf die Umlaute gut
verzichten, dann spare ich mir den switch vergleich und der code wird
noch etwas schneller ^^
Harry L. schrieb:> Das Kunststück,das für alle denkbaren IDE/Editoren/OS hinzubekommen will> ich sehen!
Ist doch einfach:
Mein Beispielcode von oben.
Font von meiner Library, 'ä' gegen 0x84 ersetzt, die
Charset-Konfiguration aus dem Makefile entfernt.
Im main meines Beispielcodes folgende beide Zeilen direkt nach dem Code
zum print von Zeile 1 eingefügt:
1
lcd_gotoxy(0,1);
2
lcd_puts("Test: ä");
Ergebnis ist das angehangene Bild. Ich mag was mit dem Auge habe aber
ich sehe kein "ä", du etwa? Sowie ich aber den Charset wieder einfüge
gibts auch ein "ä".
Ich kann alternativ auch im Font 'ä' durch 0xe4 ersetzen, dann steht da
auch ein ä auf dem Display.
Das zeigt: Es kommt drauf an, welches Textencoding der Compiler benutzt
um ein 0x84 (oder 0xe4) als 'ä' zu erkennen.
OLEDer schrieb:> Ich hätte jetzt gedacht, das Atmel Studio so etwas hin bekommt. Naja, so> kann man sich täuschen. Aber ich denke, ich kann auf die Umlaute gut> verzichten, dann spare ich mir den switch vergleich und der code wird> noch etwas schneller ^^
Nimm doch die aktuelle Lib, da ist auch kein Switch-Vergleich mehr drin
;)
M. K. schrieb:> Das zeigt: Es kommt drauf an, welches Textencoding der Compiler benutzt> um ein 0x84 (oder 0xe4) als 'ä' zu erkennen.
So ein Blödsinn!
Es kommt bei solchen Anwendungen (das ist kein PC-Programm bei dem es so
hübsche Dinge wie i18n gibt!!) darauf an, was du als "ä" definierst!
Außerdem nutzt nicht jeder Makefiles, und IDEs haben z.T. sehr
unterschiedliche Vorstellungen von der Zeichencodierung.
Bei Displays, die einen integrierten Char-Generator haben, kommt es
zusätzlich darauf an, an welcher Position das "ä" steht.
So, wie du das gelöst hast, funktioniert das bei dir - eine allgemein
gültige Lösung ist das jedenfalls nicht.
Aber, wenn du meinst, daß du das alles so richtig verstanden
hast....bitte sehr!
Hab keinerlei Lust, hier ein weiteres Faß auf zu machen.
M. K. schrieb:> Das ist zwar richtig aber später in der main wird wohl kaum einer auf> die Idee kommen, statt z.B. 'ä' ein '0x84' zu schreiben
Ich habe mir dann immer mit sowas beholfen:
1
#define sz "\xdf"
2
#define ae "\xe4"
3
4
...
5
printf("Damit geht das verl"aesz"lich");
Harry L. schrieb:> Hab keinerlei Lust, hier ein weiteres Faß auf zu machen.
Fein, wir haben vom letzten noch genug. :/
OLEDer schrieb:> Zu den Umlauten:>> Ich hätte jetzt gedacht, das Atmel Studio so etwas hin bekommt.
Offensichtlich haben sie bei Atmel/Microchip nicht dran gedacht, ein
iconv-Binary mitzuliefern.
Mach doch bei ihnen einfach mal einen Bugreport auf.
Harry L. schrieb:> So ein Blödsinn!> Es kommt bei solchen Anwendungen (das ist kein PC-Programm bei dem es so> hübsche Dinge wie i18n gibt!!) darauf an, was du als "ä" definierst!
Das ist völlig richtig aber: Der Compiler ist doch ein PC-Programm und
der muss doch den Kram 1. erstmal einlesen (Quellcode usw.) und 2.
daraus was für den Mikrocontroller Ausführbares machen (Hex-Files,
EEPRom-Files usw.). Deswegen heißt das eine ja auch input und das andere
exec.
Harry L. schrieb:> So, wie du das gelöst hast, funktioniert das bei dir - eine allgemein> gültige Lösung ist das jedenfalls nicht.
Wenn man die Randbedingungen beachtet, die ich in der Readme angegeben
habe, dann funktioniert das nicht nur bei mir so sondern bei jedem.
Harry L. schrieb:> Hab keinerlei Lust, hier ein weiteres Faß auf zu machen.
Gute Idee.
Jörg W. schrieb:> Ich habe mir dann immer mit sowas beholfen:> #define sz "\xdf"> #define ae "\xe4">> ...> printf("Damit geht das verl"ae sz"lich");
Ein der wenigen sinnvollen Lösungen!
Harry L. schrieb:> Jörg W. schrieb:>> Ich habe mir dann immer mit sowas beholfen:>> #define sz "\xdf">> #define ae "\xe4">>>> ...>> printf("Damit geht das verl"ae sz"lich");>> Ein der wenigen sinnvollen Lösungen!
Sinnvoll ist es natürlich auch, wenn man den Text flüssig schreiben
kann. Bei dieser Variante ist man halt komplett unabhängig vom host und
execution charset.
Harry L. schrieb:> Jörg W. schrieb:>> Ich habe mir dann immer mit sowas beholfen:>> #define sz "\xdf">> #define ae "\xe4">>>> ...>> printf("Damit geht das verl"ae sz"lich");>> Ein der wenigen sinnvollen Lösungen!
Würde nur mit deinem Font nicht funktionieren da da ä als 0x84 definiert
ist und ß mit 0xe1. 0xdf (223) und 0xe4 (228) kennt dein Font nicht.
Wenn die Codes nicht zum geplanten Charset passen kannst du dich auf den
Kopf stellen und mit den Füßen wackeln und es wird nicht fnuktionieren.
Jörg W. schrieb:> innvoll ist es natürlich auch, wenn man den Text flüssig schreiben> kann. Bei dieser Variante ist man halt komplett unabhängig vom host und> execution charset.
Einen Tod musst du sterben....
Mich mit dem Compiler über den verwendeten Zeichensatz herum zu streiten
wiederstrebt mir zu tiefst.
Der Code sollte auf jedem System mit jeder Codepage zum selben Ergebnis
führen.
Harry L. schrieb:> Einen Tod musst du sterben....
Ja, und bevor ich den Tod sterbe mit irgendwelchen kryptischen
Hex-Zahlen geh ich lieber her und sage konkret, welches Charset zu
verwenden ist. Ich finde nämlich ein
1
#define sz "\xdf"
2
#define ae "\xe4"
3
4
...
5
printf("Damit geht das verl"aesz"lich");
ist bei weitem nicht so leicht zu lesen wie ein
1
printf("Damit geht das verläßlich");
Harry L. schrieb:> Mich mit dem Compiler über den verwendeten Zeichensatz herum zu streiten> wiederstrebt mir zu tiefst.
Was hat das mit herumstreiten zu tun. Das sind stink normale
Einstellparameter. Wenn man so Sachen wie delay_ms verwendet muss man
dem Compiler ja auch die korrekte Taktfrequenz des µCs mitteilen. Da
kann man im makefile, das man ja eigentlich auch beim Code mitliefert,
auch direkt die flags für die entsprechenden Charsets setzen.
Harry L. schrieb:> Der Code sollte auf jedem System mit jeder Codepage zum selben Ergebnis> führen.
Das kann schon per Definition nicht funktionieren da es unterschiedliche
Charsets ad absurdum führen würde. Latin-1 und DOS-Latin-1 z.B. klingen
ähnlich und haben Umlaute und Co doch nicht an den gleichen Stellen
stehen. Zwei Charsets, die insbesondere beim extenden Set definitiv zu
unterschiedlichen Ergebnissen kommen.