Forum: Mikrocontroller und Digitale Elektronik Denke ich zu kompliziert?


von jay (Gast)


Lesenswert?

Hallo miteinander,

ich würde an dieser Stelle gerne was ansprechen, was mich schon länger
interessiert.

Kurz noch bischen was zu mir: Ich habe vor ein paar Jahren 
Elektrotechnik studiert. Schon zu Beginn habe ich mit den Atmel 
Prozessoren herumgespielt.
Einfache, kleine Projekte durchgezogen, die irgendwie funktioniert 
haben.

Nach dem Studium bin ich hatte ich Glück eine Stelle als 
Embedded-Software
Entwickler zu kriegen. Im Automotive-Umfeld, also Steuergeräte-Software, 
wenn man so sagen will.

Größtenteils werden die Applikationen ja nur noch generiert, z.B. mit 
MATlab. Was allerdings weiterhin per Hand geschrieben wird sind die 
Basissoftware, also Hardware-"Treiber", Betriebssysteme, 
Kommunikationsstacks etc.

Dank Standards wie AUTOSAR wurden die Softwarearchitekturen ja teilweise
strukturiert und genormmt.
Es gibt (teils mehrere) Abstraktionsschichten, genau definierte 
Schnittstellen etc.

Grundsätzlich alles sehr durchdacht und nützlich im produktiven (und
Sicherheitskritischen!) Umfeld.

Allerdings ertappe ich mich immer mehr dabei meine Spielereien zuhause 
auch derart strukturieren zu wollen wie ichs im Beruf gewohnt bin.

Natürlich schaded Struktur auch bei schwachbrüstigeren Prozessoren 
zuhause nicht.

Mir fällt aber auf, dass die meisten Projekte hier ziemlicher Wildwuchs 
sind.
Ich rede nicht von Anfängerfragen sondern Projekten von fähigen Leuten, 
Programmierer, vor denen ich meinen Hut ziehe. Gutes Beispiel wäre da 
vielleicht die berühmte PeDa Entprellroutine. Teils wilde 
Bitmanipulationen, gemixt mit Hardwarezugriffen. Zwar perfekt optimiert, 
aber mich wunderts nicht wieso Anfänger damit oft Probleme haben.

Ich selbst verwende meist ein (einfaches) Zeitscheibenbetriebssystem. Da 
würd ich z.B. in einem häufigen Task die Entprellung durchführen. Der 
Interrupt gehört dem Betriebssystemtimer, da hat der Benutzer (auch 
wenns ich selbst bin) nichts verloren :-)

Von Hardware- und Registerzugriffe abstrahiere ich auch komplett. Meine
"Applikation" würde eine Status-Led nie durch "PORTA |= (1 << 
STATUS_LED);" einschalten sondern eher durch 
"Dio_WriteChannel(STATUS_LED, TRUE);".
Wie diese Funktion das dann mappt (multiplexed? active-high oder -low?)
interessiert die "Applikation" garnicht.

Findet ihr das schon übertrieben? Wie handhabt ihr das? Kennt ihr mein 
Problem?

Mir ist auch klar dass ich auf die Art auf nem Atmel nie Dinge wie eine 
VGA-Karte implementieren könnte. (Dafür gibts ja Assembler :-))

Letzendlich hab ich wohl ein Luxusproblem weil mittlerweile auch für 
zuhause relativ viel Leistung erhältlich ist.

von Reinhard Kern (Gast)


Lesenswert?

jay schrieb:
> "Dio_WriteChannel(STATUS_LED, TRUE);".
> Wie diese Funktion das dann mappt (multiplexed? active-high oder -low?)
> interessiert die "Applikation" garnicht.

Es ist absolut sinnvoll, eine "Hardware Abstraction Layer" HAL 
einzuziehen, auch schon bei kleinsten Projekten. Ich benutze für jedes 
Stück Hardware Unterprogramme zum Schalten oder Steuern, meist in 
Assembler. Sowas wie SetLed (Nummer, EinAus) oder MotorSpeed (Drehzahl).

Gruss Reinhard

von Karl H. (kbuchegg)


Lesenswert?

jay schrieb:

> Kennt ihr mein
> Problem?

Natürlich.

Man muss den goldenen Mittelweg finden zwischen zuviel und zuwenig 
'Bürokratie'. Da du auf einem AVR kein Betriebssystem hast, musst du in 
dein Programm mehr oder weniger die Teile des BS mit 'einbauen', die du 
brauchst. Und da gibts dann eben verschiedene Sichtweisen.

Die angesprochene 'Entprellung' würde sich ein einer regulären 
Applikation/BS/Treiber Architektur ja im Treiber wiederfinden. Also an 
einer Stelle an der auch in deiner hochgelobten (nicht böse gemeint) 
BS-Architektur jede Schweinerei erlaubt ist. Von daher ist da auch 
nichts dabei, wenn der ISR Code für viele ein Buch mit 7-Siegeln ist. 
Und es ist auch nichts dabei, wenn man nicht versteht wie diese 
Entprellung funktioniert. Oder verstehst du wie die Socket-Library zur 
Netzwerkanbindung speziell in den unteren Schichten ganz genau 
funktioniert? Wohl eher nicht - was dich aber nicht daran hindert, sie 
zu verwenden.

von (prx) A. K. (prx)


Lesenswert?

jay schrieb:
> Ich selbst verwende meist ein (einfaches) Zeitscheibenbetriebssystem. Da
> würd ich z.B. in einem häufigen Task die Entprellung durchführen. Der
> Interrupt gehört dem Betriebssystemtimer, da hat der Benutzer (auch
> wenns ich selbst bin) nichts verloren :-)

