Skip to content
Snippets Groups Projects
Commit 86f48253 authored by Peter Gerwinski's avatar Peter Gerwinski
Browse files

weitere Beispiele; download.sh; Übung und Musterlösung überarbeitet 14.1.2021

parent 892b3fb0
Branches
No related tags found
No related merge requests found
#include <avr/io.h>
int main (void)
{
DDRD = 0x7c; /* binär: 0111 1100 */
PORTD = 0x41; /* binär: 0100 0001 */
while (1);
return 0;
}
#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;
}
#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;
}
#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;
}
#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;
}
#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;
}
#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;
}
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
% 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 % Copyright (C) 2013, 2015, 2016, 2017, 2018, 2019, 2020, 2021 Peter Gerwinski
% %
% This document is free software: you can redistribute it and/or % This document is free software: you can redistribute it and/or
...@@ -20,7 +20,7 @@ ...@@ -20,7 +20,7 @@
% Attribution-ShareAlike 3.0 Unported License along with this % Attribution-ShareAlike 3.0 Unported License along with this
% document. If not, see <http://creativecommons.org/licenses/>. % document. If not, see <http://creativecommons.org/licenses/>.
% README: Fakultät, Länge von Strings (Neuauflage), Hexdumps % README: Zahlensysteme, Mikrocontroller
\documentclass[a4paper]{article} \documentclass[a4paper]{article}
...@@ -30,328 +30,363 @@ ...@@ -30,328 +30,363 @@
\begin{document} \begin{document}
\section*{Hardwarenahe Programmierung\\ \section*{Hardwarenahe Programmierung\\
Musterlösung zu den Übungsaufgaben -- 7.\ Januar 2021} Musterlösung zu den Übungsaufgaben -- 14.\ Januar 2021}
\exercise{Fakultät} \exercise{Zahlensysteme}
Die Fakultät $n!$ einer ganzen Zahl $n \ge 0$ ist definiert als: Wandeln Sie ohne Hilfsmittel
\begin{eqnarray*}
1 & \mbox{für} & n = 0, \\
n \cdot (n-1)! & \mbox{für} & n > 0.
\end{eqnarray*}
Mit anderen Worten: $n! = 1\cdot2\cdot3\cdot\dots\cdot n$. \begin{minipage}[t]{0.3\textwidth}
\begin{itemize}
Die folgende Funktion \lstinline{fak()} berechnet die Fakultät \emph{rekursiv}
(Datei: \gitfile{hp}{2020ws/20210107}{aufgabe-1.c}):
\begin{lstlisting}
int fak (int n)
{
if (n <= 0)
return 1;
else
return n * fak (n - 1);
}
\end{lstlisting}
\begin{enumerate}[\quad(a)]
\item \item
Schreiben Sie eine Funktion, die die Fakultät \emph{iterativ} berechnet,\\ nach Dezimal:
d.\,h.\ mit Hilfe einer Schleife anstelle von Rekursion. \begin{itemize}
\points{3} \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 \item
Wie viele Multiplikationen (Landau-Symbol) nach Hexadezimal:
erfordern beide Versionen der Fakultätsfunktion\\ \begin{itemize}
in Abhängigkeit von \lstinline$n$? \item[(d)]
Begründen Sie Ihre Antwort. 0010\,0000$_2$
\points{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 \item
Wieviel Speicherplatz (Landau-Symbol) nach Binär:
erfordern beide Versionen der Fakultätsfunktion\\ \begin{itemize}
in Abhängigkeit von \lstinline$n$? \item[(g)]
Begründen Sie Ihre Antwort. 750$_8$
\points{3} \item[(h)]
\end{enumerate} 42$_{10}$
\item[(i)]
AFFE$_{16}$
\end{itemize}
\end{itemize}
\end{minipage}
\medskip
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 tiefgestellte Zahl steht für die Basis des Zahlensystems.
Jede Teilaufgabe zählt 1 Punkt. \addtocounter{points}{12}
(In der Klausur sind Hilfsmittel zugelassen,
daher ist dies \emph{keine\/} typische Klausuraufgabe.)
\solution \solution
Wandeln Sie ohne Hilfsmittel
\begin{itemize}
\item
nach Dezimal:
\begin{itemize} \begin{itemize}
\item[(a)] \item[(a)]
\textbf{Schreiben Sie eine Funktion, die die Fakultät \emph{iterativ} berechnet,\\ $0010\,0000_2 = 32_{10}$
d.\,h.\ mit Hilfe einer Schleife anstelle von Rekursion.}
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}
Eine Eins mit fünf Nullen dahinter steht binär für $2^5 = 32$:\\
mit $1$ anfangen und fünfmal verdoppeln.
\item[(b)] \item[(b)]
\textbf{Wie viele Multiplikationen (Landau-Symbol) $42_{16} = 4 \cdot 16 + 2 \cdot 1 = 64 + 2 = 66$
erfordern beide Versionen der Fakultätsfunktion\\ \item[(c)]
in Abhängigkeit von \lstinline$n$? $17_8 = 1 \cdot 8 + 7 \cdot 1 = 8 + 7 = 15$
Begründen Sie Ihre Antwort.} \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
nach Hexadezimal:
\begin{itemize}
\item[(d)]
$0010\,0000_2 = 20_{16}$
In beiden Fällen werden $n$ Zahlen miteinander multipliziert -- Umwandlung von Binär nach Hexadezimal geht ziffernweise:\\
oder $n - 1$, wenn man Multiplikationen mit 1 ausspart. Vier Binärziffern werden zu einer Hex-Ziffer.
In jedem Fall hängt die Anzahl der Multiplikationen \item[(e)]
linear von $n$ ab; es sind $\mathcal{O}(n)$ Multiplikationen. $\rm 42_{10} = 32_{10} + 10_{10} = 20_{16} + A_{16} = 2A_{16}$
Insbesondere arbeiten also beide Versionen gleich schnell. \item[(f)]
$\rm 192.168.20.254_{256} = C0\,A8\,14\,FE_{16}$
\item[(c)] Umwandlung von der Basis 256 nach Hexadezimal geht ziffernweise:\\
\textbf{Wieviel Speicherplatz (Landau-Symbol) Eine 256er-Ziffer wird zu zwei Hex-Ziffern.
erfordern beide Versionen der Fakultätsfunktion\\
in Abhängigkeit von \lstinline$n$? Da die 256er-Ziffern dezimal angegeben sind,
Begründen Sie Ihre Antwort.} müssen wir viermal Dezimal nach Hexadezimal umwandeln.
Hierfür bieten sich unterschiedliche Wege an.
Die iterative Version der Funktion benötigt 2 Variable vom Typ \lstinline{int},
nämlich \lstinline{n} und \lstinline{f}. $\rm 192_{10} = 128_{10} + 64_{10} = 1100\,0000_{2} = C0_{16}$
Dies ist eine konstante Zahl;
der Speicherplatzverbrauch ist daher $\mathcal{O}(1)$. $\rm 168_{10} = 10_{10} \cdot 16_{10} + 8_{10} = A_{16} \cdot 10_{16} + 8_{16} = A8_{16}$
Die rekursive Version der Funktion erzeugt $20_{10} = 16_{10} + 4_{10} = 10_{16} + 4_{16} = 14$
jedesmal, wenn sie sich selbst aufruft,
eine zusätzliche Variable \lstinline{n}. $\rm 254_{10} = 255_{10} - 1_{10} = FF_{16} - 1_{16} = FE_{16}$
Es sind $n + 1$ Aufrufe; die Anzahl der Variablen \lstinline{n}
hängt linear von $n$ ab; der Speicherplatzverbrauch ist also $\mathcal{O}(n)$.
\end{itemize} \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}$
\exercise{Länge von Strings} 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$
Diese Aufgabe ist eine Neuauflage von Aufgabe 3 der Umwandlung von Hexadezimal nach Binär geht ziffernweise:\\
Übung vom 14.\ November 2019,\\ Eine Hex-Ziffer wird zu vier Binärziffern.
ergänzt um die Teilaufgaben (f) und (g). \end{itemize}
\end{itemize}
\medskip \medskip
Strings werden in der Programmiersprache C durch Zeiger auf \lstinline{char}-Variable realisiert. 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.
Beispiel: \lstinline{char *hello_world = "Hello, world!\n"} \end{itemize}
Die Systembibliothek stellt eine Funktion \lstinline{strlen()} zur Ermittlung der Länge von Strings\\ \exercise{Mikrocontroller}
zur Verfügung (\lstinline{#include <string.h>}).
\begin{enumerate}[\quad(a)] \begin{minipage}[t]{10cm}
\item An die vier Ports eines ATmega16-Mikrocontrollers sind Leuchtdioden angeschlossen:
Auf welche Weise ist die Länge eines Strings gekennzeichnet? \begin{itemize}
\points{1}
\item \item
Wie lang ist die Beispiel-String-Konstante \lstinline{"Hello, world!\n"}, von links nach rechts an die Ports A, B, C und D,
und wieviel Speicherplatz belegt sie?\\
\points{2}
\item \item
Schreiben Sie eine eigene Funktion \lstinline{int strlen (char *s)}, von oben nach unten an die Bits Nr.\ 0 bis 7.
die die Länge eines Strings zurückgibt.\\ \end{itemize}
\points{3}
\end{enumerate}
\goodbreak Wir betrachten das folgende Programm (\gitfile{hp}{2020ws/20210114}{aufgabe-2.c}):
Wir betrachten nun die folgenden Funktionen (Datei: \gitfile{hp}{2020ws/20210107}{aufgabe-2.c}): \begin{lstlisting}[gobble=6]
\begin{center} #include <avr/io.h>
\begin{minipage}{8cm}
\begin{lstlisting}[gobble=8] int main (void)
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; DDRA = 0xff;
int len = strlen (s); DDRB = 0xff;
while (i < len) DDRC = 0xff;
x += s[i++]; DDRD = 0xff;
return x; PORTA = 0x1f;
PORTB = 0x10;
PORTD = 0x10;
PORTC = 0xfc;
while (1);
return 0;
} }
\end{lstlisting} \end{lstlisting}
\vspace*{-1cm} \end{minipage}\hfill
\begin{minipage}[t]{3cm}
\strut\\[-\baselineskip]
\includegraphics[width=3cm]{leds.jpg}
\end{minipage} \end{minipage}
\end{center}
\begin{enumerate}[\quad(a)]\setcounter{enumi}{3} \vspace*{-3cm}
\item
Was bewirken die beiden Funktionen? \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} \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 \item
Schreiben Sie eine eigene Funktion, Alle Antworten bitte mit Begründung.
die dieselbe Aufgabe erledigt wie \lstinline{fun_2()},\\ \end{itemize}
nur effizienter. \end{minipage}
\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}
\solution \solution
\begin{itemize} \begin{itemize}
\item[(a)] \item[(a)]
\textbf{Auf welche Weise ist die Länge eines Strings gekennzeichnet?} \textbf{Was bewirkt dieses Programm?}
Ein String ist ein Array von \lstinline{char}s. \newcommand{\x}{$\bullet$}
Nach den eigentlichen Zeichen des Strings enthält das Array \renewcommand{\o}{$\circ$}
\textbf{ein Null-Symbol} (Zeichen mit Zahlenwert 0,
nicht zu verwechseln mit der Ziffer \lstinline{'0'}) als Ende-Markierung. \begin{minipage}[t]{0.75\textwidth}\parskip\smallskipamount
Die Länge eines Strings ist die Anzahl der Zeichen Es läßt die LEDs in dem rechts abgebildeten Muster aufleuchten,\\
\emph{vor\/} diesem Symbol. 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)] \item[(b)]
{\bf Wie lang ist die Beispiel-String-Konstante \lstinline{"Hello, world!\n"}, \textbf{Wozu dienen die ersten vier Zeilen des Hauptprogramms?}
und wieviel Speicherplatz belegt sie?}
Sie ist 14 Zeichen lang (\lstinline{'\n'} ist nur 1 Zeichen; Mit diesen Zeilen werden alle jeweils 8 Bits aller 4 Ports
das Null-Symbol, das das Ende markiert, zählt hier nicht mit) als Output-Ports konfiguriert.
und belegt Speicherplatz für 15 Zeichen
(15 Bytes -- einschließlich Null-Symbol / Ende-Markierung).
\item[(c)] \item[(c)]
\textbf{Schreiben Sie eine eigene Funktion \lstinline{int strlen (char *s)}, \textbf{Was würde stattdessen die Zeile \lstinline{DDRA, DDRB, DDRC, DDRD = 0xff;} bewirken?}
die die Länge eines Strings zurückgibt.}
Siehe die Dateien \gitfile{hp}{2020ws/20210107}{loesung-2c-1.c} (mit Array-Index) Der Komma-Operator in C bewirkt, daß der erste Wert berechnet
und \gitfile{hp}{2020ws/20210107}{loesung-2c-2.c} (mit Zeiger-Arithmetik). und wieder verworfen wird und stattdessen der zweite Wert weiterverarbeitet wird.
Beide Lösungen sind korrekt und arbeiten gleich schnell. 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"} Da es sich bei den \lstinline{DDR}-Variablen
kann normalerweise ignoriert werden; um \lstinline{volatile}-Variable handelt,
auf manchen Systemen (z.\,B.\ MinGW) hat jedoch die eingebaute Funktion \lstinline{strlen()} nimmt der Compiler an, daß der Lesezugriff schon irgendeinen Sinn hätte.
beim Linken Vorrang vor der selbstgeschriebenen, Der Fehler bliebe also unbemerkt.
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()}).
\item[(d)] \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.
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}).
\item[(e)]
\textbf{Schreiben Sie eine eigene Funktion,
die dieselbe Aufgabe erledigt wie \lstinline{fun_2()},
nur effizienter.}
Die Funktion wird effizienter, Hierzu vertauschen wir die Zuweisungen
wenn man auf den Aufruf von \lstinline{strlen()} verzichtet an \lstinline{PORTA} und \lstinline{PORTD}
und stattdessen die Ende-Prüfung in derselben Schleife vornimmt, sowie die Zuweisungen
in der man auch die Zahlenwerte der Zeichen des Strings aufsummiert. an \lstinline{PORTB} und \lstinline{PORTC}:
Die Funktion \lstinline{fun_3()} in der Datei \gitfile{hp}{2020ws/20210107}{loesung-2e-1.c} \begin{lstlisting}[gobble=8]
realisiert dies mit einem Array-Index, PORTD = 0x1f;
Die Funktion \lstinline{fun_4()} in der Datei \gitfile{hp}{2020ws/20210107}{loesung-2e-2.c} PORTC = 0x10;
mit Zeiger-Arithmetik. PORTA = 0x10;
Beide Lösungen sind korrekt und arbeiten gleich schnell. PORTB = 0xfc;
\end{lstlisting}
\textbf{Bemerkung:} Die effizientere Version der Funktion Damit ergibt sich eine Spiegelung an der vertikalen Achse.
arbeitet doppelt so schnell wie die ursprüngliche,
hat aber ebenfalls die Ordnung $\mathcal{O}(n)$ -- siehe unten.
\item[(f)] Alternativ kann man auch an der horizontalen Achse spiegeln.
\textbf{Von welcher Ordnung (Landau-Symbol) sind die beiden Funktionen Dafür muß man die Bits in den Hexadezimalzahlen umdrehen:
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 \begin{lstlisting}[gobble=8]
auf alle Zeichen des Strings der Länge $n$ zu, PORTA = 0xf8;
hat also $\mathcal{O}(n)$. PORTB = 0x08;
PORTD = 0x08;
PORTC = 0x3f;
\end{lstlisting}
\lstinline{fun_1()} ruft in jedem Schleifendurchlauf Die Frage, welche der beiden Spiegelungen gewünscht ist,
(zum Prüfen der \lstinline{while}-Bedingung) einmal \lstinline{strlen()} auf wäre übrigens \emph{auch in der Klausur zulässig}.
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 \item[(e)]
und greift anschließend in einer Schleife auf alle Zeichen des Strings zu, \textbf{Wozu dient das \lstinline{while (1)}?}
hat also $\mathcal{O}(n+n) = \mathcal{O}(n)$.
\item[(g)] Mit dem \lstinline{return}-Befehl am Ende des Hauptprogramms
\textbf{Von welcher Ordnung (Landau-Symbol) ist Ihre effizientere Funktion?\\ gibt das Programm die Kontrolle an das Betriebssystem zurück.
Begründen Sie Ihre Antwort.}
In beiden o.\,a.\ Lösungsvarianten Dieses Programm jedoch läuft auf einem Mikrocontroller,
-- \gitfile{hp}{2020ws/20210107}{loesung-2e-1.c} auf dem es kein Betriebssystem gibt.
und \gitfile{hp}{2020ws/20210107}{loesung-2e-2.c} -- Wenn das \lstinline{return} ausgeführt würde,
arbeitet die Funktion mit einer einzigen Schleife, hätte es ein undefiniertes Verhalten zur Folge.
die gleichzeitig die Zahlenwerte addiert und das Ende des Strings sucht.
Mit jeweils einer einzigen Schleife Um dies zu verhindern, endet das Programm in einer Endlosschleife,
haben beide Funktionen die Ordnung $\mathcal{O}(n)$. 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).
\end{itemize} \end{itemize}
\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.
\solution
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{document} \end{document}
No preview for this file type
...@@ -114,7 +114,7 @@ ...@@ -114,7 +114,7 @@
von oben nach unten an die Bits Nr.\ 0 bis 7. von oben nach unten an die Bits Nr.\ 0 bis 7.
\end{itemize} \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] \begin{lstlisting}[gobble=6]
#include <avr/io.h> #include <avr/io.h>
...@@ -161,105 +161,6 @@ ...@@ -161,105 +161,6 @@
\end{itemize} \end{itemize}
\end{minipage} \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} \begin{flushright}
\textit{Viel Erfolg!} \textit{Viel Erfolg!}
\end{flushright} \end{flushright}
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment