Forum: Projekte & Code Ausgabe mittels printf über UART für ATmega / ATtiny


von Ralph S. (jjflash)


Angehängte Dateien:

Lesenswert?

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:
1
        MCU            PORT    Funk.1   Funk.2   Anschlusspin
2
--------------------------------------------------------------
3
      8 polige
4
5
ATtiny25 - ATtiny85    PB1      TxD       Do         6
6
                       PB0      RxD       Di         5
7
--------------------------------------------------------------
8
     14 polige
9
10
ATtiny24 - ATtiny84    PA5      TxD       Do         8
11
                       PA6      RxD       Di         7
12
--------------------------------------------------------------
13
ATtiny2313 / 4313      PD1      TxD                  3
14
                       PD0      RxD                  2
15
--------------------------------------------------------------
16
      28 polige
17
18
ATmega8 und            PD1      TxD                  3
19
ATmega48 - 328         PD0      RxD                  2
20
--------------------------------------------------------------

von Ralph S. (jjflash)


Lesenswert?

oh, böser Fehler:

Ich habe falsche Headerdatei hochgeladen, im Abschnitt
1
  #if (readint_enable == 1)
2
3
    int checkint16(char *p, int *myi);
4
    int16_t readint();
5
6
  #endif

ist die Zeile mit
1
    int checkint16(char *p, int *myi);

zu entfernen !

Sorry

von Tim  . (cpldcpu)


Lesenswert?

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.

von Ralph S. (jjflash)


Lesenswert?

... 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

von W.S. (Gast)


Lesenswert?

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.

von Ralph S. (jjflash)


Lesenswert?

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.

von Jost (Gast)


Lesenswert?

Elm Chan hat sich daran auch schon ausgetobt.
http://elm-chan.org/fsw/strf/xprintf.html

Gruß, Jost

von W.S. (Gast)


Lesenswert?

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.

von Ralph S. (jjflash)


Lesenswert?

... 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?

von W.S. (Gast)


Lesenswert?

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.

von Ralph S. (jjflash)


Lesenswert?

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

von Purzel H. (hacky)


Lesenswert?

> 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.

von W.S. (Gast)


Lesenswert?

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.

von Oliver S. (oliverso)


Lesenswert?

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

: Bearbeitet durch User
von Ralph S. (jjflash)


Lesenswert?

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...

von Carsten (Gast)


Lesenswert?

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 ;)

von Carsten (Gast)


Lesenswert?

PS: Was dabei raus kommt, wenn man den Naysayers den Laden überlässt, 
sieht man aktuell ja am Brexit... Insofern, Ralph, Danke und weiter so 
:)

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.