Kann man so machen, muss man so nicht machen. Multitasking mit allem 
Gedöns ist bei einem kleinen Einstiegs-8051 etwas fehl am Platze. Genau 
da kommt PeDa aber her.

Ansonsten gibts keinen Grund, päpstlicher zu sein als der Papst. Es 
spricht nämlich nichts dagegen, in dem Interrupt-Handler vom Timer eine 
Liste von Funktionen aufzurufen, neudeutsch Callbacks genannt. Den Umweg 
über Tasks muss man nicht in jedem Fall gehen.

> "Dio_WriteChannel(STATUS_LED, TRUE);".
> Wie diese Funktion das dann mappt (multiplexed? active-high oder -low?)
> interessiert die "Applikation" garnicht.

Echte Abstraktion geht andersrum. Eine Klasse/Funktionsgruppe für die 
Statusanzeige. Sowas wie
   statusDisplay.activate();
Wie das darin dann realisiert wird, ist Sache von deren Implementierung.

von jay (Gast)


Lesenswert?

A. K. schrieb:
> Echte Abstraktion geht andersrum. Eine Klasse/Funktionsgruppe für die
> Statusanzeige. Sowas wie
>    statusDisplay.activate();

Naja, du führst hier eher eine zusätzliche Zwischenschicht ein, als 
"andersrum" würd ich das nicht bezeichnen.
Und ja, auch sowas mach ich gelegentlich. Spätestens wenn mehr Logik 
nötig ist als nur 1 Funktionsaufruf wie im Status_Led Beispiel.

Ich finde es interessant dass ich noch nicht komplett in der Luft 
zerissen wurde für meine Ansichten. Dieses Forum schätze ich eher wegen 
seinem hochoptimierten anstatt übersichtlichen Code :-)

von Thomas_L (Gast)


Lesenswert?

Schau dir mal die Entwicklungsumgebung des Arduino an, da wird genau das 
gemacht was Du da beschreibst. Die Arduino-bibliothek hat Funktionen für 
den üblichen Standardkram (Port ein, aus, ADC auslesen, Text über die 
serielle Ausgeben etc... ). Da aber die Handassemblierung auf einem 
Blatt Papier und die anschließende Eingabe des Binärcodes über 
Dipschalter der einzg professinelle Weg ist, ist die Verwendung von 
Entwicklungsumgebungen und Bibliotheken böse und gotteslästerlich, denn 
schon in der Biebel steht:" Unter Schmerzen sollst du deine Programme 
entwickeln".
Amen!

Ps: Wer in diesem Text Satiere findet kann sie gerne behalten mit nach 
Hause nehmen. ;-)

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

jay schrieb:
> Dieses Forum schätze ich eher wegen
> seinem hochoptimierten anstatt übersichtlichen Code :-)

Wenn du so eine Implementierung ordentlich machst, bekommst du es
trotzdem hin, dass dein
1
statusDisplay.activate();

zu einem
1
sbi PORTA, 5

zusammendunstet. ;-)

von Peter D. (peda)


Lesenswert?

jay schrieb:
> Gutes Beispiel wäre da
> vielleicht die berühmte PeDa Entprellroutine. Teils wilde
> Bitmanipulationen ...

Weil einige Leute das EXOR exotisch finden, würde ich es trotzdem nicht 
als "wild" bezeichnen.
Es sind ganz normale logische Verknüpfungen, die statt nur auf einem Bit 
auf einer Wortbreite arbeiten und somit mehrere Entpreller parallel 
darstellen.

Old School entspricht das einer Schleife über ein Array mit if/else 
Auswertung. Nur eben schneller und kleiner.
Es gibt auch Aufgaben, wo ein ATtiny13 völlig reicht und dann kann 
sparsamer Speicherverbrauch eine Rolle spielen. Und bequemer Weise nimmt 
man dann eben für einen Cortex M3 einfach den gleichen Code.

Daß es im Timerinterrupt läuft, ist auch nur eine Variation, wenn man 
kein RTOS benutzt. Man kann natürlich auch eine Task aufsetzen.


jay schrieb:
> ... gemixt mit Hardwarezugriffen.

Der einzige Hardwarezugriff ist das Port Einlesen und das kann man nicht 
weglassen.
Das kann natürlich auch eine Funktion sein, wie z.B. bei der 
Tastaturmatrix mit ADC.

jay schrieb:
> Zwar perfekt optimiert,
> aber mich wunderts nicht wieso Anfänger damit oft Probleme haben.

Das Problem der Anfänger ist eher die Einsicht, warum man das Entprellen 
braucht und warum man es nicht mit Warteschleifen machen sollte.
Und das Entprellen von Tasten und Encodern ist eine Aufgabe, die oft 
nichtmal "richtige" Programmierer zufriedenstellend lösen können. Das 
ist also nicht nur ein Anfängerproblem.


Prinzipell hast Du natürlich Recht, daß sich der Programmierstil für nen 
kleinen 8Bitter gegenüber z.B. Windows deutlich unterscheidet.
Man hat dann nicht die Zeit und Lust, viele Zwischenschichten zu 
implementieren.
Auch verliert man dann den Überblick über die Ausführungszeit und das 
Echtzeitverhalten spielt bei hardwarenaher Programmierung ja eine sehr 
große Rolle.
Bekannter Maßen haben große Systeme deshalb oft Schwierigkeiten mit 
Echtzeit und lagern dann solche Aufgaben z.B. in einen FPGA aus.

Ein Mainloop+Interrupt Programm läßt sich dagegen sehr leicht auf 
Einhaltung der Echtzeit verifizieren.


