Lernt man C und und sieht sich Beispiele im Internet oder Büchern an,
wird zum Verdeutlichen der Beispiele für die Ausgabe sehr häufig printf
verwendet.
Bewegt man sich an einem PC auf der Konsole ist eine printf-Ausgabe
logischerweise kein Problem, auf einem Mikrocontroller ist das für einen
Anfänger bisweilen schon etwas schwieriger.
Im Rahmen von Hilfedateien für mein eigenes (sehr kleines)
Entwicklungssystem erkläre ich C - Syntax und Befehle ebenfalls mittels
printf.
Damit diese Beispiele auch auf einem (sehr kleinen) Mikrocontroller
nachvollzogen werden können habe ich uart_printf geschrieben deren
Ausgaben dann auf einem Terminalprogramm am PC angesehen werden können.
uart_printf kann mit folgenden AVR-Controllern verwendet werden
(getestet):
- ATtiny2313/4313
- ATtiny25 - ATtiny85
- ATtiny24 - ATtiny84
- ATmega8
- ATmega48 - ATmega328
Die Standardeinsteillung der Baudrate beträgt 19200 Baud, Protokoll ist
8N1.
Normalerweise packt man ein printf nicht gerne in eine MCU, da der
Platzbedarf, insbesondere der Float-Ausgabe wegen, recht hoch ist.
Die Implementation von Float-Ausgaben ist in meinem uart_printf von
daher
NICHT vorhanden und hält den Speicherplatzbedarf deshalb sehr klein.
Folgendes Programm belegt auf einem ATtiny2313 genau 990 Byte und
erscheint mir von daher klein genug (deaktiviert man uart_printf.h die
Einlesefunktion readint, sind es sogar nur noch 706 Bytes):
1
#include <util/delay.h>
2
#include <avr/io.h>
3
4
#include "uart_printf.h"
5
6
/* -----------------------------------
7
MAIN
8
----------------------------------- */
9
int main(void)
10
{
11
uint16_t counter = 0;
12
13
// macht printf ueber RS-232 verfuegbar machen
14
// Baudrate siehe uart_printf.h
15
uart_init();
16
17
while(1)
18
{
19
printf("\r Zaehlerstand: %d ", counter);
20
_delay_ms(1000);
21
counter++;
22
}
23
24
}
Für die Ausgaben von Kommazahlen habe ich etwas eingeführt, das ich
Pseudokommazahl nenne.
Verfügbare Formater sind:
1
%s : Ausgabe Textstring
2
%d : dezimale Ausgabe
3
%x : hexadezimale Ausgabe
4
ist Wert > 0xff erfolgt 4-stellige
5
Ausgabe
6
ist Wert <= 0xff erfolgt 2-stellige
7
Ausgabe
8
%k : Integerausgabe als Pseudokommazahl
9
Die globale Varialbe printfkomma
10
zeigt an, an welcher Stelle ein Dezimal-
11
punkt eingefuegt wird.
12
13
printfkomma= 3;
14
printf("Zahl: %k", 28123);
15
16
Ausgabe: 28.123
17
18
%c : Ausgabe als Asciizeichen
Damit für Beispiele auch Eingaben gemacht werden können ist (über ein
Macro) ein getch sowie eine Funktion
readint()
vorhanden. readint liefert einen 16-Bit signed Integer (nicht ganz, für
negative Zahlen ist "nur" -32767 anstelle -32768 eingebbar):
1
int main(void)
2
{
3
uint16_t zahl;
4
5
uart_init();
6
7
8
while(1)
9
{
10
printf("\r\n Eingabe Zahl: ");
11
zahl= readint();
12
printf("\n\r %dd = %xh ", zahl, zahl);
13
}
14
15
}
Anschlüsse der Controller zu einem seriellen Adapter:
Das kann man sich übrigens auch in 1 Minute bei Atmel-Start
zusammenklicken. Ich finde es recht nützlich:
https://start.atmel.com/
Einfach bei der UART-Komponente "Printf support" aktivieren.
... na ja, erstens wusste ich das nicht, zweitens verwende ich kein
Atmel Studio (ich guter alter Väter Sitte mit Makefile) ... und drittens
und am wichtigsten ist mir die Codegröße damir das auch in kleine
Controller passt. Zudem sollte UART auf vielen MCUs laufen... und si
gibt es ähnliche Software für MCS51, STM8 und STM32
Ralph S. schrieb:> Bewegt man sich an einem PC auf der Konsole ist eine printf-Ausgabe> logischerweise kein Problem, auf einem Mikrocontroller ist das für einen> Anfänger bisweilen schon etwas schwieriger.
Tja, auf einem µC hat man eben kein Betriebssystem, kein RAM ohne Ende
und keinen gigahertzschnelle CPU.
Warum dann überhaupt printf ?
Es ist doch klar, daß printf immer ein Textinterpreter ist, der in einem
Formatstring Ausschau hält nach Formatzeichen, die er dann zu
interpretieren hat.
Das hat einen Sack voll Nachteile:
1. man mutet dem kleinen µC zu, daß er Anweisungen zur Laufzeit
interpretativ verarbeitet, die man mit ezwas mehr Gehirnschmalz auch zur
Übersetzungszeit hätte auflösen können
2. der Interpreter kostet Platz
3. der Linker kann von allem Zeugs, was zum Interpreter gehört,
garnichts wegoptimieren. Wenn man z.B. zwar Hex-Ausgaben grad mal nicht
braucht, der Interpreter das aber in seinem Funktionsumfang drin hat,
dann hat man die betreffenden Routinen als toten Code in seiner
Firmware.
Also wozu?
Aus schierer Gedankenlosigkeit oder Bequemlichkeit, oder weil man als
Anfänger nur so etwas beigebracht gekriegt hat, oder aus Rechthaberei,
wie ich sie hier in diesem Forum schon so oft sehen mußte. Da wird
anstelle einer der Situation angemessenen eigenen Funktion mit Krampf
irgend eine dämliche "Standard"-Funktion hergenommen, die so schlecht
paßt, daß sie mehr an Anpassungsaufwand erfordert, als sie tatsächlich
nützt.
Meine Idee zum Thema wäre eher, für Ausgaben auf sowas wie UART nur die
Einzelzeichen-Ausgabe vorzusehen, darauf dann eine recht einfach
machbare String-Ausgabe vorzusehen - und in einem anderen Unit/Lib ein
paar Ausgabekonvertierungen vorzuhalten, z.B. Integer-Ausgabe,
Hex-Ausgabe, Float-Ausgabe. Was davon in einem Projekt grad nicht
gebraucht wird, das linkt der Linker dann auch erst gar nicht in die
Firmware hinein.
Auf diese Weise programmiert man platz- und rechenzeit-sparend.
Also überlege es dir noch einmal, wie du es denn am liebsten hättest.
W.S.
W.S., Du hast mit vielem (wie oft) was du sagst Recht.
W.S. schrieb:> Warum dann überhaupt printf ?
Das ist schon fast eine religiöse Frage. Mein printf ist für jemanden
geschrieben, der einen C-Compiler und Linker noch nie in der Hand gehabt
hat, es ist für jemanden geschrieben, der Neuland betritt. Irgendwie
muss man anfangen.
Wenn du jemandem eine Schleife erklären möchtest, kannst du nicht
vorraussetzen, dass er das hier:
1
void putstring(char *p)
2
{
3
while(*p)
4
{
5
uart_putchar( *p++ );
6
}
7
}
versteht.
W.S. schrieb:> 3. der Linker kann von allem Zeugs, was zum Interpreter gehört,> garnichts wegoptimieren
Ich komme gerade mal nach 6 Unterrichtseinheiten dazu, zu erklären was
ein Linker macht...
W.S. schrieb:> Meine Idee zum Thema wäre eher, für Ausgaben auf sowas wie UART nur die> Einzelzeichen-Ausgabe vorzusehen, darauf dann eine recht einfach> machbare String-Ausgabe vorzusehen - und in einem anderen Unit/Lib ein> paar Ausgabekonvertierungen vorzuhalten, z.B. Integer-Ausgabe,> Hex-Ausgabe, Float-Ausgabe. Was davon in einem Projekt grad nicht> gebraucht wird, das linkt der Linker dann auch erst gar nicht in die> Firmware hinein.
komplett richtig (wenn man den Platz nicht hat oder etwas schnell sein
muss).
Aber, smile, wegen dir hab ich jetzt ganz genau hingesehen: Meine printf
Implementierung belegt auf einem ATtiny2313 ganz genau 656 Byte.
Wie gesagt, immer schön dran denken, dass jeder einmal angefangen hat.
Bei mir was es in grauer Vorzeit mit Borland Produkten und natürlich
wurden mir Beispiele mit printf erklärt. Ich weiß heute allerdings auch,
wann ich das weg zu lassen habe... und wann ich es benutzen kann.
Ralph S. schrieb:> Aber, smile, wegen dir hab ich jetzt ganz genau hingesehen: Meine printf> Implementierung belegt auf einem ATtiny2313 ganz genau 656 Byte.
Und? Wozu dient diese Angabe? Ich könnte ja auch argumetieren, daß meine
komplette Gleitkommabibliothek einschließlich Ausgabekonvertierung
stolze 028Ah Befehlsworte lang ist (für nen PIC16). Aber was bringt das?
Garnix.
Ralph S. schrieb:> Ich komme gerade mal nach 6 Unterrichtseinheiten dazu, zu erklären was> ein Linker macht...
Ein schlechter Linker linkt eben alles, was er kriegt zusammen. Ein
guter Linker hingegen kann aus den vorliegenden Objektdateien und
-bibliotheken selektiv heraussuchen, was er linkt und was mangels
Referenzierung (sprich Nichtgebrauch) toter Code sein wird, den man
deshalb getrost weglassen kann.
Wenn du nun eine Funktion printf hast, die eben auch float kann, dann
wird alles, was zu float gehören muß, eben mit eingebunden, egal ob du
es im konkreten Fall gebrauchst oder nicht. Wenn du hingegen mehrere
Einzelfunktionen hast Float_Out(..), Dezi_Out(..), Hex_Out(..) und du
brauchst im konkreten Falle nur Dezi_Out, dann kann der ganze Schmonzes
für float und hex entfallen und deine Firmware ist entsprechend kleiner
- und schneller, denn es braucht zur Laufzeit nichts interpretiert zu
werden.
Ein typisches Beispiel für in die Hose gegangene Sprachentwicklung sind
die "Strings" in C. Sind ja keine Strings, sondern nur Felder von char's
mit einem Nullbyte als Abschluß. Wenn man mal mit IDA oder sowas
ähnlichem sich übliche Programme für den PC anschaut, dann graust es
einen, denn da kann man sehen, daß sowas wie strlen abertausendmale
benutzt wird und jedesmal eiert der ganze Algorithmus durch's stupide
Abzählen, bis das Nullbyte gefunden ist. Ich stelle hier mal die
Behauptung auf, daß typische Programme am PC so etwa 30..50% ihrer
Laufzeit in strlen verbringen. Und alles nur wegen Dummheiten beim Legen
der Fundamente der benutzten Sprache C.
W.S.
... irgendwie ... weiß ich jetzt nicht, was du mir sagen willst !
W.S. schrieb:> Und alles nur wegen Dummheiten beim Legen> der Fundamente der benutzten Sprache C.
Das dürfte historische Gründe haben. Im übrigen würde mich
interessieren, warum du, wie ich weiß, dann dennoch auch in C
programmierst.
Über "Speicherplatzverschwendung" kann man endlos diskutieren. Es ist
wohl unbestritten, dass C++ deutlich mehr Resourcen benötigt als C, aber
auf großen Systemen (und umfangreichen Programmen) die bessere Wahl ist
(aber bspw. auf Mikrocontrollern nur mit Bedacht eingesetzt werden
"sollte").
Über Programmierung kann man sich hinlänglich lange streiten.
Ob im Falle von C ein Chararray das Sinnvollste ist, was man für einen
String anwenden kann mag ich nicht diskutieren.
Historisch gessehen dürfte das Nullbyte am Ende wohl die geschickte
Lösung sein. Ich weiß nicht wie oft ich geflucht hab, weil das
Längenbyte eines Pascalstrings mich damals stark einengte.
Mein erster selbstgeschriebener Editor benutzte dann einen dynamischen
String in einer doppelt verketteten Liste. War unglaublich mühselig.
W.S. schrieb:> Ein schlechter Linker linkt eben alles, was er kriegt zusammen. Ein> guter Linker hingegen kann aus den vorliegenden Objektdateien und> -bibliotheken selektiv heraussuchen, was er linkt und was mangels> Referenzierung (sprich Nichtgebrauch) toter Code sein wird, den man> deshalb getrost weglassen kann.
Du wiederholst dich. Das was du sagst ist absolut richtig, aber auch
absolut hinlänglich bekannt.
Es geht nicht darum, mir beizubringen wie etwas funktioniert, es geht
darum, wie ich anderen entwas beibringen kann und wie ich einen Einstieg
finde.
Wer einen zu Unterweisenden mit zu komplexen Dingen am Anfang erschlägt
darf sich nicht wundern, wenn er danach tot ist. Die Didaktiklehre sagt:
vom Einfachen zum komplexen.
Optimiert wird am Schluß und nicht am Anfang.
W.S. schrieb:> Wenn du nun eine Funktion printf hast, die eben auch float kann, dann> wird alles, was zu float gehören muß, eben mit eingebunden
Mein printf kann kein float (weil auf sehr kleinen Mikrocontrollern zu
groß).
---------------------------------
Das hier ist entstanden, damit ich auf allen von mir verwendeten
Controllern (und auch am PC) dieselben Vorraussetzungen für den Anfang
habe und es egal ist, auf welchem System ich mich bewege.
Im Übrigen (auch hier wirst du wohl wieder etwas zornig sein) lasse ich
am Anfang sämtliche Hardware beim Erklären weg und komme erst später
(beim Erklären von Interrupts) dazu, aufzuzeigen, wie die Hardware etwas
macht.
----------------------------------
Nenn mich einen schlechten Ausbilder, dann ist das halt so (deiner
Meinung nach) und ich kann das auch nicht ändern.
(Im Übrigen wurde mir, was mir nicht gefallen hatte, untersagt zur
Erläuterung mit Maschinensprache einzusteigen. Hier hatte ich immer
gerne MCS-51 zum Aufzeigen genommen gehabt).
Lange Rede kurzer Sinn:
W.S. mag kein printf und verwendet es auch nicht. W.S. hat sich auch
niemals Beispiele angesehen gehabt (als er noch angefangen hatte) bei
denen ein printf vorkam. W.S. schließt sofort jede (Web)seite, in denen
das Wort printf auftaucht. W.S. muß der Vater (oder Opa) von Ritchie
und/oder Kernighan sein, weil er grundsätzlich alleine weiß, wie man
Softwaremodule aufzubauen hat, was bspw. in einen Header darf und was
nicht (bspw. nie nie nie niemals auch nur ein einziges Byte Code, da ein
Header schlicht das Interface einer Library ist und die Library so
geschrieben sein muß dass ein Neukompilieren der Library nicht zu
erfolgen hat.... wir reden hier von .a Dateien). Irgendwie macht dann
wohl eine "Softwaremodul" aus .c und .h keinen Sinn, wenn es nicht in
einer Library Platz findet.
Vielleicht sollte man dann einen Stil pflegen wie die ersten (Turbo)
Pascal Programme und einfach nur #include irgendwas.inc machen (was dann
aber auch wieder alles kompliliert und einfügt).
Naaaaaaaaatürlich kann ich, wenn ich sehr sehr viele kleine Dateimodul
zu einer Library vereinige es dem Linker sehr einfach machen, Dinge, die
im Code nicht aufgerufen werden nicht mit einzubinden. Schlicht sehr
sehr viele kleine Dateien werden einfach nur unübersichtlich.
Im übrigen (und ich bin mit Sicherheit kein Microsoft Fan) hat man -
wenn ich es noch richtig weiß - bis knapp nach dem Jahr 2000 immer noch
Initialisierungssequenzen von CGA-Grafikkarten in Mikrosoft System
gefunden ... die niemals zur Ausführung kommen konnten.
Mit ganz großer Sicherheit sind die Leute von Microsoft besser als ich
(und auch besser als W.S.).
----------------------------
W.S. warum... fühlst du dich bemüßigt permanent DEINE Vorstellung von
Programmierung anderen aufzuwingen zu MÜSSEN.. und wenn sie nicht deiner
Meinung sind ballerst sie mit allgemeingültigem Wissen zu?
Ich habe mir wegen dir tatsächlich mal Code der Lernbetty angesehen und
weiß, dass du es fachlich gar nicht nötig hast dich ins Licht zu stellen
oder dich beweisen zu müssen.
Ich (und wahrscheinlich viele andere auch) haben schon mitbekommen, dass
du etwas auf dem Kasten haben mußt, aber es gibt niemals nur eine Sicht
der Dinge.
Desweiteren: wieso hast du es nötig, dich hinter so etwas wie W.S. ohne
einen Namen zu verstecken?
W.S. schrieb:> Ralph S. schrieb:>> Ich komme gerade mal nach 6 Unterrichtseinheiten dazu, zu erklären was>> ein Linker macht...Ralph S. schrieb:> Nenn mich einen schlechten Ausbilder, dann ist das halt so (deiner> Meinung nach) und ich kann das auch nicht ändern.
Ach.. so herum ist das.
Nein, ich nenne dich nicht einen schlechten Ausbilder. Ich werde - wo es
geht - auch nicht persönlich, obwohl ich in diesem Forum schon an genug
Leute gekommen bin, die mangels Sachargumenten irgendwann zu
persönlichen Beleidigungen gewechselt haben. Und ich bin nicht der Opa
von K&R, um das mal klarzustellen.
Das, was mich tatsächlich ärgert, ist die heutzutage anzutreffende
Ignoranz, die auch einen Geruch nach Konditionieren anstelle von Lernen
beinhaltet: Da wollen Leute irgendwas machen/basteln, ohne auch nur im
Entferntesten die Basis dafür in ihrem Kopfe zu haben. Statt zu lernen
die Dinge zu verstehen, wird dieser eigentlich notwendige Teil
ausgelassen und später durch nervige Fragen in diesem Forum ersetzt.
Also, wenn du junge Leute ausbildest und es dir nicht erlaubt ist, denen
die schieren Grundlagen beizubringen, angefangen bei schlichter Logik
über den Mikroprozessor zum Mikrocontroller und angefangen bei logischen
Verknüpfungen über Maschinenbefehle und das Lernen von Algorithmen hin
zu höheren Programmiersprachen, dann.. ja dann bist auch du ein Teil
derer, die ungewollt dazu beitragen, daß all diejenigen, die heute mit
einem Mikrocontroller irgendwas bauen wollen, eben unfähig sind, die
allereinfachsten Algorithmen auf die Beine zu stellen, also sowas wie
das Entprellen der Taste oder das Umwandeln einer Zahl in eine
Ziffernfolge. Und die kriegen dann von dir beigebracht, daß man ja nur C
zu können braucht und daß man da printf benutzt. Und wenn diese Leute
dann einstmals ihrerseits den nachfolgenden etwas beibringen
wollen/sollen/müssen, dann wissen nicht einmal die Lehrer noch das, was
ihre Studenten eigentlich beherrschen sollten.
Ich finde solche Aussichten nicht entzückend.
Du etwa?
Was also soll man tun mit einer Generation, die Ergebnisse haben will,
selbst aber sich im Schlaraffenland wähnt und mit Selbstverständlichkeit
erwartet, daß ihnen die fertig gebratenen Mikrocontroller von selbst in
den Mund fliegen?
Die einzige Antwort, die ich habe, besteht darin, eben Alternativen
anzubieten. Auch für printf. Wer sich die Mühe macht, selbige anzusehen
und draus zu lernen, wie sowas geht, der hat anschließend etwas
dazuverstanden und seinen Horizont ein bissel erweitert. Und wer sagt
"was soll mir das, ich will das berüchtigte Rad nicht verstehen
geschweige denn nochmal erfinden", der muß halt zusehen, wie er
zurechtkommt. Ich zwinge niemandem was auf. Aber ich erkläre jemandem,
der Blödsinn macht, DASS er Blödsinn macht und warum. Mehr kann man
nicht tun.
W.S.
Es ist müßig darüber zu diskutieren, wie die Bildungspolitik im Moment
ist. Leider ist es Fakt, dass das Bundesinstitut für Berufsbildung
(BIBB) in ihren "sachlich und zeitlichen Gliederungen" vorschreibt, wie
das zu funktionieren hat und noch unsäglicher sind die sogenannten
Lernfelder in denen vorgegeben wird, wann etwas zu vermitteln ist.
Da passiert es bspw. dass Installationstechnik vermittelt wird, das
erste mal ein FPGA angefasst wird, aber die absoluten Grundlagen wie
ohmsches Gesetz, Kondensator an Wechselspannung nicht im entferntesten
sitzt.
Es wird an eine Siemens Logo herumgespielt ohne zu wissen was das
eigentlich ist.
Ich gebe dir mit den Dingen der beruflichen Bildung recht. Eigentlich
gehört eine Diskussion hierüber jedoch nicht in diesen Thread.
Es streiten sich seit hunderten von Jahren die Menschen darüber, WIE
etwas zu vermitteln ist (und die Lehre der Didaktik ist eine eigene
Wissenschaft für sich, die sich jedem Zeitalter den Menschen und ihren
Auffassungsgaben angepasst hat).
Die Methode, nach der Menschen vor 100 Jahren etwas verstanden haben
funktioniert heute nicht mehr und es müssen neue Methoden her (leider
wird derart schnell nach immer neuen Methoden gesucht, dass nichts mehr
wirklich funktioniert).
Ich gebe dir komplett Recht, dass die Grundlagen nicht mehr gründlich
(bis gar nicht) mehr vermittelt werden sollen. Es sollen nur noch
irgendwelche Module zusammengesetzt werden die eben wie eine Blackbox
funktionieren.
All das sei jetzt mal dahingestellt (im Übrigen habe ich keine Studenten
sondern Auszubildende im Feld Elektroniker für Geräte und Systeme sowie
Physiklaborant).
Wenn ich jetzt zu den Mikrocontrollern komme und zur Sprache C (oder
jeder anderen Programmiersprache) stehst du wieder vor dem Dilemma: Wie
fängt man an.
Unabhänig davon, welche Vorgaben ICH habe finde ich es nicht sonderlich
zielführend massiv mit Hardwareinterna (egal welcher CPU auch immer)
anzufangen (ich habe schon Probleme den Sinn eines Halb- und
Volladdierers zu vermitteln).
Der erste Kontakt mit "Hardware" besteht bei mir in aller Regel mit dem
Begriff "Schieberegister" und dass sich darin das Wort Register befindet
und es ein Speicher mit genau einem Byte OHNE Adresse handelt. In aller
Regel fängt hier schon ein Unverständnis an (welches auszuräumen gilt)
und es geht weiter damit, was der Sinn eines Registers ist (in diesem
Falle ein Byte zu speichern) und darum, wie nun der Inhalt dieses
(Schiebe)registers verändert werden kann... und dass die Veränderung -
Achtung Schlüsselwort - Zugriff heißt.
Hier fängst du jetzt an, zum ersten mal ein serielles Protokoll
darzustellen und es stellt sich auch der Aha-Effekt ein. Als nächstes
bringst du dann, dass ein Mikrocontroller je nach Ausführung voll mit
solchen Registern ist, die nicht nur die Aufgabe haben einfach nur einen
Wert zu beinhalten, sondern die etwas selbsttätig in Abhängigkeit ihres
Wertes machen.
So, jetzt kommen wir wieder zum Thema Zugriff. Wie beschreibe ich nun
ein internes Register mit einem Wert, und dann muß ich etwas in der Art
wie das hier bringen:
#define DIRECTION_REG_PORTX *(unsigned char*)0xabcd
Soooooooooooooooo, und genau jetzt bin ich beim Thema: Um obiges zu
verstehen musst du schon etwas besser in C sein und schon mal relativ
genau Wissen und eine Vorstellung davon haben, was Zeiger sind und wie
diese funktionieren.
Ich kann also nicht einfach gleich mit der Hardware anfangen sondern ich
muß schlicht erst einmal etwas abstraktes schaffen und Hilfsmittel an
der Hand haben, um bspw. Zeiger zu erklären um danach die Hardware zu
erklären.
Wie du vllt. sehen kannst bin ich schon einf Freund davon, auf Register
direkt zugreifen zu können um genau selbst die Kontrolle zu haben wie
etwas initialisiert wird.
Aaaaaaaaaaaaaaber: immer und immer wieder mag ich das auch nicht machen
und ich nehme auch gerne einmal vorgefertigtes. Wichtig ist hierbei zu
verstehen wie das grundsätzlich funktioniert.
---------------------------------------
Aber wie gesagt: eigentlich gehört diese Diskussion nicht in diesen
Thread. Im Gegensatz zu dir freue ich mich, wenn sich junge Menschen mit
diesem Thema beschäftigen und hier kann es dann schon sein dass
bisweilen merkwürdig anmutende Fragen auftreten (die dich innerlich den
Kopf schütteln lassen), aber hier gilt es dann (ohne persönliches) diese
auf Weg zu bringen dass sie in der Lage sind sich selbst weiter
reinzubeisen.
Manchmal hat man hier dann Highlights wie im Falle eines ehemaligen
Auszubildenden der dann anschließend studiert hat und heute leitender
Softwareentwicklungsingeneur bei einer Fa. für Automobilzubehör ist.
Da bin ich stolz drauf (vor allem wenn er sagt, dass er viel von mir
gelernt hat).
Gruß Ralph
> void putstring(char *p){> while(*p) { uart_putchar( *p++ ); }> }
Solcher Code ist sowieso schlimmster Abfall. Denn er ist blockierend.
Dazu gibt es nur eines zu sagen : NIE !
Mit printf() is so weit von embedded wie man nur sein kann.
Ralph S. schrieb:> Es streiten sich seit hunderten von Jahren die Menschen darüber, WIE> etwas zu vermitteln ist..Ralph S. schrieb:> Wenn ich jetzt zu den Mikrocontrollern komme und zur Sprache C (oder> jeder anderen Programmiersprache) stehst du wieder vor dem Dilemma: Wie> fängt man an.
Tja - ich kann dich und dein Dilemma wirklich gut verstehen, schließlich
hatte ich vor Urzeiten auch mal eine Weile an der Post-FH in der
Ringbahnstraße Digitalelektronik gelesen - jedoch liegt mir das Thema
Werkstudenten in der Firma weitaus näher.
Aber wie etwas zu vermitteln ist, ist sonnenklar: der Reihe nach,
beginnend mit den Grundlagen.
Das ist wie beim Hausbau: zuerst die Fundamente, dann die Mauern, dann
erst das Dach. Sonst fehlen den Studenten schlichtweg die
Voraussetzungen zum Begreifen. Ja, ist nicht einfach und wenn man einen
Kurs übernimmt, für den ein anderer Kurs vorausgesetzt werden MUSS -
aber realiter nicht stattgefunden hat, dann geht das Ganze in die Hose.
Ich kann dir da auch keinen "goldenen" Rat geben, wie du ein Thema am
besten liest, ohne daß deine Schüler dessen Grundlagen kennen. Aber ganz
generell gesagt, geht das alles in die Richtung Überflieger, die zwar
irgend etwas so lala benutzen können, selbiges jedoch nicht verstehen.
Und um auf printf für die ATtiny und so zurückzukommen: es mag dir eine
mentale Herausforderung gewesen sein, sowas zu schreiben - eben Hobby.
Sowas ist OK. Aber mit Abstand gesehen, wäre es besser, sich über das
Verstehen der eigentlichen Konvertierungs-Algorithmen auszulassen.
Kennst du eigentlich die Bücher von Lampe,Jorke,Wengel? Die haben sich
zwar über den Z80 ausgelassen, aber didaktisch und algorithmisch sind
deren Ausführungen noch immer das Beste, was man sich anlesen kann.
Aber hier hat jemand nicht weiter gedacht, als bis zu seiner Hutkrempe:
Name H. schrieb:> Solcher Code ist sowieso schlimmster Abfall. Denn er ist blockierend.
Normalerweise ist ein µC bedeutend schneller als eine serielle
Übertragung. Deswegen wird er beim Senden größerer Mengen von Daten
immer in den Zustand kommen, daß er auf das Ende des Sendens warten
muß. Man kann sowas abmildern, indem man geeignet große Puffer im
Lowlevel-Treiber vorsieht, aber man kann das nicht 100% vermeiden.
Aber das betrifft das Thema "printf auf einem kleinen µC" überhaupt
nicht.
W.S.
Tim . schrieb:> Das kann man sich übrigens auch in 1 Minute bei Atmel-Start> zusammenklicken.Ralph S. schrieb:> ... na ja, erstens wusste ich das nicht, zweitens verwende ich> kein> Atmel Studio (ich guter alter Väter Sitte mit Makefile) ...
printf kommt mit der avrlibc, die du selbstverständlich auch nutzt. Ein
wenig überraschendes
1
#include<stdio.h>
und dazu ein eigenes putchar ist alles, was es dafür braucht. Dazu
kommmt das in drei Größen, per Compileroption auswählbar.
Das soll deine pädagogische Leistung nicht schmälern, aber kennen könnte
man die Tools schon, die man so benutzt.
Oliver
Oliver S. schrieb:> printf kommt mit der avrlibc, die du selbstverständlich auch nutzt. Ein> wenig überraschendes #include <stdio.h>und dazu ein eigenes putchar ist> alles,
zusätzlich dazu, dass du hierfür den I/O Stream (bei einem AVR) umleiten
mußt: Hast du gesehen, wie groß der Code des printf in der LIBC wird?
Das... ist ganz genau der Grund, qarum ich das nicht verwenden mag.
Es ging um die Schaffung eines kleinsten gemeinsamen Nenners, der auf
einem ATtiny2313 noch genau so läuft wiw auf einem STM32 oder einem
AT89S52.
Genau darum, dass Erklärbeispiele alle dieselbe Basis verwenden egal
welches Target man hat (und wenn das Target ein Konsolenprogeamm für
Linux ist.) Es soll schlicht die ersten Schritte erleichtern...
UUUUUUND: Es soll dort wo es notwendig ist durch geeignetete Lösungen
ersetzt eerden. Dort wo es nicht notwendig ist kann es bleiben und
derjenige der programmiert soll in der Lage sein zu erkennen wann man
etwas übernehmen kann und wann nicht.
Im übrigen finde ich das printf relativ anschaulich, wenn es darum geht,
Funktionen mit variabler Parameteranzahl zu erstellen...
Schade mal wieder, wie alles zeredet wird. Da macht sich Ralph die Mühe
und schreibt einen (im didaktischen Bereich -- vielleicht nicht an
Schulen oder Unis, aber doch für Umsteiger vom PC auf den Embedded
Bereich) knappen, brauchbaren Code, der für Debugging-Zwecke einen
Haufen Schreibarbeit erspart, und schon tauchen die Puristen auf aus der
''früher war alles besser, und ich bin schlauer als du!''-Fraktion.
Wenn ich hier manchen Code, der gefeiert wird, anschaue, könnte ich auch
die ganz große Software-Architekten-Keule auspacken und jedes Stückchen
in Grund und Boden kommentieren mit Besserwissertum. Motiviert das?
Genauso könnten es andere Experten hier mit meinen Schaltungen tun.
Motiviert das? Oder wird da nur das eigene Ego gestreichelt?
Wieso sehen Dies heutzutage so aus, wie sie aussehen? Weil sie modular
und entkoppelt aufgebaut sind und deswegen immer wieder einsetzbar für
vielfältigste Zwecke. Ansonsten wären Chip-Layouts mit Zillionen
Transistoren gar nicht mehr zu handhaben. Und so ist es mit der Software
auch: Man baut Module, und ein ganz kleines, vielseitiges solches Modul
ist eben printf.
printf liefert das, was man als einigermaßen C-kundiger Mensch erwartet,
auch auf einem AT. Wir reden hier vom Hobbybereich. Der ATxyz hat zu
wenig Speicher, um printf zum Debuggen benutzen zu können? Dann nimm den
ATabc, mit doppelt oder viermal so viel. Für ein Hobbyprojekt mit, wenn
es haushoch kommt, von mir aus 10 ATs, ob das jetzt ATtinys sind oder
ATmegas oder gleich Arduino Nanos, wenn man clever einkauft, macht das
vielleicht 20 Euro aus. Ein Hobbyprojekt stirbt daran nicht, es sei
denn, der AT muss unbedingt in eine Unterputzdose, aber dann ist das
sowieso nicht mehr VDE-konform.
Natürlich ist das hier weder eine kostenlose Berufsschule noch eine
gesponsorte Uni oder ein FabLab. Aber wenn sich wer die Mühe macht, so
einen kompakten Code zu schreiben und sich dann mit ihm auch noch so
sehr befasst, weil er ihn hier öffentlich zur Verfügung stellen will,
finde ich trotz aller vielleicht angemessener (!) Kritik doch zuallerst
einmal ein Dankeschön angebrachter als dieses ''Alles Schei***''...
... und eins noch: Die Welt ist inzwischen, wie sie ist. Bei manchen
hier glaube ich herauszuhören, dass sie es ganz gut finden würden, wenn
Lehrer wieder prügeln dürften. Junge, begeisterte Menschen zu finden,
die sich so tief in die Elektronik und die Software versenken wollen,
dass sie einen uC in C programmieren, ist schwer. Mit ''du hast doch
keine Ahnung, kauf dir erstmal diese zwanzig Bücher: ...'' wird es mit
dem Fachkräftemangel in Deutschland auch nicht besser -- mit uart_printf
vielleicht schon ;)