diff --git a/20210114/blink-0a.c b/20210114/blink-0a.c new file mode 100644 index 0000000000000000000000000000000000000000..569e7c5b9160c1fe750f1b34492dec99ef814012 --- /dev/null +++ b/20210114/blink-0a.c @@ -0,0 +1,9 @@ +#include <avr/io.h> + +int main (void) +{ + DDRD = 0x7c; /* binär: 0111 1100 */ + PORTD = 0x41; /* binär: 0100 0001 */ + while (1); + return 0; +} diff --git a/20210114/blink-0b.c b/20210114/blink-0b.c new file mode 100644 index 0000000000000000000000000000000000000000..1f9ee2b0d4bd483103e56c571180f6e50f11dba9 --- /dev/null +++ b/20210114/blink-0b.c @@ -0,0 +1,13 @@ +#include <avr/io.h> + +#define F_CPU 16000000l +#include <util/delay.h> + +int main (void) +{ + DDRD = 0x7c; /* binär: 0111 1100 */ + _delay_ms (1); + PORTD = 0x40; /* binär: 0100 0000 */ + while (1); + return 0; +} diff --git a/20210114/blink-0c.c b/20210114/blink-0c.c new file mode 100644 index 0000000000000000000000000000000000000000..28fe2e148c88fa68547d55e5ba025a70c5ea42ae --- /dev/null +++ b/20210114/blink-0c.c @@ -0,0 +1,13 @@ +#include <avr/io.h> + +#define F_CPU 16000000l +#include <util/delay.h> + +int main (void) +{ + DDRD = 0x7d; /* binär: 0111 1101 */ + _delay_ms (1); + PORTD = 0x40; /* binär: 0100 0000 */ + while (1); + return 0; +} diff --git a/20210114/blink-3a.c b/20210114/blink-3a.c new file mode 100644 index 0000000000000000000000000000000000000000..388ed658bb7494d5483f311908a1251892aef196 --- /dev/null +++ b/20210114/blink-3a.c @@ -0,0 +1,18 @@ +#include <avr/io.h> + +#define F_CPU 16000000 +#include <util/delay.h> + +int main (void) +{ + DDRD = 0x7c; /* binär: 0111 1100 */ + PORTD = 0x42; /* binär: 0100 0010: PORT für Input für 1 setzen = internen Pull-Up-Widerstand aktivieren */ + while (1) + { + while ((PIND & 0x02) == 0) /* binär: 0000 0010 */ + ; /* just wait */ + PORTD ^= 0x40; + _delay_ms (200); + } + return 0; +} diff --git a/20210114/blink-3c.c b/20210114/blink-3c.c new file mode 100644 index 0000000000000000000000000000000000000000..d978187a6dd73fb489ef5a231c92032405715aa7 --- /dev/null +++ b/20210114/blink-3c.c @@ -0,0 +1,18 @@ +#include <avr/io.h> + +#define F_CPU 16000000 +#include <util/delay.h> + +int main (void) +{ + DDRD = 0x7c; /* binär: 0111 1100 */ + PORTD = 0xc0; /* 0x40 = 0100 0000; 0xc0 = 1100 0000 */ + while (1) + { + while ((PIND & 0x02) == 0) + ; /* just wait */ + PORTD ^= 0x40; + _delay_ms (200); + } + return 0; +} diff --git a/20210114/blink-3d.c b/20210114/blink-3d.c new file mode 100644 index 0000000000000000000000000000000000000000..7940918580dac53ea5ca7cb717062a6a2e4fc4d9 --- /dev/null +++ b/20210114/blink-3d.c @@ -0,0 +1,18 @@ +#include <avr/io.h> + +#define F_CPU 16000000 +#include <util/delay.h> + +int main (void) +{ + DDRD = 0x7c; /* binär: 0111 1100 */ + PORTD = 0xc0; /* 0x40 = 0100 0000; 0xc0 = 1100 0000 */ + while (1) + { + while ((PIND & 0x02) == 0) + ; /* just wait */ + PORTD ^= 0x80; + _delay_ms (200); + } + return 0; +} diff --git a/20210114/blink-3e.c b/20210114/blink-3e.c new file mode 100644 index 0000000000000000000000000000000000000000..20dd315377a479c739502993dcb88b28015e9ebc --- /dev/null +++ b/20210114/blink-3e.c @@ -0,0 +1,18 @@ +#include <avr/io.h> + +#define F_CPU 16000000 +#include <util/delay.h> + +int main (void) +{ + DDRD = 0xfc; /* binär: 1111 1100 */ + PORTD = 0xc0; /* 0x40 = 0100 0000; 0xc0 = 1100 0000 */ + while (1) + { + while ((PIND & 0x02) == 0) + ; /* just wait */ + PORTD ^= 0x80; + _delay_ms (200); + } + return 0; +} diff --git a/20210114/download.sh b/20210114/download.sh new file mode 100755 index 0000000000000000000000000000000000000000..770c3b5dca74ac09778be055c9d6f5adb0df293b --- /dev/null +++ b/20210114/download.sh @@ -0,0 +1,3 @@ +port=$(ls -rt /dev/ttyACM* | tail -1) +echo avrdude -P $port -c arduino -p m328p -U flash:w:$(ls -rt *.hex | tail -1) +avrdude -P $port -c arduino -p m328p -U flash:w:$(ls -rt *.hex | tail -1) 2>/dev/null diff --git a/20210114/hp-musterloesung-20210114.tex b/20210114/hp-musterloesung-20210114.tex index 2027ef6d209d940a82a925f8d8fee50f54ab0048..cb7514e9303ffa538c78d1a9ca7bc5efc8e9b141 100644 --- a/20210114/hp-musterloesung-20210114.tex +++ b/20210114/hp-musterloesung-20210114.tex @@ -1,4 +1,4 @@ -% hp-musterloesung-20210107.pdf - Solutions to the Exercises on Low-Level Programming +% hp-musterloesung-20210114.pdf - Solutions to the Exercises on Low-Level Programming % Copyright (C) 2013, 2015, 2016, 2017, 2018, 2019, 2020, 2021 Peter Gerwinski % % This document is free software: you can redistribute it and/or @@ -20,7 +20,7 @@ % Attribution-ShareAlike 3.0 Unported License along with this % document. If not, see <http://creativecommons.org/licenses/>. -% README: Fakultät, Länge von Strings (Neuauflage), Hexdumps +% README: Zahlensysteme, Mikrocontroller \documentclass[a4paper]{article} @@ -30,328 +30,363 @@ \begin{document} \section*{Hardwarenahe Programmierung\\ - Musterlösung zu den Übungsaufgaben -- 7.\ Januar 2021} + Musterlösung zu den Übungsaufgaben -- 14.\ Januar 2021} + + \exercise{Zahlensysteme} + + Wandeln Sie ohne Hilfsmittel + + \begin{minipage}[t]{0.3\textwidth} + \begin{itemize} + \item + nach Dezimal: + \begin{itemize} + \item[(a)] + 0010\,0000$_2$ + \item[(b)] + 42$_{16}$ + \item[(c)] + 17$_8$ + \end{itemize} + \end{itemize} + \end{minipage}\hfill + \begin{minipage}[t]{0.3\textwidth} + \begin{itemize} + \item + nach Hexadezimal: + \begin{itemize} + \item[(d)] + 0010\,0000$_2$ + \item[(e)] + 42$_{10}$ + \item[(f)] + 192.168.20.254$_{256}$ + \end{itemize} + \end{itemize} + \end{minipage}\hfill + \begin{minipage}[t]{0.3\textwidth} + \begin{itemize} + \item + nach Binär: + \begin{itemize} + \item[(g)] + 750$_8$ + \item[(h)] + 42$_{10}$ + \item[(i)] + AFFE$_{16}$ + \end{itemize} + \end{itemize} + \end{minipage} + + \medskip - \exercise{Fakultät} + Berechnen Sie ohne Hilfsmittel: + \begin{itemize} + \item[(j)] + 750$_8$ \& 666$_8$ + \item[(k)] + A380$_{16}$ + B747$_{16}$ + \item[(l)] + AFFE$_{16} >> 1$ + \end{itemize} - Die Fakultät $n!$ einer ganzen Zahl $n \ge 0$ ist definiert als: - \begin{eqnarray*} - 1 & \mbox{für} & n = 0, \\ - n \cdot (n-1)! & \mbox{für} & n > 0. - \end{eqnarray*} + Die tiefgestellte Zahl steht für die Basis des Zahlensystems. + Jede Teilaufgabe zählt 1 Punkt. \addtocounter{points}{12} - Mit anderen Worten: $n! = 1\cdot2\cdot3\cdot\dots\cdot n$. + (In der Klausur sind Hilfsmittel zugelassen, + daher ist dies \emph{keine\/} typische Klausuraufgabe.) - Die folgende Funktion \lstinline{fak()} berechnet die Fakultät \emph{rekursiv} - (Datei: \gitfile{hp}{2020ws/20210107}{aufgabe-1.c}): + \solution - \begin{lstlisting} - int fak (int n) - { - if (n <= 0) - return 1; - else - return n * fak (n - 1); - } - \end{lstlisting} + Wandeln Sie ohne Hilfsmittel - \begin{enumerate}[\quad(a)] - \item - Schreiben Sie eine Funktion, die die Fakultät \emph{iterativ} berechnet,\\ - d.\,h.\ mit Hilfe einer Schleife anstelle von Rekursion. - \points{3} + \begin{itemize} \item - Wie viele Multiplikationen (Landau-Symbol) - erfordern beide Versionen der Fakultätsfunktion\\ - in Abhängigkeit von \lstinline$n$? - Begründen Sie Ihre Antwort. - \points{2} + nach Dezimal: + \begin{itemize} + \item[(a)] + $0010\,0000_2 = 32_{10}$ + + Eine Eins mit fünf Nullen dahinter steht binär für $2^5 = 32$:\\ + mit $1$ anfangen und fünfmal verdoppeln. + \item[(b)] + $42_{16} = 4 \cdot 16 + 2 \cdot 1 = 64 + 2 = 66$ + \item[(c)] + $17_8 = 1 \cdot 8 + 7 \cdot 1 = 8 + 7 = 15$ + \end{itemize} + Umwandlung von und nach Dezimal ist immer rechenaufwendig. + Umwandlungen zwischen Binär, Oktal und Hexadezimal gehen ziffernweise + und sind daher wesentlich einfacher. \item - Wieviel Speicherplatz (Landau-Symbol) - erfordern beide Versionen der Fakultätsfunktion\\ - in Abhängigkeit von \lstinline$n$? - Begründen Sie Ihre Antwort. - \points{3} - \end{enumerate} + nach Hexadezimal: + \begin{itemize} + \item[(d)] + $0010\,0000_2 = 20_{16}$ - \solution + Umwandlung von Binär nach Hexadezimal geht ziffernweise:\\ + Vier Binärziffern werden zu einer Hex-Ziffer. + \item[(e)] + $\rm 42_{10} = 32_{10} + 10_{10} = 20_{16} + A_{16} = 2A_{16}$ + \item[(f)] + $\rm 192.168.20.254_{256} = C0\,A8\,14\,FE_{16}$ - \begin{itemize} - \item[(a)] - \textbf{Schreiben Sie eine Funktion, die die Fakultät \emph{iterativ} berechnet,\\ - d.\,h.\ mit Hilfe einer Schleife anstelle von Rekursion.} + Umwandlung von der Basis 256 nach Hexadezimal geht ziffernweise:\\ + Eine 256er-Ziffer wird zu zwei Hex-Ziffern. - Datei: \gitfile{hp}{2020ws/20210107}{loesung-1.c} - \begin{lstlisting}[gobble=8] - int fak (int n) - { - int f = 1; - for (int i = 2; i <= n; i++) - f *= i; - return f; - } - \end{lstlisting} + Da die 256er-Ziffern dezimal angegeben sind, + müssen wir viermal Dezimal nach Hexadezimal umwandeln. + Hierfür bieten sich unterschiedliche Wege an. - \item[(b)] - \textbf{Wie viele Multiplikationen (Landau-Symbol) - erfordern beide Versionen der Fakultätsfunktion\\ - in Abhängigkeit von \lstinline$n$? - Begründen Sie Ihre Antwort.} + $\rm 192_{10} = 128_{10} + 64_{10} = 1100\,0000_{2} = C0_{16}$ - In beiden Fällen werden $n$ Zahlen miteinander multipliziert -- - oder $n - 1$, wenn man Multiplikationen mit 1 ausspart. - In jedem Fall hängt die Anzahl der Multiplikationen - linear von $n$ ab; es sind $\mathcal{O}(n)$ Multiplikationen. - Insbesondere arbeiten also beide Versionen gleich schnell. + $\rm 168_{10} = 10_{10} \cdot 16_{10} + 8_{10} = A_{16} \cdot 10_{16} + 8_{16} = A8_{16}$ - \item[(c)] - \textbf{Wieviel Speicherplatz (Landau-Symbol) - erfordern beide Versionen der Fakultätsfunktion\\ - in Abhängigkeit von \lstinline$n$? - Begründen Sie Ihre Antwort.} - - Die iterative Version der Funktion benötigt 2 Variable vom Typ \lstinline{int}, - nämlich \lstinline{n} und \lstinline{f}. - Dies ist eine konstante Zahl; - der Speicherplatzverbrauch ist daher $\mathcal{O}(1)$. - - Die rekursive Version der Funktion erzeugt - jedesmal, wenn sie sich selbst aufruft, - eine zusätzliche Variable \lstinline{n}. - Es sind $n + 1$ Aufrufe; die Anzahl der Variablen \lstinline{n} - hängt linear von $n$ ab; der Speicherplatzverbrauch ist also $\mathcal{O}(n)$. + $20_{10} = 16_{10} + 4_{10} = 10_{16} + 4_{16} = 14$ + + $\rm 254_{10} = 255_{10} - 1_{10} = FF_{16} - 1_{16} = FE_{16}$ + \end{itemize} + \item + nach Binär: + \begin{itemize} + \item[(g)] + $750_8 = 111\,101\,000_2$ + + Umwandlung von Oktal nach Binär geht ziffernweise:\\ + Eine Oktalziffer wird zu drei Binärziffern. + \item[(h)] + $\rm 42_{10} = 2A_{16}$ (siehe oben) $= 0010\,1010_{16}$ + + Umwandlung von Hexadezimal nach Binär geht ziffernweise:\\ + Eine Hex-Ziffer wird zu vier Binärziffern. + \item[(i)] + $\rm AFFE_{16} = 1010\,1111\,1111\,1110_2$ + + Umwandlung von Hexadezimal nach Binär geht ziffernweise:\\ + Eine Hex-Ziffer wird zu vier Binärziffern. + \end{itemize} \end{itemize} - - \exercise{Länge von Strings} - - Diese Aufgabe ist eine Neuauflage von Aufgabe 3 der - Übung vom 14.\ November 2019,\\ - ergänzt um die Teilaufgaben (f) und (g). - + \medskip - Strings werden in der Programmiersprache C durch Zeiger auf \lstinline{char}-Variable realisiert. - - Beispiel: \lstinline{char *hello_world = "Hello, world!\n"} - - Die Systembibliothek stellt eine Funktion \lstinline{strlen()} zur Ermittlung der Länge von Strings\\ - zur Verfügung (\lstinline{#include <string.h>}). - - \begin{enumerate}[\quad(a)] - \item - Auf welche Weise ist die Länge eines Strings gekennzeichnet? - \points{1} - \item - Wie lang ist die Beispiel-String-Konstante \lstinline{"Hello, world!\n"}, - und wieviel Speicherplatz belegt sie?\\ - \points{2} - \item - Schreiben Sie eine eigene Funktion \lstinline{int strlen (char *s)}, - die die Länge eines Strings zurückgibt.\\ - \points{3} - \end{enumerate} + Berechnen Sie ohne Hilfsmittel: + \begin{itemize} + \item[(j)] + $750_8\,\&\,666_8 + = 111\,101\,000_2\,\&\,110\,110\,110_2 + = 110\,100\,000_2 + = 640_8$ + + Binäre Und-Operationen lassen sich am leichtesten + in binärer Schreibweise durchführen. + Umwandlung zwischen Oktal und Binär geht ziffernweise: + Eine Oktalziffer wird zu drei Binärziffern und umgekehrt. + + Mit etwas Übung funktionieren diese Operationen + auch direkt mit Oktalzahlen im Kopf. + + \item[(k)] + $\rm\phantom{+}A380_{16}$\\ + $\rm+\kern2ptB747_{16}$\\[-\medskipamount] + \rule{1.4cm}{0.5pt}\\ + $\rm 15AC7_{16}$ + \begin{picture}(0,0) + \put(-1.4,0.35){\mbox{\scriptsize\bf 1}} + \end{picture} + + Mit Hexadezimalzahlen (und Binär- und Oktal- und sonstigen Zahlen) + kann man genau wie mit Dezimalzahlen schriftlich rechnen. + Man muß nur daran denken, daß der "`Zehner"'-Überlauf nicht bei + $10_{10}$ stattfindet, sondern erst bei $10_{16} = 16_{10}$ + (hier: $\rm 8_{16} + 4_{16} = C_{16}$ und + $\rm 3_{16} + 7_{16} = A_{16}$, aber + $\rm A_{16} + B_{16} = 10_{10} + 11_{10} + = 21_{10} = 16_{10} + 5_{10} = 10_{16} + 5_{16} = 15_{16}$). + + \item[(l)] + $\rm AFFE_{16} >> 1 + = 1010\,1111\,1111\,1110_2 >> 1 + = 0101\,0111\,1111\,1111_2 + = 57FF_{16}$ + + Bit-Verschiebungen lassen sich am leichtesten + in binärer Schreibweise durchführen. + Umwandlung zwischen Hexadezimal und Binär geht ziffernweise: + Eine Hex-Ziffer wird zu vier Binärziffern und umgekehrt. + + Mit etwas Übung funktionieren diese Operationen + auch direkt mit Hexadezimalzahlen im Kopf. - \goodbreak + \end{itemize} - Wir betrachten nun die folgenden Funktionen (Datei: \gitfile{hp}{2020ws/20210107}{aufgabe-2.c}): - \begin{center} - \begin{minipage}{8cm} - \begin{lstlisting}[gobble=8] - int fun_1 (char *s) - { - int x = 0; - for (int i = 0; i < strlen (s); i++) - x += s[i]; - return x; - } - \end{lstlisting} - \end{minipage}% - \begin{minipage}{6cm} - \vspace*{-1cm} - \begin{lstlisting}[gobble=8] - int fun_2 (char *s) - { - int i = 0, x = 0; - int len = strlen (s); - while (i < len) - x += s[i++]; - return x; - } - \end{lstlisting} - \vspace*{-1cm} - \end{minipage} - \end{center} - \begin{enumerate}[\quad(a)]\setcounter{enumi}{3} - \item - Was bewirken die beiden Funktionen? - \points{2} - \item - Schreiben Sie eine eigene Funktion, - die dieselbe Aufgabe erledigt wie \lstinline{fun_2()},\\ - nur effizienter. - \points{4} - \item - Von welcher Ordnung (Landau-Symbol) sind die beiden Funktionen - hinsichtlich der Anzahl ihrer Zugriffe auf die Zeichen im String? - Begründen Sie Ihre Antwort. - Sie dürfen für \lstinline{strlen()} Ihre eigene Version der Funktion voraussetzen. - \points{3} - \item - Von welcher Ordnung (Landau-Symbol) ist Ihre effizientere Funktion?\\ - Begründen Sie Ihre Antwort. - \points{1} - \end{enumerate} + \exercise{Mikrocontroller} + + \begin{minipage}[t]{10cm} + An die vier Ports eines ATmega16-Mikrocontrollers sind Leuchtdioden angeschlossen: + \begin{itemize} + \item + von links nach rechts an die Ports A, B, C und D, + \item + von oben nach unten an die Bits Nr.\ 0 bis 7. + \end{itemize} + + Wir betrachten das folgende Programm (\gitfile{hp}{2020ws/20210114}{aufgabe-2.c}): + + \begin{lstlisting}[gobble=6] + #include <avr/io.h> + + int main (void) + { + DDRA = 0xff; + DDRB = 0xff; + DDRC = 0xff; + DDRD = 0xff; + PORTA = 0x1f; + PORTB = 0x10; + PORTD = 0x10; + PORTC = 0xfc; + while (1); + return 0; + } + \end{lstlisting} + \end{minipage}\hfill + \begin{minipage}[t]{3cm} + \strut\\[-\baselineskip] + \includegraphics[width=3cm]{leds.jpg} + \end{minipage} + + \vspace*{-3cm} + + \strut\hfill + \begin{minipage}{11.8cm} + \begin{itemize} + \item[(a)] + Was bewirkt dieses Programm? \points{4} + \item[(b)] + Wozu dienen die ersten vier Zeilen des Hauptprogramms? \points{2} + \item[(c)] + Was würde stattdessen die Zeile \lstinline{DDRA, DDRB, DDRC, DDRD = 0xff;} bewirken? + \points{2} + \item[(d)] + Schreiben Sie das Programm so um, + daß die durch das Programm dargestellte Figur spiegelverkehrt erscheint. \points{3} + \item[(e)] + Wozu dient das \lstinline{while (1)}? \points{2} + \item + Alle Antworten bitte mit Begründung. + \end{itemize} + \end{minipage} \solution \begin{itemize} \item[(a)] - \textbf{Auf welche Weise ist die Länge eines Strings gekennzeichnet?} - - Ein String ist ein Array von \lstinline{char}s. - Nach den eigentlichen Zeichen des Strings enthält das Array - \textbf{ein Null-Symbol} (Zeichen mit Zahlenwert 0, - nicht zu verwechseln mit der Ziffer \lstinline{'0'}) als Ende-Markierung. - Die Länge eines Strings ist die Anzahl der Zeichen - \emph{vor\/} diesem Symbol. + \textbf{Was bewirkt dieses Programm?} + + \newcommand{\x}{$\bullet$} + \renewcommand{\o}{$\circ$} + + \begin{minipage}[t]{0.75\textwidth}\parskip\smallskipamount + Es läßt die LEDs in dem rechts abgebildeten Muster aufleuchten,\\ + das z.\,B.\ als die Ziffer 4 gelesen werden kann. + + (Das Zeichen \x\ steht für eine leuchtende, \o\ für eine nicht leuchtende LED.) + + Die erste Spalte (Port A) von unten nach oben gelesen (Bit 7 bis 0)\\ + entspricht der Binärdarstellung von \lstinline{0x1f}: 0001\,1111. + + Die dritte Spalte (Port C) von unten nach oben gelesen (Bit 7 bis 0)\\ + entspricht der Binärdarstellung von \lstinline{0xfc}: 1111\,1100. + + Die zweite und vierte Spalte (Port B und D) von unten nach oben gelesen\\ + (Bit 7 bis 0) entsprechen der Binärdarstellung von \lstinline{0x10}: 0001\,0000. + + Achtung: Die Zuweisung der Werte an die Ports erfolgt im Programm\\ + \emph{nicht\/} in der Reihenfolge A B C D, sondern in der Reihenfolge A B D C. + \end{minipage}\hfill + \begin{minipage}[t]{0.15\textwidth} + \vspace*{-0.5cm}% + \begin{tabular}{cccc} + \x & \o & \o & \o \\ + \x & \o & \o & \o \\ + \x & \o & \x & \o \\ + \x & \o & \x & \o \\ + \x & \x & \x & \x \\ + \o & \o & \x & \o \\ + \o & \o & \x & \o \\ + \o & \o & \x & \o \\ + \end{tabular} + \end{minipage} \item[(b)] - {\bf Wie lang ist die Beispiel-String-Konstante \lstinline{"Hello, world!\n"}, - und wieviel Speicherplatz belegt sie?} + \textbf{Wozu dienen die ersten vier Zeilen des Hauptprogramms?} - Sie ist 14 Zeichen lang (\lstinline{'\n'} ist nur 1 Zeichen; - das Null-Symbol, das das Ende markiert, zählt hier nicht mit) - und belegt Speicherplatz für 15 Zeichen - (15 Bytes -- einschließlich Null-Symbol / Ende-Markierung). + Mit diesen Zeilen werden alle jeweils 8 Bits aller 4 Ports + als Output-Ports konfiguriert. \item[(c)] - \textbf{Schreiben Sie eine eigene Funktion \lstinline{int strlen (char *s)}, - die die Länge eines Strings zurückgibt.} + \textbf{Was würde stattdessen die Zeile \lstinline{DDRA, DDRB, DDRC, DDRD = 0xff;} bewirken?} - Siehe die Dateien \gitfile{hp}{2020ws/20210107}{loesung-2c-1.c} (mit Array-Index) - und \gitfile{hp}{2020ws/20210107}{loesung-2c-2.c} (mit Zeiger-Arithmetik). - Beide Lösungen sind korrekt und arbeiten gleich schnell. + Der Komma-Operator in C bewirkt, daß der erste Wert berechnet + und wieder verworfen wird und stattdessen der zweite Wert weiterverarbeitet wird. + Konkret hier hätte das zur Folge, + daß \lstinline{DDRA}, \lstinline{DDRB} und \lstinline{DDRC} + gelesen und die gelesenen Werte ignoriert werden; + anschließend wird \lstinline{DDRD} der Wert \lstinline{0xff} zugewiesen. + Damit würde also nur einer von vier Ports überhaupt konfiguriert. - Die Warnung \lstinline[style=terminal]{conflicting types for built-in function "strlen"} - kann normalerweise ignoriert werden; - auf manchen Systemen (z.\,B.\ MinGW) hat jedoch die eingebaute Funktion \lstinline{strlen()} - beim Linken Vorrang vor der selbstgeschriebenen, - so daß die selbstgeschriebene Funktion nie aufgerufen wird. - In solchen Fällen ist es zulässig, die selbstgeschriebene Funktion - anders zu nennen (z.\,B.\ \lstinline{my_strlen()}). + Da es sich bei den \lstinline{DDR}-Variablen + um \lstinline{volatile}-Variable handelt, + nimmt der Compiler an, daß der Lesezugriff schon irgendeinen Sinn hätte. + Der Fehler bliebe also unbemerkt. \item[(d)] - \textbf{Was bewirken die beiden Funktionen?} + \textbf{Schreiben Sie das Programm so um, + daß die durch das Programm dargestellte Figur spiegelverkehrt erscheint.} - Beide addieren die Zahlenwerte der im String enthaltenen Zeichen - und geben die Summe als Funktionsergebnis zurück. + Hierzu vertauschen wir die Zuweisungen + an \lstinline{PORTA} und \lstinline{PORTD} + sowie die Zuweisungen + an \lstinline{PORTB} und \lstinline{PORTC}: - Im Falle des Test-Strings \lstinline{"Hello, world!\n"} - lautet der Rückgabewert 1171 (siehe \gitfile{hp}{2020ws/20210107}{loesung-2d-1.c} und \gitfile{hp}{2020ws/20210107}{loesung-2d-2.c}). + \begin{lstlisting}[gobble=8] + PORTD = 0x1f; + PORTC = 0x10; + PORTA = 0x10; + PORTB = 0xfc; + \end{lstlisting} + + Damit ergibt sich eine Spiegelung an der vertikalen Achse. + + Alternativ kann man auch an der horizontalen Achse spiegeln. + Dafür muß man die Bits in den Hexadezimalzahlen umdrehen: + + \begin{lstlisting}[gobble=8] + PORTA = 0xf8; + PORTB = 0x08; + PORTD = 0x08; + PORTC = 0x3f; + \end{lstlisting} + + Die Frage, welche der beiden Spiegelungen gewünscht ist, + wäre übrigens \emph{auch in der Klausur zulässig}. \item[(e)] - \textbf{Schreiben Sie eine eigene Funktion, - die dieselbe Aufgabe erledigt wie \lstinline{fun_2()}, - nur effizienter.} - - Die Funktion wird effizienter, - wenn man auf den Aufruf von \lstinline{strlen()} verzichtet - und stattdessen die Ende-Prüfung in derselben Schleife vornimmt, - in der man auch die Zahlenwerte der Zeichen des Strings aufsummiert. - - Die Funktion \lstinline{fun_3()} in der Datei \gitfile{hp}{2020ws/20210107}{loesung-2e-1.c} - realisiert dies mit einem Array-Index, - Die Funktion \lstinline{fun_4()} in der Datei \gitfile{hp}{2020ws/20210107}{loesung-2e-2.c} - mit Zeiger-Arithmetik. - Beide Lösungen sind korrekt und arbeiten gleich schnell. - - \textbf{Bemerkung:} Die effizientere Version der Funktion - arbeitet doppelt so schnell wie die ursprüngliche, - hat aber ebenfalls die Ordnung $\mathcal{O}(n)$ -- siehe unten. - - \item[(f)] - \textbf{Von welcher Ordnung (Landau-Symbol) sind die beiden Funktionen - hinsichtlich der Anzahl ihrer Zugriffe auf die Zeichen im String? - Begründen Sie Ihre Antwort. - Sie dürfen für \lstinline{strlen()} Ihre eigene Version der Funktion voraussetzen.} - - Vorüberlegung: \lstinline{strlen()} greift in einer Schleife - auf alle Zeichen des Strings der Länge $n$ zu, - hat also $\mathcal{O}(n)$. - - \lstinline{fun_1()} ruft in jedem Schleifendurchlauf - (zum Prüfen der \lstinline{while}-Bedingung) einmal \lstinline{strlen()} auf - und greift anschließend auf ein Zeichen des Strings zu, - hat also $\mathcal{O}\bigl(n\cdot(n+1)\bigr) = \mathcal{O}(n^2)$. - - \lstinline{fun_2()} ruft einmalig \lstinline{strlen()} auf - und greift anschließend in einer Schleife auf alle Zeichen des Strings zu, - hat also $\mathcal{O}(n+n) = \mathcal{O}(n)$. - - \item[(g)] - \textbf{Von welcher Ordnung (Landau-Symbol) ist Ihre effizientere Funktion?\\ - Begründen Sie Ihre Antwort.} - - In beiden o.\,a.\ Lösungsvarianten - -- \gitfile{hp}{2020ws/20210107}{loesung-2e-1.c} - und \gitfile{hp}{2020ws/20210107}{loesung-2e-2.c} -- - arbeitet die Funktion mit einer einzigen Schleife, - die gleichzeitig die Zahlenwerte addiert und das Ende des Strings sucht. - - Mit jeweils einer einzigen Schleife - haben beide Funktionen die Ordnung $\mathcal{O}(n)$. + \textbf{Wozu dient das \lstinline{while (1)}?} - \end{itemize} + Mit dem \lstinline{return}-Befehl am Ende des Hauptprogramms + gibt das Programm die Kontrolle an das Betriebssystem zurück. - \exercise{Hexdumps} - - Das folgende Programm (\gitfile{hp}{2020ws/20210107}{aufgabe-2.c}) liest - einen String ein und gibt die ASCII-Werte der Buchstaben hexadezimal aus. - (Anders als z.\,B.\ \lstinline{scanf()} - akzeptiert die Funktion \lstinline{fgets()} zum Lesen von Strings auch Leerzeichen, - und sie vermeidet Pufferüberläufe.) - \begin{lstlisting}[style=numbered] - #include <stdio.h> - - int main (void) - { - char buffer[100]; - fgets (buffer, 100, stdin); - for (char *p = buffer; *p; p++) - printf ("%02x", *p); - printf ("\n"); - } - \end{lstlisting} - Beispiel: Bei der Eingabe von \lstinline[style=cmd]{Dies ist ein Test.} - erscheint die Ausgabe\\ - \lstinline[style=terminal]{44696573206973742065696e20546573742e0a}. - - Schreiben Sie ein Programm, das diese Umwandlung in umgekehrter Richtung vornimmt, - also z.\,B.\ bei Eingabe von \lstinline[style=cmd]{44696573206973742065696e20546573742e0a} - wieder \lstinline[style=terminal]{Dies ist ein Test.} ausgibt. - - \points{6} - - Hinweis für die Klausur: - Abgabe in digitaler Form ist erwünscht, aber nicht zwingend. + Dieses Programm jedoch läuft auf einem Mikrocontroller, + auf dem es kein Betriebssystem gibt. + Wenn das \lstinline{return} ausgeführt würde, + hätte es ein undefiniertes Verhalten zur Folge. - \solution + Um dies zu verhindern, endet das Programm in einer Endlosschleife, + mit der wir den Mikrocontroller anweisen, + nach der Ausführung des Programms \emph{nichts mehr\/} zu tun + (im Gegensatz zu: \emph{irgendetwas Undefiniertes\/} zu tun). - Siehe \gitfile{hp}{2020ws/20210107}{loesung-2.c}. - - Das Programm macht mehrfach davon Gebrauch, - daß in C Zeichen und Zahlen äquivalent sind. - Wenn z.\,B.\ die \lstinline{char}-Variable \lstinline{c} - den Wert \lstinline{'3'} (Ziffer 3) enthält, - dann hat der Ausdruck \lstinline{c - '0'} den Wert \lstinline{3} (Zahlenwert 3). - Hierfür ist es insbesondere nicht nötig, vorauszusetzen, - daß wir den ASCII-Zeichensatz verwenden und \lstinline{'0'} - den Wert \lstinline{48} hat. - - Bei Eingabe von \lstinline[style=cmd]{44696573206973742065696e20546573742e0a} - gibt das Programm zusätzlich eine Leerzeile aus. - Die liegt daran, daß das \lstinline[style=cmd]{0a} am Ende - bereits eine Zeilenschaltung enthält und das Programm mit - \lstinline{printf ("\n")} eine zusätzliche Zeilenschaltung ausgibt. + \end{itemize} \end{document} diff --git a/20210114/hp-uebung-20210114.pdf b/20210114/hp-uebung-20210114.pdf index 9afd3ffcd9d2f7db7bdc28cf1ebfeb186060650d..0ae342976a00e5c500c3c9a39d463bd4650869f9 100644 Binary files a/20210114/hp-uebung-20210114.pdf and b/20210114/hp-uebung-20210114.pdf differ diff --git a/20210114/hp-uebung-20210114.tex b/20210114/hp-uebung-20210114.tex index c1af612e29887e3ab2b8c650a00a5e526fcc368c..eb358f56632229ddaa946ea6b758195c0785c8dc 100644 --- a/20210114/hp-uebung-20210114.tex +++ b/20210114/hp-uebung-20210114.tex @@ -114,7 +114,7 @@ von oben nach unten an die Bits Nr.\ 0 bis 7. \end{itemize} - Wir betrachten das folgende Programm (\gitfile{hp}{2019ws/20191121}{aufgabe-2.c}): + Wir betrachten das folgende Programm (\gitfile{hp}{2020ws/20210114}{aufgabe-2.c}): \begin{lstlisting}[gobble=6] #include <avr/io.h> @@ -161,105 +161,6 @@ \end{itemize} \end{minipage} - \exercise{LED-Blinkmuster} - - Wir betrachten das folgende Programm für einen ATmega32-Mikro-Controller - (Datei: \gitfile{hp}{2019ws/20191128}{aufgabe-3.c}). - - \begin{minipage}[t]{7cm} - \begin{lstlisting}[gobble=6] - #include <stdint.h> - #include <avr/io.h> - #include <avr/interrupt.h> - - uint8_t counter = 1; - uint8_t leds = 0; - - ISR (TIMER0_COMP_vect) - { - if (counter == 0) - { - leds = (leds + 1) % 8; - PORTC = leds << 4; - } - counter++; - } - \end{lstlisting} - \end{minipage}\hfill\begin{minipage}[t]{8.5cm} - \begin{lstlisting}[gobble=6] - void init (void) - { - cli (); - TCCR0 = (1 << CS01) | (1 << CS00); - TIMSK = 1 << OCIE0; - sei (); - DDRC = 0x70; - } - - int main (void) - { - init (); - while (1) - ; /* do nothing */ - return 0; - } - \end{lstlisting} - \end{minipage} - - An die Bits Nr.\ 4, 5 und 6 des Output-Ports C des Mikro-Controllers sind LEDs angeschlossen.\\ - Sobald das Programm läuft, blinken diese in charakteristischer Weise: - \begin{quote} - \newcommand{\tdn}[1]{\raisebox{-2pt}{#1}} - \begin{tabular}{|c|c|c|c|}\hline - \tdn{Phase} & \tdn{LED oben (rot)} & \tdn{LED Mitte (gelb)} & \tdn{LED unten (grün)} \\[2pt]\hline - 1 & aus & aus & an \\\hline - 2 & aus & an & aus \\\hline - 3 & aus & an & an \\\hline - 4 & an & aus & aus \\\hline - 5 & an & aus & an \\\hline - 6 & an & an & aus \\\hline - 7 & an & an & an \\\hline - 8 & aus & aus & aus \\\hline - \end{tabular} - \end{quote} - Jede Phase dauert etwas länger als eine halbe Sekunde. - Nach 8 Phasen wiederholt sich das Schema. - - Erklären Sie das Verhalten des Programms anhand des Quelltextes: - \vspace{-\medskipamount} - \begin{itemize}\itemsep0pt - \item[(a)] - Wieso macht das Programm überhaupt etwas, - wenn doch das Hauptprogramm nach dem Initialisieren lediglich eine Endlosschleife ausführt, - in der \emph{nichts} passiert? - \points{1} - \item[(b)] - Wieso wird die Zeile \lstinline|PORTC = leds << 4;| überhaupt aufgerufen, - wenn dies doch nur unter der Bedingung \lstinline|counter == 0| passiert, - wobei die Variable \lstinline|counter| auf 1 initialisiert, - fortwährend erhöht und nirgendwo zurückgesetzt wird? - \points{2} - \item[(c)] - Wie kommt das oben beschriebene Blinkmuster zustande? - \points{2} - \item[(d)] - Wieso dauert eine Phase ungefähr eine halbe Sekunde? - \points{2} - \item[(e)] - Was bedeutet "`\lstinline|ISR (TIMER0_COMP_vect)|"'? - \points{1} - \end{itemize} - - Hinweis: - \vspace{-\medskipamount} - \begin{itemize}\itemsep0pt - \item - Die Funktion \lstinline|init()| sorgt dafür, daß der Timer-Interrupt Nr.\ 0 des Mikro-Controllers - etwa 488mal pro Sekunde aufgerufen wird. - Außerdem initialisiert sie die benötigten Bits an Port C als Output-Ports. - Sie selbst brauchen die Funktion \lstinline|init()| nicht weiter zu erklären. - \end{itemize} - \begin{flushright} \textit{Viel Erfolg!} \end{flushright}