Peter

von mens profunda (Gast)


Lesenswert?

Das ist eine absolute Unsitte. Genauso wie irgendwelche Makro-Akrobatik. 
Man verwendet die Standardsyntax. Es gibt nichts nervigeres als sich in 
ein Programm einlesen zu müssen, bei dem ein Künstler C zu irgendeinem 
kranken Dialekt verbogen hat. Wozu muss ich erst einen Berg von 
Sourcedateien durchforsten um die scheiss Definition von 
Dio_WriteChannel() zu finden?

Gerade im Embeddedbereich sollte die Vermeidung unnötiger Komplexität 
und damit die Reduzierung der LOC auf das nötigste oberste Priorität 
haben.

Aber wenn ich mir die Posts oben so durchlese, dann ist klar, warum man 
auf der Autobahn öfters neue deutsche Luxuskarossen mit Warnblinker auf 
dem Standstreifen stehen sieht oder warum beim Eurofighter gerne mal 
mitten im Flug alle Displays ausfallen.

von der Neue (Gast)


Lesenswert?

Auf jeden Fall mal ein Aspekt den man nicht (nur) außer Acht lassen 
darf.

Zu sehr verzetteln, wenn ich das mal so nenne, führt zu Wasserköpfen. 
Und das wird natürlich auch im embedded zunehmen wenn sich 
Softwarespezialisten analog der PC Programmierung austoben können weil 
ja nunmal die Leistung da ist und keine Notwendigkeit herrscht zu 
kleckern.

Daß das schwarz/weiß ist, weiß glaube ich jeder, aber man muss wie immer 
auch mal beide Seiten der Medaille betrachten. Und der Vergleich zu den 
blinkenden Autos hinkt ja (leider) nicht mal. Zumal der Autor seine 
Vorgehensweise ja als impliziert überlegen annimmt.

von Wilhelm F. (Gast)


Lesenswert?

jay schrieb:

> Allerdings ertappe ich mich immer mehr dabei meine Spielereien zuhause
> auch derart strukturieren zu wollen wie ichs im Beruf gewohnt bin.

Das ist ja im Grunde nicht schlecht. Man hat im Beruf was gelernt, was 
nicht nur Frickelei ist. Früher hatte ich in meiner Hobby-Software nie 
Define-Gräber, heute schon. Weil ich den Sinn begriff.

Apropos: Was genau ist HAL? Ist damit auch der andere Begriff 
"Kapselung" gemeint? Ein Kollege damals in einem anderen Team sprach mal 
von Kapselung bspw. der I/O, das wäre besser für spätere 
Änderungen/Anpassungen.

Alles wird man nie mehr lernen, also, man wird quasi eines Tages mal 
etwas dumm sterben. Deswegen kann ich heute auch mal gerne Fünfe gerade 
sein lassen.

von Läubi .. (laeubi) Benutzerseite


Lesenswert?


von Wilhelm F. (Gast)


Lesenswert?

Läubi .. schrieb:

> Wilhelm Ferkes schrieb:
>> Was genau ist HAL?
> Hardware Abstraction Layer:
> http://de.wikipedia.org/wiki/Hardwareabstraktionsschicht

Danke, Läubi.

Also was, was ich schon kenne. Nur ein neumodischerer Begriff.

von Bronco (Gast)


Lesenswert?

jay schrieb:
> Findet ihr das schon übertrieben? Wie handhabt ihr das? Kennt ihr mein
> Problem?

Meine Wenigkeit hat den gleichen beruflichen Hintergrund.
Und ja, ich mach es so strukturiert, und zwar weil es mir Spaß macht.
Ich erzeuge mir für meinen 16-Bit-PIC automatisch Code per Perl-Skripten 
aus XML-Config-Dateien. Ich hab x Schichten, die alle gegeneinander 
kapseln und abstrahieren. Und bei mir wissen die höheren 
Software-Schichten nichts mehr davon, auf was für einem µC sie laufen 
(d.h. PORTA etc. ist dort gar nicht mehr bekannt).
Und das alles, weil es mir Spaß macht und ich es schön finde.

von Storm (Gast)


Lesenswert?

Bronco schrieb:
> Und das alles, weil es mir Spaß macht und ich es schön finde.

Wenn es dich glücklich macht...

Bei uns in der Firma hat der Chef selber noch 8051 programmiert, deshalb 
würde jemand mit deiner Einstellung nicht lange bei uns überleben :-)

Bei uns heisst eher die Devise: klar strukturierter und 
nachvollziehbarer Code, das vorher auf Papier / Whiteboard entwickelt 
wurde und durch Diskussionen "nachgereift" hat. Struktur: sehr oft ein 
etwas größerer state-machine.

Vorteil: wir schließen unsere Projekte trotz 70% Softwareanteil in der 
Regel innerhalb der geplanten Zeit ab (allerdings programmieren bei uns 
ausschließlich Elektroingenieure, wir haben keinen einzigen 
Informatiker).

von Wilhelm F. (Gast)


Lesenswert?

Bronco schrieb:

> Und das alles, weil es mir Spaß macht und ich es schön finde.

Macht Abstrahierung den Code nicht lahmer?

von Walter T. (nicolas)


Lesenswert?

Thomas_L schrieb:
> Schau dir mal die Entwicklungsumgebung des Arduino an, da wird genau das
> gemacht was Du da beschreibst. Die Arduino-bibliothek hat Funktionen für
> den üblichen Standardkram (Port ein, aus, ADC auslesen, Text über die
> serielle Ausgeben etc... ).

