Für die beliebten LC-Displays mit I²C-Adapter auf HD44780-Basis hier ein Treiber. Anpassungen an andere Display-Formate, I²C-Adresse etc. in lcd_config.h und ggf. lcd_map.inc (für exotische Displays) Um das zu compilieren: * Zip-File Im workspace-Folder entpacken * die .ioc-Datei mit CubeMX öffnen und Projekt generieren. * Projekt in Atollic importieren. Weder schön noch fertig... "Auf die Schnelle zusammen geklöppelt" - aber funktioniert. :) Vielleicht kann es ja jemand brauchen. Die jeweils aktuelle Version gibt es hier zum Download: https://cloud.it-livetalk.de/index.php/s/sF3otLQ3dpBFJNE
:
Bearbeitet durch User
Harry L. schrieb: > Die jeweils aktuelle Version gibt es hier zum Download: Das Forum bietet die Möglichkeit, Dateien anzuhängen. Nutze sie!
Rufus Τ. F. schrieb: > Harry L. schrieb: >> Die jeweils aktuelle Version gibt es hier zum Download: > > Das Forum bietet die Möglichkeit, Dateien anzuhängen. Nutze sie! Nein, mach ich in dem Fall bewusst nicht, weil ich so die Datei jederzeit aktualisieren kann. Das ist auch kein x-beliebiger Werbe-versiffter Filehoster, sondern mein eigener Server.
:
Bearbeitet durch User
Und sobald Dein eigener Server ausfällt, hat niemand hier im Forum was davon. Vorschlag: Lad' die Datei hier hoch, und weise deutlich darauf hin, daß aktuellere Versionen auf Deinem Server zu finden sein werden. Dann hat man im Falle Deines Ablebens/Ausfalls noch was davon.
Auf besonderen Wunsch von Rufus nochmal das aktuelle File als Anhang. Das kann (und wird vermutlich) morgen bereits veraltet sein. Die aktuelle Version gibts immer über diesen Link: https://cloud.it-livetalk.de/index.php/s/sF3otLQ3dpBFJNE
Harry L. schrieb: > Das kann (und wird vermutlich) morgen bereits veraltet sein. > > Die aktuelle Version gibts immer über diesen Link: Warum veröffentlicht man dann eine unstabile und noch nicht fertige Version?
Bimbo. schrieb: > Harry L. schrieb: >> Das kann (und wird vermutlich) morgen bereits veraltet sein. >> >> Die aktuelle Version gibts immer über diesen Link: > > Warum veröffentlicht man dann eine unstabile und noch nicht fertige > Version? Woraus liest du, daß die Version instabil wäre? Wann ist eine Software fertig? Solche Kommentare kannst du dir auch sparen! Nimm es oder lass es!
Harry L. schrieb: > Woraus liest du, daß die Version instabil wäre? Hieraus: Harry L. schrieb: > Weder schön noch fertig... Harry L. schrieb: > Das kann (und wird vermutlich) morgen bereits veraltet sein. > > Die aktuelle Version gibts immer über diesen Link: Eine halbwegs fertige Software wird morgen noch nicht veraltet sein. Und der Hineis auf die aktuelle Version lässt auch auf "work in progress" deuten. Ist ja nichts schlimmes - ich würds aber erst präsentieren, wenn ich erwarte dass meine Version morgen noch nicht bereits veraltet ist.
Harry L. schrieb: > Auf besonderen Wunsch von Rufus nochmal das aktuelle File als Anhang. Danke. Allerdings ist die Frage schon gerechtfertigt, was Du an einem Stück doch eher im Funktionsumfang noch überschaubarer Software noch so viel ändern willst, daß sie morgen schon veraltet ist. Du könntest übrigens, damit Nutzer Deiner Software leicht sehen können, was sich getan hat, auf ein Versionskontrollsystem wie git zurückgreifen, und Deine Software auf gitlab o.ä. hosten. Wie fändest Du das?
Rufus Τ. F. schrieb: > Harry L. schrieb: >> Auf besonderen Wunsch von Rufus nochmal das aktuelle File als Anhang. > > Danke. > > > Allerdings ist die Frage schon gerechtfertigt, was Du an einem Stück > doch eher im Funktionsumfang noch überschaubarer Software noch so viel > ändern willst, daß sie morgen schon veraltet ist. > > Du könntest übrigens, damit Nutzer Deiner Software leicht sehen können, > was sich getan hat, auf ein Versionskontrollsystem wie git > zurückgreifen, und Deine Software auf gitlab o.ä. hosten. > > Wie fändest Du das? Ja, könnte ich. Wird wohl auch früher oder später da landen. Aktuell erweitere ich das um weitere Display-Typen - alles, was ich hier so finde. Am eigentlichen Code wird sich nicht mehr viel ändern. Für mich ist das nur ein Baustein eines anderen Projekt, den ich hier zur Verfügung stelle, weil die Frage danach bereits öfter auftauchte, aber der meiste Code, den man im Netz findet eben nicht für die I²C-Variante geeignet ist. Dachte nicht, daß das zu solchen Diskussionen führen würde.
Ok, also hier jetzt doch noch einmal eine Version als Anhang, da ich die inzwischen -für meine Bedürfnisse- als "ferig" betrachte. Was sich geändert hat: * ein Freund hat noch seine OLED-Varianten hinzugefügt. * der Code wurde aufgeräumt * zahlreiche Kommentare wurden hinzugefügt Was noch offen ist: * das Definieren von eigenen Zeichen - brauch ich derzeit nicht, und mach ich, wenn ich das brauche. Die (leere) Funktion gibt es bereits. Wenn jemand Lust hat, das zu ergänzen und zu testen.... bitte Mail an: dertrickreiche at gmail.com [Disclaimer] Die Software hat am 26.03.2019 um 23:00 hier in Witten auf ca. 180m ü.n.N. mit den verschiedensten Displays an einem Nucleo-F303RE funktioniert, und weitere Probleme konnte ich nicht identifizieren. take it or leave it!
:
Bearbeitet durch User
> [Disclaimer] > Die Software hat am 26.03.2019 um 23:00 hier in Witten auf ca. 180m > ü.n.N. mit den verschiedensten Displays an einem Nucleo-F303RE > funktioniert, und weitere Probleme konnte ich nicht identifizieren. > > take it or leave it! Das ist doch mal eine klare Aussage. :-)
Noch besser wäre es auf GitHub hochzuladen, dann kann es die Community unterstützen.
Ich hab die Funktion zum Definieren von eigenen Zeichen und ein Demo-Projekt hinzu gefügt. Außerdem wurde ein kleinerer Fehler beseitigt.
Harry L. schrieb: > Um das zu compilieren: > * Zip-File Im workspace-Folder entpacken > * die .ioc-Datei mit CubeMX öffnen und Projekt generieren. > * Projekt in Atollic importieren. > > Weder schön noch fertig... > > "Auf die Schnelle zusammen geklöppelt" - aber funktioniert. :) > Vielleicht kann es ja jemand brauchen. So. Also braucht man dafür zwingend einen Workspace (deiner Atollic IDE) und Cube. Wer nicht genau DAS vorliegen hat, kriegt ein Problem. Dein Projekt enthält rund 4 MB an diversesten CMSIS-Treibern und anderem Zeugs. Wird das tatsächlich für so eine kleine LCD-Ausgabe benötigt? Wohl eher nicht. Nun, deine eigene Einschätzung teile ich vollkommen, habe aber schwere Zweifel, ob das jemand wirklich gebrauchen kann. Wohlgemerkt: brauchen könnte es sicherlich mancher, aber brauchbar ist es eher nur auf deinem PC mit genau deiner Umgebung. Ich hätte mir eher eine dramatisch zusammengeschrumpfte Version vorstellen können, die nur aus 4 Dateien besteht: - display.h - display.c - i2c.h - i2c.c wobei erstere 2 Dateien unabhängig sind vom konkreten µC und nur vom Displaytyp abhängen - und nur i2c.c abhängig ist vom konkreten µC. Und idealerweise sollten diese Dateien auch unabhängig sein von Packages deiner IDE oder deines µC-Herstellers oder sonstigen Header- und Projekt-Dateien. W.S.
W.S. schrieb: > Und idealerweise sollten diese Dateien auch unabhängig sein von Packages > deiner IDE oder deines µC-Herstellers oder sonstigen Header- und > Projekt-Dateien. Was genau hast an "[STM32/HAL] generischer Treiber" nicht verstanden? Dieser Code ist für STM32 und HAL. Niemand zwingt dich, den zu nutzen! Um den in ein eigenes HAL-Projekt zu integrieren, benötigt man genau die folgenden 4 Files: lcd_i2c.c lcd_i2c.h lcd_config.h lcd_map.inc Und für Projekte mit HAL für STM32 nutzen wohl die meisten Attolic oder CubeIDE. Wer das nicht so macht, sollte wissen, was er tut, und in der Lage dein, diese 4 Files als notwendig zu identifizieren.
Harry L. schrieb: > Dieser Code ist für STM32 und HAL. > > Niemand zwingt dich, den zu nutzen! Eben. Du sagst es. Er ist nur für STM32 und HAL (und Atollic). Und mir ist vollkommen klar, daß mich niemand zwingt. Ich habe von Anfang an deine eigene Einschätzung geteilt. Das war auch nicht das Thema, sondern der Umstand, daß dein Treiber eben kein generischer Treiber für diese I2C-Displays ist, sondern eben ein sehr spezieller Treiber. Das ist so, müßte aber nicht so sein. W.S.
W.S. schrieb: > Das war auch nicht das Thema, sondern der Umstand, daß dein Treiber eben > kein generischer Treiber für diese I2C-Displays ist, Doch, genau das ist er: Ein generischer Treiber für STM32 mit HAL. Der läuft unverändert mit allen STM32 von M0 bis M7. W.S. schrieb: > Das ist so, müßte aber nicht so sein. Ach so? Dann zeig mir mal, wie du das Architektur-übergreifend machen willst, wenn sich die Peripherie zwischen ST und z.B. NXP komplett unterscheidet. Aber w.g.: das war auch zu keinem Zeitpunkt mein Anspruch.
@Harry: letztens hast du dich doch so sehr damit geschmückt, dass du jahrzehnte an Programmiererfahrung hast und dann weiste nichtmal wie man einen Treiber schreibt, der verschiedene I2C Hardware ansteuern kann? Selbst einen Treiber kann man aufteilen, in den Hardwareteil und in den Protokollteil (bei größeren Dingen gehen durchaus noch mehr Schichten). Der Protokolltreiber bekommt eben beim Init Funktionspointer für read/write/control Funktionen. Diese Funktionen sind dann der Hardwarespezifische Teil. So läuft bei uns auf Arbeit zB derselbe NOR Flash Treiber auf ST/NXP/Atmel ;) Aber du hast dich eben für den Vendor-Lock-In "HAL" entschieden mit Funktionsdirektaufrufen und Bugs ohne Ende.
1 | static struct st7789spicallbacks displayspi; |
2 | |
3 | static void display_ncs(uint8_t onoff){ |
4 | gpio_onoff(PORTA, 15, onoff); |
5 | }
|
6 | |
7 | static void display_dc(uint8_t onoff){ |
8 | gpio_onoff(PORTB, 4, onoff); |
9 | }
|
10 | |
11 | static void display_write(uint32_t bytes, uint8_t *buf){ |
12 | spi_w_bytes(DISP_SPI, bytes, buf); |
13 | }
|
14 | |
15 | static void display_read(uint32_t bytes, uint8_t *buf){ |
16 | spi_r_bytes_bidir(DISP_SPI, bytes, 0, buf); |
17 | }
|
18 | |
19 | void init_display(void){ |
20 | |
21 | // SPI GPIO+CLK init
|
22 | rcc_enable_clock(RCC_GPIOA); |
23 | gpio_initpin(PORTA, 15, GPO_PP, GPIO_HS, 0); // SPI_NSS |
24 | gpio_onoff(PORTA, 15, 1); |
25 | rcc_enable_clock(RCC_GPIOB); |
26 | gpio_initpin(PORTB, 4, GPO_PP, GPIO_HS, 0); // Data/Command |
27 | gpio_initpin(PORTB, 3, AF_PP, GPIO_HS, AF5_SPI1_TO_2); // SPI_SCK |
28 | gpio_initpin(PORTB, 5, AF_PP, GPIO_HS, AF5_SPI1_TO_2); // SPI_MOSI/MISO (bidir!) |
29 | rcc_enable_clock(RCC_SPI1); |
30 | |
31 | // SPI Init
|
32 | spi_init_master( |
33 | DISP_SPI, // SPI Base |
34 | 0, // LSB first = 1 |
35 | BR_DIV4, // CLK div -> 60MHz/4 = 15MHz |
36 | 0, // CPOL |
37 | 0, // CPHA |
38 | SPI_8BIT); |
39 | |
40 | // DMA CLK
|
41 | rcc_enable_clock(RCC_DMA1); |
42 | rcc_enable_clock(RCC_DMA2); |
43 | |
44 | // device descriptor init
|
45 | displayspi.ncs = display_ncs; |
46 | displayspi.dc = display_dc; |
47 | displayspi.write = display_write; |
48 | displayspi.read = display_read; |
49 | |
50 | // sw reset
|
51 | st7789spi_SWRESET(&displayspi); |
52 | sleep_ms(10); |
53 | |
54 | // display on
|
55 | st7789spi_SLPOUT(&displayspi); |
56 | sleep_ms(10); |
57 | st7789spi_DISPON(&displayspi); |
58 | st7789spi_NORON(&displayspi); |
59 | st7789spi_INVON(&displayspi); |
60 | |
61 | // Displaygröße
|
62 | st7789spi_CASET(&displayspi, 0, 239); |
63 | st7789spi_RASET(&displayspi, 0, 239); |
64 | |
65 | // 16bit RGB
|
66 | st7789spi_COLMOD(&displayspi, st7789_col16bit); |
67 | }
|
68 | |
69 | void display_sendout(struct gui_buf *buf, void (*callb)(void)){ |
70 | |
71 | if (dma_check_active(DISP_SPI_DMA)){ |
72 | /* dma is busy with last one */
|
73 | return; |
74 | }
|
75 | |
76 | if (0 == buf->ystart){ |
77 | st7789spi_RAMWR_commandonly(&displayspi); |
78 | }else{ |
79 | st7789spi_RAMWRC_commandonly(&displayspi); |
80 | }
|
81 | |
82 | display_ncs(0); |
83 | |
84 | int err = spi_dmamode( |
85 | DISP_SPI, // Welcher SPI |
86 | (uint8_t*)buf->buf, // SPI Sendebuffer |
87 | NULL, // SPI Empfangsbuffer |
88 | DISP_SPI_DMA, // DMA Sendestream |
89 | NULL, // DMA Empfangsstream |
90 | (buf->ysize*buf->xsize), // Anzahl der zu übertragenden Daten |
91 | SPI_8BIT, // Bitbreite auf dem SPI |
92 | callb_dma_spi_int, // IRQ Handler DMA |
93 | callb, // IRQ Handler DMA Daten |
94 | callb_dma_spi_irq_spi_err, // IRQ Handler SPI Err |
95 | NULL // IRQ Handler SPI Err Daten |
96 | );
|
97 | |
98 | if (err){ |
99 | display_ncs(1); |
100 | }
|
101 | }
|
Was dort zu sehen ist, ist mein HAL. Das ist dann wirklich ein echter HAL und nicht dieser STM32 möchtegern HAL. Dieser stell dem Programm Display init/send bereit. Somit kann meine Software auch ohne große Änderungen ein anderes Display ansteuern. Dabei initilisiert der HAL die STM32 Hardware und stellt das dann per Funktionspointer in einem Struct dem Displaytreiber bereit.
Ganz, gant toll, "dein HAL"! Diese wunderbare Trennung zwischen Schnittstelle und Display... Wenn man das Display nur mal -dem Layout geschuldet- an andere Pins anschließen will, muß an erstmal in deiner tollen Init-Funktion herumpfuschen. Genau SO wünscht man sich ja einen Abstraktions-Layer.... Daß ich ST HAL nutze ist bereits im Thread-Titel erkennbar, also nerv hier nicht weiter rum und geh mit W.S. ein Bier trinken! Ich hab absolut keinen Bock, mich ständig dafür rechtfertigen zu müssen, und schon gar nicht gegenüber Leuten, die das nur vom Hörensagen und/oder flüchtigen Blicken in den Code kennen, und dabei sowieso der Ansicht sind, alles so viel besser zu können.
Harry L. schrieb: > Ich hab absolut keinen Bock, mich ständig dafür rechtfertigen zu müssen Naja, das kommt ja nicht von ungefähr. So wie du in fast jedem STM32 Thread den HAL als das beste der Welt anpreist ;) Harry L. schrieb: > und schon gar nicht gegenüber Leuten, die das nur vom Hörensagen > und/oder flüchtigen Blicken in den Code kennen, und dabei sowieso der > Ansicht sind, alles so viel besser zu können. Also ich musste ja mal mit dem HAL arbeiten, das war einfach nur ein Graus und eine Schlangengrube an Bugs. Zudem hatte ich immer Konkrete Bugs dir gegenüber genannt, für dein fehlendes Kurzeitfedächtnis kann ich nix. Ist ja schön für dich, dass du nur Spielzeug entwickeltst und daher nicht auf diese Bugs stößt. Harry L. schrieb: > Wenn man das Display nur mal -dem Layout geschuldet- an andere Pins > anschließen will, muß an erstmal in deiner tollen Init-Funktion > herumpfuschen. Ach? Das ist bei deinem Projekt einfacher? CubeMX aufmachen, Pins ändern, Code neu erzeugen. Aber ja, das sollte noch per defines in den header, da jaste recht. (Das Projekt ist noch am entstehen)
Mw E. schrieb: > Harry L. schrieb: >> Wenn man das Display nur mal -dem Layout geschuldet- an andere Pins >> anschließen will, muß an erstmal in deiner tollen Init-Funktion >> herumpfuschen. > > Ach? Das ist bei deinem Projekt einfacher? > CubeMX aufmachen, Pins ändern, Code neu erzeugen. Hab kurz ins Projekt reingeschaut und seh auf die schnelle nur eine einzige Abhängigkeit des gesamten LCD Codes (Display-Eigenschaften und STM HAL ausgenommen). Jene Abhängigkeit ist vom Typ I2C_HandleTypeDef und wird sauber bei der Initialisierung übergeben. Bei deinem Code-Snippet oben zähl ich etwa 10 Abhängigkeiten und obwohl du irgnedwas von Funktionspointern schreibst is davon nichts zu sehn.
:
Bearbeitet durch User
Harry L. schrieb: > Ich hab absolut keinen Bock, mich ständig dafür rechtfertigen zu müssen, Also erstens habe ICH hier niemals so etwas von dir verlangt. Und zweitens wirst du akzeptieren müssen, daß andere Leute ihre eigene Meinung zu deinem Projekt haben und auch das Recht haben, selbig zu äußern. Und drittens kann ich das tatsächlich besser als du. Lies weiter: Harry L. schrieb: > W.S. schrieb: >> Das ist so, müßte aber nicht so sein. > > Ach so? > > Dann zeig mir mal, wie du das Architektur-übergreifend machen willst, > wenn sich die Peripherie zwischen ST und z.B. NXP komplett > unterscheidet. So. hier zeige ich es dir: Ich habe dir einen Auszug aus einem meiner Projekte drangehängt. Nur einen Auszug, sonst nichts. Es ist ein Treiber für eines der Displays, die Pollin im Programm hat bzw. hatte. Die Gemeinsamkeit mit deinem Projekt besteht darin, daß dieses Tian-Ma LCD auch ein alphanumerisches Display ist und daß es auch per I2C angesteuert werden muß. Daß es auch noch einen speziellen Resetpin hat, muß im Treiber berücksichtigt werden. Nun schau in die Zip-Datei und du findest dort tianma.c nebst tianma.h sowie i2c.h vor. Hierbei enthält der eigentliche Displaytreiber tianma.c nur den allernötigsten Bezug auf eine Zielplattform, der darin besteht, daß man mit irgend einem Pin das Resetbein des LCD ansteuern muß. Das ist der ganze Bezug auf die konkrete Plattform. Ich hätte das auch in einen Extra-Lowlevel-Treiber auslagern können, dann wäre der ganze Treiber tianma.c plattformunabhängig. Das physische Ansteuern des LCD erfolgt über den Treiber i2c.c, den ich hier aber nicht beifüge, da dieser eben hardwareabhängig ist. Dem Displaytreiber tianma.c kann und SOLL das auch egal sein, denn er baut auf dem Interface desjenigen I2C-Treibers auf, der zur konkreten Plattform paßt. Ich habe für die I2C-Ansteuerung mehrere Lowlevel-Treiber im Portfolio: sowohl solche, die die vorhandene I2C-Peripherie des Chips verwenden als auch einen, der rein softwaremäßig arbeitet und lediglich zwei beliebige Pins des Chips zugewiesen kriegen muß - allerdings müssen diese als Open Drain benutzbar sein und der tatsächliche Pinzustand muß lesbar sein (trifft z.B. für den LPC1114 nicht! zu). So, dieser Display-Treiber kann damit auf fast völlig beliebigen Plattformen benutzt werden, ARM, MIPS, PIC, MSP und so weiter. Einzig das o.g. Reset und ein allgemeiner I2C Lowlevel-Treiber müssen vorhanden sein. So macht man so etwas. Ich hoffe, daß du damit etwas dazugelernt hast. W.S.
W.S. schrieb: > Und drittens kann ich das tatsächlich besser als du. Lies weiter: Das seh ich nicht so. Es ist "anders" und nicht "besser". Bei deinem Beispiel muss I2C Code hinzugefügt werden. Das Beispiel ganz oben ist plug&play tauglich. Ansonsten ist der Code trotz all deiner Überheblichkeit ziemlich ähnlich. Er unterscheidet sich eigentlich nur darin dass die HAL-Aufrufe als Customization-Points herausgeführt sind.
W.S. schrieb: > Und drittens kann ich das tatsächlich besser als du. Wissen wir alle bereits. Deine unerträgliche Arroganz nervt! W.S. schrieb: > So macht man so etwas. Nein, nur du meinst, daß man "es so macht". Dein Code ist wie üblich gespickt mit Magic Numbers und wird dadurch nicht gerade lesbarer. Dein I²C-Code (lt. i2c.h) bildet auch nur die minimale Funktionalität ab. So lange das Display das Einzige ist, was an diesem Bus hängt mag das ausreichend sein, aber sobald da noch was Anderes dranhängt, für das man evtl. Interrupts benötigt, fängt man wieder von Vorne an. Das geht mit HAL deutlich besser und komfortabler, aber, das wirst du ohnehin nicht akzeptieren, da du ja offenbar keine anderen Götter neben dir duldest... Also verschon mich mit deinen "Weisheiten" von vor >20J. Ich schau mir gerne bei Leuten, die das wirklich können Coding-Techniken ab, aber dein Code gehört definitiv nicht dazu.
:
Bearbeitet durch User
Harry L. schrieb: > Also verschon mich mit deinen "Weisheiten" von vor >20J. Sehe ich genauso. W.S. meint desöfteren, Code hier in P&C schlechtzumachen, nur weil er nicht so programmiert wurde, wie er es machen würde. Statt einen eigenen Thread unter "Projekte und Code" aufzumachen, um seinen Code vorzustellen, redet er mittels Binsenweisheiten, die jedes kleine Kind bereits kennt, erstmal alles platt. P.S. Der Code von W.S. ist gespickt mit gotos innerhalb von while-Schleifen, wo ein einfaches "break" denselben Effekt hätte. "break" scheint er aber nicht zu kennen. Naja, C ist nicht gerade seine Stärke.
:
Bearbeitet durch Moderator
Harry L. schrieb: > und geh mit W.S. ein Bier trinken! Lieber nich, seine Magic Numbers kann er behalten. Harry L. schrieb: > also nerv > hier nicht weiter rum Da würde ich dich bitten dies auch nicht in anderen Threads zu tun mit deinem HAL Fanboytum.
@Harry Vielen Dank für die Mühe und die Veröffentlichung. Gruß Daniel
Frank M. schrieb: > Der Code von W.S. ist gespickt mit gotos innerhalb von while-Schleifen, > wo ein einfaches "break" denselben Effekt hätte. "break" scheint er aber > nicht zu kennen. Ach nö. Ich kenne break durchaus, genauso wie for, mag beides jedoch nicht wirklich. Und? Break ist hier die schlechtere Wahl, weil es ne ganze Kette von Aufrufen gibt, bei denen man die folgenden nicht ausführen darf, wenn der vorherige ein false geliefert hat - also ist ohnehin goto angesagt. Alternativ könnte man daraus ein tief verschachteltes if(.... if(... machen, aber das ist nun wirklich unleserlich. Der eigentliche Punkt ist jedoch, daß dieser Treiber für das besagte LCD eben wirklich weitestgehend unabhängig ist von Plattform, Compiler und Hersteller. Der Code des TO hingegen ist strikt an ST und deren Zeugs gebunden, was dessen Verwendung eben genau so einschränkt, wie ich das weiter oben geschrieben habe. Plattformunabhängig macht man sowas, indem man aus einem Treiber alles herausnimmt, was plattformabhängig ist und selbiges in einem quasi darunter liegenden Treiber hat. Der wiederum braucht sich nicht um die Befindlichkeiten eines LCD's zu scheren. Genau DAS wollte der TO ausdrücklich gezeigt kriegen - und ich habe es ihm gezeigt! Also mault nicht herum. W.S.
W.S. schrieb: > Break ist hier die schlechtere Wahl, weil es ne ganze Kette von Aufrufen > gibt, bei denen man die folgenden nicht ausführen darf, wenn der > vorherige ein false geliefert hat - also ist ohnehin goto angesagt. Unsinn. Hier ein Beispiel, ich habe mir direkt mal Deine Funktion LCD_BufOut() herausgepickt:
1 | bool LCD_BufOut (void) |
2 | { int i; |
3 | bool erg; |
4 | |
5 | erg = Do_I2C_Start(LcdAdr, I2CWRITE); |
6 | if (!erg) goto raus; |
7 | |
8 | erg = Do_I2C_Write(0x80); // CO=1, RS=0 -> Control schreiben |
9 | if (!erg) goto raus; |
10 | |
11 | erg = Do_I2C_Write(2); // Home |
12 | if (!erg) goto raus; |
13 | |
14 | erg = Do_I2C_Write(0x80); // CO=1, RS=0 -> Control schreiben |
15 | if (!erg) goto raus; |
16 | |
17 | erg = Do_I2C_Write(0x80); // set DDRAM Adr |
18 | if (!erg) goto raus; |
19 | |
20 | erg = Do_I2C_Write(0x40); // CO=0, RS=1 -> Daten schreiben |
21 | if (!erg) goto raus; |
22 | |
23 | i = 0; |
24 | while (i<cbuflen) |
25 | { erg = Do_I2C_Write(LCDBUF[i]); |
26 | if (!erg) goto raus; |
27 | ++i; |
28 | }
|
29 | raus:
|
30 | Do_I2C_Stop(); |
31 | return erg; |
32 | }
|
Umgeschrieben ohne goto:
1 | bool LCD_BufOut (void) |
2 | {
|
3 | int i; |
4 | bool erg = false; |
5 | |
6 | if (Do_I2C_Start(LcdAdr, I2CWRITE) && |
7 | Do_I2C_Write(0x80) && // CO=1, RS=0 -> Control schreiben |
8 | Do_I2C_Write(2) && // Home |
9 | Do_I2C_Write(0x80) && // CO=1, RS=0 -> Control schreiben |
10 | Do_I2C_Write(0x80) && // set DDRAM Adr |
11 | Do_I2C_Write(0x40)) // CO=0, RS=1 -> Daten schreiben |
12 | {
|
13 | erg = true; |
14 | |
15 | for (i = 0; i < cbuflen; ++i) |
16 | {
|
17 | if (! Do_I2C_Write(LCDBUF[i])) |
18 | {
|
19 | erg = false; |
20 | break; |
21 | }
|
22 | }
|
23 | }
|
24 | Do_I2C_Stop(); |
25 | return erg; |
26 | }
|
Meine Variante ist nicht nur kürzer, sondern auch noch lesbarer, weil der Lesefluss nicht mehr durch die dauernden Aufrufe von gotos behindert wird. Dabei musste ich noch nichtmals auf Deine Platzspartricks wie die Positionierung von Statements nach '{' zurückgreifen. Die Krücke von while-Schleife habe ich direkt mal zwecks besserer Lesbarkeit in eine for-Schleife geändert. > Alternativ könnte man daraus ein tief verschachteltes if(.... if(... > machen, aber das ist nun wirklich unleserlich. Unsinn, das ist nix tief verschachtelt. Gegenbeweis siehe oben: Man sieht jetzt schön die Reihenfolge der Bytes, die da fließen. Die Funktionskette im if-Statement wird von oben nach unten abgearbeitet und automatisch abgebrochen, sobald einer der Aufrufe false zurückliefert. Das dauernde Setzen der Variablen erg kann man sich auch dabei sparen. > Der eigentliche Punkt ist jedoch, daß dieser Treiber für das besagte LCD > eben wirklich weitestgehend unabhängig ist von Plattform, Compiler und > Hersteller. Mit dem Editor brauche ich weniger als eine Minute, um per Global-Replace den Aufruf der HAL-I2C-Funktionen auf eine Mapper-Funktion zu ändern. Das habe ich übrigens so gemacht, um meine eigene I2C-Lib ohne HAL hier einzubinden. Das ist überhaupt keine Kunst. > Der Code des TO hingegen ist strikt an ST und deren Zeugs > gebunden, was dessen Verwendung eben genau so einschränkt, wie ich das > weiter oben geschrieben habe. Du lamentierst stundenlang über eine Sache, die sich in wenigen Sekunden beheben lässt. P.S. Du scheinst ein Problem mit der Bezeichnung "generisch" zu haben. Dieses "generisch" bezog der TO auf die STM32-Familie durch Verwendung von HAL. Zugegeben: ich mag auch kein HAL, aber deshalb hänge ich mich nicht stundenlang an einer Bezeichnung auf, indem ich sie absichtlich missverstehe.
:
Bearbeitet durch Moderator
Wenn W.S. vom C Programmieren erzählt klingt das so als würde ein Blinder vom Sehen erzählen.
Frank M. schrieb: > W.S. schrieb: >> Break ist hier die schlechtere Wahl, weil es ne ganze Kette von Aufrufen >> gibt, bei denen man die folgenden nicht ausführen darf, wenn der >> vorherige ein false geliefert hat - also ist ohnehin goto angesagt. Befindlichkeiten mit angeblicher Expertenkenntnis um sich selber hoch herauszustellen. > Unsinn. Hier ein Beispiel, ich habe mir direkt mal Deine Funktion > LCD_BufOut() herausgepickt: > ... > Umgeschrieben ohne goto: > ... > Meine Variante ist nicht nur kürzer, sondern auch noch lesbarer, weil > der Lesefluss nicht mehr durch die dauernden Aufrufe von gotos behindert > wird. Wirklich gut! Sehr viel lesbarer, kürzer und logischer aufgebaut. So wünsche ich mir Code von Entwicklerkollegen. Ich würde sogar noch weiter gehen und die Bitpatterns per #define o.ä. mit lesbaren Namen versehen. Ist schneller zu verstehen und man ändert das bei Bedarf an einer einzigen Stelle und fertig. W.S. schrieb: > So, dieser Display-Treiber kann damit auf fast völlig beliebigen > Plattformen benutzt werden, ARM, MIPS, PIC, MSP und so weiter. Einzig > das o.g. Reset und ein allgemeiner I2C Lowlevel-Treiber müssen vorhanden > sein. > > So macht man so etwas. Ich hoffe, daß du damit etwas dazugelernt hast. Ohje, ohje: Heute noch 'goto' außerhalb der Sondererlaubnis im Linux-Kernel zu benutzen und sich über andere Leute aufzuregen ist schon wirklich ziemlich hart. Und ich dachte immer, daß hier alles nur Profis unterwegs sind, wenn sie sich derart hervortun. Muß wohl meine Wahrnehmung mal neu justieren.
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.