Er hat "Jehovah" gesagt...

Komisch, auch ich ertappe mich immer wieder, die Zeitschlitze, die 
früher gemütlich in der Hauptschleife liefen so schnell sie konnten in 
zyklisch aufgerufene "Tasks" zu verpacken. Auch die Abstraktion durch 
eine immer weiter gewachsene Ansammlung an Libraries nimmt eher zu, so 
daß viele Sachen dann eher extrem herkömmlich aussehen (rs232_putc, 
i2c_putc, lcd_putc, glcd_putc). So µC-Aussehsachen ("PORTD |= (1 << 
PD1);") finde ich nur noch

a) an aktuellen Baustellen, und
b) bei Debug-Code
c) in den "unteren Layern".

"Codegräber" sind dann eher Projekte, wo Konzepte schnell "mal eben" 
ausprobiert werden oder extrem effiziente Programmierung notwendig ist. 
Und genau darin sehe ich auch den Grund, warum diese hier so häufig 
auftauchen: Oft hat hier auftauchender Quelltext nur einen einzigen 
Grund oder nur eine einzige Funktion oder einen noch wenig 
konsolidierten Zwischenstand.
Unter die erste Kategorie fallen oft die Standardlösungen "wie geht 
das?" (z.B. Tasterentprellung).
Unter die zweite Kategorie fallen die "kleinen Geistesblitze": Extrem 
einfache und doch extrem nützliche Kleinprojekte (z.B. I2C-Sniffer) und
unter die letzte Kategorie fällt der Großteil der hier veröffentlichten 
Projekte.

Größer und langfristig wachsende Projekte werden ja weniger gepostet und 
diskutiert als auf eigene Projektseiten ausgelagert. Also ist die 
Einschätzung eher dem Foren-BIAS geschuldet.

Viele Grüße
Nicolas

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Storm schrieb:
> Bei uns in der Firma hat der Chef selber noch 8051 programmiert, deshalb
> würde jemand mit deiner Einstellung nicht lange bei uns überleben :-)

Das erinnert mich an die Firma, die Steuergeräte für Baumaschinen
baut.  Hat mal jemand hier berichtet ...  Darin werden keinerlei
Interrupts benutzt, weil der Cheffe auch mal 8051 programmiert hat
und das Prinzip von Interrupts nie verstanden hatte. =:-)

Nur, weil der Chef mal irgendwann irgendwas irgendwie gelernt hat,
heißt das allein noch nicht, dass es ein halbes Jahrhundert später
immer noch eine zweckmäßige Vorgehensweise wäre.

Wilhelm Ferkes schrieb:
> Macht Abstrahierung den Code nicht lahmer?

Nur, wenn man nicht ordentlich drüber nachdenkt.

von Reinhard Kern (Gast)


Lesenswert?

Wilhelm Ferkes schrieb:
> Macht Abstrahierung den Code nicht lahmer?

Wenn man ausschliesslich danach geht, dürfte man seinen Code überhaupt 
nicht strukturieren - jeder Unterprogrammaufruf kostet nun mal mehr als 
ein direkt durchlaufendes Programm. Andersrum, ein optimal schnelles 
Programm wäre unleserlich. Man strukturiert aber ja im Interesse der 
Wartbarkeit und Wiederverwendbarkeit. Es gibt in der Praxis nur wenige 
Fälle, wo man in Assembler die Ausführungszeit jeder einzelnen 
Instruktion berücksichtigen muss, da muss man dann in Kauf nehmen, dass 
es (höchstens) einen einzigen Programmierer gibt, der das Programm 
versteht, für die grosse Masse an Software gilt das nicht. Viel 
wichtiger ist, dass man bei der nächsten Waschmaschine nicht wieder von 
vorne anfangen muss.

Gruss Reinhard

von Edson (Gast)


Lesenswert?

jay schrieb:
> Ich selbst verwende meist ein (einfaches) Zeitscheibenbetriebssystem. Da
> würd ich z.B. in einem häufigen Task die Entprellung durchführen. Der
> Interrupt gehört dem Betriebssystemtimer, da hat der Benutzer (auch
> wenns ich selbst bin) nichts verloren :-)

Das halte ich keinesfalls für zu kompliziert gedacht, sondern praktisch. 
Viele (Hobby-)Projekte benötigen aber nicht mal ein solches einfaches 
Betriebssystem weil sie nur einen Haupt-Task besitzen. Und da ist die 
Entprellroutine im Timerinterrupt eben gut aufgehoben. Du kannst 
natürlich auch für einfache Dinge einen generellen Ansatz verwenden, als 
Profi ist man dazu ja auch angehalten - aber im Hobby möchte man 
vielleicht auch mal den Spaß haben, eine spezielle Aufgabe mit einem 
speziellen Controller auf eine sehr individuelle Weise zu lösen. Was ich 
als komplizierter ansehe, aber trotzdem liebe und auch gerne mache. 
Meine Freizeitprojekte, viele sind es ohnehin nicht, beinhalten beides. 
Also hardwarenahes Bit-schubsen manchmal überdeckt von abstrahierten 
Schichten, machmal "pur".

Um auf deine Frage zu antworten: nein, ich glaube nicht.

von jay (Gast)


Lesenswert?

mens profunda schrieb:
> Wozu muss ich erst einen Berg von
> Sourcedateien durchforsten um die scheiss Definition von
> Dio_WriteChannel() zu finden?

Ich finde eher, andersherum wird ein Schuh draus.
Eben genau durch diese Abstraktion weis ich doch sofort, was Sache ist.

Ich habe z.B. vor Kurzem erst ein Projekt übernommen, dass sich im 
Endstadium befindet. Nur noch gelegentliche Bugfixe und ChangeRequests 
kommen da rein.

Da die Software (genauer: die Schnittstellen) zu geschätzten 60% 
identisch mit der meines letzten Projekts waren (das nebenbei bemerkt 
auf einem anderen Prozessor lief) konnte ich mich sehr schnell 
einarbeiten. Die Applikation (und damit der komplete Sinn und Zweck der 
ECU) waren natürlich anders.

Man kann vieles über das "Bürokratiemonster" AUTOSAR sagen, und bestimmt 
nicht nur positives. Aber deine Liegengebliebenen Autos folgen bestimmt 
nicht aus der strengen Softwarearchitektur sondern generell aus dem 
Anstieg an LOC im Auto.
Stell dir vor, die selbe Zunahem an LOC hätte komplett 
unstrukturiert/unabstrahiert stattgefunden...

Aber ich schweife zu sehr ab. Es geht ja ums private, nicht ums 
Geschäft.

Mir macht es übrigens auch Spaß, die Architektur zu durchdenken und zu 
planen.

Und ja, zum debuggen haue ich auch mal ein PORTA |= ... irgendwo rein 
:-)

von Bronco (Gast)


Lesenswert?

Jörg Wunsch schrieb:
> Das erinnert mich an die Firma, die Steuergeräte für Baumaschinen
> baut.  Hat mal jemand hier berichtet ...  Darin werden keinerlei
> Interrupts benutzt, weil der Cheffe auch mal 8051 programmiert hat
> und das Prinzip von Interrupts nie verstanden hatte. =:-)

Ich hatte mal einen Chef, der lieber "+ 0xFFFF" geschrieben hat als "- 
1", weil dies auf dem 8051 angeblich schneller sei. Natürlich ohne 
jeglichen Kommentar, was er eigentlich vor hatte.
Daß wir MSP430 programmiert haben, war nebensächlich.

von W.S. (Gast)


Lesenswert?

jay schrieb:
> Ich selbst verwende meist ein (einfaches) Zeitscheibenbetriebssystem. Da
> würd ich z.B. in einem häufigen Task die Entprellung durchführen. Der
> Interrupt gehört dem Betriebssystemtimer, da hat der Benutzer (auch
> wenns ich selbst bin) nichts verloren :-)

Du siehst dich selbst zweigespalten auf dem uC? Einmal als Benutzer und 
das andere Mal als was bitte?

Meine Meinung zu deinem Problem: Wer beruflich mit sicherheitsrelevanten 
Dingen umgehen muß, muß sich dort auch den Vorgaben beugen und so 
entwickeln, daß es branchenkonform ist - auch wenn es mit etwas Abstand 
betrachtet ziemlich aufgebläht wirkt. Das ist soweit klar.

Aber für alle anderen Betätigungsfelder sollte man die Sache etwas 
kritischer sehen: aufgeblähte Konstukte sind selten bis nie wirklich 
gut. Ein übles Beispiel ist die ST-Library für deren Cortexe. Igitt, 
extrem aufgebläht und dennoch alles andere als komfortabel. Die Frage 
ist also die nach vernünftigen Strukturen und dem rechten Augenmaß.

Manche Sachen sind in diesem Forum allerdings zu engstirnig gesehen, ich 
denke gerade an das von dir genannte Problem der Entprellung. Eigentlich 
ist das gar kein Problem, sondern kommt aus einer zu simplen 
prozeduralen Denkweise nach dem Muster "Mit_dem_Kopf_durch_die_Wand": 
Zuerst Taste abfragen wollen (hier an dieser Stelle fragen wir die Taste 
ab und wenn gedrückt machen wir xyz und dann entprellen wir). Für winzig 
kleine Projekte mach ich es genauso, wenn es angemessen ist. Aber für 
größere Projekte gibt es bei mir keine Tastenabfragen und Entprellungen. 
Dort sitzt im Timerinterrupt nicht nur die interne Uhr, die diverse 
Softwaretimer verwaltet, sondern auch die Tastatur-Verwaltung. Alles 
zusammen generiert "Events", die in eine Warteschlange gepackt werden. 
Die restlichen Teile der Firmware werden von der Grundschleife aus dann 
mit diesen Events beglückt und haben nix mit irgendwelchen Entprellungen 
etc. zu tun. Das Ganze ist ein bissel Windowslike:

immerzu:
  if EventAvailable() then DispatchEvent(GetEvent());
  ...
  ...
  goto immerzu;

Aber mal ne Frage an dich: Wozu dient bei dir denn der Timerinterrupt, 
wenn er sich nicht um die Erzeugung von firmwareinternen Botschaften 
kümmert? Bloß zum Umschalten von Tasks?


W.S.

von Bronco (Gast)


Lesenswert?

jay schrieb:
>> Wozu muss ich erst einen Berg von
>> Sourcedateien durchforsten um die scheiss Definition von
>> Dio_WriteChannel() zu finden?
>
> Ich finde eher, andersherum wird ein Schuh draus.
> Eben genau durch diese Abstraktion weis ich doch sofort, was Sache ist.

Wenn es richtig gemacht ist, brauchst Du Dich gar nicht dafür zu 
interessieren, wie Dio_WriteChannel() definiert ist.
Vorausgesetzt, Du ziehst das konsequent durch, dann sind die einzelnen 
Abstraktionsschichten gegeneinander komplett gekapselt, und in einer 
höheren Schicht darfst Du Dich als "Anwender" der unteren Schichten 
sehen.

Wenn Du nun Deine Plattform immer wieder in verschiedenen Projekten 
einsetzt, wird sie mit der Zeit auch immer fehlerfreier, weil sie eine 
bessere Testabdeckung erhält. Warum also das Rad immer wieder neu 
erfinden und dabei neue Bugs reinmachen?

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Mein Senf dzu:

jay schrieb:

> Nach dem Studium bin ich hatte ich Glück eine Stelle als
> Embedded-Software Entwickler zu kriegen.
> Im Automotive-Umfeld, also Steuergeräte-Software
>
> Größtenteils werden die Applikationen ja nur noch generiert, z.B. mit
> MATlab. [...]
> Dank Standards wie AUTOSAR wurden die Softwarearchitekturen ja
> teilweise strukturiert und genormmt.

und

Wilhelm Ferkes schrieb:
>
> Macht Abstrahierung den Code nicht lahmer?

Wenn sie mit Sinn und Verstand eingesetzt wird: Nein, bzw. minimal.

Wenn sie wie im o.g. Umfeld eingesetzt wird: Ja.

Was in dem Bereich abgeht ist teilweise einfach nur krank.

Krank ist: Standards wie AUTOSAR zu verwenden und gleichzeitig Tools zu 
verwenden, die im Binärcode rumpatchen (ELF, IHEX, ...) weil man das vor 
15 Jahren auch schon so gemacht hat anstatt sauber zu programmieren.

Krank ist: Die eigene Software nicht mehr unter Kontrolle zu haben nach 
dem Motto "Um Gottes Willen nicht mehr anfassen!".  Anstatt den ganzen 
Klump sauber zu machen nach dem aktuellen Stand der Kunst, werden Tools 
wie Compiler und Linker aufgebohrt weil keiner die Firmware-Quelle mehr 
anfassen will / darf / kann.

Krank ist: In den Compiler solche Hacks einzubauen, die als 
höchstkritisch einstuft werden und von denen dringend abgeraten wird. 
Gemacht wird es natürlich trotzdem weil: Wir haben das Sagen denn mehr 
Umsatz als das Bruttosozialprodukt jeder florierenden Bananenrepublik.

Krank ist: 3 Monate nach so bewerteten Änderungen mit den aufgebohrten 
Tools produktiv zu gehen.

Krank ist: Sobald irgendwas unangenehm ist, es unter dem Teppich der 
nächsten "Abstraktionsebene" zu kehren uns so zu tun, als wäre dadurch 
die Hacks oder der Overhead oder der Legacy-Code nicht mehr da.

Krank ist: Autogeneratoren zu verwenden die C-Funktionen erzeugen mit 60 
oder mehr Funktionsargumenten und zu erwarten, daß das keinen Overhead 
macht.

Dazu ein ganz konkretes (nachgestelltes) Beispiel aus dem Umfeld das vor 
Augen führt, was die tollen Codegeneratoren so rauswerfen.  Das Beispiel 
implementiert eine 8.8 Fixed-Point Multiplikation mit Saturierung, d.h. 
bei Überlauf wird der Maximal/Minimalwert geliefert.  3.3 * 3.3 etwa 
wird abgebildet auf 9.9.  Saturierte Fixed-Point Arithmetik ist üblich 
in dem Umfeld.
 
1
#include <stdint.h>
2
3
#define MIN(A, B) ((A) < (B) ? (A) : (B))
4
#define MAX(A, B) ((A) > (B) ? (A) : (B))
5
6
// Saturate so that -A <= X < A
7
#define SAT(X,A)  (MAX (MIN (X, A), -(A)))
8
9
// Saturate so signed 16 Bits
10
#define SAT16(X)  ((int16_t) (SAT ((int32_t) (X), ((int32_t) 1 << 16))))
11
12
// 8.8 signed Fixed-Point Multiply
13
#define MUL88(A, B)  ((((int32_t) (A)) * ((int32_t) (B))) >> 8)
14
15
// Saturated Version thereof
16
#define SAT16_MUL88(A, B) SAT16 (MUL88(A, B))
17
18
int16_t add3 (int16_t a, int16_t b, int16_t c)
19
{
20
    return SAT16_MUL88 (SAT16_MUL88 (a, b), c);
21
}
  
Sieht alles ganz toll und aufgeräumt aus und ist gleichbedeutend mit:
  
1
typedef signed short int16_t;
2
typedef signed long  int32_t;
3
int16_t add3 (int16_t a, int16_t b, int16_t c)
4
{
5
    return ((int16_t) (((((((int32_t) (((((int32_t) (((int16_t) (((((((int32_t) (((((int32_t) (a)) * ((int32_t) (b))) >> 8))) < (((int32_t) 1 << 16)) ? ((int32_t) (((((int32_t) (a)) * ((int32_t) (b))) >> 8))) : (((int32_t) 1 << 16)))) > (-(((int32_t) 1 << 16))) ? ((((int32_t) (((((int32_t) (a)) * ((int32_t) (b))) >> 8))) < (((int32_t) 1 << 16)) ? ((int32_t) (((((int32_t) (a)) * ((int32_t) (b))) >> 8))) : (((int32_t) 1 << 16)))) : (-(((int32_t) 1 << 16))))))))) * ((int32_t) (c))) >> 8))) < (((int32_t) 1 << 16)) ? ((int32_t) (((((int32_t) (((int16_t) (((((((int32_t) (((((int32_t) (a)) * ((int32_t) (b))) >> 8))) < (((int32_t) 1 << 16)) ? ((int32_t) (((((int32_t) (a)) * ((int32_t) (b))) >> 8))) : (((int32_t) 1 << 16)))) > (-(((int32_t) 1 << 16))) ? ((((int32_t) (((((int32_t) (a)) * ((int32_t) (b))) >> 8))) < (((int32_t) 1 << 16)) ? ((int32_t) (((((int32_t) (a)) * ((int32_t) (b))) >> 8))) : (((int32_t) 1 << 16)))) : (-(((int32_t) 1 << 16))))))))) * ((int32_t) (c))) >> 8))) : (((int32_t) 1 << 16)))) > (-(((int32_t) 1 << 16))) ? ((((int32_t) (((((int32_t) (((int16_t) (((((((int32_t) (((((int32_t) (a)) * ((int32_t) (b))) >> 8))) < (((int32_t) 1 << 16)) ? ((int32_t) (((((int32_t) (a)) * ((int32_t) (b))) >> 8))) : (((int32_t) 1 << 16)))) > (-(((int32_t) 1 << 16))) ? ((((int32_t) (((((int32_t) (a)) * ((int32_t) (b))) >> 8))) < (((int32_t) 1 << 16)) ? ((int32_t) (((((int32_t) (a)) * ((int32_t) (b))) >> 8))) : (((int32_t) 1 << 16)))) : (-(((int32_t) 1 << 16))))))))) * ((int32_t) (c))) >> 8))) < (((int32_t) 1 << 16)) ? ((int32_t) (((((int32_t) (((int16_t) (((((((int32_t) (((((int32_t) (a)) * ((int32_t) (b))) >> 8))) < (((int32_t) 1 << 16)) ? ((int32_t) (((((int32_t) (a)) * ((int32_t) (b))) >> 8))) : (((int32_t) 1 << 16)))) > (-(((int32_t) 1 << 16))) ? ((((int32_t) (((((int32_t) (a)) * ((int32_t) (b))) >> 8))) < (((int32_t) 1 << 16)) ? ((int32_t) (((((int32_t) (a)) * ((int32_t) (b))) >> 8))) : (((int32_t) 1 << 16)))) : (-(((int32_t) 1 << 16))))))))) * ((int32_t) (c))) >> 8))) : (((int32_t) 1 << 16)))) : (-(((int32_t) 1 << 16)))))));
6
}
 
Krank ist: Anstatt solcher Monster-Makros oder -Funktionsaufrufe, keine 
Inline-Funktionen verwenden zu wollen / können / dürfen, welche dem 
Compiler die notwendige semantische Information liefern, um den Code 
bestmöglich zu optimieren.

Krank ist: Solche Tools einzusetzen, wenn du jeden Programmierer, der 
ähnliches absondert (z.B. die g.g. Funktionsaufrufe mit über 60 
Parametern), ohne Umschweife vor die Tür setzen würdest.

Hier noch das umgebrochene Kunstwerk, damit man es in Gänze bewundern 
kann: Und das ist lediglich ein ganz einfaches Beispiel!
1
 int16_t add3 (int16_t a, int16_t b, int16_t c)
2
{
3
    return ((int16_t) (((((((int32_t) (((((int32_t) (((int16_t) 
4
    (((((((int32_t) (((((int32_t) (a)) * ((int32_t) (b))) >> 8))) < (((int32_t)
5
    1 << 16)) ? ((int32_t) (((((int32_t) (a)) * ((int32_t) (b))) >> 8))) 
6
    : (((int32_t) 1 << 16)))) > (-(((int32_t) 1 << 16))) ? ((((int32_t) 
7
    (((((int32_t) (a)) * ((int32_t) (b))) >> 8))) < (((int32_t) 1 << 16)) 
8
    ? ((int32_t) (((((int32_t) (a)) * ((int32_t) (b))) >> 8))) : (((int32_t) 
9
    1 << 16)))) : (-(((int32_t) 1 << 16))))))))) * ((int32_t) (c))) >> 8))) 
10
    < (((int32_t) 1 << 16)) ? ((int32_t) (((((int32_t) (((int16_t) 
11
    (((((((int32_t) (((((int32_t) (a)) * ((int32_t) (b))) >> 8))) <
12
    (((int32_t) 1 << 16)) ? ((int32_t) (((((int32_t) (a)) * ((int32_t) (b)))
13
    >> 8))) : (((int32_t) 1 << 16)))) > (-(((int32_t) 1 << 16))) ? ((((int32_t)
14
    (((((int32_t) (a)) * ((int32_t) (b))) >> 8))) < (((int32_t) 1 << 16)) 
15
    ? ((int32_t) (((((int32_t) (a)) * ((int32_t) (b))) >> 8))) : (((int32_t)
16
    1 << 16)))) : (-(((int32_t) 1 << 16))))))))) * ((int32_t) (c))) >> 8)))
17
    : (((int32_t) 1 << 16)))) > (-(((int32_t) 1 << 16))) ? ((((int32_t)
18
    (((((int32_t) (((int16_t) (((((((int32_t) (((((int32_t) (a)) * ((int32_t)
19
    (b))) >> 8))) < (((int32_t) 1 << 16)) ? ((int32_t) (((((int32_t) (a))
20
    * ((int32_t) (b))) >> 8))) : (((int32_t) 1 << 16)))) > (-(((int32_t)
21
    1 << 16))) ? ((((int32_t) (((((int32_t) (a)) * ((int32_t) (b))) >> 8)))
22
    < (((int32_t) 1 << 16)) ? ((int32_t) (((((int32_t) (a)) * ((int32_t)
23
    (b))) >> 8))) : (((int32_t) 1 << 16)))) : (-(((int32_t) 1 << 16)))))))))
24
    * ((int32_t) (c))) >> 8))) < (((int32_t) 1 << 16)) ? ((int32_t)
25
    (((((int32_t) (((int16_t) (((((((int32_t) (((((int32_t) (a))
26
    * ((int32_t) (b))) >> 8))) < (((int32_t) 1 << 16)) ? ((int32_t)
27
    (((((int32_t) (a)) * ((int32_t) (b))) >> 8))) : (((int32_t) 1 << 16))))
28
    > (-(((int32_t) 1 << 16))) ? ((((int32_t) (((((int32_t) (a)) *
29
    ((int32_t) (b))) >> 8))) < (((int32_t) 1 << 16)) ? ((int32_t) (((((int32_t)
30
    (a)) * ((int32_t) (b))) >> 8))) : (((int32_t) 1 << 16)))) : (-(((int32_t)
31
    1 << 16))))))))) * ((int32_t) (c))) >> 8))) : (((int32_t) 1 << 16))))
32
    : (-(((int32_t) 1 << 16)))))));
33
}

von Harald W. (wilhelms)


Lesenswert?

Thomas_L schrieb:

> schon in der Biebel steht:" Unter Schmerzen sollst du deine Programme
> entwickeln".

Das heisst nicht "Biebel", das heisst "Bi-AVR-bel!" :-)
Meint
Harald

von Peter D. (peda)


Lesenswert?

jay schrieb:
> Mir fällt aber auf, dass die meisten Projekte hier ziemlicher Wildwuchs
> sind.

Das ganze hat hauptsächlich historische Ursachen. Als ich 1997 mit den 
AVRs (AT90S1200) anfing, gab es garnichts dazu.
Nur einen rudimentären Assembler mit Bugs und sehr eingeschränkten 
Macro-Fähigkeiten und einen Simulator.
Man mußte sich also alles selber erarbeiten. Klar, daß dann jeder seinen 
eigenen Stil entwickelt.
Und später schmeißt man einmal entwickelte Routinen ja nicht weg und 
fängt nochmal neu an. Man baut darauf auf.

Die Weise der Programmierung und der Support durch die Hersteller hat 
sich in den 15 Jahren auch deutlich verändert.
Und wenn man länger programmiert, ändert man nicht ständig alles, 
sondern führt neue Sachen sukzessive ein. Sonst würde man ja nie was 
schaffen und nur ewig dem Neuesten hinterher rennen.

Es ist auch eine Frage, wie intensiv man programmiert. Ob den ganzen Tag 
oder nur mal nebenbei als Firmware zu dem entwickelten Gerät. Ich mache 
letzteres, bin also garkein "richtiger" Programmierer.


Peter

von Steel (Gast)


Lesenswert?

Bemerkenswert finde ich, dass hier anscheindend professionelle 
Software-Entwickler sind, die das auch immer noch als ihr Hobby 
betreiben.

Ich habe vor dem Berufseinstieg als Schüler und Student auch viele viele 
Jahre hobbymäßig (embedded) Software gemacht.

Heute habe ich da privat einfach keine Lust mehr zu. Und auch keine 
Zeit.


Naja, in der Automobilbranche braucht man ja auch nur 35h die Woche zu 
arbeiten, da hat man natürlich Freizeit genug ;-).

von Edson (Gast)


Lesenswert?

Steel schrieb:
> Bemerkenswert finde ich, dass hier anscheindend professionelle
> Software-Entwickler sind, die das auch immer noch als ihr Hobby
> betreiben.

Findest du das ungewöhnlich? Ich finde das bei dieser Thematik ziemlich 
normal. Wäre das nicht mein Hobby, hätte ich es nie zum Beruf gemacht.

> Ich habe vor dem Berufseinstieg als Schüler und Student auch viele viele
> Jahre hobbymäßig (embedded) Software gemacht.
>
> Heute habe ich da privat einfach keine Lust mehr zu. Und auch keine
> Zeit.

Keine Zeit ist eine Ausrede und kein Grund. Aber wenn du keine Lust 
hast, lass es einfach. Das bleibt einem ja unbenommen, wie Dittsche 
sagen würde.

> Naja, in der Automobilbranche braucht man ja auch nur 35h die Woche zu
> arbeiten, da hat man natürlich Freizeit genug ;-).

Ich habe mit dieser unsäglichen Branche nichts (mehr) am Hut, und da bin 
ich froh darüber. Eine 35h-Woche hatte ich nie und habe ich jetzt auch 
nicht.

von Bronco (Gast)


Lesenswert?

Johann L. schrieb:
> Hier noch das umgebrochene Kunstwerk, damit man es in Gänze bewundern
> kann: Und das ist lediglich ein ganz einfaches Beispiel!

Wurde das zufälligerweise mit einem Autocode-Generator eines grafisches 
Programmiertools erzeugt, deren Erzeuger in einer Schwäbischen Großstadt 
sitzt?

von Karl H. (kbuchegg)


Lesenswert?

Edson schrieb:
> Steel schrieb:
>> Bemerkenswert finde ich, dass hier anscheindend professionelle
>> Software-Entwickler sind, die das auch immer noch als ihr Hobby
>> betreiben.
>
> Findest du das ungewöhnlich? Ich finde das bei dieser Thematik ziemlich
> normal. Wäre das nicht mein Hobby, hätte ich es nie zum Beruf gemacht.

Na, ja.
Irgendwann ist der Dampf heraussen. Wenn du 25 Jahre lang tagtäglich 
mindestens 8 Stunden in der SW-Entwicklung hockst, hast du irgendwann 
abends die Nase voll :-)

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
Noch kein Account? Hier anmelden.